jackmellis / vue-hoc Goto Github PK
View Code? Open in Web Editor NEWCreate Higher Order Vue Components
Create Higher Order Vue Components
Much of process options can be worked out statically with a preprocess function, which would cut down on work during rendering
Currently if you create a HOC around a component that has named slots, all of the provided slots will be converted into default slots.
So instead of having
{
default: [ vNode ],
header: [ vNode ],
footer: [ vNode ],
}
you get
{
default: [ vNode, vNode, vNode ],
}
normalizeSlots
should only be normalizing default
slots. And I guess we should be doing something with scopedSlots
instead...
basically just a shortcut for createSink(() => {})
?
Effectively just a wrapper for withState + withHandlers + mapProps
You can pass on all sorts of options (not just props listeners attrs) so we should not exclude them
I wish to make a withStyle HOC component to style my components.
import { createHOCc } from 'vue-hoc';
export function withStyle(style) {
return createHOCc(null, {style});
};
Then I used it this way to create a red button:
import {withStyle} from '../HOC/withStyle.js';
const style = {
background: '#F00'
};
export default withStyle(style)('button');
The issue appears when I try to render it:
import euiButton from '../UI/styledButton.jsx';
export default {
components: {
styledButton
},
render() {
return (
<v-app>
<v-content>
Hello World
<styledButton>MyButton</styledButton>
</v-content>
</v-app>
);
}
};
In the dom, an extra pair of <template>
is created:
And my button doesn't appear.
Why is this occurs ?
Thanks
Why do you override the $createElemen
method of the current instance via mixins
as the $createElemen
method of the parent instance?
this.$createElement = this.$parent.$createElement
I'm extending a data table component. I'd like to be able for a HOC that wraps the table's "no-data" slot with an alert tag and a td tag, so I don't have to write the same wrapping tags constantly. Is this possible? I tried to modify the slots in the renderWith options, but it didn't seem to take effect.
Whenever a prop is attached to a HOC, it is rendered to the DOM. For example, if I'm using a HOC for Vuetify's VDataTable
component, I see this if I inspect the DOM:
<div data-v-a0f8bd1c="" items="[object Object],[object Object],[object Object],[object Object]" pagination="[object Object]" hide-actions="" must-sort="">
...
Is there any way do avoid this?
If a component has multiple slots i..e
<foo>
<span>a</span>
<span>b</span>
</foo>
currently it will cut one of those slots. Needs to be something like:
if (isTextNode(vnode)) {
slots[key][i] = context.$createElement('template', { slot: key }, [vnode]);
} else {
slots[key][i].context = context;
On top of this, it looks like having elements and text content at the root slot level does not work nicely either. i.e.
<foo>
<span>a</span> b
</foo>
Looks like the b will be lost...
Not sure if this is possible but see if we can intercept emit calls from a componentFromSlot component
I'm using Vuetify's VSelect component and wrapping it with some custom prop defaults. If the HOC is functional, the v-validate (via VeeValidate) directive doesn't work. Removing functional: true makes the validation work again. Is this a bug or a technical limitation?
I've noticed that createHOC
looses data.attributes
in produced components which leads to loosing class and other attributes in actual DOM.
E.g.
export const BackBtn = createHOC(IconBtn, {
name: 'BackBtn',
functional: true,
// render (h, ctx) {
// return h(IconBtn, { ...ctx.data, props: { ...ctx.props, icon: 'arrow_back' } })
// }
}, {
props: { icon: 'arrow_back' }
})
When using in template like
<back-btn class="green--text"></back-btn>
Does not include class green-text
But when defined like:
export const BackBtn = createHOC({}, {
name: 'BackBtn',
functional: true,
render (h, ctx) {
return h(IconBtn, { ...ctx.data, props: { ...ctx.props, icon: 'arrow_back' } })
}
})
It does.
In registerModule, if you try to register foo/bah/baz
when foo or bah haven't already been registered, it fails.
I think we should recursively check each part of the path and if it doesn't exist, create an empty module to contain it.
Basically a shortcut for adding an object property or a provide function to a component.
provide(() => ({ foo: 'bah' }))
inject([ 'foo' ])
Lines 25 to 27 in ec91d6b
You can not get full props
in Componet.props
due to the exist of mixin
or extend
.
But props can pass to the inner Component
correctly by process options in running time.
So should we remove these lines?
withMethods
(and related mapActionsToMethods
from vuex-compose) don't seem to work with components that use decorator syntax (e.g vue-property-decorator, vue-class-component).
(not just props/attrs/listeners)
Same as withHandlers except it uses the nativeOn
property
In order to create hoc with named slots, we should let the expression to be true:
// vue/src/core/instance/render-helpers/resolve-slots.js
if ((child.context === context || child.functionalContext === context) &&
data && data.slot != null
) {
...
}
So I saw vue-hoc did two things:
// 1.
created(){
this.$createElement = this.$parent.$createElement;
}
// 2.
normalizeSlots(this.$slots, this.$parent)
But sometimes, it didn't work because of the hoc's $parent
is not it's $vnode.context
.
Although I don't known why, but I tried to fix it by:
// 1.
created() {
this.$createElement = this.$vnode.context.$createElement
this._c = this.$vnode.context._c
}
// 2.
normalizeSlots(this.$slots, this.$vnode.context)
It works!
So, is this the correct way to solve this, or am I lost some special case.
If there is no falseFn provided to branch HOC, it creates new one by wrapping the render function of provided Component. Problem is that first wrapped render function shared between subsequent branch hoc calls despite each call provided with another component.
Consider that example:
const withLoader = branch(p => p.loading, h => h(Loading))
const C1WithLoader = withLoader(C1) //C1 is some component
const C2WithLoader = withLoader(C2) //C2 is some other component
// somewhere in a code
template: `<div><C1/> <C2/></div>` // I expect C1 and C2 rendered properly
now when I render C1WithLoader and C2WithLoader I would expect them to use render functions from C1 and C2 accordingly. But instead, render function for C1 will be called for both components, which lead to unexpected results.
Problem is in this line:
https://github.com/jackmellis/vue-hoc/blob/master/packages/vue-compose/src/hocs/branch.js#L6
as falseFn exists in outer scope, it will work only for the first time, and then any next call with another ctor will reuse that function.
I can create PR for that problem if desired.
Rather than just assigning the options to the hoc object, loop through each option and use Vue.config.mergingStrategies to merge them. If no strategy exists, just assume latest wins.
Right now if you pass a prop into a child component, but that prop is not recognised, it is just abandoned. It would be good if any unknown props could be merged into attrs
Here https://github.com/jackmellis/vue-hoc/blob/master/src/createHOC.js#L3 we are including Vue.
I think we can assume that the person that include vue-hoc already include Vue. Vue should maybe be an external variable.
With this, we would be able to create npm package that doesn't include Vue in the bundle.
withGetters currently attempts to invoke any getters that return functions
Thank you for the awesome work.
I am trying to access a computed property of the original component. Here is the code
import SourceComponent from '...';
const options = {
methods: {
myFunc() {
console.log('computedRows', this.computedRows);
}
}
}
export default createHOC(SourceComponent, options, {});
Where computedRows
is a computed property in the Source component. But the console line above prints undefined
.
Will also need to write a flowtype for courier
I'm trying to make a HOC for debounced input. I'm using the same technique shown in the vue.js guide.
However, the method added to this
in the created method does not seem to be available.
Error in the console: TypeError: this.debouncedInput is not a function
Relevant code:
import { createHOCc } from 'vue-hoc'
import { debounce } from 'lodash'
const withDebouncedInput = createHOCc(
{
methods: {
input(value) {
this.$emit('debounced-input', value)
},
created() {
this.debouncedInput = debounce(this.input, 500)
},
},
},
{
listeners: {
input(arg) {
this.$emit('input', arg)
this.debouncedInput(arg)
},
},
}
)
(
test: Function,
trueRender: Function,
falseRender?: Function,
) => (Component) => Component
example:
branch(
(props) => props.foo === true, // or function(){ this.foo === true }
// if true
(h) => {
return h('div');
}
// if false
function(h){
return h('span');
}
)(Component)
slightly restricted as you can't provide an entirely new component to instantiate so you're forced to just provide a render function. Fine if you're using jsx or pure renders, but not if you're used to template syntax...
This is related to issue #25
I'm using a HOC around Vuetify's VDataTable
component. VDataTable
uses a mixin called data-iterable
, which has a customFilter
prop. However, VDataTable
overrides this prop with its own customFilter
prop.
Normal behavior is for a component to override the props of their included mixins. However, when creating my HOC, I noticed my custom component actually inherits the customFilter
prop from the data-iterable
mixin, not the VDataTable
component.
This seems to happen because the getProps
method uses the component's props as the initial value when running mixins.reduce()
. This means props are being overridden in exactly the opposite way that they should.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.