@@ -214,8 +214,8 @@ async def test_keys_properly_propagated(display: DisplayFixture):
214
214
215
215
The `key` property was being lost in its propagation from the server-side ReactPy
216
216
definition to the front-end JavaScript.
217
-
218
- This property is required for certain JS components, such as the GridLayout from
217
+
218
+ This property is required for certain JS components, such as the GridLayout from
219
219
react-grid-layout.
220
220
"""
221
221
module = reactpy .web .module_from_file (
@@ -224,50 +224,171 @@ async def test_keys_properly_propagated(display: DisplayFixture):
224
224
GridLayout = reactpy .web .export (module , "GridLayout" )
225
225
226
226
await display .show (
227
- lambda : GridLayout ({
228
- "layout" : [
229
- {
230
- "i" : "a" ,
231
- "x" : 0 ,
232
- "y" : 0 ,
233
- "w" : 1 ,
234
- "h" : 2 ,
235
- "static" : True ,
236
- },
237
- {
238
- "i" : "b" ,
239
- "x" : 1 ,
240
- "y" : 0 ,
241
- "w" : 3 ,
242
- "h" : 2 ,
243
- "minW" : 2 ,
244
- "maxW" : 4 ,
245
- },
246
- {
247
- "i" : "c" ,
248
- "x" : 4 ,
249
- "y" : 0 ,
250
- "w" : 1 ,
251
- "h" : 2 ,
252
- }
253
- ],
254
- "cols" : 12 ,
255
- "rowHeight" : 30 ,
256
- "width" : 1200 ,
257
- },
227
+ lambda : GridLayout (
228
+ {
229
+ "layout" : [
230
+ {
231
+ "i" : "a" ,
232
+ "x" : 0 ,
233
+ "y" : 0 ,
234
+ "w" : 1 ,
235
+ "h" : 2 ,
236
+ "static" : True ,
237
+ },
238
+ {
239
+ "i" : "b" ,
240
+ "x" : 1 ,
241
+ "y" : 0 ,
242
+ "w" : 3 ,
243
+ "h" : 2 ,
244
+ "minW" : 2 ,
245
+ "maxW" : 4 ,
246
+ },
247
+ {
248
+ "i" : "c" ,
249
+ "x" : 4 ,
250
+ "y" : 0 ,
251
+ "w" : 1 ,
252
+ "h" : 2 ,
253
+ },
254
+ ],
255
+ "cols" : 12 ,
256
+ "rowHeight" : 30 ,
257
+ "width" : 1200 ,
258
+ },
258
259
reactpy .html .div ({"key" : "a" }, "a" ),
259
260
reactpy .html .div ({"key" : "b" }, "b" ),
260
261
reactpy .html .div ({"key" : "c" }, "c" ),
261
262
)
262
263
)
263
264
264
- parent = await display .page .wait_for_selector (".react-grid-layout" , state = "attached" )
265
+ parent = await display .page .wait_for_selector (
266
+ ".react-grid-layout" , state = "attached"
267
+ )
265
268
children = await parent .query_selector_all ("div" )
266
269
267
270
# The children simply will not render unless they receive the key prop
268
271
assert len (children ) == 3
269
272
270
273
274
+ async def test_subcomponent_notation_as_str_attrs (display : DisplayFixture ):
275
+ module = reactpy .web .module_from_file (
276
+ "subcomponent-notation" ,
277
+ JS_FIXTURES_DIR / "subcomponent-notation.js" ,
278
+ )
279
+ InputGroup , InputGroupText , FormControl , FormLabel = reactpy .web .export (
280
+ module , ["InputGroup" , "InputGroup.Text" , "Form.Control" , "Form.Label" ]
281
+ )
282
+
283
+ content = reactpy .html .div (
284
+ {"id" : "the-parent" },
285
+ InputGroup (
286
+ InputGroupText ({"id" : "basic-addon1" }, "@" ),
287
+ FormControl (
288
+ {
289
+ "placeholder" : "Username" ,
290
+ "aria-label" : "Username" ,
291
+ "aria-describedby" : "basic-addon1" ,
292
+ }
293
+ ),
294
+ ),
295
+ InputGroup (
296
+ FormControl (
297
+ {
298
+ "placeholder" : "Recipient's username" ,
299
+ "aria-label" : "Recipient's username" ,
300
+ "aria-describedby" : "basic-addon2" ,
301
+ }
302
+ ),
303
+ InputGroupText ({"id" : "basic-addon2" }, "@example.com" ),
304
+ ),
305
+ FormLabel ({"htmlFor" : "basic-url" }, "Your vanity URL" ),
306
+ InputGroup (
307
+ InputGroupText ({"id" : "basic-addon3" }, "https://example.com/users/" ),
308
+ FormControl ({"id" : "basic-url" , "aria-describedby" : "basic-addon3" }),
309
+ ),
310
+ InputGroup (
311
+ InputGroupText ("$" ),
312
+ FormControl ({"aria-label" : "Amount (to the nearest dollar)" }),
313
+ InputGroupText (".00" ),
314
+ ),
315
+ InputGroup (
316
+ InputGroupText ("With textarea" ),
317
+ FormControl ({"as" : "textarea" , "aria-label" : "With textarea" }),
318
+ ),
319
+ )
320
+
321
+ await display .show (lambda : content )
322
+
323
+ await display .page .wait_for_selector ("#basic-addon3" , state = "attached" )
324
+ parent = await display .page .wait_for_selector ("#the-parent" , state = "attached" )
325
+ input_group_text = await parent .query_selector_all (".input-group-text" )
326
+ form_control = await parent .query_selector_all (".form-control" )
327
+ form_label = await parent .query_selector_all (".form-label" )
328
+
329
+ assert len (input_group_text ) == 6
330
+ assert len (form_control ) == 5
331
+ assert len (form_label ) == 1
332
+
333
+
334
+ async def test_subcomponent_notation_as_obj_attrs (display : DisplayFixture ):
335
+ module = reactpy .web .module_from_file (
336
+ "subcomponent-notation" ,
337
+ JS_FIXTURES_DIR / "subcomponent-notation.js" ,
338
+ )
339
+ InputGroup , Form = reactpy .web .export (module , ["InputGroup" , "Form" ])
340
+
341
+ content = reactpy .html .div (
342
+ {"id" : "the-parent" },
343
+ InputGroup (
344
+ InputGroup .Text ({"id" : "basic-addon1" }, "@" ),
345
+ Form .Control (
346
+ {
347
+ "placeholder" : "Username" ,
348
+ "aria-label" : "Username" ,
349
+ "aria-describedby" : "basic-addon1" ,
350
+ }
351
+ ),
352
+ ),
353
+ InputGroup (
354
+ Form .Control (
355
+ {
356
+ "placeholder" : "Recipient's username" ,
357
+ "aria-label" : "Recipient's username" ,
358
+ "aria-describedby" : "basic-addon2" ,
359
+ }
360
+ ),
361
+ InputGroup .Text ({"id" : "basic-addon2" }, "@example.com" ),
362
+ ),
363
+ Form .Label ({"htmlFor" : "basic-url" }, "Your vanity URL" ),
364
+ InputGroup (
365
+ InputGroup .Text ({"id" : "basic-addon3" }, "https://example.com/users/" ),
366
+ Form .Control ({"id" : "basic-url" , "aria-describedby" : "basic-addon3" }),
367
+ ),
368
+ InputGroup (
369
+ InputGroup .Text ("$" ),
370
+ Form .Control ({"aria-label" : "Amount (to the nearest dollar)" }),
371
+ InputGroup .Text (".00" ),
372
+ ),
373
+ InputGroup (
374
+ InputGroup .Text ("With textarea" ),
375
+ Form .Control ({"as" : "textarea" , "aria-label" : "With textarea" }),
376
+ ),
377
+ )
378
+
379
+ await display .show (lambda : content )
380
+
381
+ await display .page .wait_for_selector ("#basic-addon3" , state = "attached" )
382
+ parent = await display .page .wait_for_selector ("#the-parent" , state = "attached" )
383
+ input_group_text = await parent .query_selector_all (".input-group-text" )
384
+ form_control = await parent .query_selector_all (".form-control" )
385
+ form_label = await parent .query_selector_all (".form-label" )
386
+
387
+ assert len (input_group_text ) == 6
388
+ assert len (form_control ) == 5
389
+ assert len (form_label ) == 1
390
+
391
+
271
392
def test_module_from_string ():
272
393
reactpy .web .module_from_string ("temp" , "old" )
273
394
with assert_reactpy_did_log (r"Existing web module .* will be replaced with" ):
0 commit comments