Skip to main content

typst_html/
tag.rs

1//! Predefined constants for HTML tags.
2
3#![allow(non_upper_case_globals)]
4#![allow(dead_code)]
5
6use crate::{HtmlTag, property};
7
8pub const a: HtmlTag = HtmlTag::constant("a");
9pub const abbr: HtmlTag = HtmlTag::constant("abbr");
10pub const address: HtmlTag = HtmlTag::constant("address");
11pub const area: HtmlTag = HtmlTag::constant("area");
12pub const article: HtmlTag = HtmlTag::constant("article");
13pub const aside: HtmlTag = HtmlTag::constant("aside");
14pub const audio: HtmlTag = HtmlTag::constant("audio");
15pub const b: HtmlTag = HtmlTag::constant("b");
16pub const base: HtmlTag = HtmlTag::constant("base");
17pub const bdi: HtmlTag = HtmlTag::constant("bdi");
18pub const bdo: HtmlTag = HtmlTag::constant("bdo");
19pub const blockquote: HtmlTag = HtmlTag::constant("blockquote");
20pub const body: HtmlTag = HtmlTag::constant("body");
21pub const br: HtmlTag = HtmlTag::constant("br");
22pub const button: HtmlTag = HtmlTag::constant("button");
23pub const canvas: HtmlTag = HtmlTag::constant("canvas");
24pub const caption: HtmlTag = HtmlTag::constant("caption");
25pub const cite: HtmlTag = HtmlTag::constant("cite");
26pub const code: HtmlTag = HtmlTag::constant("code");
27pub const col: HtmlTag = HtmlTag::constant("col");
28pub const colgroup: HtmlTag = HtmlTag::constant("colgroup");
29pub const data: HtmlTag = HtmlTag::constant("data");
30pub const datalist: HtmlTag = HtmlTag::constant("datalist");
31pub const dd: HtmlTag = HtmlTag::constant("dd");
32pub const del: HtmlTag = HtmlTag::constant("del");
33pub const details: HtmlTag = HtmlTag::constant("details");
34pub const dfn: HtmlTag = HtmlTag::constant("dfn");
35pub const dialog: HtmlTag = HtmlTag::constant("dialog");
36pub const div: HtmlTag = HtmlTag::constant("div");
37pub const dl: HtmlTag = HtmlTag::constant("dl");
38pub const dt: HtmlTag = HtmlTag::constant("dt");
39pub const em: HtmlTag = HtmlTag::constant("em");
40pub const embed: HtmlTag = HtmlTag::constant("embed");
41pub const fieldset: HtmlTag = HtmlTag::constant("fieldset");
42pub const figcaption: HtmlTag = HtmlTag::constant("figcaption");
43pub const figure: HtmlTag = HtmlTag::constant("figure");
44pub const footer: HtmlTag = HtmlTag::constant("footer");
45pub const form: HtmlTag = HtmlTag::constant("form");
46pub const h1: HtmlTag = HtmlTag::constant("h1");
47pub const h2: HtmlTag = HtmlTag::constant("h2");
48pub const h3: HtmlTag = HtmlTag::constant("h3");
49pub const h4: HtmlTag = HtmlTag::constant("h4");
50pub const h5: HtmlTag = HtmlTag::constant("h5");
51pub const h6: HtmlTag = HtmlTag::constant("h6");
52pub const head: HtmlTag = HtmlTag::constant("head");
53pub const header: HtmlTag = HtmlTag::constant("header");
54pub const hgroup: HtmlTag = HtmlTag::constant("hgroup");
55pub const hr: HtmlTag = HtmlTag::constant("hr");
56pub const html: HtmlTag = HtmlTag::constant("html");
57pub const i: HtmlTag = HtmlTag::constant("i");
58pub const iframe: HtmlTag = HtmlTag::constant("iframe");
59pub const img: HtmlTag = HtmlTag::constant("img");
60pub const input: HtmlTag = HtmlTag::constant("input");
61pub const ins: HtmlTag = HtmlTag::constant("ins");
62pub const kbd: HtmlTag = HtmlTag::constant("kbd");
63pub const label: HtmlTag = HtmlTag::constant("label");
64pub const legend: HtmlTag = HtmlTag::constant("legend");
65pub const li: HtmlTag = HtmlTag::constant("li");
66pub const link: HtmlTag = HtmlTag::constant("link");
67pub const main: HtmlTag = HtmlTag::constant("main");
68pub const map: HtmlTag = HtmlTag::constant("map");
69pub const mark: HtmlTag = HtmlTag::constant("mark");
70pub const menu: HtmlTag = HtmlTag::constant("menu");
71pub const meta: HtmlTag = HtmlTag::constant("meta");
72pub const meter: HtmlTag = HtmlTag::constant("meter");
73pub const nav: HtmlTag = HtmlTag::constant("nav");
74pub const noscript: HtmlTag = HtmlTag::constant("noscript");
75pub const object: HtmlTag = HtmlTag::constant("object");
76pub const ol: HtmlTag = HtmlTag::constant("ol");
77pub const optgroup: HtmlTag = HtmlTag::constant("optgroup");
78pub const option: HtmlTag = HtmlTag::constant("option");
79pub const output: HtmlTag = HtmlTag::constant("output");
80pub const p: HtmlTag = HtmlTag::constant("p");
81pub const picture: HtmlTag = HtmlTag::constant("picture");
82pub const pre: HtmlTag = HtmlTag::constant("pre");
83pub const progress: HtmlTag = HtmlTag::constant("progress");
84pub const q: HtmlTag = HtmlTag::constant("q");
85pub const rp: HtmlTag = HtmlTag::constant("rp");
86pub const rt: HtmlTag = HtmlTag::constant("rt");
87pub const ruby: HtmlTag = HtmlTag::constant("ruby");
88pub const s: HtmlTag = HtmlTag::constant("s");
89pub const samp: HtmlTag = HtmlTag::constant("samp");
90pub const script: HtmlTag = HtmlTag::constant("script");
91pub const search: HtmlTag = HtmlTag::constant("search");
92pub const section: HtmlTag = HtmlTag::constant("section");
93pub const select: HtmlTag = HtmlTag::constant("select");
94pub const slot: HtmlTag = HtmlTag::constant("slot");
95pub const small: HtmlTag = HtmlTag::constant("small");
96pub const source: HtmlTag = HtmlTag::constant("source");
97pub const span: HtmlTag = HtmlTag::constant("span");
98pub const strong: HtmlTag = HtmlTag::constant("strong");
99pub const style: HtmlTag = HtmlTag::constant("style");
100pub const sub: HtmlTag = HtmlTag::constant("sub");
101pub const summary: HtmlTag = HtmlTag::constant("summary");
102pub const sup: HtmlTag = HtmlTag::constant("sup");
103pub const table: HtmlTag = HtmlTag::constant("table");
104pub const tbody: HtmlTag = HtmlTag::constant("tbody");
105pub const td: HtmlTag = HtmlTag::constant("td");
106pub const template: HtmlTag = HtmlTag::constant("template");
107pub const textarea: HtmlTag = HtmlTag::constant("textarea");
108pub const tfoot: HtmlTag = HtmlTag::constant("tfoot");
109pub const th: HtmlTag = HtmlTag::constant("th");
110pub const thead: HtmlTag = HtmlTag::constant("thead");
111pub const time: HtmlTag = HtmlTag::constant("time");
112pub const title: HtmlTag = HtmlTag::constant("title");
113pub const tr: HtmlTag = HtmlTag::constant("tr");
114pub const track: HtmlTag = HtmlTag::constant("track");
115pub const u: HtmlTag = HtmlTag::constant("u");
116pub const ul: HtmlTag = HtmlTag::constant("ul");
117pub const var: HtmlTag = HtmlTag::constant("var");
118pub const video: HtmlTag = HtmlTag::constant("video");
119pub const wbr: HtmlTag = HtmlTag::constant("wbr");
120
121// HTML spec § 13.1.2 Elements
122
123/// Whether this is a void tag whose associated element may not have
124/// children.
125pub fn is_void(tag: HtmlTag) -> bool {
126    matches!(
127        tag,
128        self::area
129            | self::base
130            | self::br
131            | self::col
132            | self::embed
133            | self::hr
134            | self::img
135            | self::input
136            | self::link
137            | self::meta
138            | self::source
139            | self::track
140            | self::wbr
141    )
142}
143
144/// Whether this is a tag containing raw text.
145pub fn is_raw(tag: HtmlTag) -> bool {
146    matches!(tag, self::script | self::style)
147}
148
149/// Whether this is a tag containing escapable raw text.
150pub fn is_escapable_raw(tag: HtmlTag) -> bool {
151    matches!(tag, self::textarea | self::title)
152}
153
154/// Whether this is a foreign tag whose associated element is from another
155/// namespace.
156///
157/// Currently includes MathML tags, but could be extended to SVG.
158pub fn is_foreign(tag: HtmlTag) -> bool {
159    self::mathml::is_mathml(tag)
160}
161
162/// Whether this is a foreign element whose tag is self-closing.
163pub fn is_foreign_self_closing(tag: HtmlTag) -> bool {
164    matches!(tag, self::mathml::mprescripts | self::mathml::mspace)
165}
166
167// HTML spec § 3.2.5.2 Kinds of content
168
169/// Whether an element is considered metadata content.
170pub fn is_metadata_content(tag: HtmlTag) -> bool {
171    matches!(
172        tag,
173        self::base
174            | self::link
175            | self::meta
176            | self::noscript
177            | self::script
178            | self::style
179            | self::template
180            | self::title
181    )
182}
183
184/// Wether an element is considered flow content.
185pub fn is_flow_content(tag: HtmlTag) -> bool {
186    matches!(
187        tag,
188        self::a
189            | self::abbr
190            | self::address
191            | self::area
192            | self::article
193            | self::aside
194            | self::audio
195            | self::b
196            | self::bdi
197            | self::bdo
198            | self::blockquote
199            | self::br
200            | self::button
201            | self::canvas
202            | self::cite
203            | self::code
204            | self::data
205            | self::datalist
206            | self::del
207            | self::details
208            | self::dfn
209            | self::dialog
210            | self::div
211            | self::dl
212            | self::em
213            | self::embed
214            | self::fieldset
215            | self::figure
216            | self::footer
217            | self::form
218            | self::h1
219            | self::h2
220            | self::h3
221            | self::h4
222            | self::h5
223            | self::h6
224            | self::header
225            | self::hgroup
226            | self::hr
227            | self::i
228            | self::iframe
229            | self::img
230            | self::input
231            | self::ins
232            | self::kbd
233            | self::label
234            | self::link
235            | self::main
236            | self::map
237            | self::mark
238            | self::mathml::math
239            | self::menu
240            | self::meta
241            | self::meter
242            | self::nav
243            | self::noscript
244            | self::object
245            | self::ol
246            | self::output
247            | self::p
248            | self::picture
249            | self::pre
250            | self::progress
251            | self::q
252            | self::ruby
253            | self::s
254            | self::samp
255            | self::script
256            | self::search
257            | self::section
258            | self::select
259            | self::slot
260            | self::small
261            | self::span
262            | self::strong
263            | self::sub
264            | self::sup
265            | self::table
266            | self::template
267            | self::textarea
268            | self::time
269            | self::u
270            | self::ul
271            | self::var
272            | self::video
273            | self::wbr
274    )
275}
276
277/// Whether an element is considered sectioning content.
278pub fn is_sectioning_content(tag: HtmlTag) -> bool {
279    matches!(tag, self::article | self::aside | self::nav | self::section)
280}
281
282/// Whether an element is considered heading content.
283pub fn is_heading_content(tag: HtmlTag) -> bool {
284    matches!(
285        tag,
286        self::h1 | self::h2 | self::h3 | self::h4 | self::h5 | self::h6 | self::hgroup
287    )
288}
289
290/// Whether an element is considered phrasing content.
291pub fn is_phrasing_content(tag: HtmlTag) -> bool {
292    matches!(
293        tag,
294        self::a
295            | self::abbr
296            | self::area
297            | self::audio
298            | self::b
299            | self::bdi
300            | self::bdo
301            | self::br
302            | self::button
303            | self::canvas
304            | self::cite
305            | self::code
306            | self::data
307            | self::datalist
308            | self::del
309            | self::dfn
310            | self::em
311            | self::embed
312            | self::i
313            | self::iframe
314            | self::img
315            | self::input
316            | self::ins
317            | self::kbd
318            | self::label
319            | self::link
320            | self::map
321            | self::mark
322            | self::mathml::math
323            | self::meta
324            | self::meter
325            | self::noscript
326            | self::object
327            | self::output
328            | self::picture
329            | self::progress
330            | self::q
331            | self::ruby
332            | self::s
333            | self::samp
334            | self::script
335            | self::select
336            | self::slot
337            | self::small
338            | self::span
339            | self::strong
340            | self::sub
341            | self::sup
342            | self::template
343            | self::textarea
344            | self::time
345            | self::u
346            | self::var
347            | self::video
348            | self::wbr
349    )
350}
351
352/// Whether an element is considered embedded content.
353pub fn is_embedded_content(tag: HtmlTag) -> bool {
354    matches!(
355        tag,
356        self::audio
357            | self::canvas
358            | self::embed
359            | self::iframe
360            | self::img
361            | self::mathml::math
362            | self::object
363            | self::picture
364            | self::video
365    )
366}
367
368/// Whether an element is considered interactive content.
369pub fn is_interactive_content(tag: HtmlTag) -> bool {
370    matches!(
371        tag,
372        self::a
373            | self::audio
374            | self::button
375            | self::details
376            | self::embed
377            | self::iframe
378            | self::img
379            | self::input
380            | self::label
381            | self::select
382            | self::textarea
383            | self::video
384    )
385}
386
387/// Whether an element is considered palpable content.
388pub fn is_palpable_content(tag: HtmlTag) -> bool {
389    matches!(
390        tag,
391        self::a
392            | self::abbr
393            | self::address
394            | self::article
395            | self::aside
396            | self::audio
397            | self::b
398            | self::bdi
399            | self::bdo
400            | self::blockquote
401            | self::button
402            | self::canvas
403            | self::cite
404            | self::code
405            | self::data
406            | self::del
407            | self::details
408            | self::dfn
409            | self::div
410            | self::dl
411            | self::em
412            | self::embed
413            | self::fieldset
414            | self::figure
415            | self::footer
416            | self::form
417            | self::h1
418            | self::h2
419            | self::h3
420            | self::h4
421            | self::h5
422            | self::h6
423            | self::header
424            | self::hgroup
425            | self::i
426            | self::iframe
427            | self::img
428            | self::input
429            | self::ins
430            | self::kbd
431            | self::label
432            | self::main
433            | self::map
434            | self::mark
435            | self::mathml::math
436            | self::menu
437            | self::meter
438            | self::nav
439            | self::object
440            | self::ol
441            | self::output
442            | self::p
443            | self::picture
444            | self::pre
445            | self::progress
446            | self::q
447            | self::ruby
448            | self::s
449            | self::samp
450            | self::search
451            | self::section
452            | self::select
453            | self::small
454            | self::span
455            | self::strong
456            | self::sub
457            | self::sup
458            | self::table
459            | self::textarea
460            | self::time
461            | self::u
462            | self::ul
463            | self::var
464            | self::video
465    )
466}
467
468/// Whether an element is considered a script-supporting element.
469pub fn is_script_supporting_element(tag: HtmlTag) -> bool {
470    matches!(tag, self::script | self::template)
471}
472
473// § 15.4 Replaced elements
474
475/// Whether the element is considered a "replaced element".
476///
477/// See:
478/// - § 15.4 Replaced elements
479/// - <https://www.w3.org/TR/css-display-3/#replaced-element>
480pub fn is_replaced(tag: HtmlTag) -> bool {
481    matches!(
482        tag,
483        self::audio
484            | self::canvas
485            | self::embed
486            | self::iframe
487            | self::img
488            | self::input
489            | self::object
490            | self::video
491    )
492}
493
494// Non-standard sets.
495
496/// Whether HTML whitespace next to an element with this tag will be collapsed
497/// (assuming normal user agent styles).
498pub fn is_whitespace_collapsing(tag: HtmlTag) -> bool {
499    // TODO: Reconsider this check. What about e.g. tables?
500    property::Display::default_for(tag) == Some(property::Display::Block)
501        || tag == self::br
502}
503
504/// Whether we group this kind of HTML element into paragraphs _if_ paragraphs
505/// are forced in some way (either through being top-level or due to being in
506/// the same flow as a Typst-native `block` element or `parbreak`). When using
507/// solely the low-level HTML API, no paragraphs are ever forced.
508///
509/// The maximal set of tags we can choose here is HTML "phrasing content" as
510/// that is the content model of `<p>`. Most elements that are phrasing content
511/// are also reasonable to group into paragraphs. However, it's a bit more
512/// subtle:
513///
514/// - A few elements that are phrasing content are `display: none` through the
515///   user agent style sheet, e.g. `<script>`. These are called hidden content.
516///   It does not make sense to group them into paragraphs as they are not
517///   visible and also not really used in prose. We exclude those.
518///
519/// - A few elements that are phrasing content are actually kind of "generic".
520///   They can be used in paragraphs and may then also only contain phrasing
521///   content or they may be used directly in the block flow and then they may
522///   also include arbitrary flow content. This includes the `<a>`, `<ins>`,
523///   `<del>`, `<noscript>`, and `<map>` elements, which have a "transparent"
524///   content model.
525///
526///   It would make sense for these elements to group into paragraphs only if
527///   their contents themselves are fully groupable. This would require
528///   realizing their bodies to check what they contain, in a way that is not
529///   unlike measurement in layouting. We currently unconditionally group these
530///   elements, but we might want to do the smarter thing in the future.
531///
532///   There are a few more elements that have a "transparent" content model, but
533///   their contents are only used as fallback content. This includes `<video>`,
534///   `<audio>`, `<canvas>`, `<object>`, and `<slot>`. Sacrificing consistency
535///   of the multi-media elements with `<img>` to make their grouping behavior
536///   depend on their _fallback_ body seems not so useful.
537///
538/// Finally, note that we don't impose Typst's ideas about blockiness here. For
539/// example, `<img>` is included here even though Typst's `image` function is
540/// block-level by default. Instead the built-in `image` show rule wraps the
541/// produced `<img>` in a Typst `block`. With `box` and `block`, it's always
542/// possible to override the default defined by this function.
543pub fn should_group_into_pars(tag: HtmlTag) -> bool {
544    is_phrasing_content(tag)
545        && property::Display::default_for(tag) != Some(property::Display::None)
546}
547
548/// Elements in the MathML namespace.
549///
550/// Only the MathML Core elements at the moment.
551pub mod mathml {
552    use super::HtmlTag;
553
554    pub const annotation: HtmlTag = HtmlTag::constant("annotation");
555    pub const annotation_xml: HtmlTag = HtmlTag::constant("annotation-xml");
556    pub const maction: HtmlTag = HtmlTag::constant("maction");
557    pub const math: HtmlTag = HtmlTag::constant("math");
558    pub const merror: HtmlTag = HtmlTag::constant("merror");
559    pub const mfrac: HtmlTag = HtmlTag::constant("mfrac");
560    pub const mi: HtmlTag = HtmlTag::constant("mi");
561    pub const mmultiscripts: HtmlTag = HtmlTag::constant("mmultiscripts");
562    pub const mn: HtmlTag = HtmlTag::constant("mn");
563    pub const mo: HtmlTag = HtmlTag::constant("mo");
564    pub const mover: HtmlTag = HtmlTag::constant("mover");
565    pub const mpadded: HtmlTag = HtmlTag::constant("mpadded");
566    pub const mphantom: HtmlTag = HtmlTag::constant("mphantom");
567    pub const mprescripts: HtmlTag = HtmlTag::constant("mprescripts");
568    pub const mroot: HtmlTag = HtmlTag::constant("mroot");
569    pub const mrow: HtmlTag = HtmlTag::constant("mrow");
570    pub const ms: HtmlTag = HtmlTag::constant("ms");
571    pub const mspace: HtmlTag = HtmlTag::constant("mspace");
572    pub const msqrt: HtmlTag = HtmlTag::constant("msqrt");
573    pub const mstyle: HtmlTag = HtmlTag::constant("mstyle");
574    pub const msub: HtmlTag = HtmlTag::constant("msub");
575    pub const msubsup: HtmlTag = HtmlTag::constant("msubsup");
576    pub const msup: HtmlTag = HtmlTag::constant("msup");
577    pub const mtable: HtmlTag = HtmlTag::constant("mtable");
578    pub const mtd: HtmlTag = HtmlTag::constant("mtd");
579    pub const mtext: HtmlTag = HtmlTag::constant("mtext");
580    pub const mtr: HtmlTag = HtmlTag::constant("mtr");
581    pub const munder: HtmlTag = HtmlTag::constant("munder");
582    pub const munderover: HtmlTag = HtmlTag::constant("munderover");
583    pub const semantics: HtmlTag = HtmlTag::constant("semantics");
584
585    /// Whether this is a MathML token element.
586    pub fn is_token(tag: HtmlTag) -> bool {
587        matches!(
588            tag,
589            self::mtext | self::mi | self::mn | self::mo | self::mspace | self::ms
590        )
591    }
592
593    /// Whether this tag is an element in the MathML namespace.
594    pub fn is_mathml(tag: HtmlTag) -> bool {
595        matches!(
596            tag,
597            self::annotation
598                | self::annotation_xml
599                | self::maction
600                | self::math
601                | self::merror
602                | self::mfrac
603                | self::mi
604                | self::mmultiscripts
605                | self::mn
606                | self::mo
607                | self::mover
608                | self::mpadded
609                | self::mphantom
610                | self::mprescripts
611                | self::mroot
612                | self::mrow
613                | self::ms
614                | self::mspace
615                | self::msqrt
616                | self::mstyle
617                | self::msub
618                | self::msubsup
619                | self::msup
620                | self::mtable
621                | self::mtd
622                | self::mtext
623                | self::mtr
624                | self::munder
625                | self::munderover
626                | self::semantics
627        )
628    }
629}