@@ -68,6 +68,7 @@ naturally appears inline after the deepest trailing text node.
6868
6969<script lang =" ts" >
7070 import type { ComarkNode as ComarkNodeType , ComponentManifest , NodeRenderData } from ' comark'
71+ import type { Snippet } from ' svelte'
7172 import type { ComponentResolver } from ' ../types.js'
7273 import ComarkNode from ' ./ComarkNode.svelte'
7374 import Resolve from ' ./Resolve.svelte'
@@ -100,6 +101,62 @@ naturally appears inline after the deepest trailing text node.
100101 ' link' , ' meta' , ' param' , ' source' , ' track' , ' wbr' ,
101102 ])
102103
104+ interface RenderChild {
105+ node: ComarkNodeType
106+ caretClass: string | null
107+ }
108+
109+ function getSlotName(node : ComarkNodeType ): string | null {
110+ if (typeof node === ' string' || ! Array .isArray (node ) || node [0 ] !== ' template' ) {
111+ return null
112+ }
113+
114+ const props = (node .length >= 2 ? node [1 ] : {}) ?? {}
115+ if (typeof props .name === ' string' && props .name ) {
116+ return props .name
117+ }
118+
119+ for (const key in props ) {
120+ if (key .startsWith (' #' ) && key .length > 1 ) {
121+ return key .slice (1 )
122+ }
123+ }
124+
125+ return null
126+ }
127+
128+ function createChildrenSnippet(
129+ snippetChildren : ComarkNodeType [],
130+ snippetRenderData : NodeRenderData ,
131+ snippetCaretClass : string | null ,
132+ ): Snippet {
133+ return ((anchor : unknown ) => {
134+ const renderNode = ComarkNode as unknown as (anchor : unknown , props : Record <string , unknown >) => void
135+ for (let i = 0 ; i < snippetChildren .length ; i ++ ) {
136+ renderNode (anchor , {
137+ node: snippetChildren [i ],
138+ components ,
139+ componentsManifest ,
140+ resolver: Resolver ,
141+ caretClass: i === snippetChildren .length - 1 ? snippetCaretClass : null ,
142+ renderData: snippetRenderData ,
143+ })
144+ }
145+ }) as unknown as Snippet
146+ }
147+
148+ function toRenderChildren(
149+ sourceChildren : ComarkNodeType [],
150+ sourceIndex : number ,
151+ totalChildren : number ,
152+ nodeCaretClass : string | null ,
153+ ): RenderChild [] {
154+ return sourceChildren .map ((child , index ) => ({
155+ node: child ,
156+ caretClass: sourceIndex === totalChildren - 1 && index === sourceChildren .length - 1 ? nodeCaretClass : null ,
157+ }))
158+ }
159+
103160 let { isText, tag, isVoid, children, Component, componentPromise, mappedProps } = $derived .by (() => {
104161 let isText = false
105162 let tag: string | null = null
@@ -159,16 +216,50 @@ naturally appears inline after the deepest trailing text node.
159216 ? { ... renderData , props: mappedProps }
160217 : renderData ,
161218 )
219+
220+ let { defaultChildren, namedSlotProps } = $derived .by (() => {
221+ const defaultChildren: RenderChild [] = []
222+ const slotProps: Record <string , Snippet > = {}
223+
224+ for (let i = 0 ; i < children .length ; i ++ ) {
225+ const child = children [i ]
226+ const slotName = getSlotName (child )
227+ if (slotName ) {
228+ const slotChildren = (child as unknown as ComarkNodeType []).slice (2 ) as ComarkNodeType []
229+ if (slotName === ' default' ) {
230+ defaultChildren .push (... toRenderChildren (slotChildren , i , children .length , caretClass ))
231+ }
232+ else {
233+ slotProps [slotName ] = createChildrenSnippet (
234+ slotChildren ,
235+ childrenRenderData ,
236+ i === children .length - 1 ? caretClass : null ,
237+ )
238+ }
239+ }
240+ else {
241+ defaultChildren .push ({ node: child , caretClass: i === children .length - 1 ? caretClass : null })
242+ }
243+ }
244+
245+ return { defaultChildren , namedSlotProps: slotProps }
246+ })
247+
248+ let componentProps = $derived (
249+ Object .keys (namedSlotProps ).length > 0
250+ ? { ... mappedProps , ... namedSlotProps }
251+ : mappedProps ,
252+ )
162253 </script >
163254
164255{#snippet renderChildren ()}
165- {#each children as child , i (i )}
256+ {#each defaultChildren as child , i (i )}
166257 <ComarkNode
167- node ={child }
258+ node ={child . node }
168259 {components }
169260 {componentsManifest }
170261 resolver ={Resolver }
171- caretClass ={i === children . length - 1 ? caretClass : null }
262+ caretClass ={child . caretClass }
172263 renderData ={childrenRenderData }
173264 />
174265 {/each }
@@ -180,11 +271,11 @@ naturally appears inline after the deepest trailing text node.
180271 style ={CARET_STYLE }>{CARET_TEXT }</span
181272 >{/if }
182273{:else if Component }
183- <Component {...mappedProps }>
274+ <Component {...componentProps }>
184275 {@render renderChildren ()}
185276 </Component >
186277{:else if componentPromise }
187- <Resolver promise ={componentPromise } props ={mappedProps }>
278+ <Resolver promise ={componentPromise } props ={componentProps }>
188279 {@render renderChildren ()}
189280 </Resolver >
190281{:else if isVoid }
0 commit comments