Skip to content

Commit e24356c

Browse files
author
Marco Vockner
committed
feat: add support for named slots
based on gnuletik#1
1 parent bd9a65c commit e24356c

File tree

1 file changed

+32
-26
lines changed

1 file changed

+32
-26
lines changed

packages/runtime-dom/src/apiCustomElement.ts

+32-26
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ export interface DefineCustomElementConfig {
4646
export function defineCustomElement<Props, RawBindings = object>(
4747
setup: (
4848
props: Readonly<Props>,
49-
ctx: SetupContext
49+
ctx: SetupContext,
5050
) => RawBindings | RenderFunction,
51-
config?: DefineCustomElementConfig
51+
config?: DefineCustomElementConfig,
5252
): VueElementConstructor<Props>
5353

5454
// overload 2: object format with no props
@@ -80,7 +80,7 @@ export function defineCustomElement<
8080
II,
8181
S
8282
> & { styles?: string[] },
83-
config?: DefineCustomElementConfig
83+
config?: DefineCustomElementConfig,
8484
): VueElementConstructor<Props>
8585

8686
// overload 3: object format with array props declaration
@@ -112,7 +112,7 @@ export function defineCustomElement<
112112
II,
113113
S
114114
> & { styles?: string[] },
115-
config?: DefineCustomElementConfig
115+
config?: DefineCustomElementConfig,
116116
): VueElementConstructor<{ [K in PropNames]: any }>
117117

118118
// overload 4: object format with object props declaration
@@ -144,7 +144,7 @@ export function defineCustomElement<
144144
II,
145145
S
146146
> & { styles?: string[] },
147-
config?: DefineCustomElementConfig
147+
config?: DefineCustomElementConfig,
148148
): VueElementConstructor<ExtractPropTypes<PropsOptions>>
149149

150150
// overload 5: defining a custom element from the returned value of
@@ -157,7 +157,7 @@ export function defineCustomElement<P>(
157157
export function defineCustomElement(
158158
options: any,
159159
config?: DefineCustomElementConfig,
160-
hydrate?: RootHydrateFunction
160+
hydrate?: RootHydrateFunction,
161161
): VueElementConstructor {
162162
const Comp = defineComponent(options) as any
163163
class VueCustomElement extends VueElement {
@@ -173,7 +173,7 @@ export function defineCustomElement(
173173
/*! #__NO_SIDE_EFFECTS__ */
174174
export const defineSSRCustomElement = ((
175175
options: any,
176-
config?: DefineCustomElementConfig
176+
config?: DefineCustomElementConfig,
177177
) => {
178178
// @ts-expect-error
179179
return defineCustomElement(options, config, hydrate)
@@ -202,14 +202,14 @@ export class VueElement extends BaseClass {
202202
private _def: InnerComponentDef,
203203
private _props: Record<string, any> = {},
204204
private _config: DefineCustomElementConfig = {},
205-
hydrate?: RootHydrateFunction
205+
hydrate?: RootHydrateFunction,
206206
) {
207207
super()
208208
this._config = extend(
209209
{
210-
shadowRoot: true
210+
shadowRoot: true,
211211
},
212-
this._config
212+
this._config,
213213
)
214214

215215
if (this._config.shadowRoot) {
@@ -219,7 +219,7 @@ export class VueElement extends BaseClass {
219219
if (__DEV__ && this.shadowRoot) {
220220
warn(
221221
`Custom element has pre-rendered declarative shadow root but is not ` +
222-
`defined as hydratable. Use \`defineSSRCustomElement\`.`
222+
`defined as hydratable. Use \`defineSSRCustomElement\`.`,
223223
)
224224
}
225225
this.attachShadow({ mode: 'open' })
@@ -331,7 +331,7 @@ export class VueElement extends BaseClass {
331331
// replace slot
332332
if (!this._config.shadowRoot) {
333333
this._slots = Array.from(this.children).map(
334-
n => n.cloneNode(true) as Element
334+
n => n.cloneNode(true) as Element,
335335
)
336336
this.replaceChildren()
337337
}
@@ -423,24 +423,30 @@ export class VueElement extends BaseClass {
423423
}
424424

425425
private _createVNode(): VNode<any, any> {
426-
let childs = null
426+
let childs: Record<string, unknown> | null = null
427427
// web components without shadow DOM do not supports native slot
428428
// so, we create a VNode based on the content of child nodes.
429-
// NB: named slots are currently not supported
430429
if (!this._config.shadowRoot) {
431-
childs = () => {
432-
const toObj = (a: NamedNodeMap) => {
433-
const res: Record<string, string | null> = {}
434-
for (let i = 0, l = a.length; i < l; i++) {
435-
const attr = a[i]
436-
res[attr.nodeName] = attr.nodeValue
430+
if (this._slots) {
431+
childs = {}
432+
this._slots.forEach(slot => {
433+
const key =
434+
slot.slot !== null && slot.slot.length ? slot.slot : 'default'
435+
if (childs !== null) {
436+
childs[key] = () => {
437+
const toObj = (a: NamedNodeMap) => {
438+
const res: Record<string, string | null> = {}
439+
for (let i = 0, l = a.length; i < l; i++) {
440+
const attr = a[i]
441+
res[attr.nodeName] = attr.nodeValue
442+
}
443+
return res
444+
}
445+
const attrs = slot.attributes ? toObj(slot.attributes) : {}
446+
attrs.innerHTML = slot.innerHTML
447+
return createVNode(slot.tagName, attrs)
448+
}
437449
}
438-
return res
439-
}
440-
return this._slots!.map(ele => {
441-
const attrs = ele.attributes ? toObj(ele.attributes) : {}
442-
attrs.innerHTML = ele.innerHTML
443-
return createVNode(ele.tagName, attrs, null)
444450
})
445451
}
446452
}

0 commit comments

Comments
 (0)