17
17
EventHandlerMapping ,
18
18
EventHandlerType ,
19
19
ImportSourceDict ,
20
- VdomAttributesAndChildren ,
20
+ Key ,
21
+ VdomChild ,
21
22
VdomDict ,
23
+ VdomDictConstructor ,
22
24
VdomJson ,
23
25
)
24
26
@@ -129,43 +131,47 @@ def is_vdom(value: Any) -> bool:
129
131
130
132
def vdom (
131
133
tag : str ,
132
- * attributes_and_children : VdomAttributesAndChildren ,
133
- key : str | int | None = None ,
134
- event_handlers : Optional [EventHandlerMapping ] = None ,
135
- import_source : Optional [ImportSourceDict ] = None ,
134
+ / ,
135
+ * children : VdomChild ,
136
+ key : Key | None = None ,
137
+ event_handlers : EventHandlerMapping | None = None ,
138
+ import_source : ImportSourceDict | None = None ,
139
+ ** attributes : Any ,
136
140
) -> VdomDict :
137
141
"""A helper function for creating VDOM dictionaries.
138
142
139
143
Parameters:
140
144
tag:
141
145
The type of element (e.g. 'div', 'h1', 'img')
142
- attributes_and_children:
143
- An optional attribute mapping followed by any number of children or
144
- iterables of children. The attribute mapping **must** precede the children,
145
- or children which will be merged into their respective parts of the model.
146
+ children:
147
+ String, compoennts, or other VDOM elements that are this element's children.
146
148
key:
147
- A string idicating the identity of a particular element. This is significant
148
- to preserve event handlers across updates - without a key, a re-render would
149
- cause these handlers to be deleted, but with a key, they would be redirected
150
- to any newly defined handlers.
149
+ A string or integer idicating the identity of a particular element. This is
150
+ significant to preserve event handlers across updates - without a key, a
151
+ re-render would cause these handlers to be deleted, but with a key, they
152
+ would be redirected to any newly defined handlers.
151
153
event_handlers:
152
- Maps event types to coroutines that are responsible for handling those events.
154
+ Maps event types to coroutines that are responsible for handling those
155
+ events.
153
156
import_source:
154
157
(subject to change) specifies javascript that, when evaluated returns a
155
158
React component.
159
+ attributes:
160
+ Remaining attributes of this element.
156
161
"""
157
162
model : VdomDict = {"tagName" : tag }
158
163
159
- attributes , children = coalesce_attributes_and_children (attributes_and_children )
160
164
attributes , event_handlers = separate_attributes_and_event_handlers (
161
- attributes , event_handlers or {}
165
+ attributes , event_handlers
162
166
)
163
167
164
168
if attributes :
169
+ if "cls" in attributes :
170
+ attributes ["class" ] = attributes .pop ("cls" )
165
171
model ["attributes" ] = attributes
166
172
167
173
if children :
168
- model ["children" ] = children
174
+ model ["children" ] = flatten_children ( children )
169
175
170
176
if event_handlers :
171
177
model ["eventHandlers" ] = event_handlers
@@ -179,39 +185,15 @@ def vdom(
179
185
return model
180
186
181
187
182
- class _VdomDictConstructor (Protocol ):
183
- def __call__ (
184
- self ,
185
- * attributes_and_children : VdomAttributesAndChildren ,
186
- key : str | int | None = ...,
187
- event_handlers : Optional [EventHandlerMapping ] = ...,
188
- import_source : Optional [ImportSourceDict ] = ...,
189
- ) -> VdomDict :
190
- ...
191
-
192
-
193
- def make_vdom_constructor (
194
- tag : str , allow_children : bool = True
195
- ) -> _VdomDictConstructor :
188
+ def make_vdom_constructor (tag : str , allow_children : bool = True ) -> VdomDictConstructor :
196
189
"""Return a constructor for VDOM dictionaries with the given tag name.
197
190
198
191
The resulting callable will have the same interface as :func:`vdom` but without its
199
192
first ``tag`` argument.
200
193
"""
201
194
202
- def constructor (
203
- * attributes_and_children : VdomAttributesAndChildren ,
204
- key : str | int | None = None ,
205
- event_handlers : Optional [EventHandlerMapping ] = None ,
206
- import_source : Optional [ImportSourceDict ] = None ,
207
- ) -> VdomDict :
208
- model = vdom (
209
- tag ,
210
- * attributes_and_children ,
211
- key = key ,
212
- event_handlers = event_handlers ,
213
- import_source = import_source ,
214
- )
195
+ def constructor (* args : Any , ** kwargs : Any ) -> VdomDict :
196
+ model = vdom (tag , * args , ** kwargs )
215
197
if not allow_children and "children" in model :
216
198
raise TypeError (f"{ tag !r} nodes cannot have children." )
217
199
return model
@@ -232,35 +214,24 @@ def constructor(
232
214
return constructor
233
215
234
216
235
- def coalesce_attributes_and_children (
236
- values : Sequence [Any ],
237
- ) -> Tuple [Mapping [str , Any ], List [Any ]]:
238
- if not values :
239
- return {}, []
240
-
241
- children_or_iterables : Sequence [Any ]
242
- attributes , * children_or_iterables = values
243
- if not _is_attributes (attributes ):
244
- attributes = {}
245
- children_or_iterables = values
246
-
247
- children : List [Any ] = []
248
- for child in children_or_iterables :
217
+ def flatten_children (children : Sequence [VdomChild ]) -> Sequence [VdomChild ]:
218
+ child_list : list [VdomChild ] = []
219
+ for child in children :
249
220
if _is_single_child (child ):
250
- children .append (child )
221
+ child_list .append (child )
251
222
else :
252
- children .extend (child )
253
-
254
- return attributes , children
223
+ child_list .extend (child )
224
+ return child_list
255
225
256
226
257
227
def separate_attributes_and_event_handlers (
258
- attributes : Mapping [str , Any ], event_handlers : EventHandlerMapping
228
+ attributes : Mapping [str , Any ],
229
+ event_handlers : EventHandlerMapping | None = None ,
259
230
) -> Tuple [Dict [str , Any ], EventHandlerDict ]:
260
231
separated_attributes = {}
261
232
separated_event_handlers : Dict [str , List [EventHandlerType ]] = {}
262
233
263
- for k , v in event_handlers .items ():
234
+ for k , v in ( event_handlers or {}) .items ():
264
235
separated_event_handlers [k ] = [v ]
265
236
266
237
for k , v in attributes .items ():
0 commit comments