@tamagui/dom 0.0.0-bootstrap.0 → 3.0.0-beta.643.1

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 (93) hide show
  1. package/dist/cjs/events.cjs +17 -0
  2. package/dist/cjs/events.native.cjs +19 -0
  3. package/dist/cjs/events.native.js +21 -0
  4. package/dist/cjs/events.native.js.map +1 -0
  5. package/dist/cjs/index.cjs +26 -0
  6. package/dist/cjs/index.native.cjs +28 -0
  7. package/dist/cjs/index.native.js +30 -0
  8. package/dist/cjs/index.native.js.map +1 -0
  9. package/dist/cjs/props.cjs +17 -0
  10. package/dist/cjs/props.native.cjs +19 -0
  11. package/dist/cjs/props.native.js +21 -0
  12. package/dist/cjs/props.native.js.map +1 -0
  13. package/dist/cjs/tables/attributes.cjs +850 -0
  14. package/dist/cjs/tables/attributes.native.cjs +862 -0
  15. package/dist/cjs/tables/attributes.native.js +864 -0
  16. package/dist/cjs/tables/attributes.native.js.map +1 -0
  17. package/dist/cjs/tables/compatibility.cjs +338 -0
  18. package/dist/cjs/tables/compatibility.native.cjs +340 -0
  19. package/dist/cjs/tables/compatibility.native.js +342 -0
  20. package/dist/cjs/tables/compatibility.native.js.map +1 -0
  21. package/dist/cjs/tables/events.cjs +169 -0
  22. package/dist/cjs/tables/events.native.cjs +175 -0
  23. package/dist/cjs/tables/events.native.js +177 -0
  24. package/dist/cjs/tables/events.native.js.map +1 -0
  25. package/dist/cjs/tables/nativeBacking.cjs +133 -0
  26. package/dist/cjs/tables/nativeBacking.native.cjs +135 -0
  27. package/dist/cjs/tables/nativeBacking.native.js +137 -0
  28. package/dist/cjs/tables/nativeBacking.native.js.map +1 -0
  29. package/dist/cjs/tables/tags.cjs +576 -0
  30. package/dist/cjs/tables/tags.native.cjs +578 -0
  31. package/dist/cjs/tables/tags.native.js +580 -0
  32. package/dist/cjs/tables/tags.native.js.map +1 -0
  33. package/dist/cjs/tables/types.cjs +17 -0
  34. package/dist/cjs/tables/types.native.cjs +19 -0
  35. package/dist/cjs/tables/types.native.js +21 -0
  36. package/dist/cjs/tables/types.native.js.map +1 -0
  37. package/dist/esm/events.mjs +0 -0
  38. package/dist/esm/events.native.js +0 -0
  39. package/dist/esm/index.mjs +15 -0
  40. package/dist/esm/index.native.js +15 -0
  41. package/dist/esm/props.mjs +0 -0
  42. package/dist/esm/props.native.js +0 -0
  43. package/dist/esm/tables/attributes.mjs +821 -0
  44. package/dist/esm/tables/attributes.mjs.map +1 -0
  45. package/dist/esm/tables/attributes.native.js +831 -0
  46. package/dist/esm/tables/attributes.native.js.map +1 -0
  47. package/dist/esm/tables/compatibility.mjs +314 -0
  48. package/dist/esm/tables/compatibility.mjs.map +1 -0
  49. package/dist/esm/tables/compatibility.native.js +314 -0
  50. package/dist/esm/tables/compatibility.native.js.map +1 -0
  51. package/dist/esm/tables/events.mjs +145 -0
  52. package/dist/esm/tables/events.mjs.map +1 -0
  53. package/dist/esm/tables/events.native.js +149 -0
  54. package/dist/esm/tables/events.native.js.map +1 -0
  55. package/dist/esm/tables/nativeBacking.mjs +106 -0
  56. package/dist/esm/tables/nativeBacking.mjs.map +1 -0
  57. package/dist/esm/tables/nativeBacking.native.js +106 -0
  58. package/dist/esm/tables/nativeBacking.native.js.map +1 -0
  59. package/dist/esm/tables/tags.mjs +550 -0
  60. package/dist/esm/tables/tags.mjs.map +1 -0
  61. package/dist/esm/tables/tags.native.js +550 -0
  62. package/dist/esm/tables/tags.native.js.map +1 -0
  63. package/dist/esm/tables/types.mjs +0 -0
  64. package/dist/esm/tables/types.native.js +0 -0
  65. package/package.json +57 -7
  66. package/src/events.ts +58 -0
  67. package/src/index.ts +19 -0
  68. package/src/props.ts +699 -0
  69. package/src/tables/attributes.ts +863 -0
  70. package/src/tables/compatibility.ts +360 -0
  71. package/src/tables/events.ts +176 -0
  72. package/src/tables/nativeBacking.ts +132 -0
  73. package/src/tables/tags.ts +557 -0
  74. package/src/tables/types.ts +202 -0
  75. package/types/events.d.ts +58 -0
  76. package/types/events.d.ts.map +11 -0
  77. package/types/index.d.ts +20 -0
  78. package/types/index.d.ts.map +11 -0
  79. package/types/props.d.ts +499 -0
  80. package/types/props.d.ts.map +11 -0
  81. package/types/tables/attributes.d.ts +21 -0
  82. package/types/tables/attributes.d.ts.map +11 -0
  83. package/types/tables/compatibility.d.ts +28 -0
  84. package/types/tables/compatibility.d.ts.map +11 -0
  85. package/types/tables/events.d.ts +5 -0
  86. package/types/tables/events.d.ts.map +11 -0
  87. package/types/tables/nativeBacking.d.ts +28 -0
  88. package/types/tables/nativeBacking.d.ts.map +11 -0
  89. package/types/tables/tags.d.ts +36 -0
  90. package/types/tables/tags.d.ts.map +11 -0
  91. package/types/tables/types.d.ts +135 -0
  92. package/types/tables/types.d.ts.map +11 -0
  93. package/README.md +0 -1
@@ -0,0 +1,863 @@
1
+ import type { AttributeRow, TagName } from './types'
2
+
3
+ /**
4
+ * The attribute table: every non-event prop in the Tamagui DOM contract.
5
+ *
6
+ * `tags` is the authority for the unsupported-prop diagnostic, `type` is the
7
+ * source the prop-interface generator emits, and `nativeProp` records what
8
+ * actually carries the value on native. A row with `native: 'none'` still
9
+ * type-checks and works on web; using it in a native build is a diagnostic.
10
+ *
11
+ * Props that only make sense on a text-entry control (`autoCapitalize`,
12
+ * `enterKeyHint`, `inputMode`, `spellCheck`) are scoped to input and textarea
13
+ * here even though React Strict DOM declares them globally. See
14
+ * `compatibility.ts`.
15
+ *
16
+ * The `aria-*` rows map to the legacy accessibility props on purpose, and it is
17
+ * worth knowing why before anyone simplifies them. React Native does accept
18
+ * some `aria-*` props directly and translates them itself, so those mappings
19
+ * look redundant — but the set differs per host. `View` handles thirteen of
20
+ * them, `Text` handles seven, and neither handles `aria-modal`, `aria-posinset`
21
+ * or `aria-setsize`. Since one row has to be right for every backing a tag can
22
+ * lower to, the mapping that every host accepts unconditionally is the correct
23
+ * one. Verified against react-native 0.86.2's `View.js` and `Text.js`, not
24
+ * against its types. `id` is the exception: View, Text and TextInput all take
25
+ * it, so that row passes it straight through.
26
+ */
27
+
28
+ const TEXT_ENTRY: readonly TagName[] = ['input', 'textarea']
29
+ const ANCHOR: readonly TagName[] = ['a']
30
+ const IMAGE: readonly TagName[] = ['img']
31
+
32
+ /** roles authors may set, excluding the abstract roles */
33
+ export const ARIA_ROLES: readonly string[] = [
34
+ 'alert',
35
+ 'alertdialog',
36
+ 'application',
37
+ 'article',
38
+ 'banner',
39
+ 'blockquote',
40
+ 'button',
41
+ 'caption',
42
+ 'cell',
43
+ 'checkbox',
44
+ 'code',
45
+ 'columnheader',
46
+ 'combobox',
47
+ 'complementary',
48
+ 'contentinfo',
49
+ 'definition',
50
+ 'deletion',
51
+ 'dialog',
52
+ 'document',
53
+ 'emphasis',
54
+ 'feed',
55
+ 'figure',
56
+ 'form',
57
+ 'grid',
58
+ 'gridcell',
59
+ 'group',
60
+ 'heading',
61
+ 'img',
62
+ 'input',
63
+ 'insertion',
64
+ 'link',
65
+ 'list',
66
+ 'listbox',
67
+ 'listitem',
68
+ 'log',
69
+ 'main',
70
+ 'marquee',
71
+ 'math',
72
+ 'menu',
73
+ 'menubar',
74
+ 'menuitem',
75
+ 'menuitemcheckbox',
76
+ 'menuitemradio',
77
+ 'meter',
78
+ 'navigation',
79
+ 'none',
80
+ 'note',
81
+ 'option',
82
+ 'paragraph',
83
+ 'progressbar',
84
+ 'radio',
85
+ 'radiogroup',
86
+ 'region',
87
+ 'row',
88
+ 'rowgroup',
89
+ 'rowheader',
90
+ 'scrollbar',
91
+ 'search',
92
+ 'searchbox',
93
+ 'separator',
94
+ 'slider',
95
+ 'spinbutton',
96
+ 'status',
97
+ 'strong',
98
+ 'subscript',
99
+ 'superscript',
100
+ 'switch',
101
+ 'tab',
102
+ 'table',
103
+ 'tablist',
104
+ 'tabpanel',
105
+ 'term',
106
+ 'textbox',
107
+ 'time',
108
+ 'timer',
109
+ 'toolbar',
110
+ 'tooltip',
111
+ 'tree',
112
+ 'treegrid',
113
+ 'treeitem',
114
+ ]
115
+
116
+ /** autofill hints shared by web and react native */
117
+ export const AUTO_COMPLETE_VALUES: readonly string[] = [
118
+ 'additional-name',
119
+ 'address-line1',
120
+ 'address-line2',
121
+ 'birthdate-day',
122
+ 'birthdate-full',
123
+ 'birthdate-month',
124
+ 'birthdate-year',
125
+ 'cc-csc',
126
+ 'cc-exp',
127
+ 'cc-exp-day',
128
+ 'cc-exp-month',
129
+ 'cc-exp-year',
130
+ 'cc-number',
131
+ 'cc-name',
132
+ 'cc-given-name',
133
+ 'cc-middle-name',
134
+ 'cc-family-name',
135
+ 'cc-type',
136
+ 'country',
137
+ 'current-password',
138
+ 'email',
139
+ 'family-name',
140
+ 'gender',
141
+ 'given-name',
142
+ 'honorific-prefix',
143
+ 'honorific-suffix',
144
+ 'name',
145
+ 'name-family',
146
+ 'name-given',
147
+ 'name-middle',
148
+ 'name-middle-initial',
149
+ 'name-prefix',
150
+ 'name-suffix',
151
+ 'new-password',
152
+ 'nickname',
153
+ 'on',
154
+ 'one-time-code',
155
+ 'organization',
156
+ 'organization-title',
157
+ 'password',
158
+ 'password-new',
159
+ 'postal-address',
160
+ 'postal-address-country',
161
+ 'postal-address-extended',
162
+ 'postal-address-extended-postal-code',
163
+ 'postal-address-locality',
164
+ 'postal-address-region',
165
+ 'postal-code',
166
+ 'street-address',
167
+ 'sms-otp',
168
+ 'tel',
169
+ 'tel-country-code',
170
+ 'tel-national',
171
+ 'tel-device',
172
+ 'url',
173
+ 'username',
174
+ 'username-new',
175
+ 'off',
176
+ ]
177
+
178
+ /** every html input type; the ones native cannot render are a native build error */
179
+ export const HTML_INPUT_TYPES: readonly string[] = [
180
+ 'checkbox',
181
+ 'color',
182
+ 'date',
183
+ 'datetime-local',
184
+ 'email',
185
+ 'file',
186
+ 'hidden',
187
+ 'month',
188
+ 'number',
189
+ 'password',
190
+ 'radio',
191
+ 'range',
192
+ 'search',
193
+ 'submit',
194
+ 'tel',
195
+ 'text',
196
+ 'time',
197
+ 'url',
198
+ 'week',
199
+ ]
200
+
201
+ /**
202
+ * Input types react native can render with a text-entry control.
203
+ *
204
+ * `hidden` and `submit` were here and should not have been: hidden renders
205
+ * nothing at all and submit is a button, so neither is a text-entry control and
206
+ * claiming native support for them would pass a build that cannot render.
207
+ */
208
+ export const NATIVE_INPUT_TYPES: readonly string[] = [
209
+ 'email',
210
+ 'number',
211
+ 'password',
212
+ 'search',
213
+ 'tel',
214
+ 'text',
215
+ 'url',
216
+ ]
217
+
218
+ const ariaState = (name: string, nativeProp: string | null): AttributeRow => ({
219
+ group: 'aria',
220
+ tags: '*',
221
+ type: 'boolean',
222
+ nativeProp,
223
+ web: 'host',
224
+ native: nativeProp ? 'polyfill' : 'none',
225
+ })
226
+
227
+ const ariaRef = (): AttributeRow => ({
228
+ group: 'aria',
229
+ tags: '*',
230
+ type: 'string',
231
+ nativeProp: null,
232
+ web: 'host',
233
+ native: 'none',
234
+ })
235
+
236
+ const ariaNumber = (nativeProp: string | null = null): AttributeRow => ({
237
+ group: 'aria',
238
+ tags: '*',
239
+ type: 'number',
240
+ nativeProp,
241
+ web: 'host',
242
+ native: nativeProp ? 'polyfill' : 'none',
243
+ })
244
+
245
+ const ariaText = (nativeProp: string | null = null): AttributeRow => ({
246
+ group: 'aria',
247
+ tags: '*',
248
+ type: 'string',
249
+ nativeProp,
250
+ web: 'host',
251
+ native: nativeProp ? 'polyfill' : 'none',
252
+ })
253
+
254
+ export const ATTRIBUTES: Readonly<Record<string, AttributeRow>> = {
255
+ // accessibility
256
+ 'aria-activedescendant': ariaRef(),
257
+ 'aria-atomic': ariaState('aria-atomic', null),
258
+ 'aria-autocomplete': {
259
+ group: 'aria',
260
+ tags: '*',
261
+ type: `'none' | 'inline' | 'list' | 'both'`,
262
+ nativeProp: null,
263
+ web: 'host',
264
+ native: 'none',
265
+ },
266
+ 'aria-busy': ariaState('aria-busy', 'accessibilityState.busy'),
267
+ 'aria-checked': {
268
+ group: 'aria',
269
+ tags: '*',
270
+ type: `boolean | 'mixed'`,
271
+ nativeProp: 'accessibilityState.checked',
272
+ web: 'host',
273
+ native: 'polyfill',
274
+ },
275
+ 'aria-colcount': ariaNumber(),
276
+ 'aria-colindex': ariaNumber(),
277
+ 'aria-colindextext': ariaText(),
278
+ 'aria-colspan': ariaNumber(),
279
+ 'aria-controls': ariaRef(),
280
+ 'aria-current': {
281
+ group: 'aria',
282
+ tags: '*',
283
+ type: `boolean | 'page' | 'step' | 'location' | 'date' | 'time'`,
284
+ nativeProp: null,
285
+ web: 'host',
286
+ native: 'none',
287
+ },
288
+ 'aria-describedby': {
289
+ ...ariaRef(),
290
+ note: 'react native has no described-by relationship; put the description in aria-label instead',
291
+ },
292
+ 'aria-details': ariaRef(),
293
+ 'aria-disabled': ariaState('aria-disabled', 'accessibilityState.disabled'),
294
+ 'aria-errormessage': ariaRef(),
295
+ 'aria-expanded': ariaState('aria-expanded', 'accessibilityState.expanded'),
296
+ 'aria-flowto': ariaRef(),
297
+ 'aria-haspopup': {
298
+ group: 'aria',
299
+ tags: '*',
300
+ type: `'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'`,
301
+ nativeProp: null,
302
+ web: 'host',
303
+ native: 'none',
304
+ },
305
+ 'aria-hidden': {
306
+ group: 'aria',
307
+ tags: '*',
308
+ type: 'boolean',
309
+ nativeProp: 'accessibilityElementsHidden',
310
+ web: 'host',
311
+ native: 'polyfill',
312
+ note: 'also sets importantForAccessibility on android so descendants are hidden',
313
+ },
314
+ 'aria-invalid': {
315
+ group: 'aria',
316
+ tags: '*',
317
+ type: `boolean | 'grammar' | 'spelling'`,
318
+ nativeProp: null,
319
+ web: 'host',
320
+ native: 'none',
321
+ },
322
+ 'aria-keyshortcuts': ariaText(),
323
+ 'aria-label': ariaText('accessibilityLabel'),
324
+ 'aria-labelledby': {
325
+ group: 'aria',
326
+ tags: '*',
327
+ type: 'string',
328
+ nativeProp: 'accessibilityLabelledBy',
329
+ web: 'host',
330
+ native: 'polyfill',
331
+ },
332
+ 'aria-level': ariaNumber(),
333
+ 'aria-live': {
334
+ group: 'aria',
335
+ tags: '*',
336
+ type: `'off' | 'assertive' | 'polite'`,
337
+ nativeProp: 'accessibilityLiveRegion',
338
+ web: 'host',
339
+ native: 'polyfill',
340
+ },
341
+ 'aria-modal': ariaState('aria-modal', 'accessibilityViewIsModal'),
342
+ 'aria-multiline': ariaState('aria-multiline', null),
343
+ 'aria-multiselectable': ariaState('aria-multiselectable', null),
344
+ 'aria-orientation': {
345
+ group: 'aria',
346
+ tags: '*',
347
+ type: `'horizontal' | 'vertical'`,
348
+ nativeProp: null,
349
+ web: 'host',
350
+ native: 'none',
351
+ },
352
+ 'aria-owns': ariaRef(),
353
+ 'aria-placeholder': ariaText(),
354
+ // react-native 0.86.2 has no accessibilityPosInSet — checked View.js and
355
+ // ViewAccessibility.d.ts, it exists in neither. Mapping to it would have the
356
+ // prop silently dropped at the host, which is worse than declaring it web-only
357
+ 'aria-posinset': ariaNumber(),
358
+ 'aria-pressed': {
359
+ group: 'aria',
360
+ tags: '*',
361
+ type: `boolean | 'mixed'`,
362
+ nativeProp: null,
363
+ web: 'host',
364
+ native: 'none',
365
+ },
366
+ 'aria-readonly': ariaState('aria-readonly', null),
367
+ 'aria-required': ariaState('aria-required', null),
368
+ 'aria-roledescription': ariaText(),
369
+ 'aria-rowcount': ariaNumber(),
370
+ 'aria-rowindex': ariaNumber(),
371
+ 'aria-rowindextext': ariaText(),
372
+ 'aria-rowspan': ariaNumber(),
373
+ 'aria-selected': ariaState('aria-selected', 'accessibilityState.selected'),
374
+ // same: no accessibilitySetSize anywhere in react-native 0.86.2
375
+ 'aria-setsize': ariaNumber(),
376
+ 'aria-sort': {
377
+ group: 'aria',
378
+ tags: '*',
379
+ type: `'none' | 'ascending' | 'descending' | 'other'`,
380
+ nativeProp: null,
381
+ web: 'host',
382
+ native: 'none',
383
+ },
384
+ 'aria-valuemax': ariaNumber('accessibilityValue.max'),
385
+ 'aria-valuemin': ariaNumber('accessibilityValue.min'),
386
+ 'aria-valuenow': ariaNumber('accessibilityValue.now'),
387
+ 'aria-valuetext': ariaText('accessibilityValue.text'),
388
+
389
+ // global
390
+ autoFocus: {
391
+ group: 'global',
392
+ tags: '*',
393
+ type: 'boolean',
394
+ nativeProp: null,
395
+ web: 'host',
396
+ native: 'none',
397
+ note: 'focus a native element through a ref in an effect instead',
398
+ },
399
+ dir: {
400
+ group: 'global',
401
+ tags: '*',
402
+ type: `'auto' | 'ltr' | 'rtl'`,
403
+ nativeProp: 'writingDirection',
404
+ web: 'host',
405
+ native: 'polyfill',
406
+ },
407
+ elementTiming: {
408
+ group: 'global',
409
+ tags: '*',
410
+ type: 'string',
411
+ nativeProp: null,
412
+ web: 'host',
413
+ native: 'none',
414
+ note: 'element timing is a browser performance api',
415
+ },
416
+ hidden: {
417
+ group: 'global',
418
+ tags: '*',
419
+ type: `true | 'hidden' | 'until-found'`,
420
+ nativeProp: 'style.display',
421
+ web: 'host',
422
+ native: 'polyfill',
423
+ note: 'native applies display none and has no until-found reveal',
424
+ },
425
+ id: {
426
+ group: 'global',
427
+ tags: '*',
428
+ type: 'string',
429
+ // react native takes `id` itself on View, Text and TextInput and assigns it
430
+ // to nativeID, so there is nothing to rename
431
+ nativeProp: 'id',
432
+ web: 'host',
433
+ native: 'polyfill',
434
+ },
435
+ inert: {
436
+ group: 'global',
437
+ tags: '*',
438
+ type: 'boolean',
439
+ nativeProp: null,
440
+ web: 'host',
441
+ native: 'none',
442
+ },
443
+ lang: {
444
+ group: 'global',
445
+ tags: '*',
446
+ type: 'string',
447
+ nativeProp: null,
448
+ web: 'host',
449
+ native: 'none',
450
+ },
451
+ role: {
452
+ group: 'global',
453
+ tags: '*',
454
+ type: 'AriaRole',
455
+ nativeProp: 'role',
456
+ web: 'host',
457
+ native: 'polyfill',
458
+ },
459
+ tabIndex: {
460
+ group: 'global',
461
+ tags: '*',
462
+ type: '0 | -1',
463
+ nativeProp: 'focusable',
464
+ web: 'host',
465
+ native: 'polyfill',
466
+ },
467
+
468
+ // react
469
+ suppressHydrationWarning: {
470
+ group: 'react',
471
+ tags: '*',
472
+ type: 'boolean',
473
+ nativeProp: null,
474
+ web: 'host',
475
+ native: 'none',
476
+ },
477
+
478
+ children: {
479
+ group: 'react',
480
+ tags: '*',
481
+ nativeProp: 'children',
482
+ web: 'host',
483
+ native: 'host',
484
+ note: 'the content model in the tag table decides the type: no children on a void tag, text only inside an option',
485
+ },
486
+
487
+ // supplied by the styling frontend, never generated as a prop here
488
+ style: {
489
+ group: 'frontend',
490
+ tags: '*',
491
+ nativeProp: 'style',
492
+ web: 'host',
493
+ native: 'host',
494
+ note: 'each frontend supplies its own style contract: tamagui style props, className, or style() handles',
495
+ },
496
+ 'data-*': {
497
+ group: 'data',
498
+ tags: '*',
499
+ type: 'string | number | boolean',
500
+ nativeProp: null,
501
+ web: 'host',
502
+ native: 'none',
503
+ note: 'data-testid is the one exception and reaches testID on native',
504
+ },
505
+ 'data-testid': {
506
+ group: 'data',
507
+ tags: '*',
508
+ type: 'string',
509
+ nativeProp: 'testID',
510
+ web: 'host',
511
+ native: 'polyfill',
512
+ },
513
+
514
+ // text entry
515
+ autoCapitalize: {
516
+ group: 'element',
517
+ tags: TEXT_ENTRY,
518
+ type: `'none' | 'sentences' | 'words' | 'characters'`,
519
+ nativeProp: 'autoCapitalize',
520
+ web: 'host',
521
+ native: 'host',
522
+ },
523
+ autoComplete: {
524
+ group: 'element',
525
+ tags: ['input', 'select', 'textarea'],
526
+ type: 'AutoComplete',
527
+ nativeProp: 'autoComplete',
528
+ web: 'host',
529
+ native: 'host',
530
+ },
531
+ enterKeyHint: {
532
+ group: 'element',
533
+ tags: TEXT_ENTRY,
534
+ type: `'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send'`,
535
+ nativeProp: 'enterKeyHint',
536
+ web: 'host',
537
+ native: 'host',
538
+ },
539
+ inputMode: {
540
+ group: 'element',
541
+ tags: TEXT_ENTRY,
542
+ type: `'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'`,
543
+ nativeProp: 'inputMode',
544
+ web: 'host',
545
+ native: 'host',
546
+ },
547
+ spellCheck: {
548
+ group: 'element',
549
+ tags: TEXT_ENTRY,
550
+ type: 'boolean',
551
+ nativeProp: 'spellCheck',
552
+ web: 'host',
553
+ native: 'host',
554
+ note: 'ios only on native',
555
+ },
556
+
557
+ // anchor
558
+ download: {
559
+ group: 'element',
560
+ tags: ANCHOR,
561
+ type: 'string',
562
+ nativeProp: null,
563
+ web: 'host',
564
+ native: 'none',
565
+ },
566
+ href: {
567
+ group: 'element',
568
+ tags: ANCHOR,
569
+ type: 'string',
570
+ nativeProp: null,
571
+ web: 'host',
572
+ native: 'none',
573
+ note: 'native has no navigation; handle onClick and call your router or Linking',
574
+ },
575
+ referrerPolicy: {
576
+ group: 'element',
577
+ tags: ['a', 'img'],
578
+ type: `'no-referrer' | 'no-referrer-when-downgrade' | 'origin' | 'origin-when-cross-origin' | 'same-origin' | 'strict-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url'`,
579
+ nativeProp: 'referrerPolicy',
580
+ web: 'host',
581
+ native: 'host',
582
+ note: 'native honours it for image requests only',
583
+ },
584
+ rel: {
585
+ group: 'element',
586
+ tags: ANCHOR,
587
+ type: 'string',
588
+ nativeProp: null,
589
+ web: 'host',
590
+ native: 'none',
591
+ },
592
+ target: {
593
+ group: 'element',
594
+ tags: ANCHOR,
595
+ type: `'_self' | '_blank' | '_parent' | '_top'`,
596
+ nativeProp: null,
597
+ web: 'host',
598
+ native: 'none',
599
+ },
600
+
601
+ // button, input, option, optgroup, textarea
602
+ disabled: {
603
+ group: 'element',
604
+ tags: ['button', 'input', 'optgroup', 'option', 'textarea'],
605
+ type: 'boolean',
606
+ nativeProp: 'disabled',
607
+ web: 'host',
608
+ native: 'polyfill',
609
+ note: 'native also clears focusable, and editable on a text-entry control',
610
+ },
611
+ type: {
612
+ group: 'element',
613
+ tags: ['button', 'input'],
614
+ perTag: {
615
+ button: { type: `'button' | 'submit'` },
616
+ input: {
617
+ type: 'InputType',
618
+ note: 'on native the type selects the keyboard and secure entry rather than reaching one prop, and the types with no text-entry control are a build error',
619
+ },
620
+ },
621
+ nativeProp: null,
622
+ web: 'host',
623
+ native: 'polyfill',
624
+ },
625
+
626
+ // image
627
+ alt: {
628
+ group: 'element',
629
+ tags: IMAGE,
630
+ type: 'string',
631
+ nativeProp: 'alt',
632
+ web: 'host',
633
+ native: 'host',
634
+ },
635
+ crossOrigin: {
636
+ group: 'element',
637
+ tags: IMAGE,
638
+ type: `'anonymous' | 'use-credentials'`,
639
+ nativeProp: 'crossOrigin',
640
+ web: 'host',
641
+ native: 'host',
642
+ },
643
+ decoding: {
644
+ group: 'element',
645
+ tags: IMAGE,
646
+ type: `'async' | 'auto' | 'sync'`,
647
+ nativeProp: null,
648
+ web: 'host',
649
+ native: 'none',
650
+ },
651
+ draggable: {
652
+ group: 'element',
653
+ tags: IMAGE,
654
+ type: 'boolean',
655
+ nativeProp: null,
656
+ web: 'host',
657
+ native: 'none',
658
+ },
659
+ fetchPriority: {
660
+ group: 'element',
661
+ tags: IMAGE,
662
+ type: `'high' | 'low' | 'auto'`,
663
+ nativeProp: null,
664
+ web: 'host',
665
+ native: 'none',
666
+ },
667
+ height: {
668
+ group: 'element',
669
+ tags: IMAGE,
670
+ type: 'number',
671
+ nativeProp: 'height',
672
+ web: 'host',
673
+ native: 'host',
674
+ },
675
+ loading: {
676
+ group: 'element',
677
+ tags: IMAGE,
678
+ type: `'eager' | 'lazy'`,
679
+ nativeProp: null,
680
+ web: 'host',
681
+ native: 'none',
682
+ },
683
+ src: {
684
+ group: 'element',
685
+ tags: IMAGE,
686
+ type: 'string',
687
+ nativeProp: 'src',
688
+ web: 'host',
689
+ native: 'host',
690
+ },
691
+ srcSet: {
692
+ group: 'element',
693
+ tags: IMAGE,
694
+ type: 'string',
695
+ nativeProp: 'srcSet',
696
+ web: 'host',
697
+ native: 'host',
698
+ },
699
+ width: {
700
+ group: 'element',
701
+ tags: IMAGE,
702
+ type: 'number',
703
+ nativeProp: 'width',
704
+ web: 'host',
705
+ native: 'host',
706
+ },
707
+
708
+ // form controls
709
+ checked: {
710
+ group: 'element',
711
+ tags: ['input'],
712
+ type: `boolean | 'mixed'`,
713
+ nativeProp: null,
714
+ web: 'host',
715
+ native: 'none',
716
+ note: 'checkbox and radio inputs have no native rendering',
717
+ },
718
+ defaultChecked: {
719
+ group: 'element',
720
+ tags: ['input'],
721
+ type: 'boolean',
722
+ nativeProp: null,
723
+ web: 'host',
724
+ native: 'none',
725
+ note: 'checkbox and radio inputs have no native rendering',
726
+ },
727
+ defaultValue: {
728
+ group: 'element',
729
+ tags: ['input', 'select', 'textarea'],
730
+ type: 'string',
731
+ perTag: { select: { type: 'string | readonly string[]' } },
732
+ nativeProp: 'defaultValue',
733
+ web: 'host',
734
+ native: 'host',
735
+ },
736
+ for: {
737
+ group: 'element',
738
+ tags: ['label'],
739
+ type: 'string',
740
+ nativeProp: null,
741
+ web: 'host',
742
+ native: 'none',
743
+ note: 'native has no label association; wrap the control or drive it from your own state',
744
+ },
745
+ label: {
746
+ group: 'element',
747
+ tags: ['optgroup', 'option'],
748
+ type: 'string',
749
+ nativeProp: null,
750
+ web: 'host',
751
+ native: 'none',
752
+ },
753
+ max: {
754
+ group: 'element',
755
+ tags: ['input'],
756
+ type: 'string | number',
757
+ nativeProp: null,
758
+ web: 'host',
759
+ native: 'none',
760
+ },
761
+ maxLength: {
762
+ group: 'element',
763
+ tags: TEXT_ENTRY,
764
+ type: 'number',
765
+ nativeProp: 'maxLength',
766
+ web: 'host',
767
+ native: 'host',
768
+ },
769
+ min: {
770
+ group: 'element',
771
+ tags: ['input'],
772
+ type: 'string | number',
773
+ nativeProp: null,
774
+ web: 'host',
775
+ native: 'none',
776
+ },
777
+ minLength: {
778
+ group: 'element',
779
+ tags: TEXT_ENTRY,
780
+ type: 'number',
781
+ nativeProp: null,
782
+ web: 'host',
783
+ native: 'none',
784
+ },
785
+ multiple: {
786
+ group: 'element',
787
+ tags: ['input', 'select'],
788
+ type: 'boolean',
789
+ nativeProp: null,
790
+ web: 'host',
791
+ native: 'none',
792
+ },
793
+ name: {
794
+ group: 'element',
795
+ tags: ['input', 'select', 'textarea'],
796
+ type: 'string',
797
+ nativeProp: null,
798
+ web: 'host',
799
+ native: 'none',
800
+ note: 'form field names only matter to a form submission, which native does not have',
801
+ },
802
+ placeholder: {
803
+ group: 'element',
804
+ tags: TEXT_ENTRY,
805
+ type: 'string',
806
+ nativeProp: 'placeholder',
807
+ web: 'host',
808
+ native: 'host',
809
+ },
810
+ readOnly: {
811
+ group: 'element',
812
+ tags: TEXT_ENTRY,
813
+ type: 'boolean',
814
+ nativeProp: 'editable',
815
+ web: 'host',
816
+ native: 'polyfill',
817
+ },
818
+ required: {
819
+ group: 'element',
820
+ tags: ['input', 'select', 'textarea'],
821
+ type: 'boolean',
822
+ nativeProp: null,
823
+ web: 'host',
824
+ native: 'none',
825
+ note: 'native has no form validation',
826
+ },
827
+ rows: {
828
+ group: 'element',
829
+ tags: ['textarea'],
830
+ type: 'number',
831
+ nativeProp: 'numberOfLines',
832
+ web: 'host',
833
+ native: 'polyfill',
834
+ },
835
+ step: {
836
+ group: 'element',
837
+ tags: ['input'],
838
+ type: `number | 'any'`,
839
+ nativeProp: null,
840
+ web: 'host',
841
+ native: 'none',
842
+ },
843
+ value: {
844
+ group: 'element',
845
+ tags: ['input', 'li', 'option', 'select', 'textarea'],
846
+ type: 'string',
847
+ perTag: {
848
+ li: {
849
+ type: 'number',
850
+ note: 'the list counter is not rendered on either platform, matching the list-style reset',
851
+ },
852
+ select: { type: 'string | readonly string[]' },
853
+ },
854
+ nativeProp: 'value',
855
+ web: 'host',
856
+ native: 'polyfill',
857
+ },
858
+ }
859
+
860
+ export const ATTRIBUTE_NAMES: readonly string[] = Object.keys(ATTRIBUTES)
861
+
862
+ /** props the styling frontend supplies, so the DOM contract does not generate them */
863
+ export const FRONTEND_PROPS: readonly string[] = ['style']