posthtml-component 2.0.0-beta.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1062 -1043
- package/package.json +11 -7
- package/src/index.d.ts +214 -0
- package/src/index.js +1 -1
- package/src/process-attributes.js +3 -3
- package/src/valid-attributes.js +2 -2
package/README.md
CHANGED
|
@@ -1,1043 +1,1062 @@
|
|
|
1
|
-
[
|
|
2
|
-
[
|
|
3
|
-
[
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
``` html
|
|
39
|
-
<!-- src/
|
|
40
|
-
<
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
and
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
|
121
|
-
|
|
122
|
-
|
|
|
123
|
-
|
|
|
124
|
-
|
|
|
125
|
-
|
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
|
|
|
129
|
-
| **
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
</
|
|
357
|
-
</
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
<
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
</div>
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
<
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
<
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
<
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
<
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
<
|
|
469
|
-
<
|
|
470
|
-
|
|
471
|
-
</
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
<
|
|
475
|
-
</
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
<
|
|
488
|
-
|
|
489
|
-
</
|
|
490
|
-
<
|
|
491
|
-
<
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
</
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
<div class="modal">
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
<
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
</
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
<
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
```html
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
```
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
<div
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
<div class="modal
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
```
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
```html
|
|
650
|
-
|
|
651
|
-
<
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
</
|
|
656
|
-
<
|
|
657
|
-
|
|
658
|
-
</
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
```
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
```html
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
</
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
<
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
```
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
```html
|
|
764
|
-
<!--
|
|
765
|
-
<button type="submit" class="btn-
|
|
766
|
-
```
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
```html
|
|
771
|
-
<!--
|
|
772
|
-
<
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
```
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
```
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
<div class="modal
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
<
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
<button type="button" class="btn btn-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
>
|
|
907
|
-
|
|
908
|
-
<
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
<
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
</
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
<
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
>
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1
|
+
[npm]: https://www.npmjs.com/package/posthtml-component
|
|
2
|
+
[npm-version-shield]: https://img.shields.io/npm/v/posthtml-component.svg
|
|
3
|
+
[npm-stats]: http://npm-stat.com/charts.html?package=posthtml-component
|
|
4
|
+
[npm-stats-shield]: https://img.shields.io/npm/dt/posthtml-component.svg
|
|
5
|
+
[github-ci]: https://github.com/posthtml/posthtml-components/actions/workflows/build.yml
|
|
6
|
+
[github-ci-shield]: https://github.com/posthtml/posthtml-components/actions/workflows/build.yml/badge.svg
|
|
7
|
+
[license]: ./LICENSE
|
|
8
|
+
[license-shield]: https://img.shields.io/npm/l/posthtml-component.svg
|
|
9
|
+
|
|
10
|
+
<div align="center">
|
|
11
|
+
<img width="150" height="150" alt="PostHTML" src="https://posthtml.github.io/posthtml/logo.svg">
|
|
12
|
+
<h1>PostHTML Components</h1>
|
|
13
|
+
<p>Laravel Blade-inspired components for PostHTML</p>
|
|
14
|
+
|
|
15
|
+
[![Version][npm-version-shield]][npm]
|
|
16
|
+
[![Build][github-ci-shield]][github-ci]
|
|
17
|
+
[![License][license-shield]][license]
|
|
18
|
+
[![Downloads][npm-stats-shield]][npm-stats]
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm i -D posthtml-component
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Introduction
|
|
28
|
+
|
|
29
|
+
This PostHTML plugin provides an HTML-friendly syntax for using components in your HTML templates.
|
|
30
|
+
If you are familiar with Blade, React, Vue or similar, you will find the syntax to be familiar, as this plugin is inspired by them.
|
|
31
|
+
|
|
32
|
+
**See also the first [PostHTML Bootstrap UI](https://github.com/thewebartisan7/posthtml-bootstrap-ui) using this plugin and check also the [starter template here](https://github.com/thewebartisan7/posthtml-bootstrap-ui-starter).**
|
|
33
|
+
|
|
34
|
+
## Basic example
|
|
35
|
+
|
|
36
|
+
Create the component:
|
|
37
|
+
|
|
38
|
+
``` html
|
|
39
|
+
<!-- src/button.html -->
|
|
40
|
+
<button type="button" class="btn">
|
|
41
|
+
<yield></yield>
|
|
42
|
+
</button>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Use it:
|
|
46
|
+
|
|
47
|
+
``` html
|
|
48
|
+
<!-- src/index.html -->
|
|
49
|
+
<html>
|
|
50
|
+
<body>
|
|
51
|
+
<x-button type="submit" class="btn-primary">Submit</x-button>
|
|
52
|
+
</body>
|
|
53
|
+
</html>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Init PostHTML:
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
// index.js
|
|
60
|
+
const posthtml = require('posthtml')
|
|
61
|
+
const components = require('posthtml-components')
|
|
62
|
+
const { readFileSync, writeFileSync } = require('node:fs')
|
|
63
|
+
|
|
64
|
+
posthtml([
|
|
65
|
+
components({ root: './src' })
|
|
66
|
+
])
|
|
67
|
+
.process(readFileSync('src/index.html', 'utf8'))
|
|
68
|
+
.then(result => writeFileSync('dist/index.html', result.html, 'utf8'))
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Result:
|
|
72
|
+
|
|
73
|
+
``` html
|
|
74
|
+
<!-- dist/index.html -->
|
|
75
|
+
<html>
|
|
76
|
+
<body>
|
|
77
|
+
<button type="submit" class="btn btn-primary">Submit</button>
|
|
78
|
+
</body>
|
|
79
|
+
</html>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
You might have noticed that the `src/button.html` component contains `type` and `class` attributes, and that we also passed those attributes when we used it in `src/index.html`.
|
|
83
|
+
|
|
84
|
+
The result is that `type` was overridden, and `class` was merged.
|
|
85
|
+
|
|
86
|
+
By default, `class` and `style` attributes are merged, while all others attribute are overridden. You can also override `class` and `style` attributes by prepending `override:` to the class attribute.
|
|
87
|
+
|
|
88
|
+
For example:
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<x-button override:class="btn-custom">Submit</x-button>
|
|
92
|
+
|
|
93
|
+
<!-- Output -->
|
|
94
|
+
<button type="button" class="btn-custom">Submit</button>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
All attributes that you pass to the component will be added to the first node of your component or to the node with an attribute named `attributes`, _only_ if they are not defined as `props` via `<script props>` or if they are not "known attributes" (see
|
|
98
|
+
[valid-attributes.js](https://github.com/thewebartisan7/posthtml-components/blob/main/src/valid-attributes.js)).
|
|
99
|
+
|
|
100
|
+
You can also define which attributes are considered to be valid, via the plugin's options.
|
|
101
|
+
|
|
102
|
+
More details on this in [Attributes](#attributes) section.
|
|
103
|
+
|
|
104
|
+
### yield tag
|
|
105
|
+
|
|
106
|
+
The `<yield></yield>` tag is where content that you pass to a component will be injected.
|
|
107
|
+
|
|
108
|
+
The plugin configures the PostHTML parser to recognize self-closing tags, so you can also just write is as `<yield />`.
|
|
109
|
+
|
|
110
|
+
For brevity, we will use self-closing tags in the examples.
|
|
111
|
+
|
|
112
|
+
### More examples
|
|
113
|
+
|
|
114
|
+
See also the `docs-src` folder where you can find more examples.
|
|
115
|
+
|
|
116
|
+
You can clone this repo and run `npm run build` to compile them.
|
|
117
|
+
|
|
118
|
+
## Options
|
|
119
|
+
|
|
120
|
+
| Name | Type | Default | Description |
|
|
121
|
+
|--------------------------|-------------------|----------------------------------------------|-----------------------------------------------------------------------------------------|
|
|
122
|
+
| **root** | `String` | `'./'` | Root path for components lookup. |
|
|
123
|
+
| **folders** | `String[]` | `['']` | Array of paths relative to `options.root` or defined namespaces. |
|
|
124
|
+
| **tagPrefix** | `String` | `'x-'` | Tag prefix. |
|
|
125
|
+
| **tag** | `String\|Boolean` | `false` | Component tag. Use with `options.attribute`. Boolean only `false`. |
|
|
126
|
+
| **attribute** | `String` | `'src'` | Component attribute for setting path. |
|
|
127
|
+
| **namespaces** | `String[]` | `[]` | Array of namespace root paths, fallback paths, and custom override paths. |
|
|
128
|
+
| **namespaceSeparator** | `String` | `'::'` | Namespace separator for tag names. |
|
|
129
|
+
| **fileExtension** | `String` | `'html'` | File extension for component files. |
|
|
130
|
+
| **yield** | `String` | `'yield'` | Tag name for injecting main component content. |
|
|
131
|
+
| **slot** | `String` | `'slot'` | Tag name for slots. |
|
|
132
|
+
| **fill** | `String` | `'fill'` | Tag name for filling slots. |
|
|
133
|
+
| **slotSeparator** | `String` | `':'` | Name separator for `<slot>` and `<fill>` tags. |
|
|
134
|
+
| **push** | `String` | `'push'` | Tag name for `<push>`. |
|
|
135
|
+
| **stack** | `String` | `'stack'` | Tag name for `<stack>`. |
|
|
136
|
+
| **propsScriptAttribute** | `String` | `'props'` | Attribute in `<script props>` for retrieving component props. |
|
|
137
|
+
| **propsContext** | `String` | `'props'` | Name of the object inside the script for processing props. |
|
|
138
|
+
| **propsAttribute** | `String` | `'props'` | Attribute to define props as JSON. |
|
|
139
|
+
| **propsSlot** | `String` | `'props'` | Used to retrieve props passed to slot via `$slots.slotName.props`. |
|
|
140
|
+
| **parserOptions** | `Object` | `{recognizeSelfClosing: true}` | Pass options to `posthtml-parser`. |
|
|
141
|
+
| **expressions** | `Object` | `{}` | Pass options to `posthtml-expressions`. |
|
|
142
|
+
| **plugins** | `Array` | `[]` | PostHTML plugins to apply to every parsed component. |
|
|
143
|
+
| **matcher** | `Object` | `[{tag: options.tagPrefix}]` | Array of objects used to match tags. |
|
|
144
|
+
| **attrsParserRules** | `Object` | `{}` | Additional rules for attributes parser plugin. |
|
|
145
|
+
| **strict** | `Boolean` | `true` | Toggle exception throwing. |
|
|
146
|
+
| **mergeCustomizer** | `Function` | `function` | Callback for lodash `mergeWith` to merge `options.expressions.locals` and props. |
|
|
147
|
+
| **utilities** | `Object` | `{merge: _.mergeWith, template: _.template}` | Utility methods passed to `<script props>`. |
|
|
148
|
+
| **elementAttributes** | `Object` | `{}` | Object with tag names and function modifiers of `valid-attributes.js`. |
|
|
149
|
+
| **safelistAttributes** | `String[]` | `['data-*']` | Array of attribute names to add to default valid attributes. |
|
|
150
|
+
| **blocklistAttributes** | `String[]` | `[]` | Array of attribute names to remove from default valid attributes. |
|
|
151
|
+
|
|
152
|
+
## Features
|
|
153
|
+
|
|
154
|
+
### Tag names and x-tags
|
|
155
|
+
|
|
156
|
+
You can use the components in multiple ways, or also a combination of them.
|
|
157
|
+
|
|
158
|
+
If you to use components as 'includes', you may define a tag and src attribute name.
|
|
159
|
+
|
|
160
|
+
Using our previous button component example, we can define the tag and attribute names and then use it in this way:
|
|
161
|
+
|
|
162
|
+
```hbs
|
|
163
|
+
<!-- src/index.html -->
|
|
164
|
+
<html>
|
|
165
|
+
<body>
|
|
166
|
+
<component src="button.html">Submit</component>
|
|
167
|
+
</body>
|
|
168
|
+
</html>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Init PostHTML:
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
// index.js
|
|
175
|
+
|
|
176
|
+
require('posthtml')(
|
|
177
|
+
require('posthtml-components')({
|
|
178
|
+
root: './src',
|
|
179
|
+
tag: 'component',
|
|
180
|
+
attribute: 'src'
|
|
181
|
+
}))
|
|
182
|
+
.process(/* ... */)
|
|
183
|
+
.then(/* ... */)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
If you need more control over tag matching, you can pass an array of matcher or single object via `options.matcher` like this:
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
// index.js
|
|
190
|
+
const options = {
|
|
191
|
+
root: './src',
|
|
192
|
+
matcher: [{tag: 'a-tag'}, {tag: 'another-one'}, {tag: new RegExp(`^app-`, 'i')}]
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
require('posthtml')(require('posthtml-components')(options))
|
|
196
|
+
.process(/* ... */)
|
|
197
|
+
.then(/* ... */)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
With `posthtml-components` you don't need to specify the path name when you are using `x-tag-name` syntax.
|
|
201
|
+
|
|
202
|
+
Setup PostHTML:
|
|
203
|
+
|
|
204
|
+
```js
|
|
205
|
+
// index.js
|
|
206
|
+
const options = {
|
|
207
|
+
root: './src',
|
|
208
|
+
tagPrefix: 'x-'
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
require('posthtml')(require('posthtml-components')(options))
|
|
212
|
+
.process(/* ... */)
|
|
213
|
+
.then(/* ... */)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Use:
|
|
217
|
+
|
|
218
|
+
``` html
|
|
219
|
+
<!-- src/index.html -->
|
|
220
|
+
<html>
|
|
221
|
+
<body>
|
|
222
|
+
<x-button>Submit</x-button>
|
|
223
|
+
</body>
|
|
224
|
+
</html>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
If your components are in a subfolder then you can use `dot` to access it:
|
|
228
|
+
|
|
229
|
+
``` html
|
|
230
|
+
<!-- src/components/forms/button.html -->
|
|
231
|
+
<x-forms.button>Submit</x-forms.button>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
If your components are in a sub-folder with multiple files, then in order to avoid writing out the main file name you can use `index.html` without specifying it.
|
|
235
|
+
|
|
236
|
+
Here's an example:
|
|
237
|
+
|
|
238
|
+
``` html
|
|
239
|
+
<!-- src/components/modals/index.html -->
|
|
240
|
+
<x-modal.index>Submit</x-modal.index>
|
|
241
|
+
|
|
242
|
+
<!-- You may omit "index" part since the file is named "index.html" -->
|
|
243
|
+
<x-modal>Submit</x-modal>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
#### Parser options
|
|
247
|
+
|
|
248
|
+
You may pass options to `posthtml-parser` via `options.parserOptions`.
|
|
249
|
+
|
|
250
|
+
```js
|
|
251
|
+
// index.js
|
|
252
|
+
const options = {
|
|
253
|
+
root: './src',
|
|
254
|
+
parserOptions: { decodeEntities: true }
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
require('posthtml')(require('posthtml-components')(options))
|
|
258
|
+
.process('some HTML', options.parserOptions)
|
|
259
|
+
.then(/* ... */)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Important: as you can see, whatever `parserOptions` you pass to the plugin, must also be passed in the `process` method in your code, otherwise your PostHTML build will use `posthtml-parser` defaults and will override anything you've passed to `posthtml-component`.
|
|
263
|
+
|
|
264
|
+
#### Self-closing tags
|
|
265
|
+
|
|
266
|
+
The plugin supports self-closing tags by default, but you need to make sure to enable them in the `process` method in your code too, by passing `recognizeSelfClosing: true` in the options object:
|
|
267
|
+
|
|
268
|
+
```js
|
|
269
|
+
// index.js
|
|
270
|
+
require('posthtml')(require('posthtml-components')({root: './src'}))
|
|
271
|
+
.process('your HTML...', {recognizeSelfClosing: true})
|
|
272
|
+
.then(/* ... */)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
If you don't add this to `process`, PostHTML will use `posthtml-parser` defaults and will not support self-closing component tags. This will result in everything after a self-closing tag not being output.
|
|
276
|
+
|
|
277
|
+
### Multiple folders
|
|
278
|
+
|
|
279
|
+
You have full control over where your component files exist. Once you set the base root path of your components, you can then set multiple folders.
|
|
280
|
+
|
|
281
|
+
For example if your root is `./src` and then you have several folders where you have your components, for example `./src/components` and `./src/layouts`, you can set up the plugin like below:
|
|
282
|
+
|
|
283
|
+
```js
|
|
284
|
+
// index.js
|
|
285
|
+
const options = {
|
|
286
|
+
root: './src',
|
|
287
|
+
folders: ['components', 'layouts']
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
require('posthtml')(require('posthtml-components')(options))
|
|
291
|
+
.process(/* ... */)
|
|
292
|
+
.then(/* ... */)
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Namespaces
|
|
296
|
+
|
|
297
|
+
With namespaces, you can define a top level root path to your components.
|
|
298
|
+
|
|
299
|
+
It can be useful for handling custom themes, where you define a specific top level root with a fallback root for when a component is not found, and a custom root for overriding.
|
|
300
|
+
|
|
301
|
+
This makes it possible to create folder structures like this:
|
|
302
|
+
|
|
303
|
+
- `src` (root folder)
|
|
304
|
+
- `components` (folder for components like modal, button, etc.)
|
|
305
|
+
- `layouts` (folder for layout components like base layout, header, footer, etc.)
|
|
306
|
+
- `theme-dark` (namespace folder for theme-dark)
|
|
307
|
+
- `components` (folder for components for theme dark)
|
|
308
|
+
- `layouts` (folder for layout components for dark theme)
|
|
309
|
+
- `theme-light` (namespace folder for theme-light)
|
|
310
|
+
- `components` (folder for components for light theme)
|
|
311
|
+
- `layouts` (folder for layout components for dark theme)
|
|
312
|
+
- `custom` (custom folder for override your namespace themes)
|
|
313
|
+
- `theme-dark` (custom folder for override dark theme)
|
|
314
|
+
- `components` (folder for override components of theme dark)
|
|
315
|
+
- `layouts` (folder for override layout components of dark theme)
|
|
316
|
+
- `theme-light` (custom folder for override light theme)
|
|
317
|
+
- `components` (folder for override components of theme dark)
|
|
318
|
+
- `layouts` (folder for override layout components of dark theme)
|
|
319
|
+
|
|
320
|
+
And the options would be like:
|
|
321
|
+
|
|
322
|
+
```js
|
|
323
|
+
// index.js
|
|
324
|
+
const options = {
|
|
325
|
+
// Root for component without namespace
|
|
326
|
+
root: './src',
|
|
327
|
+
// Folders is always appended in 'root' or any defined namespace's folders (base, fallback or custom)
|
|
328
|
+
folders: ['components', 'layouts'],
|
|
329
|
+
namespaces: [{
|
|
330
|
+
// Namespace name will be prepended to tag name (example <x-theme-dark::button>)
|
|
331
|
+
name: 'theme-dark',
|
|
332
|
+
// Root of the namespace
|
|
333
|
+
root: './src/theme-dark',
|
|
334
|
+
// Fallback root when a component is not found in namespace
|
|
335
|
+
fallback: './src',
|
|
336
|
+
// Custom root for overriding, the lookup happens here first
|
|
337
|
+
custom: './src/custom/theme-dark'
|
|
338
|
+
}, {
|
|
339
|
+
// Light theme
|
|
340
|
+
name: 'theme-light',
|
|
341
|
+
root: './src/theme-light',
|
|
342
|
+
fallback: './src',
|
|
343
|
+
custom: './src/custom/theme-light'
|
|
344
|
+
}, {
|
|
345
|
+
/* ... */
|
|
346
|
+
}]
|
|
347
|
+
};
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Use the component namespace:
|
|
351
|
+
|
|
352
|
+
```xml
|
|
353
|
+
<!-- src/index.html -->
|
|
354
|
+
<html>
|
|
355
|
+
<body>
|
|
356
|
+
<x-theme-dark::button>Submit</theme-dark::button>
|
|
357
|
+
<x-theme-light::button>Submit</theme-light::button>
|
|
358
|
+
</body>
|
|
359
|
+
</html>
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Slots
|
|
363
|
+
|
|
364
|
+
Components may define slots that can be filled with content when used.
|
|
365
|
+
|
|
366
|
+
For example:
|
|
367
|
+
|
|
368
|
+
```xml
|
|
369
|
+
<!-- src/modal.html -->
|
|
370
|
+
<div class="modal">
|
|
371
|
+
<div class="modal-header">
|
|
372
|
+
<slot:header />
|
|
373
|
+
</div>
|
|
374
|
+
<div class="modal-body">
|
|
375
|
+
<slot:body />
|
|
376
|
+
</div>
|
|
377
|
+
<div class="modal-footer">
|
|
378
|
+
<slot:footer />
|
|
379
|
+
</div>
|
|
380
|
+
</div>
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
Use the component:
|
|
384
|
+
|
|
385
|
+
```xml
|
|
386
|
+
<!-- src/index.html -->
|
|
387
|
+
<x-modal>
|
|
388
|
+
<fill:header>Header content</fill:header>
|
|
389
|
+
<fill:body>Body content</fill:body>
|
|
390
|
+
<fill:footer>Footer content</fill:footer>
|
|
391
|
+
</x-modal>
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Result:
|
|
395
|
+
|
|
396
|
+
```html
|
|
397
|
+
<!-- dist/index.html -->
|
|
398
|
+
<div class="modal">
|
|
399
|
+
<div class="modal-header">
|
|
400
|
+
Header content
|
|
401
|
+
</div>
|
|
402
|
+
<div class="modal-body">
|
|
403
|
+
Body content
|
|
404
|
+
</div>
|
|
405
|
+
<div class="modal-footer">
|
|
406
|
+
Footer content
|
|
407
|
+
</div>
|
|
408
|
+
</div>
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
By default, the slot content is replaced, but you can also prepend or append the content, or keep the default content by not filling the slot.
|
|
412
|
+
|
|
413
|
+
Add some default content in the component:
|
|
414
|
+
|
|
415
|
+
```xml
|
|
416
|
+
<!-- src/modal.html -->
|
|
417
|
+
<div class="modal">
|
|
418
|
+
<div class="modal-header">
|
|
419
|
+
<slot:header>Default header</slot:header>
|
|
420
|
+
</div>
|
|
421
|
+
<div class="modal-body">
|
|
422
|
+
<slot:body>content</slot:body>
|
|
423
|
+
</div>
|
|
424
|
+
<div class="modal-footer">
|
|
425
|
+
<slot:footer>Footer</slot:footer>
|
|
426
|
+
</div>
|
|
427
|
+
</div>
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
```xml
|
|
431
|
+
<!-- src/index.html -->
|
|
432
|
+
<x-modal>
|
|
433
|
+
<fill:body prepend>Prepend body</fill:body>
|
|
434
|
+
<fill:footer append>content</fill:footer>
|
|
435
|
+
</x-modal>
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Result:
|
|
439
|
+
|
|
440
|
+
```html
|
|
441
|
+
<!-- dist/index.html -->
|
|
442
|
+
<div class="modal">
|
|
443
|
+
<div class="modal-header">
|
|
444
|
+
Default header
|
|
445
|
+
</div>
|
|
446
|
+
<div class="modal-body">
|
|
447
|
+
Prepend body content
|
|
448
|
+
</div>
|
|
449
|
+
<div class="modal-footer">
|
|
450
|
+
Footer content
|
|
451
|
+
</div>
|
|
452
|
+
</div>
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Stacks
|
|
456
|
+
|
|
457
|
+
You may push content to named stacks which can be rendered somewhere else, like in another component. This can be particularly useful for specifying any JavaScript or CSS required by your components.
|
|
458
|
+
|
|
459
|
+
First, add a `<stack>` tag to your HTML:
|
|
460
|
+
|
|
461
|
+
```diff
|
|
462
|
+
<!-- src/index.html -->
|
|
463
|
+
<html>
|
|
464
|
+
<head>
|
|
465
|
+
+ <stack name="styles" />
|
|
466
|
+
</head>
|
|
467
|
+
<body>
|
|
468
|
+
<x-modal>
|
|
469
|
+
<fill:header>Header content</fill:header>
|
|
470
|
+
<fill:body>Body content</fill:body>
|
|
471
|
+
<fill:footer>Footer content</fill:footer>
|
|
472
|
+
</x-modal>
|
|
473
|
+
|
|
474
|
+
+ <stack name="scripts" />
|
|
475
|
+
</body>
|
|
476
|
+
</html>
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Then, in modal components or any other child components, you can push content to this stack:
|
|
480
|
+
|
|
481
|
+
```xml
|
|
482
|
+
<!-- src/modal.html -->
|
|
483
|
+
<div class="modal">
|
|
484
|
+
<div class="modal-header">
|
|
485
|
+
<slot:header />
|
|
486
|
+
</div>
|
|
487
|
+
<div class="modal-body">
|
|
488
|
+
<slot:body />
|
|
489
|
+
</div>
|
|
490
|
+
<div class="modal-footer">
|
|
491
|
+
<slot:footer />
|
|
492
|
+
</div>
|
|
493
|
+
</div>
|
|
494
|
+
|
|
495
|
+
<push name="styles">
|
|
496
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
497
|
+
</push>
|
|
498
|
+
|
|
499
|
+
<push name="scripts">
|
|
500
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
501
|
+
</push>
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
The output will be:
|
|
505
|
+
|
|
506
|
+
```html
|
|
507
|
+
<!-- dist/index.html -->
|
|
508
|
+
<html>
|
|
509
|
+
<head>
|
|
510
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
511
|
+
</head>
|
|
512
|
+
<body>
|
|
513
|
+
<div class="modal">
|
|
514
|
+
<div class="modal-header">
|
|
515
|
+
Header content
|
|
516
|
+
</div>
|
|
517
|
+
<div class="modal-body">
|
|
518
|
+
Body content
|
|
519
|
+
</div>
|
|
520
|
+
<div class="modal-footer">
|
|
521
|
+
Footer content
|
|
522
|
+
</div>
|
|
523
|
+
</div>
|
|
524
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
525
|
+
</body>
|
|
526
|
+
</html>
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
The `once` attribute allows you to push content only once per rendering cycle.
|
|
530
|
+
|
|
531
|
+
For example, if you are rendering a given component within a loop, you may wish to only push the JavaScript and CSS the first time the component is rendered.
|
|
532
|
+
|
|
533
|
+
Example.
|
|
534
|
+
|
|
535
|
+
```html
|
|
536
|
+
<!-- src/modal.html -->
|
|
537
|
+
<div class="modal">
|
|
538
|
+
<!-- ... -->
|
|
539
|
+
</div>
|
|
540
|
+
|
|
541
|
+
<!-- The push content will be pushed only once in the stack -->
|
|
542
|
+
|
|
543
|
+
<push name="styles" once>
|
|
544
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
545
|
+
</push>
|
|
546
|
+
|
|
547
|
+
<push name="scripts" once>
|
|
548
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
549
|
+
</push>
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
By default, the content is pushed in the stack in the given order. If you would like to prepend content onto the beginning of a stack, you may use the `prepend` attribute:
|
|
553
|
+
|
|
554
|
+
```html
|
|
555
|
+
<push name="scripts">
|
|
556
|
+
<!-- This will be second -->
|
|
557
|
+
<script src="/example.js"></script>
|
|
558
|
+
</push>
|
|
559
|
+
|
|
560
|
+
<!-- Later... -->
|
|
561
|
+
<push name="scripts" prepend>
|
|
562
|
+
<!-- This will be first -->
|
|
563
|
+
<script src="/example-2.js"></script>
|
|
564
|
+
</push>
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### Props
|
|
568
|
+
|
|
569
|
+
`props` can be passed to components in HTML attributes. To use them in a component, they must be defined in the component's `<script props>` tag.
|
|
570
|
+
|
|
571
|
+
For example:
|
|
572
|
+
|
|
573
|
+
```html
|
|
574
|
+
<!-- src/alert.html -->
|
|
575
|
+
<script props>
|
|
576
|
+
module.exports = {
|
|
577
|
+
title: props.title || 'Default title'
|
|
578
|
+
}
|
|
579
|
+
</script>
|
|
580
|
+
<div>
|
|
581
|
+
{{ title }}
|
|
582
|
+
</div>
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
Use:
|
|
586
|
+
|
|
587
|
+
```html
|
|
588
|
+
<x-alert title="Hello world!" />
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
The output will be:
|
|
592
|
+
|
|
593
|
+
```html
|
|
594
|
+
<div>
|
|
595
|
+
Hello world!
|
|
596
|
+
</div>
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
If no `title` attribute is passed to the component, the default value will be used.
|
|
600
|
+
|
|
601
|
+
```html
|
|
602
|
+
<x-my-alert />
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
The output will be:
|
|
606
|
+
|
|
607
|
+
```html
|
|
608
|
+
<div>
|
|
609
|
+
Default title
|
|
610
|
+
</div>
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
Inside `<script props>` you have access to passed props via an object named `props`.
|
|
614
|
+
|
|
615
|
+
Here's an example of what you can do with it:
|
|
616
|
+
|
|
617
|
+
```html
|
|
618
|
+
<!-- src/modal.html -->
|
|
619
|
+
<script props>
|
|
620
|
+
module.exports = {
|
|
621
|
+
title: props.title || 'Default title',
|
|
622
|
+
size: props.size ? `modal-${props.size}` : '',
|
|
623
|
+
items: Array.isArray(props.items) ? props.items.concat(['first', 'second']) : ['first', 'second']
|
|
624
|
+
}
|
|
625
|
+
</script>
|
|
626
|
+
<div class="modal {{ size }}">
|
|
627
|
+
<div class="modal-header">
|
|
628
|
+
{{ title }}
|
|
629
|
+
</div>
|
|
630
|
+
<div class="modal-body">
|
|
631
|
+
<each loop="item in items"><span>{{ item }}</span></each>
|
|
632
|
+
</div>
|
|
633
|
+
</div>
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
Use:
|
|
637
|
+
|
|
638
|
+
```html
|
|
639
|
+
<x-modal
|
|
640
|
+
size="xl"
|
|
641
|
+
title="My modal title"
|
|
642
|
+
items='["third", "fourth"]'
|
|
643
|
+
class="modal-custom"
|
|
644
|
+
/>
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
The output will be:
|
|
648
|
+
|
|
649
|
+
```html
|
|
650
|
+
<div class="modal modal-custom modal-xl">
|
|
651
|
+
<div class="modal-header">
|
|
652
|
+
My modal title
|
|
653
|
+
</div>
|
|
654
|
+
<div class="modal-body">
|
|
655
|
+
<span>first</span>
|
|
656
|
+
<span>second</span>
|
|
657
|
+
<span>third</span>
|
|
658
|
+
<span>fourth</span>
|
|
659
|
+
</div>
|
|
660
|
+
</div>
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
Notice how the `class` attribute that we passed to the component is merged with `class` attribute value of the first node inside of it.
|
|
664
|
+
|
|
665
|
+
You can change how attributes are merged with global props defined via options, by passing a callback function.
|
|
666
|
+
|
|
667
|
+
By default, all props are scoped to the component, and are not available to nested components. You can however change this accordingly to your need.
|
|
668
|
+
|
|
669
|
+
Create a component:
|
|
670
|
+
|
|
671
|
+
```html
|
|
672
|
+
<!-- src/child.html -->
|
|
673
|
+
<script props>
|
|
674
|
+
module.exports = {
|
|
675
|
+
title: props.title || 'Default title'
|
|
676
|
+
}
|
|
677
|
+
</script>
|
|
678
|
+
<div>
|
|
679
|
+
Prop in child: {{ title }}
|
|
680
|
+
</div>
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
Create a `<x-parent>` component that uses `<x-child>`:
|
|
684
|
+
|
|
685
|
+
```html
|
|
686
|
+
<!-- src/parent.html -->
|
|
687
|
+
<script props>
|
|
688
|
+
module.exports = {
|
|
689
|
+
title: props.title || 'Default title'
|
|
690
|
+
}
|
|
691
|
+
</script>
|
|
692
|
+
<div>
|
|
693
|
+
Prop in parent: {{ title }}
|
|
694
|
+
<x-child />
|
|
695
|
+
</div>
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
Use it:
|
|
699
|
+
|
|
700
|
+
```html
|
|
701
|
+
<x-parent title="My title" />
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
The output will be:
|
|
705
|
+
|
|
706
|
+
```html
|
|
707
|
+
<div>
|
|
708
|
+
Prop in parent: My title
|
|
709
|
+
<div>
|
|
710
|
+
Prop in child: Default title
|
|
711
|
+
</div>
|
|
712
|
+
</div>
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
As you can see, `title` in `<x-child>` component renders the default value and not the one set via `<x-parent>`.
|
|
716
|
+
|
|
717
|
+
To change this, we must prepend `aware:` to the attribute name in order to pass the props to nested components.
|
|
718
|
+
|
|
719
|
+
```html
|
|
720
|
+
<x-parent aware:title="My title" />
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
The output now will be:
|
|
724
|
+
|
|
725
|
+
```html
|
|
726
|
+
<div>
|
|
727
|
+
Prop in parent: My title
|
|
728
|
+
<div>
|
|
729
|
+
Prop in child: My title
|
|
730
|
+
</div>
|
|
731
|
+
</div>
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
### Attributes
|
|
735
|
+
|
|
736
|
+
You can pass any attributes to your components and they will be added to the first node of your component,
|
|
737
|
+
or to the node with an attribute named `attributes`.
|
|
738
|
+
|
|
739
|
+
If you are familiar with Vue.js, this is the same as so-called
|
|
740
|
+
[fallthrough attribute](https://vuejs.org/guide/components/attrs.html). Or, with Laravel Blade, it's
|
|
741
|
+
[component-attributes](https://laravel.com/docs/11.x/blade#component-attributes).
|
|
742
|
+
|
|
743
|
+
By default, `class` and `style` are merged with existing `class` and `style` attribute. All other attributes are overridden by default.
|
|
744
|
+
|
|
745
|
+
If you pass an attribute that is defined as a `prop`, it will not be added to the component's node.
|
|
746
|
+
|
|
747
|
+
Here's an example:
|
|
748
|
+
|
|
749
|
+
```html
|
|
750
|
+
<!-- src/button.html -->
|
|
751
|
+
<script props>
|
|
752
|
+
module.exports = {
|
|
753
|
+
label: props.label || 'A button'
|
|
754
|
+
}
|
|
755
|
+
</script>
|
|
756
|
+
<button type="button" class="btn">
|
|
757
|
+
{{ label }}
|
|
758
|
+
</button>
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
Use the component:
|
|
762
|
+
|
|
763
|
+
```html
|
|
764
|
+
<!-- src/index.html -->
|
|
765
|
+
<x-button type="submit" class="btn-primary" label="My button" />
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
Result:
|
|
769
|
+
|
|
770
|
+
```html
|
|
771
|
+
<!-- dist/index.html -->
|
|
772
|
+
<button type="submit" class="btn btn-primary">My button</button>
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
If you need to override `class` and `style` attribute values (instead of merging them), just prepend `override:` to the attribute name:
|
|
776
|
+
|
|
777
|
+
```html
|
|
778
|
+
<!-- src/index.html -->
|
|
779
|
+
<x-button type="submit" override:class="btn-custom" label="My button" />
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
Result:
|
|
783
|
+
|
|
784
|
+
```html
|
|
785
|
+
<!-- dist/index.html -->
|
|
786
|
+
<button type="submit" class="btn-custom">My button</button>
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
If you want the attributes to be passed to a certain node, use the `attributes` attribute:
|
|
790
|
+
|
|
791
|
+
```html
|
|
792
|
+
<!-- src/my-component.html -->
|
|
793
|
+
<div class="first-node">
|
|
794
|
+
<div class="second-node" attributes>
|
|
795
|
+
Hello world!
|
|
796
|
+
</div>
|
|
797
|
+
</div>
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
Use the component:
|
|
801
|
+
|
|
802
|
+
```html
|
|
803
|
+
<!-- src/index.html -->
|
|
804
|
+
<x-my-component class="my-class" />
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
Result:
|
|
808
|
+
|
|
809
|
+
```html
|
|
810
|
+
<!-- dist/index.html -->
|
|
811
|
+
<div class="first-node">
|
|
812
|
+
<div class="second-node my-class">
|
|
813
|
+
Hello world!
|
|
814
|
+
</div>
|
|
815
|
+
</div>
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
You can add custom rules to define how attributes are parsed - we use [posthtml-attrs-parser](https://github.com/posthtml/posthtml-attrs-parser) to handle them.
|
|
819
|
+
|
|
820
|
+
### Advanced attributes configurations
|
|
821
|
+
|
|
822
|
+
If default configurations for valid attributes are not right for you, you may configure them as explained below.
|
|
823
|
+
|
|
824
|
+
```js
|
|
825
|
+
// index.js
|
|
826
|
+
const { readFileSync, writeFileSync } = require('fs')
|
|
827
|
+
|
|
828
|
+
const posthtml = require('posthtml')
|
|
829
|
+
const components = require('posthtml-components')
|
|
830
|
+
|
|
831
|
+
const options = {
|
|
832
|
+
root: './src',
|
|
833
|
+
// Add attributes to specific tag or override defaults
|
|
834
|
+
elementAttributes: {
|
|
835
|
+
DIV: (defaultAttributes) => {
|
|
836
|
+
/* Add new one */
|
|
837
|
+
defaultAttributes.push('custom-attribute-name');
|
|
838
|
+
|
|
839
|
+
return defaultAttributes;
|
|
840
|
+
},
|
|
841
|
+
DIV: (defaultAttributes) => {
|
|
842
|
+
/* Override all */
|
|
843
|
+
defaultAttributes = ['custom-attribute-name', 'another-one'];
|
|
844
|
+
|
|
845
|
+
return defaultAttributes;
|
|
846
|
+
},
|
|
847
|
+
},
|
|
848
|
+
|
|
849
|
+
// Add attributes to all tags, use '*' as wildcard for attribute name that starts with
|
|
850
|
+
safelistAttributes: [
|
|
851
|
+
'custom-attribute-name',
|
|
852
|
+
'attribute-name-start-with-*'
|
|
853
|
+
],
|
|
854
|
+
|
|
855
|
+
// Remove attributes from all tags that support it
|
|
856
|
+
blocklistAttributes: [
|
|
857
|
+
'role'
|
|
858
|
+
]
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
posthtml(components(options))
|
|
862
|
+
.process(readFileSync('src/index.html', 'utf8'))
|
|
863
|
+
.then(result => writeFileSync('dist/index.html', result.html, 'utf8'))
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
## Examples
|
|
867
|
+
|
|
868
|
+
You can work with `<slot>` and `<fill>` or you can create component for each block of your component, and you can also support both of them.
|
|
869
|
+
|
|
870
|
+
You can find an example of this inside `docs-src/components/modal`. Following is a short explanation of both approaches.
|
|
871
|
+
|
|
872
|
+
### Using slots
|
|
873
|
+
|
|
874
|
+
Let's suppose we want to create a component for [bootstrap modal](https://getbootstrap.com/docs/5.2/components/modal/).
|
|
875
|
+
|
|
876
|
+
The code required is:
|
|
877
|
+
|
|
878
|
+
```html
|
|
879
|
+
<!-- Modal HTML -->
|
|
880
|
+
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
|
881
|
+
<div class="modal-dialog">
|
|
882
|
+
<div class="modal-content">
|
|
883
|
+
<div class="modal-header">
|
|
884
|
+
<h1 class="modal-title fs-5" id="exampleModalLabel">Modal title</h1>
|
|
885
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
886
|
+
</div>
|
|
887
|
+
<div class="modal-body">
|
|
888
|
+
...
|
|
889
|
+
</div>
|
|
890
|
+
<div class="modal-footer">
|
|
891
|
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
892
|
+
<button type="button" class="btn btn-primary">Save changes</button>
|
|
893
|
+
</div>
|
|
894
|
+
</div>
|
|
895
|
+
</div>
|
|
896
|
+
</div>
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
There is almost three block of code: the header, the body and the footer.
|
|
900
|
+
|
|
901
|
+
So we could create a component with three slots:
|
|
902
|
+
|
|
903
|
+
```diff
|
|
904
|
+
<!-- Modal component -->
|
|
905
|
+
<div class="modal fade" tabindex="-1" aria-hidden="true">
|
|
906
|
+
<div class="modal-dialog">
|
|
907
|
+
<div class="modal-content">
|
|
908
|
+
<div class="modal-header">
|
|
909
|
+
- <h1 class="modal-title fs-5" id="exampleModalLabel">Modal title</h1>
|
|
910
|
+
+ <slot:header />
|
|
911
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
912
|
+
</div>
|
|
913
|
+
<div class="modal-body">
|
|
914
|
+
+ <slot:body />
|
|
915
|
+
</div>
|
|
916
|
+
<div class="modal-footer">
|
|
917
|
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
918
|
+
+ <slot:footer />
|
|
919
|
+
- <button type="button" class="btn btn-primary">Save changes</button>
|
|
920
|
+
</div>
|
|
921
|
+
</div>
|
|
922
|
+
</div>
|
|
923
|
+
</div>
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
We can then use it like this:
|
|
927
|
+
|
|
928
|
+
```html
|
|
929
|
+
<x-modal
|
|
930
|
+
id="exampleModal"
|
|
931
|
+
aria-labelledby="exampleModalLabel"
|
|
932
|
+
>
|
|
933
|
+
<slot:header>
|
|
934
|
+
<h5 class="modal-title" id="exampleModalLabel">My modal</h5>
|
|
935
|
+
</slot:header>
|
|
936
|
+
|
|
937
|
+
<slot:body>
|
|
938
|
+
Modal body content goes here...
|
|
939
|
+
</slot:body>
|
|
940
|
+
|
|
941
|
+
<slot:footer close="false">
|
|
942
|
+
<button type="button" class="btn btn-primary">Confirm</button>
|
|
943
|
+
</slot:footer>
|
|
944
|
+
</x-modal>
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
### Splitting component in small component
|
|
948
|
+
|
|
949
|
+
Another approach is to split the component in smaller components, passing attributes to each of them.
|
|
950
|
+
|
|
951
|
+
So we create a main component and then three different smaller components:
|
|
952
|
+
|
|
953
|
+
```html
|
|
954
|
+
<!-- Main modal component -->
|
|
955
|
+
<div class="modal fade" tabindex="-1" aria-hidden="true">
|
|
956
|
+
<div class="modal-dialog">
|
|
957
|
+
<div class="modal-content">
|
|
958
|
+
<yield />
|
|
959
|
+
</div>
|
|
960
|
+
</div>
|
|
961
|
+
</div>
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
```html
|
|
965
|
+
<!-- Header modal component -->
|
|
966
|
+
<div class="modal-header">
|
|
967
|
+
<yield />
|
|
968
|
+
</div>
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
```html
|
|
972
|
+
<!-- Body modal component -->
|
|
973
|
+
<div class="modal-body">
|
|
974
|
+
<yield />
|
|
975
|
+
</div>
|
|
976
|
+
```
|
|
977
|
+
|
|
978
|
+
```html
|
|
979
|
+
<!-- Footer modal component -->
|
|
980
|
+
<div class="modal-footer">
|
|
981
|
+
<yield />
|
|
982
|
+
</div>
|
|
983
|
+
```
|
|
984
|
+
|
|
985
|
+
And then you can use it like this:
|
|
986
|
+
|
|
987
|
+
```html
|
|
988
|
+
<x-modal
|
|
989
|
+
id="exampleModal"
|
|
990
|
+
aria-labelledby="exampleModalLabel"
|
|
991
|
+
>
|
|
992
|
+
<x-modal.header>
|
|
993
|
+
<h5 class="modal-title" id="exampleModalLabel">My modal</h5>
|
|
994
|
+
</x-modal.header>
|
|
995
|
+
|
|
996
|
+
<x-modal.body>
|
|
997
|
+
Modal body content goes here...
|
|
998
|
+
</x-modal.body>
|
|
999
|
+
|
|
1000
|
+
<x-modal.footer>
|
|
1001
|
+
<button type="button" class="btn btn-primary">Confirm</button>
|
|
1002
|
+
</x-modal.footer>
|
|
1003
|
+
</x-modal>
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
As said in this way you can pass attributes to each of them, without defining props.
|
|
1007
|
+
|
|
1008
|
+
### Combine slots and small component
|
|
1009
|
+
|
|
1010
|
+
You can also combine both approaches, and then use them with slots or with small components:
|
|
1011
|
+
|
|
1012
|
+
```html
|
|
1013
|
+
|
|
1014
|
+
<!-- Modal -->
|
|
1015
|
+
<div
|
|
1016
|
+
class="modal fade"
|
|
1017
|
+
tabindex="-1"
|
|
1018
|
+
aria-hidden="true"
|
|
1019
|
+
aria-modal="true"
|
|
1020
|
+
role="dialog"
|
|
1021
|
+
>
|
|
1022
|
+
<div class="modal-dialog">
|
|
1023
|
+
<div class="modal-content">
|
|
1024
|
+
<if condition="$slots.header?.filled">
|
|
1025
|
+
<x-modal.header>
|
|
1026
|
+
<slot:header />
|
|
1027
|
+
</x-modal.header>
|
|
1028
|
+
</if>
|
|
1029
|
+
<if condition="$slots.body?.filled">
|
|
1030
|
+
<x-modal.body>
|
|
1031
|
+
<slot:body />
|
|
1032
|
+
</x-modal.body>
|
|
1033
|
+
</if>
|
|
1034
|
+
<if condition="$slots.footer?.filled">
|
|
1035
|
+
<x-modal.footer close="{{ $slots.footer?.props.close }}">
|
|
1036
|
+
<slot:footer />
|
|
1037
|
+
</x-modal.footer>
|
|
1038
|
+
</if>
|
|
1039
|
+
<yield />
|
|
1040
|
+
</div>
|
|
1041
|
+
</div><!-- /.modal-dialog -->
|
|
1042
|
+
</div><!-- /.modal -->
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
Now you can use your component with slots or with small components.
|
|
1046
|
+
|
|
1047
|
+
As you may notice, by using slots, you already can use also your small components, and so you can also pass props
|
|
1048
|
+
via `$slots` which has all the `props` passed via slot, and as well check if slot is filled.
|
|
1049
|
+
|
|
1050
|
+
## Migration
|
|
1051
|
+
|
|
1052
|
+
If you are migrating from `posthtml-extend` and/or `posthtml-modules` please to follow updates here:
|
|
1053
|
+
[posthtml-components/issues/16](https://github.com/thewebartisan7/posthtml-components/issues/16).
|
|
1054
|
+
|
|
1055
|
+
## Contributing
|
|
1056
|
+
|
|
1057
|
+
See [PostHTML Guidelines](https://github.com/posthtml/posthtml/tree/master/docs) and [contribution guide](CONTRIBUTING.md).
|
|
1058
|
+
|
|
1059
|
+
## Credits
|
|
1060
|
+
|
|
1061
|
+
Thanks to all PostHTML contributors and especially to `posthtml-extend` and `posthtml-modules` contributors, as part of code is ~~stolen~~ inspired from these plugins.
|
|
1062
|
+
Huge thanks also to Laravel Blade template engine.
|