import type { DefaultStyle, TagName, TagRow } from './types' /** * The tag table: the 49 elements of the Tamagui DOM contract. * * `display` and `backing` are independent columns. `p` is a block element * backed by a native Text, `button` is inline-block backed by a native View. * The compiler reads `backing` to inject primitives and `content` to report * invalid nesting; the runtime reads the defaults to build each element. * * Element defaults follow React Strict DOM's resets: an explicit, equal * starting point on both platforms instead of the browser default stylesheet on * web and nothing on native. Differences from RSD are in `compatibility.ts`. */ const MONOSPACE: DefaultStyle = { fontFamily: 'monospace' } const HEADING: DefaultStyle = { fontSize: '1.5rem', fontWeight: 'bold' } const NO_FORM_SUBMISSION = 'renders as a container on native; there is no form submission, validation or reset' const NO_NATIVE_PICKER = 'native has no menu-based select control, so this tag is a native build error' export const TAGS: Readonly> = { a: { display: 'inline', content: 'phrasing', backing: 'text', role: 'link', element: 'HTMLAnchorElement', props: 'anchor', web: 'host', native: 'polyfill', note: 'native has no navigation for href, target, rel, download or referrerPolicy', }, article: { display: 'block', content: 'flow', backing: 'view', element: 'HTMLElement', props: 'common', web: 'host', native: 'polyfill', }, aside: { display: 'block', content: 'flow', backing: 'view', element: 'HTMLElement', props: 'common', web: 'host', native: 'polyfill', }, b: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', defaults: { fontWeight: 'bold' }, web: 'host', native: 'polyfill', }, bdi: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', web: 'host', native: 'polyfill', note: 'native has no bidirectional isolation; the text renders in the inherited direction', }, bdo: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', web: 'host', native: 'polyfill', note: 'native honours dir as a writing direction but does not override embedded bidi runs', }, blockquote: { display: 'block', content: 'flow', backing: 'view', element: 'HTMLQuoteElement', props: 'common', web: 'host', native: 'polyfill', }, br: { display: 'inline', content: 'void', backing: 'text', element: 'HTMLBRElement', props: 'common', web: 'host', native: 'polyfill', }, button: { display: 'inline-block', content: 'flow', backing: 'view', role: 'button', element: 'HTMLButtonElement', props: 'button', defaults: { borderWidth: 1 }, web: 'host', native: 'polyfill', note: 'html restricts button content to phrasing; the native backing is a view, so block children are allowed', }, code: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', defaults: MONOSPACE, web: 'host', native: 'polyfill', }, del: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLModElement', props: 'common', defaults: { textDecorationLine: 'line-through' }, web: 'host', native: 'polyfill', }, div: { display: 'block', content: 'flow', backing: 'view', element: 'HTMLDivElement', props: 'common', web: 'host', native: 'polyfill', }, em: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', defaults: { fontStyle: 'italic' }, web: 'host', native: 'polyfill', }, fieldset: { display: 'block', content: 'flow', backing: 'view', element: 'HTMLFieldSetElement', props: 'common', web: 'host', native: 'polyfill', note: NO_FORM_SUBMISSION, }, footer: { display: 'block', content: 'flow', backing: 'view', element: 'HTMLElement', props: 'common', web: 'host', native: 'polyfill', }, form: { display: 'block', content: 'flow', backing: 'view', element: 'HTMLFormElement', props: 'common', web: 'host', native: 'polyfill', note: NO_FORM_SUBMISSION, }, h1: { display: 'block', content: 'phrasing', backing: 'text', role: 'heading', element: 'HTMLHeadingElement', props: 'common', defaults: HEADING, web: 'host', native: 'polyfill', }, h2: { display: 'block', content: 'phrasing', backing: 'text', role: 'heading', element: 'HTMLHeadingElement', props: 'common', defaults: HEADING, web: 'host', native: 'polyfill', }, h3: { display: 'block', content: 'phrasing', backing: 'text', role: 'heading', element: 'HTMLHeadingElement', props: 'common', defaults: HEADING, web: 'host', native: 'polyfill', }, h4: { display: 'block', content: 'phrasing', backing: 'text', role: 'heading', element: 'HTMLHeadingElement', props: 'common', defaults: HEADING, web: 'host', native: 'polyfill', }, h5: { display: 'block', content: 'phrasing', backing: 'text', role: 'heading', element: 'HTMLHeadingElement', props: 'common', defaults: HEADING, web: 'host', native: 'polyfill', }, h6: { display: 'block', content: 'phrasing', backing: 'text', role: 'heading', element: 'HTMLHeadingElement', props: 'common', defaults: HEADING, web: 'host', native: 'polyfill', }, header: { display: 'block', content: 'flow', backing: 'view', role: 'header', element: 'HTMLElement', props: 'common', web: 'host', native: 'polyfill', }, hr: { display: 'block', content: 'void', backing: 'view', element: 'HTMLHRElement', props: 'common', defaults: { backgroundColor: 'black', height: 1 }, web: 'host', native: 'polyfill', }, i: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', defaults: { fontStyle: 'italic' }, web: 'host', native: 'polyfill', }, img: { display: 'inline', content: 'void', backing: 'image', element: 'HTMLImageElement', props: 'image', defaults: { objectFit: 'fill' }, web: 'host', native: 'polyfill', note: 'width and height props set an aspect ratio on native, where images have no intrinsic layout size until they load', }, input: { display: 'inline-block', content: 'void', backing: 'textinput', element: 'HTMLInputElement', props: 'input', defaults: { borderWidth: 1 }, web: 'host', native: 'polyfill', note: 'native supports the text-like input types only; checkbox, color, date, datetime-local, file, month, radio, range, time and week are a native build error', }, ins: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLModElement', props: 'common', defaults: { textDecorationLine: 'underline' }, web: 'host', native: 'polyfill', }, kbd: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', defaults: MONOSPACE, web: 'host', native: 'polyfill', }, label: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLLabelElement', props: 'label', web: 'host', native: 'polyfill', note: 'native has no label association, so `for` does not focus or activate its control', }, li: { display: 'block', content: 'flow', backing: 'view', role: 'listitem', element: 'HTMLLIElement', props: 'listitem', web: 'host', native: 'polyfill', note: 'list markers and the `value` counter are not rendered on either platform, matching the list-style reset', }, main: { display: 'block', content: 'flow', backing: 'view', element: 'HTMLElement', props: 'common', web: 'host', native: 'polyfill', }, mark: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', defaults: { backgroundColor: 'yellow', color: 'black' }, web: 'host', native: 'polyfill', }, nav: { display: 'block', content: 'flow', backing: 'view', element: 'HTMLElement', props: 'common', web: 'host', native: 'polyfill', }, ol: { display: 'block', content: 'tags', childTags: ['li'], backing: 'view', role: 'list', element: 'HTMLOListElement', props: 'common', web: 'host', native: 'polyfill', }, optgroup: { display: 'block', content: 'tags', childTags: ['option'], backing: 'view', element: 'HTMLOptGroupElement', props: 'optgroup', web: 'host', native: 'none', note: NO_NATIVE_PICKER, }, option: { display: 'block', content: 'text', backing: 'text', element: 'HTMLOptionElement', props: 'option', web: 'host', native: 'none', note: NO_NATIVE_PICKER, }, p: { display: 'block', content: 'phrasing', backing: 'text', element: 'HTMLParagraphElement', props: 'common', web: 'host', native: 'polyfill', }, pre: { display: 'block', content: 'phrasing', backing: 'text', element: 'HTMLPreElement', props: 'common', defaults: MONOSPACE, web: 'host', native: 'polyfill', note: 'native preserves whitespace in text but has no scroll container, so long lines wrap instead of scrolling', }, s: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', defaults: { textDecorationLine: 'line-through' }, web: 'host', native: 'polyfill', }, section: { display: 'block', content: 'flow', backing: 'view', element: 'HTMLElement', props: 'common', web: 'host', native: 'polyfill', }, select: { display: 'inline-block', content: 'tags', childTags: ['optgroup', 'option'], backing: 'view', element: 'HTMLSelectElement', props: 'select', web: 'host', native: 'none', note: NO_NATIVE_PICKER, }, span: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLSpanElement', props: 'common', web: 'host', native: 'polyfill', }, strong: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', defaults: { fontWeight: 'bold' }, web: 'host', native: 'polyfill', }, sub: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', web: 'host', native: 'polyfill', note: 'native has no vertical-align, so subscript text sits on the baseline', }, sup: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', web: 'host', native: 'polyfill', note: 'native has no vertical-align, so superscript text sits on the baseline', }, textarea: { display: 'inline-block', content: 'void', backing: 'textinput', element: 'HTMLTextAreaElement', props: 'textarea', defaults: { borderWidth: 1 }, nativeDefaults: { verticalAlign: 'top' }, web: 'host', native: 'polyfill', note: 'the value comes from value or defaultValue; children are a build error on both platforms', }, u: { display: 'inline', content: 'phrasing', backing: 'text', element: 'HTMLElement', props: 'common', defaults: { textDecorationLine: 'underline' }, web: 'host', native: 'polyfill', }, ul: { display: 'block', content: 'tags', childTags: ['li'], backing: 'view', role: 'list', element: 'HTMLUListElement', props: 'common', web: 'host', native: 'polyfill', }, } /** * Web-only defaults: undoing a browser default, or a property with no * cross-platform spelling. `fontSize: 1em` cancels the browser's smaller * default size for monospace text, which is the whole reason the browser * renders `code`, `kbd` and `pre` at a different size from their surroundings. * * Everything here has to be a style property Tamagui actually resolves. A key * Tamagui does not know is not a silent no-op — it falls through to the element * as an attribute, which is a react warning and no styling. `list-style`, * `resize` and `overflow-wrap` are all in that category today, which is why * they are absent and recorded in `compatibility.ts` instead. */ export const TAG_WEB_DEFAULTS: Readonly>> = { code: { fontSize: '1em' }, hr: { borderStyle: 'none', borderWidth: 0, boxSizing: 'border-box' }, img: { height: 'auto', maxWidth: '100%' }, kbd: { fontSize: '1em' }, pre: { fontSize: '1em', overflow: 'auto' }, } export const TAG_NAMES: readonly TagName[] = Object.keys(TAGS) as TagName[]