attrs-in-props 3.14.6 → 3.14.8

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/index.js +1331 -0
  3. package/package.json +3 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # attrs-in-props
2
2
 
3
+ ## 3.14.8
4
+
5
+ ### Patch Changes
6
+
7
+ - Manual patch bump triggered via workflow_dispatch (scope: @symbo.ls).
8
+ No source change behind this bump — released to refresh dist or
9
+ coordinate a cross-package version line.
10
+ - Updated dependencies
11
+ - @symbo.ls/utils@3.14.15
12
+
13
+ ## 3.14.7
14
+
15
+ ### Patch Changes
16
+
17
+ - Manual patch bump triggered via workflow_dispatch (scope: @symbo.ls).
18
+ No source change behind this bump — released to refresh dist or
19
+ coordinate a cross-package version line.
20
+ - Updated dependencies
21
+ - @symbo.ls/utils@3.14.11
22
+
3
23
  ## 3.14.6
4
24
 
5
25
  ### Patch Changes
package/index.js ADDED
@@ -0,0 +1,1331 @@
1
+ 'use strict'
2
+
3
+ import { isDefined, isFunction, isString } from '@symbo.ls/utils'
4
+
5
+ export const ARIA_ROLES = [
6
+ 'alert',
7
+ 'alertdialog',
8
+ 'application',
9
+ 'article',
10
+ 'banner',
11
+ 'button',
12
+ 'cell',
13
+ 'checkbox',
14
+ 'columnheader',
15
+ 'combobox',
16
+ 'complementary',
17
+ 'contentinfo',
18
+ 'definition',
19
+ 'dialog',
20
+ 'directory',
21
+ 'document',
22
+ 'feed',
23
+ 'figure',
24
+ 'form',
25
+ 'grid',
26
+ 'gridcell',
27
+ 'group',
28
+ 'heading',
29
+ 'img',
30
+ 'link',
31
+ 'list',
32
+ 'listbox',
33
+ 'listitem',
34
+ 'log',
35
+ 'main',
36
+ 'marquee',
37
+ 'math',
38
+ 'menu',
39
+ 'menubar',
40
+ 'menuitem',
41
+ 'menuitemcheckbox',
42
+ 'menuitemradio',
43
+ 'navigation',
44
+ 'none',
45
+ 'note',
46
+ 'option',
47
+ 'presentation',
48
+ 'progressbar',
49
+ 'radio',
50
+ 'radiogroup',
51
+ 'region',
52
+ 'row',
53
+ 'rowgroup',
54
+ 'rowheader',
55
+ 'scrollbar',
56
+ 'search',
57
+ 'searchbox',
58
+ 'separator',
59
+ 'slider',
60
+ 'spinbutton',
61
+ 'status',
62
+ 'switch',
63
+ 'tab',
64
+ 'table',
65
+ 'tablist',
66
+ 'tabpanel',
67
+ 'term',
68
+ 'textbox',
69
+ 'timer',
70
+ 'toolbar',
71
+ 'tooltip',
72
+ 'tree',
73
+ 'treegrid',
74
+ 'treeitem'
75
+ ]
76
+
77
+ export const HTML_ATTRIBUTES = {
78
+ default: [
79
+ 'accesskey',
80
+ 'autofocus',
81
+ 'class',
82
+ 'contenteditable',
83
+ 'contextmenu',
84
+ 'dir',
85
+ 'draggable',
86
+ 'hidden',
87
+ 'id',
88
+ 'lang',
89
+ 'part',
90
+ 'placeholder',
91
+ 'slot',
92
+ 'spellcheck',
93
+ 'style',
94
+ 'tabindex',
95
+ 'title',
96
+ 'translate',
97
+ 'inert',
98
+ 'radiogroup',
99
+ 'role',
100
+ 'about',
101
+ 'datatype',
102
+ 'inlist',
103
+ 'prefix',
104
+ 'property',
105
+ 'resource',
106
+ 'typeof',
107
+ 'vocab',
108
+ 'autocapitalize',
109
+ 'autocorrect',
110
+ 'autosave',
111
+ 'color',
112
+ 'itemprop',
113
+ 'itemscope',
114
+ 'itemtype',
115
+ 'itemid',
116
+ 'itemref',
117
+ 'results',
118
+ 'security',
119
+ 'unselectable',
120
+ 'is'
121
+ ],
122
+
123
+ a: [
124
+ 'accesskey',
125
+ 'charset',
126
+ 'coords',
127
+ 'download',
128
+ 'href',
129
+ 'hreflang',
130
+ 'name',
131
+ 'rel',
132
+ 'rev',
133
+ 'shape',
134
+ 'target',
135
+ 'type'
136
+ ],
137
+
138
+ aria: [
139
+ 'aria-activedescendant',
140
+ 'aria-atomic',
141
+ 'aria-autocomplete',
142
+ 'aria-checked',
143
+ 'aria-colcount',
144
+ 'aria-colindex',
145
+ 'aria-colspan',
146
+ 'aria-controls',
147
+ 'aria-current',
148
+ 'aria-describedby',
149
+ 'aria-details',
150
+ 'aria-dropeffect',
151
+ 'aria-errormessage',
152
+ 'aria-expanded',
153
+ 'aria-flowto',
154
+ 'aria-grabbed',
155
+ 'aria-haspopup',
156
+ 'aria-hidden',
157
+ 'aria-invalid',
158
+ 'aria-keyshortcuts',
159
+ 'aria-label',
160
+ 'aria-labelledby',
161
+ 'aria-level',
162
+ 'aria-live',
163
+ 'aria-modal',
164
+ 'aria-multiline',
165
+ 'aria-multiselectable',
166
+ 'aria-orientation',
167
+ 'aria-owns',
168
+ 'aria-placeholder',
169
+ 'aria-posinset',
170
+ 'aria-pressed',
171
+ 'aria-readonly',
172
+ 'aria-relevant',
173
+ 'aria-required',
174
+ 'aria-roledescription',
175
+ 'aria-rowcount',
176
+ 'aria-rowindex',
177
+ 'aria-rowspan',
178
+ 'aria-selected',
179
+ 'aria-setsize',
180
+ 'aria-sort',
181
+ 'aria-valuemax',
182
+ 'aria-valuemin',
183
+ 'aria-valuenow',
184
+ 'aria-valuetext'
185
+ ],
186
+
187
+ anchor: [
188
+ 'download',
189
+ 'href',
190
+ 'hreflang',
191
+ 'media',
192
+ 'ping',
193
+ 'rel',
194
+ 'target',
195
+ 'type',
196
+ 'referrerpolicy'
197
+ ],
198
+
199
+ audio: [
200
+ 'autoplay',
201
+ 'controls',
202
+ 'crossorigin',
203
+ 'loop',
204
+ 'muted',
205
+ 'preload',
206
+ 'src'
207
+ ],
208
+
209
+ area: [
210
+ 'alt',
211
+ 'coords',
212
+ 'download',
213
+ 'href',
214
+ 'hreflang',
215
+ 'media',
216
+ 'referrerpolicy',
217
+ 'rel',
218
+ 'shape',
219
+ 'target',
220
+ 'ping'
221
+ ],
222
+
223
+ base: [
224
+ 'href',
225
+ 'target'
226
+ ],
227
+
228
+ blockquote: [
229
+ 'cite'
230
+ ],
231
+
232
+ button: [
233
+ 'disabled',
234
+ 'form',
235
+ 'formaction',
236
+ 'formenctype',
237
+ 'formmethod',
238
+ 'formnovalidate',
239
+ 'formtarget',
240
+ 'name',
241
+ 'type',
242
+ 'value'
243
+ ],
244
+
245
+ canvas: [
246
+ 'height',
247
+ 'width'
248
+ ],
249
+
250
+ col: [
251
+ 'span',
252
+ 'width'
253
+ ],
254
+
255
+ colgroup: [
256
+ 'span'
257
+ ],
258
+
259
+ data: [
260
+ 'value'
261
+ ],
262
+
263
+ details: [
264
+ 'open'
265
+ ],
266
+
267
+ del: [
268
+ 'cite',
269
+ 'datetime'
270
+ ],
271
+
272
+ dialog: [
273
+ 'open'
274
+ ],
275
+
276
+ embed: [
277
+ 'height',
278
+ 'src',
279
+ 'type',
280
+ 'width'
281
+ ],
282
+
283
+ fieldset: [
284
+ 'disabled',
285
+ 'form',
286
+ 'name'
287
+ ],
288
+
289
+ form: [
290
+ 'acceptcharset',
291
+ 'action',
292
+ 'autocomplete',
293
+ 'enctype',
294
+ 'method',
295
+ 'name',
296
+ 'novalidate',
297
+ 'target',
298
+ 'rel'
299
+ ],
300
+
301
+ html: [
302
+ 'manifest'
303
+ ],
304
+
305
+ iframe: [
306
+ 'allow',
307
+ 'allowfullscreen',
308
+ 'allowtransparency',
309
+ 'frameborder',
310
+ 'height',
311
+ 'loading',
312
+ 'marginheight',
313
+ 'marginwidth',
314
+ 'mozallowfullscreen',
315
+ 'name',
316
+ 'referrerpolicy',
317
+ 'sandbox',
318
+ 'scrolling',
319
+ 'seamless',
320
+ 'src',
321
+ 'srcdoc',
322
+ 'webkitallowfullscreen',
323
+ 'width'
324
+ ],
325
+
326
+ img: [
327
+ 'alt',
328
+ 'crossorigin',
329
+ 'decoding',
330
+ 'height',
331
+ 'ismap',
332
+ 'loading',
333
+ 'referrerpolicy',
334
+ 'sizes',
335
+ 'src',
336
+ 'srcset',
337
+ 'usemap',
338
+ 'width'
339
+ ],
340
+
341
+ ins: [
342
+ 'cite',
343
+ 'datetime'
344
+ ],
345
+
346
+ input: [
347
+ 'accept',
348
+ 'alt',
349
+ 'autocomplete',
350
+ 'capture',
351
+ 'checked',
352
+ 'crossorigin',
353
+ 'disabled',
354
+ 'form',
355
+ 'formaction',
356
+ 'formenctype',
357
+ 'formmethod',
358
+ 'formnovalidate',
359
+ 'formtarget',
360
+ 'height',
361
+ 'indeterminate',
362
+ 'list',
363
+ 'max',
364
+ 'maxlength',
365
+ 'min',
366
+ 'minlength',
367
+ 'multiple',
368
+ 'name',
369
+ 'pattern',
370
+ 'placeholder',
371
+ 'readonly',
372
+ 'required',
373
+ 'size',
374
+ 'src',
375
+ 'step',
376
+ 'type',
377
+ 'value',
378
+ 'width'
379
+ ],
380
+
381
+ keygen: [
382
+ 'challenge',
383
+ 'disabled',
384
+ 'form',
385
+ 'keytype',
386
+ 'keyparams',
387
+ 'name'
388
+ ],
389
+
390
+ label: [
391
+ 'form',
392
+ 'for'
393
+ ],
394
+
395
+ li: [
396
+ 'value'
397
+ ],
398
+
399
+ link: [
400
+ 'as',
401
+ 'crossorigin',
402
+ 'href',
403
+ 'hreflang',
404
+ 'integrity',
405
+ 'media',
406
+ 'imagesrcset',
407
+ 'imagesizes',
408
+ 'referrerpolicy',
409
+ 'rel',
410
+ 'sizes',
411
+ 'type',
412
+ 'charset'
413
+ ],
414
+
415
+ map: [
416
+ 'name'
417
+ ],
418
+
419
+ menu: [
420
+ 'type'
421
+ ],
422
+
423
+ media: [
424
+ 'autoplay',
425
+ 'controls',
426
+ 'currenttime',
427
+ 'defaultmuted',
428
+ 'defaultplaybackrate',
429
+ 'loop',
430
+ 'mediagroup',
431
+ 'muted',
432
+ 'playsinline',
433
+ 'preload',
434
+ 'src',
435
+ 'volume'
436
+ ],
437
+
438
+ meta: [
439
+ 'charset',
440
+ 'content',
441
+ 'http-equiv',
442
+ 'name',
443
+ 'media'
444
+ ],
445
+
446
+ meter: [
447
+ 'form',
448
+ 'high',
449
+ 'low',
450
+ 'max',
451
+ 'min',
452
+ 'optimum',
453
+ 'value'
454
+ ],
455
+
456
+ quote: [
457
+ 'cite'
458
+ ],
459
+
460
+ object: [
461
+ 'classid',
462
+ 'data',
463
+ 'form',
464
+ 'height',
465
+ 'name',
466
+ 'type',
467
+ 'usemap',
468
+ 'width',
469
+ 'wmode'
470
+ ],
471
+
472
+ ol: [
473
+ 'reversed',
474
+ 'start',
475
+ 'type'
476
+ ],
477
+
478
+ optgroup: [
479
+ 'disabled',
480
+ 'label'
481
+ ],
482
+
483
+ option: [
484
+ 'disabled',
485
+ 'label',
486
+ 'selected',
487
+ 'value'
488
+ ],
489
+
490
+ output: [
491
+ 'form',
492
+ 'for',
493
+ 'name'
494
+ ],
495
+
496
+ param: [
497
+ 'name',
498
+ 'value'
499
+ ],
500
+
501
+ progress: [
502
+ 'max',
503
+ 'value'
504
+ ],
505
+
506
+ slot: [
507
+ 'name'
508
+ ],
509
+
510
+ script: [
511
+ 'async',
512
+ 'charset',
513
+ 'crossorigin',
514
+ 'defer',
515
+ 'integrity',
516
+ 'nomodule',
517
+ 'nonce',
518
+ 'referrerpolicy',
519
+ 'src',
520
+ 'type'
521
+ ],
522
+
523
+ select: [
524
+ 'autocomplete',
525
+ 'disabled',
526
+ 'form',
527
+ 'multiple',
528
+ 'name',
529
+ 'required',
530
+ 'size',
531
+ 'value',
532
+
533
+ 'onchange'
534
+ ],
535
+
536
+ source: [
537
+ 'height',
538
+ 'media',
539
+ 'sizes',
540
+ 'src',
541
+ 'srcset',
542
+ 'type',
543
+ 'width'
544
+ ],
545
+
546
+ style: [
547
+ 'media',
548
+ 'nonce',
549
+ 'scoped',
550
+ 'type'
551
+ ],
552
+
553
+ table: [
554
+ 'align',
555
+ 'bgcolor',
556
+ 'border',
557
+ 'cellpadding',
558
+ 'cellspacing',
559
+ 'frame',
560
+ 'rules',
561
+ 'summary',
562
+ 'width'
563
+ ],
564
+
565
+ textarea: [
566
+ 'autocomplete',
567
+ 'cols',
568
+ 'dirname',
569
+ 'disabled',
570
+ 'form',
571
+ 'maxlength',
572
+ 'minlength',
573
+ 'name',
574
+ 'placeholder',
575
+ 'readonly',
576
+ 'required',
577
+ 'rows',
578
+ 'value',
579
+ 'wrap'
580
+ ],
581
+
582
+ td: [
583
+ 'align',
584
+ 'colspan',
585
+ 'headers',
586
+ 'rowspan',
587
+ 'scope',
588
+ 'abbr',
589
+ 'height',
590
+ 'width',
591
+ 'valign'
592
+ ],
593
+
594
+ th: [
595
+ 'align',
596
+ 'colspan',
597
+ 'headers',
598
+ 'rowspan',
599
+ 'scope',
600
+ 'abbr'
601
+ ],
602
+
603
+ time: [
604
+ 'datetime'
605
+ ],
606
+
607
+ track: [
608
+ 'default',
609
+ 'kind',
610
+ 'label',
611
+ 'src',
612
+ 'srclang'
613
+ ],
614
+
615
+ video: [
616
+ 'autoplay',
617
+ 'controls',
618
+ 'crossorigin',
619
+ 'disablepictureinpicture',
620
+ 'disableremoteplayback',
621
+ 'height',
622
+ 'loop',
623
+ 'muted',
624
+ 'playsinline',
625
+ 'poster',
626
+ 'preload',
627
+ 'src',
628
+ 'width'
629
+ ],
630
+
631
+ svg: [
632
+ 'className',
633
+ 'class',
634
+ 'color',
635
+ 'height',
636
+ 'id',
637
+ 'lang',
638
+ 'max',
639
+ 'media',
640
+ 'method',
641
+ 'min',
642
+ 'name',
643
+ 'style',
644
+ 'target',
645
+ 'type',
646
+ 'width',
647
+
648
+ // Other HTML properties supported by SVG elements in browsers
649
+ 'role',
650
+ 'tabindex',
651
+ 'crossorigin',
652
+
653
+ // SVG Specific attributes
654
+ 'accent-height',
655
+ 'accumulate',
656
+ 'additive',
657
+ 'alignment-baseline',
658
+ 'allowReorder',
659
+ 'alphabetic',
660
+ 'amplitude',
661
+ 'arabic-form',
662
+ 'ascent',
663
+ 'attributeName',
664
+ 'attributeType',
665
+ 'autoReverse',
666
+ 'azimuth',
667
+ 'baseFrequency',
668
+ 'baseline-shift',
669
+ 'baseProfile',
670
+ 'bbox',
671
+ 'begin',
672
+ 'bias',
673
+ 'by',
674
+ 'calcMode',
675
+ 'cap-height',
676
+ 'clip',
677
+ 'clip-path',
678
+ 'clipPathUnits',
679
+ 'clip-rule',
680
+ 'color-interpolation',
681
+ 'color-interpolation-filters',
682
+ 'color-profile',
683
+ 'color-rendering',
684
+ 'contentScriptType',
685
+ 'contentStyleType',
686
+ 'cursor',
687
+ 'cx',
688
+ 'cy',
689
+ 'd',
690
+ 'decelerate',
691
+ 'descent',
692
+ 'diffuseConstant',
693
+ 'direction',
694
+ 'display',
695
+ 'divisor',
696
+ 'dominant-baseline',
697
+ 'dur',
698
+ 'dx',
699
+ 'dy',
700
+ 'edgeMode',
701
+ 'elevation',
702
+ 'enable-background',
703
+ 'end',
704
+ 'exponent',
705
+ 'externalResourcesRequired',
706
+ 'fill',
707
+ 'fill-opacity',
708
+ 'fill-rule',
709
+ 'filter',
710
+ 'filterRes',
711
+ 'filterUnits',
712
+ 'flood-color',
713
+ 'flood-opacity',
714
+ 'focusable',
715
+ 'font-family',
716
+ 'font-size',
717
+ 'font-size-adjust',
718
+ 'font-stretch',
719
+ 'font-style',
720
+ 'font-variant',
721
+ 'font-weight',
722
+ 'format',
723
+ 'from',
724
+ 'fx',
725
+ 'fy',
726
+ 'g1',
727
+ 'g2',
728
+ 'glyph-name',
729
+ 'glyph-orientation-horizontal',
730
+ 'glyph-orientation-vertical',
731
+ 'glyphRef',
732
+ 'gradientTransform',
733
+ 'gradientUnits',
734
+ 'hanging',
735
+ 'href',
736
+ 'horiz-adv-x',
737
+ 'horiz-origin-x',
738
+ 'ideographic',
739
+ 'image-rendering',
740
+ 'in2',
741
+ 'in',
742
+ 'intercept',
743
+ 'k1',
744
+ 'k2',
745
+ 'k3',
746
+ 'k4',
747
+ 'k',
748
+ 'kernelMatrix',
749
+ 'kernelUnitLength',
750
+ 'kerning',
751
+ 'keyPoints',
752
+ 'keySplines',
753
+ 'keyTimes',
754
+ 'lengthAdjust',
755
+ 'letter-spacing',
756
+ 'lighting-color',
757
+ 'limitingConeAngle',
758
+ 'local',
759
+ 'marker-end',
760
+ 'markerHeight',
761
+ 'marker-mid',
762
+ 'marker-start',
763
+ 'markerUnits',
764
+ 'markerWidth',
765
+ 'mask',
766
+ 'maskContentUnits',
767
+ 'maskUnits',
768
+ 'mathematical',
769
+ 'mode',
770
+ 'numOctaves',
771
+ 'offset',
772
+ 'opacity',
773
+ 'operator',
774
+ 'order',
775
+ 'orient',
776
+ 'orientation',
777
+ 'origin',
778
+ 'overflow',
779
+ 'overline-position',
780
+ 'overline-thickness',
781
+ 'paint-order',
782
+ 'panose-1',
783
+ 'path',
784
+ 'pathLength',
785
+ 'patternContentUnits',
786
+ 'patternTransform',
787
+ 'patternUnits',
788
+ 'pointer-events',
789
+ 'points',
790
+ 'pointsAtX',
791
+ 'pointsAtY',
792
+ 'pointsAtZ',
793
+ 'preserveAlpha',
794
+ 'preserveAspectRatio',
795
+ 'primitiveUnits',
796
+ 'r',
797
+ 'radius',
798
+ 'refX',
799
+ 'refY',
800
+ 'rendering-intent',
801
+ 'repeatCount',
802
+ 'repeatDur',
803
+ 'requiredExtensions',
804
+ 'requiredFeatures',
805
+ 'restart',
806
+ 'result',
807
+ 'rotate',
808
+ 'rx',
809
+ 'ry',
810
+ 'scale',
811
+ 'seed',
812
+ 'shape-rendering',
813
+ 'slope',
814
+ 'spacing',
815
+ 'specularConstant',
816
+ 'specularExponent',
817
+ 'speed',
818
+ 'spreadMethod',
819
+ 'startOffset',
820
+ 'stdDeviation',
821
+ 'stemh',
822
+ 'stemv',
823
+ 'stitchTiles',
824
+ 'stop-color',
825
+ 'stop-opacity',
826
+ 'strikethrough-position',
827
+ 'strikethrough-thickness',
828
+ 'string',
829
+ 'stroke',
830
+ 'stroke-dasharray',
831
+ 'stroke-dashoffset',
832
+ 'stroke-linecap',
833
+ 'stroke-linejoin',
834
+ 'stroke-miterlimit',
835
+ 'stroke-opacity',
836
+ 'stroke-width',
837
+ 'surfaceScale',
838
+ 'systemLanguage',
839
+ 'tableValues',
840
+ 'targetX',
841
+ 'targetY',
842
+ 'text-anchor',
843
+ 'text-decoration',
844
+ 'textLength',
845
+ 'text-rendering',
846
+ 'to',
847
+ 'transform',
848
+ 'u1',
849
+ 'u2',
850
+ 'underline-position',
851
+ 'underline-thickness',
852
+ 'unicode',
853
+ 'unicode-bidi',
854
+ 'unicode-range',
855
+ 'units-per-em',
856
+ 'v-alphabetic',
857
+ 'values',
858
+ 'vector-effect',
859
+ 'version',
860
+ 'vert-adv-y',
861
+ 'vert-origin-x',
862
+ 'vert-origin-y',
863
+ 'v-hanging',
864
+ 'v-ideographic',
865
+ 'viewBox',
866
+ 'viewTarget',
867
+ 'visibility',
868
+ 'v-mathematical',
869
+ 'widths',
870
+ 'word-spacing',
871
+ 'writing-mode',
872
+ 'x1',
873
+ 'x2',
874
+ 'x',
875
+ 'xChannelSelector',
876
+ 'x-height',
877
+ 'xlink:actuate',
878
+ 'xlink:arcrole',
879
+ 'xlink:href',
880
+ 'xlink:role',
881
+ 'xlink:show',
882
+ 'xlink:title',
883
+ 'xlink:type',
884
+ 'xml:base',
885
+ 'xml:lang',
886
+ 'xmlns',
887
+ 'xmlns:xlink',
888
+ 'xml:space',
889
+ 'y1',
890
+ 'y2',
891
+ 'y',
892
+ 'yChannelSelector',
893
+ 'z',
894
+ 'zoomAndPan'
895
+ ]
896
+ }
897
+
898
+ export const DOM_EVENTS = [
899
+ // Clipboard Events
900
+ 'oncopy',
901
+ 'oncut',
902
+ 'onpaste',
903
+
904
+ // Composition Events
905
+ 'oncompositionend',
906
+ 'oncompositionstart',
907
+ 'oncompositionupdate',
908
+
909
+ // Focus Events
910
+ 'onfocus',
911
+ 'onfocusin',
912
+ 'onfocusout',
913
+ 'onblur',
914
+
915
+ // Form Events
916
+ 'onchange',
917
+ 'onbeforeinput',
918
+ 'oninput',
919
+ 'onreset',
920
+ 'onsubmit',
921
+ 'oninvalid',
922
+ 'onformdata',
923
+
924
+ // Image Events
925
+ 'onload',
926
+ 'onerror', // also a Media Event
927
+
928
+ // Detail Events
929
+ 'ontoggle',
930
+
931
+ // Keyboard Events
932
+ 'onkeydown',
933
+ 'onkeypress',
934
+ 'onkeyup',
935
+
936
+ // Media Events
937
+ 'onabort',
938
+ 'oncanplay',
939
+ 'oncanplaythrough',
940
+ 'oncuechange',
941
+ 'ondurationchange',
942
+ 'onemptied',
943
+ 'onencrypted',
944
+ 'onended',
945
+ 'onloadeddata',
946
+ 'onloadedmetadata',
947
+ 'onloadstart',
948
+ 'onpause',
949
+ 'onplay',
950
+ 'onplaying',
951
+ 'onprogress',
952
+ 'onratechange',
953
+ 'onseeked',
954
+ 'onseeking',
955
+ 'onstalled',
956
+ 'onsuspend',
957
+ 'ontimeupdate',
958
+ 'onvolumechange',
959
+ 'onwaiting',
960
+
961
+ // MouseEvents
962
+ 'onauxclick',
963
+ 'onclick',
964
+ 'oncontextmenu',
965
+ 'ondblclick',
966
+ 'ondrag',
967
+ 'ondragend',
968
+ 'ondragenter',
969
+ 'ondragexit',
970
+ 'ondragleave',
971
+ 'ondragover',
972
+ 'ondragstart',
973
+ 'ondrop',
974
+ 'onmousedown',
975
+ 'onmouseenter',
976
+ 'onmouseleave',
977
+ 'onmousemove',
978
+ 'onmouseout',
979
+ 'onmouseover',
980
+ 'onmouseup',
981
+
982
+ // Selection Events
983
+ 'onselect',
984
+ 'onselectionchange',
985
+ 'onselectstart',
986
+
987
+ // Touch Events
988
+ 'ontouchcancel',
989
+ 'ontouchend',
990
+ 'ontouchmove',
991
+ 'ontouchstart',
992
+
993
+ // Pointer Events
994
+ 'ongotpointercapture',
995
+ 'onpointercancel',
996
+ 'onpointerdown',
997
+ 'onpointerenter',
998
+ 'onpointerleave',
999
+ 'onpointermove',
1000
+ 'onpointerout',
1001
+ 'onpointerover',
1002
+ 'onpointerup',
1003
+ 'onlostpointercapture',
1004
+
1005
+ // UI Events
1006
+ 'onscroll',
1007
+ 'onresize',
1008
+
1009
+ // Wheel Events
1010
+ 'onwheel',
1011
+
1012
+ // Animation Events
1013
+ 'onanimationstart',
1014
+ 'onanimationend',
1015
+ 'onanimationiteration',
1016
+
1017
+ // Transition Events
1018
+ 'ontransitionstart',
1019
+ 'ontransitionrun',
1020
+ 'ontransitionend',
1021
+ 'ontransitioncancel',
1022
+
1023
+ // Svelte Transition Events
1024
+ 'onoutrostart',
1025
+ 'onoutroend',
1026
+ 'onintrostart',
1027
+ 'onintroend',
1028
+
1029
+ // Message Events
1030
+ 'onmessage',
1031
+ 'onmessageerror',
1032
+
1033
+ // Document Events
1034
+ 'onvisibilitychange',
1035
+
1036
+ // Global Events
1037
+ 'oncancel',
1038
+ 'onclose',
1039
+ 'onfullscreenchange',
1040
+ 'onfullscreenerror'
1041
+ ]
1042
+
1043
+ // Convert camelCase aria/data attrs to kebab-case: ariaLabel → aria-label, dataTestId → data-test-id
1044
+ const camelToAttr = (key) => {
1045
+ if (key.startsWith('aria') && key.length > 4 && key.charCodeAt(4) >= 65 && key.charCodeAt(4) <= 90) {
1046
+ return 'aria-' + key.charAt(4).toLowerCase() + key.slice(5).replace(/([A-Z])/g, (m) => '-' + m.toLowerCase())
1047
+ }
1048
+ if (key.startsWith('data') && key.length > 4 && key.charCodeAt(4) >= 65 && key.charCodeAt(4) <= 90) {
1049
+ return 'data-' + key.charAt(4).toLowerCase() + key.slice(5).replace(/([A-Z])/g, (m) => '-' + m.toLowerCase())
1050
+ }
1051
+ return null
1052
+ }
1053
+
1054
+ export const checkAttributeByTagName = (tag, attribute) => {
1055
+ // aria-* and data-* are valid on all elements
1056
+ if (attribute.startsWith('aria-') || attribute.startsWith('data-')) return true
1057
+ // camelCase aria/data attrs
1058
+ if (camelToAttr(attribute)) return true
1059
+
1060
+ // Global attributes (`title`, `id`, `class`, `role`, `tabindex`, `hidden`,
1061
+ // `lang`, `dir`, `draggable`, `contenteditable`, `spellcheck`, `slot`, …)
1062
+ // apply to every tag. Prior behavior only consulted HTML_ATTRIBUTES.default
1063
+ // for tags WITHOUT a per-tag list, which silently dropped global attrs on
1064
+ // every typed tag (button/a/img/input/...). Always allow defaults first,
1065
+ // then tag-specific extras.
1066
+ if (HTML_ATTRIBUTES.default.includes(attribute)) return true
1067
+
1068
+ if (Object.prototype.hasOwnProperty.call(HTML_ATTRIBUTES, tag)) {
1069
+ const attributes = HTML_ATTRIBUTES[tag]
1070
+ return attributes.includes(attribute)
1071
+ }
1072
+ return false
1073
+ }
1074
+
1075
+ export const checkEventFunctions = (key) => {
1076
+ if (!isString(key)) return false
1077
+ const normalizedKey = key.toLowerCase()
1078
+ return DOM_EVENTS.includes(normalizedKey)
1079
+ }
1080
+
1081
+ export const filterAttributesByTagName = (tag, props, cssProps) => {
1082
+ const filteredObject = {}
1083
+
1084
+ for (const key in props) {
1085
+ if (Object.prototype.hasOwnProperty.call(props, key)) {
1086
+ if (cssProps && key in cssProps) continue
1087
+
1088
+ // aria: { label: 'foo', expanded: true } → aria-label, aria-expanded
1089
+ // Function values are stored as-is here; `executeAttr` is the single
1090
+ // place that resolves reactive (el, state) → string for HTML attrs.
1091
+ // We funnel aria/data through `attr` instead of duplicating execution
1092
+ // logic so v3.14 reactive aria/data attributes work with the same
1093
+ // re-render cycle as `attr.foo` — see FA-L1.
1094
+ if (key === 'aria' && props[key] && typeof props[key] === 'object') {
1095
+ for (const ariaKey in props[key]) {
1096
+ if (isDefined(props[key][ariaKey])) {
1097
+ filteredObject['aria-' + ariaKey] = props[key][ariaKey]
1098
+ }
1099
+ }
1100
+ continue
1101
+ }
1102
+
1103
+ // data: { testId: 'foo' } → data-test-id
1104
+ if (key === 'data' && props[key] && typeof props[key] === 'object') {
1105
+ for (const dataKey in props[key]) {
1106
+ if (isDefined(props[key][dataKey])) {
1107
+ const kebab = dataKey.replace(/([A-Z])/g, (m) => '-' + m.toLowerCase())
1108
+ filteredObject['data-' + kebab] = props[key][dataKey]
1109
+ }
1110
+ }
1111
+ continue
1112
+ }
1113
+
1114
+ const isAttribute = checkAttributeByTagName(tag, key)
1115
+ const isEvent = checkEventFunctions(key)
1116
+ if (isDefined(props[key]) && (isAttribute || isEvent)) {
1117
+ const attrName = camelToAttr(key) || key
1118
+ filteredObject[attrName] = props[key]
1119
+ }
1120
+ }
1121
+ }
1122
+
1123
+ return filteredObject
1124
+ }
1125
+
1126
+ export const executeAttr = (elem, element) => {
1127
+ const attrObj = {}
1128
+ if (elem.attr) {
1129
+ for (const attrProp in elem.attr) {
1130
+ attrObj[attrProp] = elem.attr[attrProp](element, element.state, element.context)
1131
+ }
1132
+ }
1133
+ // FA-L1: aria.X and data.X with FUNCTION values must execute the same way
1134
+ // as attr.X. Without this, `aria: { label: (el, s) => s.text }` writes a
1135
+ // function reference to the DOM attribute and renders as `null`.
1136
+ // Static (non-function) aria/data values are already promoted to flat
1137
+ // attributes by `filterAttributesByTagName`; we only handle functions
1138
+ // here to avoid double-write.
1139
+ if (elem.aria && typeof elem.aria === 'object') {
1140
+ for (const ariaKey in elem.aria) {
1141
+ const v = elem.aria[ariaKey]
1142
+ if (typeof v === 'function') {
1143
+ attrObj['aria-' + ariaKey] = v(element, element.state, element.context)
1144
+ }
1145
+ }
1146
+ }
1147
+ if (elem.data && typeof elem.data === 'object') {
1148
+ for (const dataKey in elem.data) {
1149
+ const v = elem.data[dataKey]
1150
+ if (typeof v === 'function') {
1151
+ const kebab = dataKey.replace(/([A-Z])/g, (m) => '-' + m.toLowerCase())
1152
+ attrObj['data-' + kebab] = v(element, element.state, element.context)
1153
+ }
1154
+ }
1155
+ }
1156
+ return attrObj
1157
+ }
1158
+
1159
+ /**
1160
+ * Resolves a prop value: executes dynamic values and replaces template literals.
1161
+ * Shared logic for src, href, action, poster, data, etc.
1162
+ */
1163
+ export const resolvePropValue = (el, value) => {
1164
+ let resolved = el.call('exec', value, el)
1165
+ if (!resolved) return
1166
+ if (isString(resolved) && resolved.includes('{{')) {
1167
+ resolved = el.call('replaceLiteralsWithObjectFields', resolved)
1168
+ }
1169
+ return resolved
1170
+ }
1171
+
1172
+ /**
1173
+ * Resolve a file URL from context.files or context.assets.
1174
+ * Handles absolute URLs (passthrough), /files/ and /assets/ prefix routing,
1175
+ * and lookup for bundler-resolved paths. An explicit `/files/` or `/assets/`
1176
+ * prefix is authoritative — we do NOT cross-route between the two maps.
1177
+ */
1178
+ export const resolveFileSource = (el, value) => {
1179
+ let src = (el.preSrc || '') + (resolvePropValue(el, value) || '')
1180
+ if (!src) return
1181
+
1182
+ try { new URL(src); return src } catch (e) { } // absolute URL — passthrough
1183
+
1184
+ const { context } = el
1185
+ if (!context.files && !context.assets) return src
1186
+
1187
+ if (src.startsWith('/assets/')) {
1188
+ const key = src.slice(8)
1189
+ const asset = context.assets && (context.assets[src] || context.assets[key])
1190
+ if (asset && asset.content) return asset.content.src
1191
+ return src
1192
+ }
1193
+ if (src.startsWith('/files/')) {
1194
+ const key = src.slice(7)
1195
+ const file = context.files && (context.files[src] || context.files[key])
1196
+ if (file && file.content) return file.content.src
1197
+ return src
1198
+ }
1199
+
1200
+ // Unprefixed: try assets first (newer system), then files.
1201
+ if (context.assets) {
1202
+ const asset = context.assets[src]
1203
+ if (asset && asset.content) return asset.content.src
1204
+ }
1205
+ if (context.files) {
1206
+ const file = context.files[src]
1207
+ if (file && file.content) return file.content.src
1208
+ }
1209
+
1210
+ return src
1211
+ }
1212
+
1213
+ /**
1214
+ * Auto-resolve attribute transformers.
1215
+ * Attributes listed here are automatically resolved from props
1216
+ * via resolvePropValue (exec + template literal replacement).
1217
+ * src and poster also resolve from context.files for media elements.
1218
+ */
1219
+ export const ATTR_TRANSFORMS = {
1220
+ src: (el) => resolveFileSource(el, el.src),
1221
+ href: (el) => resolvePropValue(el, el.href),
1222
+ action: (el) => resolvePropValue(el, el.action),
1223
+ poster: (el) => resolveFileSource(el, el.poster),
1224
+ data: (el) => resolvePropValue(el, el.data)
1225
+ }
1226
+
1227
+ /**
1228
+ * Applies ATTR_TRANSFORMS for valid attributes on the element's tag.
1229
+ * Returns resolved attribute values from props.
1230
+ */
1231
+ export const applyAttrTransforms = (element) => {
1232
+ const tag = element.tag || 'div'
1233
+ const result = {}
1234
+ for (const attr in ATTR_TRANSFORMS) {
1235
+ if (element[attr] !== undefined && checkAttributeByTagName(tag, attr)) {
1236
+ const val = ATTR_TRANSFORMS[attr](element)
1237
+ if (val !== undefined) result[attr] = val
1238
+ }
1239
+ }
1240
+ return result
1241
+ }
1242
+
1243
+ /**
1244
+ * Resolve a case value from context.cases.
1245
+ * Returns true/false, or undefined if case is not defined.
1246
+ */
1247
+ const resolveCase = (caseKey, element) => {
1248
+ const caseFn = element.context?.cases?.[caseKey]
1249
+ if (caseFn === undefined) return undefined
1250
+ if (isFunction(caseFn)) return caseFn.call(element, element)
1251
+ return !!caseFn
1252
+ }
1253
+
1254
+ /**
1255
+ * Evaluate whether a conditional prefix key is active.
1256
+ * Supports $ (global cases), . (truthy), ! (falsy) prefixes.
1257
+ */
1258
+ const evaluateCondition = (prefix, caseKey, element) => {
1259
+ if (prefix === '$') {
1260
+ let result = resolveCase(caseKey, element)
1261
+ if (result === undefined) result = !!element[caseKey]
1262
+ return result
1263
+ }
1264
+
1265
+ // . and ! prefixes: check element/state first, then context.cases
1266
+ let isTruthy = element[caseKey] === true || element.state[caseKey]
1267
+ if (!isTruthy) {
1268
+ const caseResult = resolveCase(caseKey, element)
1269
+ if (caseResult !== undefined) isTruthy = caseResult
1270
+ }
1271
+
1272
+ return prefix === '.' ? !!isTruthy : !isTruthy
1273
+ }
1274
+
1275
+ const CONDITIONAL_PREFIXES = new Set(['$', '.', '!'])
1276
+
1277
+ /**
1278
+ * Extract HTML attributes from conditional blocks ($, ., !) in props.
1279
+ * Returns an attr object with functions that re-evaluate on each update.
1280
+ */
1281
+ export const extractConditionalAttrs = (props, tag, cssProps) => {
1282
+ const result = {}
1283
+
1284
+ const addConditionalAttr = (attrName, attrVal, prefix, caseKey) => {
1285
+ const capturedVal = attrVal
1286
+ result[attrName] = (el) => {
1287
+ if (!evaluateCondition(prefix, caseKey, el)) return undefined
1288
+ return isFunction(capturedVal) ? capturedVal(el) : capturedVal
1289
+ }
1290
+ }
1291
+
1292
+ for (const key in props) {
1293
+ const prefix = key.charAt(0)
1294
+ if (!CONDITIONAL_PREFIXES.has(prefix)) continue
1295
+
1296
+ const block = props[key]
1297
+ if (!block || typeof block !== 'object') continue
1298
+
1299
+ const caseKey = key.slice(1)
1300
+
1301
+ for (const attrKey in block) {
1302
+ if (cssProps && attrKey in cssProps) continue
1303
+
1304
+ // aria: { label: 'foo' } inside conditional block
1305
+ if (attrKey === 'aria' && block[attrKey] && typeof block[attrKey] === 'object') {
1306
+ for (const ariaKey in block[attrKey]) {
1307
+ addConditionalAttr('aria-' + ariaKey, block[attrKey][ariaKey], prefix, caseKey)
1308
+ }
1309
+ continue
1310
+ }
1311
+
1312
+ // data: { testId: 'foo' } inside conditional block
1313
+ if (attrKey === 'data' && block[attrKey] && typeof block[attrKey] === 'object') {
1314
+ for (const dataKey in block[attrKey]) {
1315
+ const kebab = dataKey.replace(/([A-Z])/g, (m) => '-' + m.toLowerCase())
1316
+ addConditionalAttr('data-' + kebab, block[attrKey][dataKey], prefix, caseKey)
1317
+ }
1318
+ continue
1319
+ }
1320
+
1321
+ const isAttribute = checkAttributeByTagName(tag, attrKey)
1322
+ const isEvent = checkEventFunctions(attrKey)
1323
+ if (!isAttribute && !isEvent) continue
1324
+
1325
+ const attrName = camelToAttr(attrKey) || attrKey
1326
+ addConditionalAttr(attrName, block[attrKey], prefix, caseKey)
1327
+ }
1328
+ }
1329
+
1330
+ return result
1331
+ }
package/package.json CHANGED
@@ -2,14 +2,14 @@
2
2
  "name": "attrs-in-props",
3
3
  "description": "Utilize props as attributes",
4
4
  "author": "symbo.ls",
5
- "version": "3.14.6",
5
+ "version": "3.14.8",
6
6
  "repository": "https://github.com/symbo-ls/smbls",
7
7
  "type": "module",
8
8
  "module": "./dist/esm/index.js",
9
9
  "main": "./dist/cjs/index.js",
10
10
  "gitHead": "9fc1b79b41cdc725ca6b24aec64920a599634681",
11
11
  "dependencies": {
12
- "@symbo.ls/utils": "^3.14.10"
12
+ "@symbo.ls/utils": "^3.14.15"
13
13
  },
14
14
  "source": "index.js",
15
15
  "browser": "./dist/esm/index.js",
@@ -25,6 +25,7 @@
25
25
  },
26
26
  "files": [
27
27
  "dist",
28
+ "*.js",
28
29
  "*.md",
29
30
  "LICENSE"
30
31
  ],