Skip to content

Commit c7fb693

Browse files
authored
Merge pull request #1 from jiliabas/spread-props
Spread props
2 parents 166f6fc + 87fa7d9 commit c7fb693

File tree

9 files changed

+295
-34
lines changed

9 files changed

+295
-34
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
node_modules
22
.DS_Store
3+
.idea/
4+
package-lock.json

dist/vue-wc-wrapper.global.js

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,54 @@ function getAttributes (node) {
9898
return res
9999
}
100100

101+
function spreadProps (component) {
102+
const result = {};
103+
spreadNext(result, component);
104+
return result
105+
}
106+
107+
function spreadNext (result, component) {
108+
if (component.props) {
109+
appendProps(result, component.props);
110+
}
111+
112+
if (component.mixins) {
113+
component.mixins.forEach(function (mixin) {
114+
spreadNext(result, mixin);
115+
});
116+
}
117+
if (component.extends) {
118+
spreadNext(result, component.extends);
119+
}
120+
}
121+
122+
function appendProps (result, props) {
123+
if (Array.isArray(props)) {
124+
processArrayProps(result, props);
125+
} else {
126+
processObjectProps(result, props);
127+
}
128+
}
129+
130+
function processObjectProps (result, props) {
131+
for (const key in props) {
132+
const camelKey = camelize(key);
133+
if (!(camelKey in result)) {
134+
result[camelKey] = props[key];
135+
}
136+
}
137+
}
138+
function processArrayProps (result, props) {
139+
props.forEach(function (prop) {
140+
if (typeof prop === 'string') {
141+
const camelKey = camelize(prop);
142+
if (!(camelKey in result)) {
143+
result[camelKey] = undefined;
144+
}
145+
}
146+
});
147+
}
148+
101149
function wrap (Vue, Component) {
102150
const isAsync = typeof Component === 'function' && !Component.cid;
103151
let isInitialized = false;
@@ -112,13 +160,13 @@ function wrap (Vue, Component) {
112160
? Component.options
113161
: Component;
114162

163+
// spread props
164+
options.props = spreadProps(options);
115165
// extract props info
116-
const propsList = Array.isArray(options.props)
117-
? options.props
118-
: Object.keys(options.props || {});
166+
const propsList = Object.keys(options.props || {});
119167
hyphenatedPropsList = propsList.map(hyphenate);
120168
camelizedPropsList = propsList.map(camelize);
121-
const originalPropsAsObject = Array.isArray(options.props) ? {} : options.props || {};
169+
const originalPropsAsObject = options.props || {};
122170
camelizedPropsMap = camelizedPropsList.reduce((map, key, i) => {
123171
map[key] = originalPropsAsObject[propsList[i]];
124172
return map
@@ -169,13 +217,13 @@ function wrap (Vue, Component) {
169217

170218
class CustomElement extends HTMLElement {
171219
constructor () {
172-
super();
173-
this.attachShadow({ mode: 'open' });
220+
const self = super();
221+
self.attachShadow({ mode: 'open' });
174222

175-
const wrapper = this._wrapper = new Vue({
223+
const wrapper = self._wrapper = new Vue({
176224
name: 'shadow-root',
177-
customElement: this,
178-
shadowRoot: this.shadowRoot,
225+
customElement: self,
226+
shadowRoot: self.shadowRoot,
179227
data () {
180228
return {
181229
props: {},
@@ -195,20 +243,20 @@ function wrap (Vue, Component) {
195243
let hasChildrenChange = false;
196244
for (let i = 0; i < mutations.length; i++) {
197245
const m = mutations[i];
198-
if (isInitialized && m.type === 'attributes' && m.target === this) {
199-
syncAttribute(this, m.attributeName);
246+
if (isInitialized && m.type === 'attributes' && m.target === self) {
247+
syncAttribute(self, m.attributeName);
200248
} else {
201249
hasChildrenChange = true;
202250
}
203251
}
204252
if (hasChildrenChange) {
205253
wrapper.slotChildren = Object.freeze(toVNodes(
206254
wrapper.$createElement,
207-
this.childNodes
255+
self.childNodes
208256
));
209257
}
210258
});
211-
observer.observe(this, {
259+
observer.observe(self, {
212260
childList: true,
213261
subtree: true,
214262
characterData: true,

dist/vue-wc-wrapper.js

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,54 @@ function getAttributes (node) {
9595
return res
9696
}
9797

98+
function spreadProps (component) {
99+
const result = {};
100+
spreadNext(result, component);
101+
return result
102+
}
103+
104+
function spreadNext (result, component) {
105+
if (component.props) {
106+
appendProps(result, component.props);
107+
}
108+
109+
if (component.mixins) {
110+
component.mixins.forEach(function (mixin) {
111+
spreadNext(result, mixin);
112+
});
113+
}
114+
if (component.extends) {
115+
spreadNext(result, component.extends);
116+
}
117+
}
118+
119+
function appendProps (result, props) {
120+
if (Array.isArray(props)) {
121+
processArrayProps(result, props);
122+
} else {
123+
processObjectProps(result, props);
124+
}
125+
}
126+
127+
function processObjectProps (result, props) {
128+
for (const key in props) {
129+
const camelKey = camelize(key);
130+
if (!(camelKey in result)) {
131+
result[camelKey] = props[key];
132+
}
133+
}
134+
}
135+
function processArrayProps (result, props) {
136+
props.forEach(function (prop) {
137+
if (typeof prop === 'string') {
138+
const camelKey = camelize(prop);
139+
if (!(camelKey in result)) {
140+
result[camelKey] = undefined;
141+
}
142+
}
143+
});
144+
}
145+
98146
function wrap (Vue, Component) {
99147
const isAsync = typeof Component === 'function' && !Component.cid;
100148
let isInitialized = false;
@@ -109,13 +157,13 @@ function wrap (Vue, Component) {
109157
? Component.options
110158
: Component;
111159

160+
// spread props
161+
options.props = spreadProps(options);
112162
// extract props info
113-
const propsList = Array.isArray(options.props)
114-
? options.props
115-
: Object.keys(options.props || {});
163+
const propsList = Object.keys(options.props || {});
116164
hyphenatedPropsList = propsList.map(hyphenate);
117165
camelizedPropsList = propsList.map(camelize);
118-
const originalPropsAsObject = Array.isArray(options.props) ? {} : options.props || {};
166+
const originalPropsAsObject = options.props || {};
119167
camelizedPropsMap = camelizedPropsList.reduce((map, key, i) => {
120168
map[key] = originalPropsAsObject[propsList[i]];
121169
return map
@@ -166,13 +214,13 @@ function wrap (Vue, Component) {
166214

167215
class CustomElement extends HTMLElement {
168216
constructor () {
169-
super();
170-
this.attachShadow({ mode: 'open' });
217+
const self = super();
218+
self.attachShadow({ mode: 'open' });
171219

172-
const wrapper = this._wrapper = new Vue({
220+
const wrapper = self._wrapper = new Vue({
173221
name: 'shadow-root',
174-
customElement: this,
175-
shadowRoot: this.shadowRoot,
222+
customElement: self,
223+
shadowRoot: self.shadowRoot,
176224
data () {
177225
return {
178226
props: {},
@@ -192,20 +240,20 @@ function wrap (Vue, Component) {
192240
let hasChildrenChange = false;
193241
for (let i = 0; i < mutations.length; i++) {
194242
const m = mutations[i];
195-
if (isInitialized && m.type === 'attributes' && m.target === this) {
196-
syncAttribute(this, m.attributeName);
243+
if (isInitialized && m.type === 'attributes' && m.target === self) {
244+
syncAttribute(self, m.attributeName);
197245
} else {
198246
hasChildrenChange = true;
199247
}
200248
}
201249
if (hasChildrenChange) {
202250
wrapper.slotChildren = Object.freeze(toVNodes(
203251
wrapper.$createElement,
204-
this.childNodes
252+
self.childNodes
205253
));
206254
}
207255
});
208-
observer.observe(this, {
256+
observer.observe(self, {
209257
childList: true,
210258
subtree: true,
211259
characterData: true,

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@vue/web-component-wrapper",
3-
"version": "1.2.0",
3+
"version": "1.3.0",
44
"description": "wrap a vue component as a web component.",
55
"main": "dist/vue-wc-wrapper.js",
66
"unpkg": "dist/vue-wc-wrapper.global.js",

src/index.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import {
66
injectHook,
77
getInitialProps,
88
createCustomEvent,
9-
convertAttributeValue
9+
convertAttributeValue,
10+
spreadProps
1011
} from './utils.js'
1112

1213
export default function wrap (Vue, Component) {
@@ -23,13 +24,13 @@ export default function wrap (Vue, Component) {
2324
? Component.options
2425
: Component
2526

27+
// spread props
28+
options.props = spreadProps(options)
2629
// extract props info
27-
const propsList = Array.isArray(options.props)
28-
? options.props
29-
: Object.keys(options.props || {})
30+
const propsList = Object.keys(options.props || {})
3031
hyphenatedPropsList = propsList.map(hyphenate)
3132
camelizedPropsList = propsList.map(camelize)
32-
const originalPropsAsObject = Array.isArray(options.props) ? {} : options.props || {}
33+
const originalPropsAsObject = options.props || {}
3334
camelizedPropsMap = camelizedPropsList.reduce((map, key, i) => {
3435
map[key] = originalPropsAsObject[propsList[i]]
3536
return map

src/utils.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,52 @@ function getAttributes (node) {
9494
}
9595
return res
9696
}
97+
98+
export function spreadProps (component) {
99+
const result = {}
100+
spreadNext(result, component)
101+
return result
102+
}
103+
104+
function spreadNext (result, component) {
105+
if (component.props) {
106+
appendProps(result, component.props)
107+
}
108+
109+
if (component.mixins) {
110+
component.mixins.forEach(function (mixin) {
111+
spreadNext(result, mixin)
112+
})
113+
}
114+
if (component.extends) {
115+
spreadNext(result, component.extends)
116+
}
117+
}
118+
119+
function appendProps (result, props) {
120+
if (Array.isArray(props)) {
121+
processArrayProps(result, props)
122+
} else {
123+
processObjectProps(result, props)
124+
}
125+
}
126+
127+
function processObjectProps (result, props) {
128+
for (const key in props) {
129+
const camelKey = camelize(key)
130+
if (!(camelKey in result)) {
131+
result[camelKey] = props[key]
132+
}
133+
}
134+
}
135+
function processArrayProps (result, props) {
136+
props.forEach(function (prop) {
137+
if (typeof prop === 'string') {
138+
const camelKey = camelize(prop)
139+
if (!(camelKey in result)) {
140+
result[camelKey] = undefined
141+
}
142+
}
143+
})
144+
}
145+

test/fixtures/spreadedProperties.html

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<script src="../../node_modules/vue/dist/vue.js"></script>
2+
<script type="module">
3+
import wrap from '../../src/index.js';
4+
5+
var mixin0 = {
6+
props: {
7+
m0: {
8+
type: String,
9+
default: 'm0'
10+
}
11+
}
12+
};
13+
var mixin1 = {
14+
props: {
15+
'm-1': {
16+
type: String,
17+
default: 'm1'
18+
}
19+
}
20+
};
21+
var mixin2 = {
22+
props: ['m2a', 'm2b']
23+
};
24+
25+
var Parent0 = {
26+
mixins:[mixin0, mixin1, mixin2],
27+
props: ['p0']
28+
};
29+
var Parent1 = {
30+
extends: Parent0,
31+
props: {
32+
'p-1': {
33+
type: String,
34+
default: 'p1'
35+
}
36+
}
37+
};
38+
39+
customElements.define('my-element', wrap(Vue, {
40+
extends: Parent1,
41+
props:['c1', 'c2'],
42+
template: `<div> {{p0}} {{p1}} {{m0}} {{m1}} {{c1}}{{c2}}{{m2a}} {{m2b}}</div>`,
43+
}));
44+
45+
window.el = document.querySelector('my-element');
46+
</script>
47+
48+
<my-element ></my-element>

test/setup.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module.exports = async function launchPage (name) {
2020
}
2121

2222
beforeAll(async () => {
23+
jest.setTimeout(10000)
2324
browser = await puppeteer.launch(puppeteerOptions)
2425
server = createServer({ root: process.cwd() })
2526
await new Promise((resolve, reject) => {

0 commit comments

Comments
 (0)