UNPKG

@hippy/vue-native-components

Version:

Native components middleware for Hippy-Vue, the components only for native, can't compatible with web.

1,052 lines (1,042 loc) 40 kB
/*! * @hippy/vue-native-components v3.2.0-beta * (Using Vue v2.6.14 and Hippy-Vue v3.2.0-beta) * Build at: Fri Apr 25 2025 20:27:30 GMT+0800 (中国标准时间) * * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2025 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function registerAnimation(Vue) { // Constants for animations const DEFAULT_OPTION = { valueType: undefined, delay: 0, startValue: 0, toValue: 0, duration: 0, direction: 'center', timingFunction: 'linear', repeatCount: 0, inputRange: [], outputRange: [], }; /** * parse value of special value type * @param {string} valueType * @param {*} originalValue */ function parseValue(valueType, originalValue) { if (valueType === 'color' && ['number', 'string'].indexOf(typeof originalValue) >= 0) { return Vue.Native.parseColor(originalValue); } return originalValue; } /** * Create the standalone animation */ function createAnimation(option) { const { mode = 'timing', valueType, startValue, toValue, ...others } = option; const fullOption = { ...DEFAULT_OPTION, ...others, }; if (valueType !== undefined) { fullOption.valueType = option.valueType; } fullOption.startValue = parseValue(fullOption.valueType, startValue); fullOption.toValue = parseValue(fullOption.valueType, toValue); fullOption.repeatCount = repeatCountDict(fullOption.repeatCount); fullOption.mode = mode; const animation = new global.Hippy.Animation(fullOption); const animationId = animation.getId(); return { animation, animationId, }; } /** * Create the animationSet */ function createAnimationSet(children, repeatCount = 0) { const animation = new global.Hippy.AnimationSet({ children, repeatCount, }); const animationId = animation.getId(); return { animation, animationId, }; } function repeatCountDict(repeatCount) { if (repeatCount === 'loop') { return -1; } return repeatCount; } /** * Generate the styles from animation and animationSet Ids. */ function createStyle(actions, animationIdsMap = {}) { const style = {}; Object.keys(actions).forEach((key) => { if (Array.isArray(actions[key])) { // Process AnimationSet from Array. const actionSet = actions[key]; const { repeatCount } = actionSet[actionSet.length - 1]; const animationSetActions = actionSet.map((animationChild) => { const { animationId, animation } = createAnimation(Object.assign({}, animationChild, { repeatCount: 0 })); Object.assign(animationIdsMap, { [animationId]: animation, }); return { animationId, follow: true }; }); const { animationId, animation } = createAnimationSet(animationSetActions, repeatCountDict(repeatCount)); style[key] = { animationId, }; Object.assign(animationIdsMap, { [animationId]: animation, }); } else { // Process standalone Animation. const action = actions[key]; const { animationId, animation } = createAnimation(action); Object.assign(animationIdsMap, { [animationId]: animation, }); style[key] = { animationId, }; } }); return style; } /** * Get animationIds from style for start/pause/destroy actions. */ function getAnimationIds(style) { const { transform, ...otherStyles } = style; let animationIds = Object.keys(otherStyles).map(key => style[key].animationId); if (Array.isArray(transform) && transform.length > 0) { const transformIds = []; transform.forEach(entity => Object.keys(entity) .forEach((key) => { if (entity[key]) { const { animationId } = entity[key]; if (typeof animationId === 'number' && animationId % 1 === 0) { transformIds.push(animationId); } } })); animationIds = [...animationIds, ...transformIds]; } return animationIds; } /** * Register the animation component. */ Vue.component('Animation', { inheritAttrs: false, props: { tag: { type: String, default: 'div', }, playing: { type: Boolean, default: false, }, actions: { type: Object, required: true, }, props: Object, }, data() { return { style: {}, animationIds: [], animationIdsMap: {}, animationEventMap: {}, }; }, watch: { playing(to, from) { if (!from && to) { this.start(); } else if (from && !to) { this.pause(); } }, actions() { this.destroy(); this.create(); // trigger actionsDidUpdate in setTimeout callback to make sure node style updated setTimeout(() => { if (typeof this.$listeners.actionsDidUpdate === 'function') { this.$listeners.actionsDidUpdate(); } }); }, }, created() { this.animationEventMap = { start: 'animationstart', end: 'animationend', repeat: 'animationrepeat', cancel: 'animationcancel', }; }, beforeMount() { this.create(); }, mounted() { const { playing } = this.$props; if (playing) { // make sure that start animation after node created setTimeout(() => { this.start(); }, 0); } }, beforeDestroy() { this.destroy(); }, methods: { create() { const { actions: { transform, ...actions } } = this.$props; this.animationIdsMap = {}; const style = createStyle(actions, this.animationIdsMap); if (transform) { const transformAnimations = createStyle(transform, this.animationIdsMap); style.transform = Object.keys(transformAnimations).map(key => ({ [key]: transformAnimations[key], })); } // Turn to be true at first startAnimation, and be false again when destroyed. this.$alreadyStarted = false; // Generated style this.style = style; }, removeAnimationEvent() { this.animationIds.forEach((animationId) => { const animation = this.animationIdsMap[animationId]; if (!animation) return; Object.keys(this.animationEventMap).forEach((key) => { if (typeof this.$listeners[key] !== 'function') return; const eventName = this.animationEventMap[key]; if (!eventName) return; animation.removeEventListener(eventName); }); }); }, addAnimationEvent() { this.animationIds.forEach((animationId) => { const animation = this.animationIdsMap[animationId]; if (!animation) return; Object.keys(this.animationEventMap).forEach((key) => { if (typeof this.$listeners[key] !== 'function') return; const eventName = this.animationEventMap[key]; if (!eventName) return; animation.addEventListener(eventName, () => { this.$emit(key); }); }); }); }, reset() { this.$alreadyStarted = false; }, start() { if (!this.$alreadyStarted) { this.animationIds = getAnimationIds(this.style); this.$alreadyStarted = true; this.removeAnimationEvent(); this.addAnimationEvent(); this.animationIds.forEach((animationId) => { const animation = this.animationIdsMap[animationId]; animation === null || animation === void 0 ? void 0 : animation.start(); }); } else { this.resume(); } }, resume() { const animationIds = getAnimationIds(this.style); animationIds.forEach((animationId) => { const animation = this.animationIdsMap[animationId]; animation === null || animation === void 0 ? void 0 : animation.resume(); }); }, pause() { if (!this.$alreadyStarted) { return; } const animationIds = getAnimationIds(this.style); animationIds.forEach((animationId) => { const animation = this.animationIdsMap[animationId]; animation === null || animation === void 0 ? void 0 : animation.pause(); }); }, destroy() { this.removeAnimationEvent(); this.$alreadyStarted = false; const animationIds = getAnimationIds(this.style); animationIds.forEach((animationId) => { const animation = this.animationIdsMap[animationId]; animation === null || animation === void 0 ? void 0 : animation.destroy(); }); }, }, render(h) { return h(this.tag, { attrs: { useAnimation: true, ...this.props, }, style: this.style, }, this.$slots.default); }, }); } /* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const getFirstComponent = (elements) => { if (!elements) return null; if (Array.isArray(elements)) return elements[0]; if (elements) return elements; }; function registerDialog(Vue) { Vue.registerElement('hi-dialog', { component: { name: 'Modal', defaultNativeStyle: { position: 'absolute', }, }, }); Vue.component('Dialog', { inheritAttrs: false, props: { collapsable: { type: Boolean, default: false, }, transparent: { type: Boolean, default: true, }, immersionStatusBar: { type: Boolean, default: true, }, autoHideStatusBar: { type: Boolean, default: false, }, autoHideNavigationBar: { type: Boolean, default: false, }, }, render(h) { const firstChild = getFirstComponent(this.$slots.default); if (firstChild) { // __modalFirstChild__ marked to remove absolute position to be compatible with hippy 2.0 if (!firstChild.data.attrs) { firstChild.data.attrs = { __modalFirstChild__: true, }; } else { Object.assign(firstChild.data.attrs, { __modalFirstChild__: true, }); } } const { collapsable, transparent, immersionStatusBar, autoHideStatusBar, autoHideNavigationBar } = this; return h('hi-dialog', { on: { ...this.$listeners }, attrs: { collapsable, transparent, immersionStatusBar, autoHideStatusBar, autoHideNavigationBar, }, }, this.$slots.default); }, }); } /* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Capitalize a word * * @param {string} str The word input * @returns string */ function capitalize(str) { if (typeof str !== 'string') { return ''; } return `${str.charAt(0).toUpperCase()}${str.slice(1)}`; } /** * Get binding events redirector * * The function should be called with `getEventRedirector.call(this, [])` * for binding this. * * @param {string[] | string[][]} events events will be redirect * @returns Object */ function getEventRedirector(events) { const on = {}; events.forEach((event) => { if (Array.isArray(event)) { // exposedEventName is used in vue declared, nativeEventName is used in native const [exposedEventName, nativeEventName] = event; if (Object.prototype.hasOwnProperty.call(this.$listeners, exposedEventName)) { // Use event handler first if declared if (this[`on${capitalize(nativeEventName)}`]) { // event will be converted like "dropped,pageSelected" which assigned to "on" object // @ts-expect-error TS(2538): Type 'any[]' cannot be used as an index type. on[event] = this[`on${capitalize(nativeEventName)}`]; } else { // if no event handler found, emit default exposedEventName. // @ts-expect-error TS(2538): Type 'any[]' cannot be used as an index type. on[event] = (evt) => this.$emit(exposedEventName, evt); } } } else if (Object.prototype.hasOwnProperty.call(this.$listeners, event)) { if (this[`on${capitalize(event)}`]) { on[event] = this[`on${capitalize(event)}`]; } else { on[event] = (evt) => this.$emit(event, evt); } } }); return on; } /* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function registerUlRefresh(Vue) { Vue.registerElement('hi-ul-refresh-wrapper', { component: { name: 'RefreshWrapper', }, }); Vue.registerElement('hi-refresh-wrapper-item', { component: { name: 'RefreshWrapperItemView', }, }); Vue.component('UlRefreshWrapper', { inheritAttrs: false, props: { bounceTime: { type: Number, defaultValue: 100, }, }, methods: { startRefresh() { Vue.Native.callUIFunction(this.$refs.refreshWrapper, 'startRefresh', null); }, refreshCompleted() { // FIXME: Here's a typo mistake `refreshComplected` in native sdk. Vue.Native.callUIFunction(this.$refs.refreshWrapper, 'refreshComplected', null); }, }, render(h) { const on = getEventRedirector.call(this, [ 'refresh', ]); return h('hi-ul-refresh-wrapper', { on, ref: 'refreshWrapper', }, this.$slots.default); }, }); Vue.component('UlRefresh', { inheritAttrs: false, render(h) { return h('hi-refresh-wrapper-item', { style: { position: 'absolute', left: 0, right: 0, }, }, [ h('div', this.$slots.default), ]); }, }); } /* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function registerSwiper(Vue) { Vue.registerElement('hi-swiper', { component: { name: 'ViewPager', processEventData(event, nativeEventName, nativeEventParams) { switch (nativeEventName) { case 'onPageSelected': event.currentSlide = nativeEventParams.position; break; case 'onPageScroll': event.nextSlide = nativeEventParams.position; event.offset = nativeEventParams.offset; break; case 'onPageScrollStateChanged': event.state = nativeEventParams.pageScrollState; break; } return event; }, }, }); Vue.registerElement('swiper-slide', { component: { name: 'ViewPagerItem', defaultNativeStyle: { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, }, }, }); Vue.component('Swiper', { inheritAttrs: false, props: { current: { type: Number, defaultValue: 0, }, needAnimation: { type: Boolean, defaultValue: true, }, }, watch: { current(to) { if (this.$props.needAnimation) { this.setSlide(to); } else { this.setSlideWithoutAnimation(to); } }, }, beforeMount() { this.$initialSlide = this.$props.current; }, methods: { setSlide(slideIndex) { Vue.Native.callUIFunction(this.$refs.swiper, 'setPage', [slideIndex]); }, setSlideWithoutAnimation(slideIndex) { Vue.Native.callUIFunction(this.$refs.swiper, 'setPageWithoutAnimation', [slideIndex]); }, }, render(h) { const on = getEventRedirector.call(this, [ ['dropped', 'pageSelected'], ['dragging', 'pageScroll'], ['stateChanged', 'pageScrollStateChanged'], ]); return h('hi-swiper', { on, ref: 'swiper', attrs: { initialPage: this.$initialSlide, }, }, this.$slots.default); }, }); } /* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const PULLING_EVENT = 'pulling'; const IDLE_EVENT = 'idle'; function registerPull(Vue) { const { callUIFunction } = Vue.Native; [ ['Header', 'header'], ['Footer', 'footer'], ].forEach(([capitalCase, lowerCase]) => { /** * PullView native component * * Methods: * expandPull() - Expand the PullView and display the content * collapsePull() - collapse the PullView and hide the content * * Events: * onReleased - Trigger when release the finger after pulling gap larger than the content height * onPulling - Trigger when pulling, will use it to trigger idle and pulling method */ Vue.registerElement(`hi-pull-${lowerCase}`, { component: { name: `Pull${capitalCase}View`, processEventData(event, nativeEventName, nativeEventParams) { switch (nativeEventName) { case `on${capitalCase}Released`: case `on${capitalCase}Pulling`: Object.assign(event, nativeEventParams); break; } return event; }, }, }); Vue.component(`pull-${lowerCase}`, { methods: { /** * Expand the PullView and display the content */ [`expandPull${capitalCase}`]() { callUIFunction(this.$refs.instance, `expandPull${capitalCase}`); }, /** * Collapse the PullView and hide the content * @param {Object} [options] additional config for pull header * @param {number} [options.time] time left to hide pullHeader after collapsePullHeader() called, unit is ms */ [`collapsePull${capitalCase}`](options) { if (capitalCase === 'Header') { // options: { time } if (typeof options !== 'undefined') { callUIFunction(this.$refs.instance, `collapsePull${capitalCase}WithOptions`, [options]); } else { callUIFunction(this.$refs.instance, `collapsePull${capitalCase}`); } } else { callUIFunction(this.$refs.instance, `collapsePull${capitalCase}`); } }, /** * Get the refresh height by @layout event * @param {Object} evt */ onLayout(evt) { this.$contentHeight = evt.height; }, /** * Trigger when release the finger after pulling gap larger than the content height * Convert to `released` event. */ [`on${capitalCase}Released`](evt) { // @ts-expect-error TS(2554): Expected 1 arguments, but got 2. this.$emit('released', evt); }, /** * Trigger when pulling * Convert to `idle` event if dragging gap less than content height * Convert to `pulling` event if dragging gap larger than content height * * @param {Object} evt Event Object * @param {number} evt.contentOffset Dragging gap, either horizion and vertical direction. */ [`on${capitalCase}Pulling`](evt) { if (evt.contentOffset > this.$contentHeight) { if (this.$lastEvent !== PULLING_EVENT) { this.$lastEvent = PULLING_EVENT; // @ts-expect-error TS(2554): Expected 1 arguments, but got 2. this.$emit(PULLING_EVENT, evt); } } else if (this.$lastEvent !== IDLE_EVENT) { this.$lastEvent = IDLE_EVENT; // @ts-expect-error TS(2554): Expected 1 arguments, but got 2. this.$emit(IDLE_EVENT, evt); } }, }, render(h) { const { released, pulling, idle } = this.$listeners; const on = { layout: this.onLayout, }; if (typeof released === 'function') { on[`${lowerCase}Released`] = this[`on${capitalCase}Released`]; } if (typeof pulling === 'function' || typeof idle === 'function') { on[`${lowerCase}Pulling`] = this[`on${capitalCase}Pulling`]; } return h(`hi-pull-${lowerCase}`, { on, ref: 'instance', }, this.$slots.default); }, }); }); } /* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ function registerWaterfall(Vue) { Vue.registerElement('hi-waterfall', { component: { name: 'WaterfallView', processEventData(event, nativeEventName, nativeEventParams) { switch (nativeEventName) { case 'onExposureReport': event.exposureInfo = nativeEventParams.exposureInfo; break; case 'onScroll': { /** * scroll event parameters * * @param {number} startEdgePos - Scrolled offset of List top edge * @param {number} endEdgePos - Scrolled offset of List end edge * @param {number} firstVisibleRowIndex - Index of the first list item at current visible screen * @param {number} lastVisibleRowIndex - Index of the last list item at current visible screen * @param {Object[]} visibleRowFrames - Frame info of current screen visible items * @param {number} visibleRowFrames[].x - Current item's horizontal offset relative to ListView * @param {number} visibleRowFrames[].y - Current item's vertical offset relative to ListView * @param {number} visibleRowFrames[].width - Current item's width * @param {number} visibleRowFrames[].height - Current item's height */ const { startEdgePos, endEdgePos, firstVisibleRowIndex, lastVisibleRowIndex, visibleRowFrames, } = nativeEventParams; Object.assign(event, { startEdgePos, endEdgePos, firstVisibleRowIndex, lastVisibleRowIndex, visibleRowFrames, }); break; } } return event; }, }, }); Vue.registerElement('hi-waterfall-item', { component: { name: 'WaterfallItem', }, }); Vue.component('Waterfall', { inheritAttrs: false, props: { // specific number of waterfall column numberOfColumns: { type: Number, default: 2, }, // inner content padding contentInset: { type: Object, default: () => ({ top: 0, left: 0, bottom: 0, right: 0 }), }, // horizontal space between columns columnSpacing: { type: Number, default: 0, }, interItemSpacing: { type: Number, default: 0, }, preloadItemNumber: { type: Number, default: 0, }, containBannerView: { type: Boolean, default: false, }, containPullHeader: { type: Boolean, default: false, }, containPullFooter: { type: Boolean, default: false, }, }, methods: { // call native methods call(action, params) { Vue.Native.callUIFunction(this.$refs.waterfall, action, params); }, startRefresh() { // @ts-expect-error TS(2554): Expected 2 arguments, but got 1. this.call('startRefresh'); }, /** @param {number} type 1.same as startRefresh */ startRefreshWithType(type) { this.call('startRefreshWithType', [type]); }, callExposureReport() { this.call('callExposureReport', []); }, /** * Scrolls to a given index of item, either immediately, with a smooth animation. * * @param {Object} scrollToIndex params * @param {number} scrollToIndex.index - Scroll to specific index. * @param {boolean} scrollToIndex.animated - With smooth animation. By default is true. */ scrollToIndex({ index = 0, animated = true }) { if (typeof index !== 'number' || typeof animated !== 'boolean') { return; } this.call('scrollToIndex', [index, index, animated]); }, /** * Scrolls to a given x, y offset, either immediately, with a smooth animation. * * @param {Object} scrollToContentOffset params * @param {number} scrollToContentOffset.xOffset - Scroll to horizon offset X. * @param {number} scrollToContentOffset.yOffset - Scroll To vertical offset Y. * @param {boolean} scrollToContentOffset.animated - With smooth animation. By default is true. */ scrollToContentOffset({ xOffset = 0, yOffset = 0, animated = true }) { if (typeof xOffset !== 'number' || typeof yOffset !== 'number' || typeof animated !== 'boolean') { return; } this.call('scrollToContentOffset', [xOffset, yOffset, animated]); }, /** * start to load more waterfall items */ startLoadMore() { // @ts-expect-error TS(2554): Expected 2 arguments, but got 1. this.call('startLoadMore'); }, }, render(h) { const on = getEventRedirector.call(this, [ 'headerReleased', 'headerPulling', 'endReached', 'exposureReport', 'initialListReady', 'scroll', ]); return h('hi-waterfall', { on, ref: 'waterfall', attrs: { numberOfColumns: this.numberOfColumns, contentInset: this.contentInset, columnSpacing: this.columnSpacing, interItemSpacing: this.interItemSpacing, preloadItemNumber: this.preloadItemNumber, containBannerView: this.containBannerView, containPullHeader: this.containPullHeader, containPullFooter: this.containPullFooter, }, }, this.$slots.default); }, }); Vue.component('WaterfallItem', { inheritAttrs: false, props: { type: { type: [String, Number], default: '', }, }, render(h) { return h('hi-waterfall-item', { on: { ...this.$listeners }, attrs: { type: this.type, }, }, this.$slots.default); }, }); } /* * Tencent is pleased to support the open source community by making * Hippy available. * * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Register all of native components */ const HippyVueNativeComponents = { install(Vue) { registerAnimation(Vue); registerDialog(Vue); registerUlRefresh(Vue); registerSwiper(Vue); registerPull(Vue); registerWaterfall(Vue); }, }; export { registerAnimation as AnimationComponent, registerDialog as DialogComponent, registerUlRefresh as ListRefreshComponent, registerPull as PullsComponents, registerSwiper as SwiperComponent, registerWaterfall as WaterfallComponent, HippyVueNativeComponents as default };