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

add slot key #10

Merged
merged 5 commits into from
Sep 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
80 changes: 80 additions & 0 deletions spec/templateSlots.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import test from 'ava';
import {mount} from 'vuenit';
import {createHOC} from '../dist';

const Component = {
template : `<div>
<div id="default"><slot>component default slot</slot></div>
<div id="named"><slot name="named_slot">component named slot</slot></div>
</div>`
};
mount(Component);

test('passes named slots by `template` tag', t => {
const hoc = createHOC(Component);
const vm = mount(hoc, {
slots: {
named_slot: '<template>hoc template slot</template>'
}
});
t.true(vm.$findOne('#named').$text === 'hoc template slot');
});

test('passes default slots by `template` tag', t => {
const hoc = createHOC(Component);
const vm = mount(hoc, {
slots: {
default: '<template>default slot</template>'
}
});
t.true(vm.$findOne('#default').$text === 'default slot');
});

test('passes both default slots and named slots by `template` tag', t => {
const hoc = createHOC(Component);
const vm = mount(hoc, {
slots: {
default: '<template>default slot</template>',
named_slot: '<template>hoc template slot</template>'
}
});
t.true(vm.$findOne('#default').$text === 'default slot');
t.true(vm.$findOne('#named').$text === 'hoc template slot');
});

test('passes default slots by `div` tag and named slots by `template` tag', t => {
const hoc = createHOC(Component);
const vm = mount(hoc, {
slots: {
default: '<div>default slot</div>',
named_slot: '<template>hoc template slot</template>'
}
});

t.true(vm.$findOne('#default').$html === '<div id="default"><div>default slot</div></div>');
t.true(vm.$findOne('#named').$html === '<div id="named">hoc template slot</div>');
});

test('passes named slots by `div` tag and default slots by `template` tag', t => {
const hoc = createHOC(Component);
const vm = mount(hoc, {
slots: {
default: '<template>default slot</template>',
named_slot: '<div>hoc template slot</div>'
}
});

t.true(vm.$findOne('#default').$html === '<div id="default">default slot</div>');
t.true(vm.$findOne('#named').$html === '<div id="named"><div>hoc template slot</div></div>');
});

test('passes named template slots through multiple hocs', t => {
const hoc1 = createHOC(Component);
const hoc2 = createHOC(hoc1);
const vm = mount(hoc2, {
slots: {
named_slot: '<template>hoc template slot</template>'
}
});
t.true(vm.$findOne('#named').$text === 'hoc template slot');
});
3 changes: 2 additions & 1 deletion src/annotations.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ export type CompnentDefinition = {
name?: string,
mixins?: Array<Object>,
render?: Function,
$createElement: Function,
};
export type Ctor = CompnentDefinition | Function;

export type NormalizeSlots = (slots: Object) => Array<Object>;
export type NormalizeSlots = (slots: Object, context: CompnentDefinition) => Array<Object>;

type RenderFnOption = {
[name: string]: Function,
Expand Down
23 changes: 23 additions & 0 deletions src/assign.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// IE9-11 do not support `Object.assign`
const assign = Object.assign || function (target, ...sources) {
if (target == null) {
throw new TypeError('Uncaught TypeError: Cannot convert undefined or null to object');
}

for (let i = 0, il = sources.length; i < il; i += 1) {
const source = sources[i];
if (source == null) {
continue;
}

for (let key in source) {
if (source.hasOwnProperty(key)) {
target[key] = source[key];
}
}
}

return target;
};

export default assign;
3 changes: 2 additions & 1 deletion src/createHOC.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {

import courier from './courier';
import {createRenderFnc} from './createRenderFn';
import assign from './assign';
import Vue from 'vue';

const defaultStrategy = (parent, child) => child;
Expand All @@ -26,7 +27,7 @@ const normalizeProps = (props: Object | Array<string> | void) => {
});
return obj;
}
return Object.assign({}, props);
return assign({}, props);
};

export const createHOC: CreateHOC = (Component, options, renderOptions) => {
Expand Down
7 changes: 4 additions & 3 deletions src/createRenderFn.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow
import courier from './courier';
import normalizeSlots from './normalizeSlots';
import assign from './assign';

import type {
Ctor,
Expand Down Expand Up @@ -48,12 +49,12 @@ const createOptionHandlers = (originalOptions, keys) => {
const optionKeys = Object.keys(option);

if (!optionKeys.some(k => isFn(option[k]))){
options[key] = (owner) => Object.assign({}, owner, option);
options[key] = (owner) => assign({}, owner, option);
return;
}

options[key] = function(owner) {
const result = Object.assign({}, owner);
const result = assign({}, owner);
const justBind = justBindFn(key);

optionKeys.forEach(k => {
Expand Down Expand Up @@ -129,7 +130,7 @@ export const createRenderFn: CreateRenderFn = (Component, options) => {
const data = getData(context || this, !!context);
const scopedSlots: Object = (context && context.data && context.data.scopedSlots) ||
(this && this.$scopedSlots);
const slots: Array<any> = (context && context.children) || (this && this.$slots && normalizeSlots(this.$slots)) || [];
const slots: Array<any> = (context && context.children) || (this && this.$slots && normalizeSlots(this.$slots, this.$parent)) || [];

data.scopedSlots = data.scopedSlots || scopedSlots;

Expand Down
24 changes: 22 additions & 2 deletions src/normalizeSlots.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,27 @@ import type {
NormalizeSlots,
} from './annotations';

const normalizeSlots: NormalizeSlots = (slots) => Object.keys(slots)
.reduce((arr, key) => arr.concat(slots[key]), []);
function isTextNode(node) {
return node != null && node.text != null && node.isComment === false;
}

const normalizeSlots: NormalizeSlots = (slots, context) => Object.keys(slots)
.reduce((arr, key) => {
slots[key].forEach(vnode => {
if (!vnode.context) {
if (isTextNode(vnode)) {
slots[key] = context.$createElement('template', {slot: key}, [vnode]);
} else {
slots[key].context = context;

if (!vnode.data) {
vnode.data = {};
}
vnode.data.slot = key;
}
}
});
return arr.concat(slots[key]);
}, []);

export default normalizeSlots;