@react-x11/components 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -4
- package/dist/charts/node.d.ts +11 -1
- package/dist/charts/node.d.ts.map +1 -1
- package/dist/charts/node.js +44 -14
- package/dist/charts/node.js.map +1 -1
- package/dist/charts/render.d.ts +12 -3
- package/dist/charts/render.d.ts.map +1 -1
- package/dist/charts/render.js +94 -25
- package/dist/charts/render.js.map +1 -1
- package/dist/code/index.d.ts.map +1 -1
- package/dist/code/index.js +27 -24
- package/dist/code/index.js.map +1 -1
- package/dist/code-editor/completion.d.ts.map +1 -1
- package/dist/code-editor/completion.js +3 -2
- package/dist/code-editor/completion.js.map +1 -1
- package/dist/code-editor/index.d.ts.map +1 -1
- package/dist/code-editor/index.js +19 -0
- package/dist/code-editor/index.js.map +1 -1
- package/dist/code-editor/node.d.ts +177 -7
- package/dist/code-editor/node.d.ts.map +1 -1
- package/dist/code-editor/node.js +1329 -164
- package/dist/code-editor/node.js.map +1 -1
- package/dist/code-language/index.d.ts +1 -1
- package/dist/code-language/index.d.ts.map +1 -1
- package/dist/code-language/index.js +1 -1
- package/dist/code-language/index.js.map +1 -1
- package/dist/code-language/languages/glsl.d.ts.map +1 -1
- package/dist/code-language/languages/glsl.js +10 -2
- package/dist/code-language/languages/glsl.js.map +1 -1
- package/dist/code-language/languages/javascript.d.ts.map +1 -1
- package/dist/code-language/languages/javascript.js +18 -3
- package/dist/code-language/languages/javascript.js.map +1 -1
- package/dist/code-language/languages/json.d.ts.map +1 -1
- package/dist/code-language/languages/json.js +10 -2
- package/dist/code-language/languages/json.js.map +1 -1
- package/dist/code-language/languages/shell.d.ts.map +1 -1
- package/dist/code-language/languages/shell.js +10 -2
- package/dist/code-language/languages/shell.js.map +1 -1
- package/dist/code-language/languages/sql.d.ts.map +1 -1
- package/dist/code-language/languages/sql.js +20 -2
- package/dist/code-language/languages/sql.js.map +1 -1
- package/dist/code-language/runs.d.ts +31 -0
- package/dist/code-language/runs.d.ts.map +1 -1
- package/dist/code-language/runs.js +105 -0
- package/dist/code-language/runs.js.map +1 -1
- package/dist/code-language/stream.d.ts +22 -0
- package/dist/code-language/stream.d.ts.map +1 -1
- package/dist/code-language/stream.js +259 -9
- package/dist/code-language/stream.js.map +1 -1
- package/dist/code-language/types.d.ts +5 -4
- package/dist/code-language/types.d.ts.map +1 -1
- package/dist/codeblock/index.d.ts +26 -2
- package/dist/codeblock/index.d.ts.map +1 -1
- package/dist/codeblock/index.js +57 -4
- package/dist/codeblock/index.js.map +1 -1
- package/dist/flow/draw.d.ts +50 -0
- package/dist/flow/draw.d.ts.map +1 -1
- package/dist/flow/draw.js +132 -33
- package/dist/flow/draw.js.map +1 -1
- package/dist/flow/gl/color.d.ts +13 -0
- package/dist/flow/gl/color.d.ts.map +1 -0
- package/dist/flow/gl/color.js +82 -0
- package/dist/flow/gl/color.js.map +1 -0
- package/dist/flow/gl/index.d.ts +60 -0
- package/dist/flow/gl/index.d.ts.map +1 -0
- package/dist/flow/gl/index.js +283 -0
- package/dist/flow/gl/index.js.map +1 -0
- package/dist/flow/gl/pack.d.ts +133 -0
- package/dist/flow/gl/pack.d.ts.map +1 -0
- package/dist/flow/gl/pack.js +408 -0
- package/dist/flow/gl/pack.js.map +1 -0
- package/dist/flow/gl/renderer.d.ts +95 -0
- package/dist/flow/gl/renderer.d.ts.map +1 -0
- package/dist/flow/gl/renderer.js +459 -0
- package/dist/flow/gl/renderer.js.map +1 -0
- package/dist/flow/gl/shaders.d.ts +79 -0
- package/dist/flow/gl/shaders.d.ts.map +1 -0
- package/dist/flow/gl/shaders.js +346 -0
- package/dist/flow/gl/shaders.js.map +1 -0
- package/dist/flow/gl/text.d.ts +318 -0
- package/dist/flow/gl/text.d.ts.map +1 -0
- package/dist/flow/gl/text.js +1103 -0
- package/dist/flow/gl/text.js.map +1 -0
- package/dist/flow/index.d.ts +1 -1
- package/dist/flow/index.d.ts.map +1 -1
- package/dist/flow/index.js +619 -64
- package/dist/flow/index.js.map +1 -1
- package/dist/flow/node.d.ts +621 -72
- package/dist/flow/node.d.ts.map +1 -1
- package/dist/flow/node.js +2253 -1018
- package/dist/flow/node.js.map +1 -1
- package/dist/flow/paint.d.ts +35 -0
- package/dist/flow/paint.d.ts.map +1 -0
- package/dist/flow/paint.js +393 -0
- package/dist/flow/paint.js.map +1 -0
- package/dist/flow/paths.d.ts +14 -0
- package/dist/flow/paths.d.ts.map +1 -1
- package/dist/flow/paths.js +45 -19
- package/dist/flow/paths.js.map +1 -1
- package/dist/flow/scene.d.ts +584 -0
- package/dist/flow/scene.d.ts.map +1 -0
- package/dist/flow/scene.js +1453 -0
- package/dist/flow/scene.js.map +1 -0
- package/dist/flow/types.d.ts +111 -1
- package/dist/flow/types.d.ts.map +1 -1
- package/dist/html/controls.d.ts +28 -0
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js +52 -2
- package/dist/html/controls.js.map +1 -1
- package/dist/html/css/calc.d.ts +14 -0
- package/dist/html/css/calc.d.ts.map +1 -0
- package/dist/html/css/calc.js +344 -0
- package/dist/html/css/calc.js.map +1 -0
- package/dist/html/css/cascade.d.ts +262 -6
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +1373 -67
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/color.d.ts +23 -0
- package/dist/html/css/color.d.ts.map +1 -0
- package/dist/html/css/color.js +740 -0
- package/dist/html/css/color.js.map +1 -0
- package/dist/html/css/content.d.ts +92 -0
- package/dist/html/css/content.d.ts.map +1 -0
- package/dist/html/css/content.js +388 -0
- package/dist/html/css/content.js.map +1 -0
- package/dist/html/css/counter-styles.d.ts +76 -0
- package/dist/html/css/counter-styles.d.ts.map +1 -0
- package/dist/html/css/counter-styles.js +893 -0
- package/dist/html/css/counter-styles.js.map +1 -0
- package/dist/html/css/decode.d.ts +12 -0
- package/dist/html/css/decode.d.ts.map +1 -0
- package/dist/html/css/decode.js +116 -0
- package/dist/html/css/decode.js.map +1 -0
- package/dist/html/css/parse.d.ts +110 -10
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +1473 -180
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/style.d.ts +501 -15
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +3729 -206
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/ua.d.ts.map +1 -1
- package/dist/html/css/ua.js +65 -16
- package/dist/html/css/ua.js.map +1 -1
- package/dist/html/css/values.d.ts +37 -3
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js +122 -48
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/css/vars.d.ts +52 -0
- package/dist/html/css/vars.d.ts.map +1 -0
- package/dist/html/css/vars.js +358 -0
- package/dist/html/css/vars.js.map +1 -0
- package/dist/html/dom.d.ts +30 -4
- package/dist/html/dom.d.ts.map +1 -1
- package/dist/html/dom.js +278 -17
- package/dist/html/dom.js.map +1 -1
- package/dist/html/fonts.d.ts +106 -0
- package/dist/html/fonts.d.ts.map +1 -0
- package/dist/html/fonts.js +565 -0
- package/dist/html/fonts.js.map +1 -0
- package/dist/html/gif.d.ts +15 -0
- package/dist/html/gif.d.ts.map +1 -0
- package/dist/html/gif.js +229 -0
- package/dist/html/gif.js.map +1 -0
- package/dist/html/index.d.ts +50 -11
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +115 -9
- package/dist/html/index.js.map +1 -1
- package/dist/html/layout/block.d.ts +226 -3
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +3077 -219
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +367 -17
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +1742 -182
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/cache.d.ts +58 -0
- package/dist/html/layout/cache.d.ts.map +1 -0
- package/dist/html/layout/cache.js +224 -0
- package/dist/html/layout/cache.js.map +1 -0
- package/dist/html/layout/collapse.d.ts +45 -0
- package/dist/html/layout/collapse.d.ts.map +1 -0
- package/dist/html/layout/collapse.js +246 -0
- package/dist/html/layout/collapse.js.map +1 -0
- package/dist/html/layout/css-grid.d.ts +7 -0
- package/dist/html/layout/css-grid.d.ts.map +1 -0
- package/dist/html/layout/css-grid.js +900 -0
- package/dist/html/layout/css-grid.js.map +1 -0
- package/dist/html/layout/flex.d.ts.map +1 -1
- package/dist/html/layout/flex.js +1025 -89
- package/dist/html/layout/flex.js.map +1 -1
- package/dist/html/layout/floats.d.ts +45 -6
- package/dist/html/layout/floats.d.ts.map +1 -1
- package/dist/html/layout/floats.js +113 -14
- package/dist/html/layout/floats.js.map +1 -1
- package/dist/html/layout/grid-lines.d.ts +39 -0
- package/dist/html/layout/grid-lines.d.ts.map +1 -0
- package/dist/html/layout/grid-lines.js +119 -0
- package/dist/html/layout/grid-lines.js.map +1 -0
- package/dist/html/layout/grid.d.ts +53 -0
- package/dist/html/layout/grid.d.ts.map +1 -0
- package/dist/html/layout/grid.js +153 -0
- package/dist/html/layout/grid.js.map +1 -0
- package/dist/html/layout/inline.d.ts +154 -1
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +3598 -175
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/layout/shaping.d.ts +6 -0
- package/dist/html/layout/shaping.d.ts.map +1 -0
- package/dist/html/layout/shaping.js +100 -0
- package/dist/html/layout/shaping.js.map +1 -0
- package/dist/html/layout/table.d.ts +3 -0
- package/dist/html/layout/table.d.ts.map +1 -1
- package/dist/html/layout/table.js +681 -175
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/layout/tracks.d.ts +44 -0
- package/dist/html/layout/tracks.d.ts.map +1 -0
- package/dist/html/layout/tracks.js +349 -0
- package/dist/html/layout/tracks.js.map +1 -0
- package/dist/html/node.d.ts +169 -4
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +1429 -137
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +92 -3
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +3635 -107
- package/dist/html/paint.js.map +1 -1
- package/dist/html/resources.d.ts +60 -14
- package/dist/html/resources.d.ts.map +1 -1
- package/dist/html/resources.js +122 -36
- package/dist/html/resources.js.map +1 -1
- package/dist/html/surfaces.d.ts +23 -0
- package/dist/html/surfaces.d.ts.map +1 -0
- package/dist/html/surfaces.js +68 -0
- package/dist/html/surfaces.js.map +1 -0
- package/dist/html/svg.d.ts +80 -0
- package/dist/html/svg.d.ts.map +1 -0
- package/dist/html/svg.js +442 -0
- package/dist/html/svg.js.map +1 -0
- package/dist/html/url.d.ts +23 -0
- package/dist/html/url.d.ts.map +1 -0
- package/dist/html/url.js +80 -0
- package/dist/html/url.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/codelines.d.ts +42 -0
- package/dist/internal/codelines.d.ts.map +1 -0
- package/dist/internal/codelines.js +170 -0
- package/dist/internal/codelines.js.map +1 -0
- package/dist/internal/collate.d.ts +3 -0
- package/dist/internal/collate.d.ts.map +1 -0
- package/dist/internal/collate.js +11 -0
- package/dist/internal/collate.js.map +1 -0
- package/dist/internal/markdown/ast.d.ts +11 -0
- package/dist/internal/markdown/ast.d.ts.map +1 -1
- package/dist/internal/markdown/parse.d.ts.map +1 -1
- package/dist/internal/markdown/parse.js +109 -8
- package/dist/internal/markdown/parse.js.map +1 -1
- package/dist/internal/prewarm.d.ts +18 -0
- package/dist/internal/prewarm.d.ts.map +1 -0
- package/dist/internal/prewarm.js +42 -0
- package/dist/internal/prewarm.js.map +1 -0
- package/dist/internal/sdf.d.ts +20 -0
- package/dist/internal/sdf.d.ts.map +1 -0
- package/dist/internal/sdf.js +216 -0
- package/dist/internal/sdf.js.map +1 -0
- package/dist/internal/splice.d.ts +12 -0
- package/dist/internal/splice.d.ts.map +1 -0
- package/dist/internal/splice.js +23 -0
- package/dist/internal/splice.js.map +1 -0
- package/dist/internal/window.d.ts +12 -0
- package/dist/internal/window.d.ts.map +1 -1
- package/dist/internal/window.js +23 -6
- package/dist/internal/window.js.map +1 -1
- package/dist/maps/anchors.d.ts +6 -1
- package/dist/maps/anchors.d.ts.map +1 -1
- package/dist/maps/anchors.js +260 -1
- package/dist/maps/anchors.js.map +1 -1
- package/dist/maps/controller.d.ts +57 -0
- package/dist/maps/controller.d.ts.map +1 -1
- package/dist/maps/controller.js +97 -18
- package/dist/maps/controller.js.map +1 -1
- package/dist/maps/gl/buckets.d.ts +5 -1
- package/dist/maps/gl/buckets.d.ts.map +1 -1
- package/dist/maps/gl/buckets.js +5 -2
- package/dist/maps/gl/buckets.js.map +1 -1
- package/dist/maps/gl/build-worker.d.ts +2 -0
- package/dist/maps/gl/build-worker.d.ts.map +1 -1
- package/dist/maps/gl/build-worker.js +1 -1
- package/dist/maps/gl/build-worker.js.map +1 -1
- package/dist/maps/gl/cover.d.ts +23 -4
- package/dist/maps/gl/cover.d.ts.map +1 -1
- package/dist/maps/gl/cover.js +61 -48
- package/dist/maps/gl/cover.js.map +1 -1
- package/dist/maps/gl/placement.d.ts +21 -8
- package/dist/maps/gl/placement.d.ts.map +1 -1
- package/dist/maps/gl/placement.js +133 -58
- package/dist/maps/gl/placement.js.map +1 -1
- package/dist/maps/gl/renderer.d.ts +36 -4
- package/dist/maps/gl/renderer.d.ts.map +1 -1
- package/dist/maps/gl/renderer.js +81 -24
- package/dist/maps/gl/renderer.js.map +1 -1
- package/dist/maps/gl/shaders.d.ts +18 -17
- package/dist/maps/gl/shaders.d.ts.map +1 -1
- package/dist/maps/gl/shaders.js +34 -32
- package/dist/maps/gl/shaders.js.map +1 -1
- package/dist/maps/gl/store.d.ts +10 -0
- package/dist/maps/gl/store.d.ts.map +1 -1
- package/dist/maps/gl/store.js +47 -4
- package/dist/maps/gl/store.js.map +1 -1
- package/dist/maps/gl/text.d.ts +153 -24
- package/dist/maps/gl/text.d.ts.map +1 -1
- package/dist/maps/gl/text.js +379 -63
- package/dist/maps/gl/text.js.map +1 -1
- package/dist/maps/gl/view.d.ts +293 -2
- package/dist/maps/gl/view.d.ts.map +1 -1
- package/dist/maps/gl/view.js +317 -82
- package/dist/maps/gl/view.js.map +1 -1
- package/dist/maps/icons.d.ts +32 -0
- package/dist/maps/icons.d.ts.map +1 -0
- package/dist/maps/icons.js +151 -0
- package/dist/maps/icons.js.map +1 -0
- package/dist/maps/index.d.ts +2 -0
- package/dist/maps/index.d.ts.map +1 -1
- package/dist/maps/index.js +2 -0
- package/dist/maps/index.js.map +1 -1
- package/dist/maps/labels.d.ts +56 -4
- package/dist/maps/labels.d.ts.map +1 -1
- package/dist/maps/labels.js +213 -46
- package/dist/maps/labels.js.map +1 -1
- package/dist/maps/node.d.ts +17 -0
- package/dist/maps/node.d.ts.map +1 -1
- package/dist/maps/node.js +64 -30
- package/dist/maps/node.js.map +1 -1
- package/dist/maps/proj.d.ts +48 -0
- package/dist/maps/proj.d.ts.map +1 -1
- package/dist/maps/proj.js +73 -0
- package/dist/maps/proj.js.map +1 -1
- package/dist/maps/sources.d.ts +5 -3
- package/dist/maps/sources.d.ts.map +1 -1
- package/dist/maps/sources.js +5 -3
- package/dist/maps/sources.js.map +1 -1
- package/dist/maps/style.d.ts +35 -0
- package/dist/maps/style.d.ts.map +1 -1
- package/dist/maps/style.js.map +1 -1
- package/dist/maps/styles.d.ts +12 -0
- package/dist/maps/styles.d.ts.map +1 -1
- package/dist/maps/styles.js +120 -6
- package/dist/maps/styles.js.map +1 -1
- package/dist/maps/tiles.d.ts +31 -11
- package/dist/maps/tiles.d.ts.map +1 -1
- package/dist/maps/tiles.js +61 -27
- package/dist/maps/tiles.js.map +1 -1
- package/dist/maps/types.d.ts +28 -4
- package/dist/maps/types.d.ts.map +1 -1
- package/dist/markdown/index.d.ts.map +1 -1
- package/dist/markdown/index.js +209 -68
- package/dist/markdown/index.js.map +1 -1
- package/dist/markdown/spans.d.ts.map +1 -1
- package/dist/markdown/spans.js +6 -0
- package/dist/markdown/spans.js.map +1 -1
- package/dist/qml/containers.d.ts.map +1 -1
- package/dist/qml/containers.js +6 -1
- package/dist/qml/containers.js.map +1 -1
- package/dist/qml/interaction.d.ts.map +1 -1
- package/dist/qml/interaction.js +38 -5
- package/dist/qml/interaction.js.map +1 -1
- package/dist/qml/layouts.d.ts.map +1 -1
- package/dist/qml/layouts.js +21 -6
- package/dist/qml/layouts.js.map +1 -1
- package/dist/qml/qtquick.d.ts.map +1 -1
- package/dist/qml/qtquick.js +9 -2
- package/dist/qml/qtquick.js.map +1 -1
- package/dist/qml/react.d.ts.map +1 -1
- package/dist/qml/react.js +9 -7
- package/dist/qml/react.js.map +1 -1
- package/dist/reorder/clock.d.ts +7 -0
- package/dist/reorder/clock.d.ts.map +1 -0
- package/dist/reorder/clock.js +26 -0
- package/dist/reorder/clock.js.map +1 -0
- package/dist/reorder/index.d.ts +25 -3
- package/dist/reorder/index.d.ts.map +1 -1
- package/dist/reorder/index.js +64 -19
- package/dist/reorder/index.js.map +1 -1
- package/dist/rich-text-editor/index.d.ts +0 -11
- package/dist/rich-text-editor/index.d.ts.map +1 -1
- package/dist/rich-text-editor/index.js +38 -9
- package/dist/rich-text-editor/index.js.map +1 -1
- package/dist/rich-text-editor/keymap.d.ts.map +1 -1
- package/dist/rich-text-editor/keymap.js +2 -1
- package/dist/rich-text-editor/keymap.js.map +1 -1
- package/dist/rich-text-editor/keys.d.ts +17 -6
- package/dist/rich-text-editor/keys.d.ts.map +1 -1
- package/dist/rich-text-editor/keys.js +135 -26
- package/dist/rich-text-editor/keys.js.map +1 -1
- package/dist/rich-text-editor/markdown.d.ts.map +1 -1
- package/dist/rich-text-editor/markdown.js +30 -1
- package/dist/rich-text-editor/markdown.js.map +1 -1
- package/dist/rich-text-editor/marks.d.ts +9 -0
- package/dist/rich-text-editor/marks.d.ts.map +1 -0
- package/dist/rich-text-editor/marks.js +83 -0
- package/dist/rich-text-editor/marks.js.map +1 -0
- package/dist/rich-text-editor/render.d.ts.map +1 -1
- package/dist/rich-text-editor/render.js +28 -10
- package/dist/rich-text-editor/render.js.map +1 -1
- package/dist/rich-text-editor/replace.d.ts +13 -0
- package/dist/rich-text-editor/replace.d.ts.map +1 -0
- package/dist/rich-text-editor/replace.js +64 -0
- package/dist/rich-text-editor/replace.js.map +1 -0
- package/dist/rich-text-editor/toolbar.d.ts.map +1 -1
- package/dist/rich-text-editor/toolbar.js +1 -1
- package/dist/rich-text-editor/toolbar.js.map +1 -1
- package/dist/rich-text-editor/virtual.d.ts.map +1 -1
- package/dist/rich-text-editor/virtual.js +17 -0
- package/dist/rich-text-editor/virtual.js.map +1 -1
- package/dist/richtext/node.d.ts +46 -2
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +187 -4
- package/dist/richtext/node.js.map +1 -1
- package/dist/richtext/runs.d.ts +13 -8
- package/dist/richtext/runs.d.ts.map +1 -1
- package/dist/richtext/runs.js +18 -8
- package/dist/richtext/runs.js.map +1 -1
- package/dist/table/index.d.ts.map +1 -1
- package/dist/table/index.js +23 -0
- package/dist/table/index.js.map +1 -1
- package/dist/table/rows.d.ts +3 -2
- package/dist/table/rows.d.ts.map +1 -1
- package/dist/table/rows.js +20 -6
- package/dist/table/rows.js.map +1 -1
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +4 -0
- package/dist/terminal/index.js.map +1 -1
- package/dist/terminal/vt/pty.d.ts +13 -2
- package/dist/terminal/vt/pty.d.ts.map +1 -1
- package/dist/terminal/vt/pty.js +18 -3
- package/dist/terminal/vt/pty.js.map +1 -1
- package/dist/terminal-output/index.d.ts.map +1 -1
- package/dist/terminal-output/index.js +103 -23
- package/dist/terminal-output/index.js.map +1 -1
- package/dist/terminal-output/runs.d.ts +4 -1
- package/dist/terminal-output/runs.d.ts.map +1 -1
- package/dist/terminal-output/runs.js +5 -1
- package/dist/terminal-output/runs.js.map +1 -1
- package/dist/three/canvas.d.ts.map +1 -1
- package/dist/three/canvas.js +85 -7
- package/dist/three/canvas.js.map +1 -1
- package/dist/three/events.d.ts +22 -4
- package/dist/three/events.d.ts.map +1 -1
- package/dist/three/events.js +34 -4
- package/dist/three/events.js.map +1 -1
- package/dist/tree/index.d.ts.map +1 -1
- package/dist/tree/index.js +17 -0
- package/dist/tree/index.js.map +1 -1
- package/package.json +42 -33
- package/src/charts/node.ts +62 -26
- package/src/charts/render.ts +120 -30
- package/src/code/index.ts +36 -32
- package/src/code-editor/completion.ts +3 -2
- package/src/code-editor/index.ts +19 -0
- package/src/code-editor/node.ts +1574 -184
- package/src/code-language/index.ts +1 -1
- package/src/code-language/languages/glsl.ts +12 -2
- package/src/code-language/languages/javascript.ts +21 -4
- package/src/code-language/languages/json.ts +12 -2
- package/src/code-language/languages/shell.ts +12 -2
- package/src/code-language/languages/sql.ts +22 -2
- package/src/code-language/runs.ts +111 -1
- package/src/code-language/stream.ts +257 -17
- package/src/code-language/types.ts +5 -4
- package/src/codeblock/index.ts +68 -4
- package/src/flow/draw.ts +167 -41
- package/src/flow/gl/color.ts +85 -0
- package/src/flow/gl/index.ts +342 -0
- package/src/flow/gl/pack.ts +585 -0
- package/src/flow/gl/renderer.ts +679 -0
- package/src/flow/gl/shaders.ts +371 -0
- package/src/flow/gl/text.ts +1295 -0
- package/src/flow/index.ts +794 -67
- package/src/flow/node.ts +2496 -1256
- package/src/flow/paint.ts +511 -0
- package/src/flow/paths.ts +80 -15
- package/src/flow/scene.ts +2199 -0
- package/src/flow/types.ts +113 -1
- package/src/html/controls.ts +73 -2
- package/src/html/css/calc.ts +385 -0
- package/src/html/css/cascade.ts +1481 -62
- package/src/html/css/color.ts +755 -0
- package/src/html/css/content.ts +417 -0
- package/src/html/css/counter-styles.ts +973 -0
- package/src/html/css/decode.ts +130 -0
- package/src/html/css/parse.ts +1514 -160
- package/src/html/css/style.ts +4131 -223
- package/src/html/css/ua.ts +66 -17
- package/src/html/css/values.ts +150 -50
- package/src/html/css/vars.ts +348 -0
- package/src/html/dom.ts +284 -17
- package/src/html/fonts.ts +641 -0
- package/src/html/gif.ts +233 -0
- package/src/html/index.ts +180 -20
- package/src/html/layout/block.ts +3560 -208
- package/src/html/layout/boxes.ts +2141 -190
- package/src/html/layout/cache.ts +289 -0
- package/src/html/layout/collapse.ts +317 -0
- package/src/html/layout/css-grid.ts +1063 -0
- package/src/html/layout/flex.ts +1115 -106
- package/src/html/layout/floats.ts +128 -14
- package/src/html/layout/grid-lines.ts +141 -0
- package/src/html/layout/grid.ts +181 -0
- package/src/html/layout/inline.ts +4187 -192
- package/src/html/layout/shaping.ts +140 -0
- package/src/html/layout/table.ts +696 -186
- package/src/html/layout/tracks.ts +437 -0
- package/src/html/node.ts +1585 -156
- package/src/html/paint.ts +4582 -267
- package/src/html/resources.ts +161 -50
- package/src/html/surfaces.ts +81 -0
- package/src/html/svg.ts +504 -0
- package/src/html/url.ts +86 -0
- package/src/index.ts +2 -0
- package/src/internal/codelines.ts +200 -0
- package/src/internal/collate.ts +12 -0
- package/src/internal/markdown/ast.ts +11 -0
- package/src/internal/markdown/parse.ts +154 -11
- package/src/internal/prewarm.ts +45 -0
- package/src/internal/sdf.ts +227 -0
- package/src/internal/splice.ts +25 -0
- package/src/internal/window.ts +36 -5
- package/src/maps/anchors.ts +307 -1
- package/src/maps/controller.ts +116 -31
- package/src/maps/gl/buckets.ts +5 -1
- package/src/maps/gl/build-worker.ts +13 -2
- package/src/maps/gl/cover.ts +79 -44
- package/src/maps/gl/placement.ts +221 -69
- package/src/maps/gl/renderer.ts +104 -20
- package/src/maps/gl/shaders.ts +35 -32
- package/src/maps/gl/store.ts +66 -17
- package/src/maps/gl/text.ts +444 -71
- package/src/maps/gl/view.ts +361 -96
- package/src/maps/icons.ts +183 -0
- package/src/maps/index.ts +4 -0
- package/src/maps/labels.ts +269 -49
- package/src/maps/node.ts +82 -49
- package/src/maps/proj.ts +87 -0
- package/src/maps/sources.ts +5 -3
- package/src/maps/style.ts +32 -0
- package/src/maps/styles.ts +215 -4
- package/src/maps/tiles.ts +64 -31
- package/src/maps/types.ts +28 -4
- package/src/markdown/index.ts +293 -92
- package/src/markdown/spans.ts +5 -0
- package/src/qml/containers.tsx +6 -1
- package/src/qml/interaction.tsx +42 -5
- package/src/qml/layouts.tsx +21 -6
- package/src/qml/qtquick.tsx +9 -2
- package/src/qml/react.tsx +7 -5
- package/src/reorder/clock.ts +27 -0
- package/src/reorder/index.ts +100 -27
- package/src/rich-text-editor/index.ts +37 -12
- package/src/rich-text-editor/keymap.ts +1 -1
- package/src/rich-text-editor/keys.ts +135 -26
- package/src/rich-text-editor/markdown.ts +36 -1
- package/src/rich-text-editor/marks.ts +101 -0
- package/src/rich-text-editor/render.ts +49 -12
- package/src/rich-text-editor/replace.ts +85 -0
- package/src/rich-text-editor/toolbar.ts +1 -1
- package/src/rich-text-editor/virtual.ts +25 -0
- package/src/richtext/node.ts +235 -14
- package/src/richtext/runs.ts +23 -12
- package/src/table/index.ts +29 -0
- package/src/table/rows.ts +18 -8
- package/src/terminal/index.ts +4 -0
- package/src/terminal/vt/pty.ts +16 -2
- package/src/terminal-output/index.ts +129 -31
- package/src/terminal-output/runs.ts +16 -2
- package/src/three/canvas.ts +102 -8
- package/src/three/events.ts +49 -9
- package/src/tree/index.ts +19 -0
package/dist/html/css/cascade.js
CHANGED
|
@@ -19,9 +19,12 @@ import { compile } from 'css-select';
|
|
|
19
19
|
import * as DomUtils from 'domutils';
|
|
20
20
|
import { Element as DomElement, isTag } from 'domhandler';
|
|
21
21
|
import { attr, tagOf } from '../dom.js';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
22
|
+
import { svgSizeHint } from '../svg.js';
|
|
23
|
+
import { asciiLower, escapeEnd, mediaMatches, readIdent, startsIdent, } from './parse.js';
|
|
24
|
+
import { applyDeclaration, blockify, settleContentVisibility, settleOverflow, settleClamp, copyStyle, decorate, inherit, initialOne, initialStyle, isInherited, } from './style.js';
|
|
24
25
|
import { parseDeclarations } from './parse.js';
|
|
26
|
+
import { CounterStyles, counterStyleRule } from './counter-styles.js';
|
|
27
|
+
import { customProperties, substituteIn } from './vars.js';
|
|
25
28
|
/** Where a declaration came from. Higher wins before specificity is asked. */
|
|
26
29
|
var Origin;
|
|
27
30
|
(function (Origin) {
|
|
@@ -32,6 +35,20 @@ var Origin;
|
|
|
32
35
|
Origin[Origin["AuthorImportant"] = 4] = "AuthorImportant";
|
|
33
36
|
Origin[Origin["InlineImportant"] = 5] = "InlineImportant";
|
|
34
37
|
})(Origin || (Origin = {}));
|
|
38
|
+
/**
|
|
39
|
+
* What makes a selector's match depend on more than the element's own tag and
|
|
40
|
+
* attributes and its ancestors' — its siblings, where it sits among them,
|
|
41
|
+
* what it contains, or where the document is scrolled to. Two elements that
|
|
42
|
+
* look alike from the root down can still differ under a rule with one of
|
|
43
|
+
* these, so an element such a rule could reach does not share its style
|
|
44
|
+
* (`Cascade.sharedStyleFor`). css-select spells some of them under other
|
|
45
|
+
* names, and those count too: `:checked` and `:selected` read which option
|
|
46
|
+
* comes first, `:disabled` and `:enabled` which legend does, and `:parent`
|
|
47
|
+
* and `:contains()` the element's contents. Over-broad on purpose: a `+` or
|
|
48
|
+
* `~` inside an attribute value, or the `~=` operator, costs sharing and
|
|
49
|
+
* nothing else.
|
|
50
|
+
*/
|
|
51
|
+
const UNSHAREABLE = /[+~]|:(?:first|last|only)-(?:child|of-type)|:nth-|:empty|:blank|:has\(|:focus-within|:target|:scope|:(?:checked|selected|disabled|enabled|parent)\b|:i?contains\(/;
|
|
35
52
|
/**
|
|
36
53
|
* Rules bucketed by the key of their rightmost compound selector. An element
|
|
37
54
|
* only ever tries `id`, its classes, its tag and the universal bucket.
|
|
@@ -44,12 +61,64 @@ class RuleIndex {
|
|
|
44
61
|
/** Whether any rule in here is pointer-sensitive, so the renderer knows
|
|
45
62
|
* whether a pointer move can change the cascade at all. */
|
|
46
63
|
hoverSensitive = false;
|
|
64
|
+
/** The buckets holding a rule an element cannot share its style under
|
|
65
|
+
* (`UNSHAREABLE`): the ids, classes and tags whose elements compute
|
|
66
|
+
* their own, and whether the universal bucket makes every element do so. */
|
|
67
|
+
ownStyleIds = new Set();
|
|
68
|
+
ownStyleClasses = new Set();
|
|
69
|
+
ownStyleTags = new Set();
|
|
70
|
+
ownStyleEverywhere = false;
|
|
71
|
+
/** How many rules are in here, so an empty index costs one comparison. */
|
|
72
|
+
size = 0;
|
|
73
|
+
_nextId = 0;
|
|
74
|
+
/**
|
|
75
|
+
* Whether a bucket here could hold a rule for `el`, by its tag, id and
|
|
76
|
+
* classes and without matching anything: an index of a rule or two is
|
|
77
|
+
* asked of every element — the user-agent sheet's `q::before` and
|
|
78
|
+
* `q::after` made every element of a document split its `class` twice —
|
|
79
|
+
* and almost none of them has a rule in it.
|
|
80
|
+
*/
|
|
81
|
+
reaches(el) {
|
|
82
|
+
if (this.universal.length || this.byTag.has(tagOf(el)))
|
|
83
|
+
return true;
|
|
84
|
+
if (this.byId.size) {
|
|
85
|
+
const id = attr(el, 'id');
|
|
86
|
+
if (id && this.byId.has(id))
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
if (this.byClass.size) {
|
|
90
|
+
const className = attr(el, 'class');
|
|
91
|
+
if (className) {
|
|
92
|
+
for (const name of className.split(/\s+/)) {
|
|
93
|
+
if (name && this.byClass.has(name))
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
47
100
|
add(rule) {
|
|
48
|
-
|
|
101
|
+
this.size += 1;
|
|
102
|
+
const indexed = {
|
|
103
|
+
rule,
|
|
104
|
+
match: null,
|
|
105
|
+
compiled: false,
|
|
106
|
+
id: this._nextId++,
|
|
107
|
+
};
|
|
49
108
|
if (rule.selector.includes(':hover') || rule.selector.includes(':active')) {
|
|
50
109
|
this.hoverSensitive = true;
|
|
51
110
|
}
|
|
52
111
|
const key = rightmostKey(rule.selector);
|
|
112
|
+
if (UNSHAREABLE.test(rule.selector)) {
|
|
113
|
+
if (key.kind === 'id')
|
|
114
|
+
this.ownStyleIds.add(key.name);
|
|
115
|
+
else if (key.kind === 'class')
|
|
116
|
+
this.ownStyleClasses.add(key.name);
|
|
117
|
+
else if (key.kind === 'tag')
|
|
118
|
+
this.ownStyleTags.add(key.name);
|
|
119
|
+
else
|
|
120
|
+
this.ownStyleEverywhere = true;
|
|
121
|
+
}
|
|
53
122
|
const bucket = key.kind === 'id'
|
|
54
123
|
? mapBucket(this.byId, key.name)
|
|
55
124
|
: key.kind === 'class'
|
|
@@ -60,6 +129,200 @@ class RuleIndex {
|
|
|
60
129
|
bucket.push(indexed);
|
|
61
130
|
}
|
|
62
131
|
}
|
|
132
|
+
/** A selector's trailing `::before`, `::after`, `::first-letter`,
|
|
133
|
+
* `::first-line` or `::marker`, or CSS 2's single-colon spelling of any of
|
|
134
|
+
* its four. */
|
|
135
|
+
const PSEUDO_ELEMENT = /::?(before|after|first-letter|first-line)$|::marker$/i;
|
|
136
|
+
/**
|
|
137
|
+
* A rule for a pseudo-element, as the pseudo-element it styles and a rule
|
|
138
|
+
* for the element it hangs off, which is what gets matched. The specificity
|
|
139
|
+
* is the whole selector's, the pseudo-element counted in. `p::before`
|
|
140
|
+
* matches `p`; `p ::before` and `p > ::before` have nothing left of their
|
|
141
|
+
* last compound and match any child, `p *` and `p > *`.
|
|
142
|
+
*/
|
|
143
|
+
function splitPseudoElement(rule) {
|
|
144
|
+
const m = PSEUDO_ELEMENT.exec(rule.selector);
|
|
145
|
+
if (!m)
|
|
146
|
+
return null;
|
|
147
|
+
const head = rule.selector.slice(0, m.index);
|
|
148
|
+
const trimmed = head.trimEnd();
|
|
149
|
+
const selector = !trimmed
|
|
150
|
+
? '*'
|
|
151
|
+
: head !== trimmed || /[>+~]$/.test(trimmed)
|
|
152
|
+
? `${trimmed} *`
|
|
153
|
+
: trimmed;
|
|
154
|
+
return {
|
|
155
|
+
which: (m[1] ?? 'marker').toLowerCase(),
|
|
156
|
+
rule: { ...rule, selector },
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The compounds of a selector that test `:hover`, each without it (and
|
|
161
|
+
* without an `:active` beside it), and whether one is followed by a sibling
|
|
162
|
+
* combinator, which reaches the element's later siblings. `nested` where a
|
|
163
|
+
* `:hover` sits inside a functional pseudo-class — `:not(:hover)`,
|
|
164
|
+
* `:is(:hover)` — and reaches elements no compound names.
|
|
165
|
+
*
|
|
166
|
+
* A `:hover` in a compound's `:has()` is the one exception, since what it
|
|
167
|
+
* reaches is known: the compound, without its `:has()`, is an ancestor of
|
|
168
|
+
* the element the pointer is over — or an earlier sibling of it or of an
|
|
169
|
+
* ancestor, where the argument starts at a sibling (Selectors 4, 4.5). So
|
|
170
|
+
* it is given as an anchor (`has`) rather than making the rule `nested`.
|
|
171
|
+
*
|
|
172
|
+
* `:active` is not the pointer's here: nothing sets it (`setPointer` is
|
|
173
|
+
* handed none), so a selector that tests only it never changes as the
|
|
174
|
+
* pointer moves — Wikipedia's buttons' `:focus:not(:active)` among them.
|
|
175
|
+
* A press that sets it would have to be counted here too.
|
|
176
|
+
*/
|
|
177
|
+
export function pointerCompounds(selector) {
|
|
178
|
+
const out = {
|
|
179
|
+
compounds: [],
|
|
180
|
+
siblings: false,
|
|
181
|
+
nested: false,
|
|
182
|
+
has: [],
|
|
183
|
+
};
|
|
184
|
+
// the compounds at the top level, each with the combinator after it
|
|
185
|
+
const parts = [];
|
|
186
|
+
let start = 0;
|
|
187
|
+
let depth = 0;
|
|
188
|
+
let quote = '';
|
|
189
|
+
const split = (end, next) => {
|
|
190
|
+
const text = selector.slice(start, end).trim();
|
|
191
|
+
if (text)
|
|
192
|
+
parts.push({ text, next });
|
|
193
|
+
else if (parts.length && next !== ' ')
|
|
194
|
+
parts[parts.length - 1].next = next;
|
|
195
|
+
};
|
|
196
|
+
for (let i = 0; i < selector.length; i += 1) {
|
|
197
|
+
const c = selector[i];
|
|
198
|
+
if (quote) {
|
|
199
|
+
if (c === quote && selector[i - 1] !== '\\')
|
|
200
|
+
quote = '';
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (c === '\\')
|
|
204
|
+
i = escapeEnd(selector, i) - 1;
|
|
205
|
+
else if (c === '"' || c === "'")
|
|
206
|
+
quote = c;
|
|
207
|
+
else if (c === '(' || c === '[')
|
|
208
|
+
depth += 1;
|
|
209
|
+
else if (c === ')' || c === ']')
|
|
210
|
+
depth = Math.max(0, depth - 1);
|
|
211
|
+
else if (depth === 0 && /[\s>+~]/.test(c)) {
|
|
212
|
+
split(i, c === '+' || c === '~' || c === '>' ? c : ' ');
|
|
213
|
+
start = i + 1;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
split(selector.length, '');
|
|
217
|
+
for (const { text, next } of parts) {
|
|
218
|
+
let bare = '';
|
|
219
|
+
let pointer = false;
|
|
220
|
+
depth = 0;
|
|
221
|
+
quote = '';
|
|
222
|
+
/** Where a top-level `:has(` starts in `bare`, and its argument in
|
|
223
|
+
* `text`, while one is open. */
|
|
224
|
+
let hasAt = -1;
|
|
225
|
+
let argAt = -1;
|
|
226
|
+
let hasPointer = false;
|
|
227
|
+
let anchored = false;
|
|
228
|
+
const args = [];
|
|
229
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
230
|
+
const c = text[i];
|
|
231
|
+
if (quote) {
|
|
232
|
+
if (c === quote && text[i - 1] !== '\\')
|
|
233
|
+
quote = '';
|
|
234
|
+
bare += c;
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (c === '\\') {
|
|
238
|
+
const end = escapeEnd(text, i);
|
|
239
|
+
bare += text.slice(i, end);
|
|
240
|
+
i = end - 1;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (c === '"' || c === "'")
|
|
244
|
+
quote = c;
|
|
245
|
+
else if (c === '(' || c === '[') {
|
|
246
|
+
if (depth === 0 && c === '(' && /:has$/i.test(bare)) {
|
|
247
|
+
hasAt = bare.length - 4;
|
|
248
|
+
argAt = i + 1;
|
|
249
|
+
hasPointer = false;
|
|
250
|
+
}
|
|
251
|
+
depth += 1;
|
|
252
|
+
}
|
|
253
|
+
else if (c === ')' || c === ']') {
|
|
254
|
+
depth = Math.max(0, depth - 1);
|
|
255
|
+
if (depth === 0 && hasAt >= 0 && c === ')') {
|
|
256
|
+
// the compound is kept without it: its argument is what the
|
|
257
|
+
// pointer changes
|
|
258
|
+
if (hasPointer) {
|
|
259
|
+
anchored = true;
|
|
260
|
+
args.push(text.slice(argAt, i));
|
|
261
|
+
bare = bare.slice(0, hasAt);
|
|
262
|
+
}
|
|
263
|
+
else
|
|
264
|
+
bare += c;
|
|
265
|
+
hasAt = -1;
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else if (c === ':' && text[i + 1] !== ':') {
|
|
270
|
+
const m = POINTER_PSEUDO_AT.exec(text.slice(i));
|
|
271
|
+
if (m) {
|
|
272
|
+
const hover = m[0].length === 6;
|
|
273
|
+
if (depth > 0) {
|
|
274
|
+
// whatever holds it in the argument, the element it tests is
|
|
275
|
+
// in the anchor's subtree or a later sibling's
|
|
276
|
+
if (hover && hasAt >= 0)
|
|
277
|
+
hasPointer = true;
|
|
278
|
+
else if (hover)
|
|
279
|
+
out.nested = true;
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
if (hover)
|
|
283
|
+
pointer = true;
|
|
284
|
+
i += m[0].length - 1;
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
bare += c;
|
|
290
|
+
}
|
|
291
|
+
if (anchored) {
|
|
292
|
+
out.has.push({
|
|
293
|
+
anchor: bare.trim() || '*',
|
|
294
|
+
siblings: args.some((arg) => arg.split(',').some((one) => /^\s*[+~]/.test(one))),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
if (!pointer)
|
|
298
|
+
continue;
|
|
299
|
+
out.compounds.push(bare.trim() || '*');
|
|
300
|
+
if (next === '+' || next === '~')
|
|
301
|
+
out.siblings = true;
|
|
302
|
+
}
|
|
303
|
+
return out;
|
|
304
|
+
}
|
|
305
|
+
/** `:hover` or `:active` at the start of a string, and nothing longer. */
|
|
306
|
+
const POINTER_PSEUDO_AT = /^:(?:hover|active)(?![\w-])/i;
|
|
307
|
+
/** `:hover` or `:active` anywhere in a selector. */
|
|
308
|
+
const POINTER_PSEUDO = /:(?:hover|active)(?![\w-])/i;
|
|
309
|
+
/**
|
|
310
|
+
* A selector compiled to a matcher over this adapter. css-select keeps the
|
|
311
|
+
* answers of a `:has()` above the subject, or of the ancestors a
|
|
312
|
+
* descendant combinator tried under one, for as long as the matcher lives
|
|
313
|
+
* (`cacheResults`) — which is the cascade's life, and a pointer move is no
|
|
314
|
+
* new cascade. So a selector that tests the pointer keeps none: with them,
|
|
315
|
+
* `#box:has(a:hover) .m` answered what it did before the first move, for
|
|
316
|
+
* good.
|
|
317
|
+
*/
|
|
318
|
+
function compileSelector(selector, adapter) {
|
|
319
|
+
return compile(noEmptyWords(selector), {
|
|
320
|
+
adapter,
|
|
321
|
+
xmlMode: false,
|
|
322
|
+
pseudos: PSEUDOS,
|
|
323
|
+
cacheResults: !POINTER_PSEUDO.test(selector),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
63
326
|
function mapBucket(map, key) {
|
|
64
327
|
let bucket = map.get(key);
|
|
65
328
|
if (!bucket) {
|
|
@@ -87,14 +350,26 @@ function rightmostKey(selector) {
|
|
|
87
350
|
quote = '';
|
|
88
351
|
continue;
|
|
89
352
|
}
|
|
90
|
-
|
|
353
|
+
// an escaped character is part of a name, whatever it is — and a hex
|
|
354
|
+
// escape takes the space after it: `.c\6c ass` is the class `class`
|
|
355
|
+
if (c === '\\')
|
|
356
|
+
i = escapeEnd(selector, i) - 1;
|
|
357
|
+
else if (c === '"' || c === "'")
|
|
91
358
|
quote = c;
|
|
92
359
|
else if (c === '(' || c === '[')
|
|
93
360
|
depth += 1;
|
|
94
361
|
else if (c === ')' || c === ']')
|
|
95
362
|
depth = Math.max(0, depth - 1);
|
|
96
363
|
else if (depth === 0 &&
|
|
97
|
-
(c === ' ' ||
|
|
364
|
+
(c === ' ' ||
|
|
365
|
+
c === '>' ||
|
|
366
|
+
c === '+' ||
|
|
367
|
+
c === '~' ||
|
|
368
|
+
// CSS's other white space: `div\fp` is a descendant too
|
|
369
|
+
c === '\t' ||
|
|
370
|
+
c === '\n' ||
|
|
371
|
+
c === '\r' ||
|
|
372
|
+
c === '\f')) {
|
|
98
373
|
start = i + 1;
|
|
99
374
|
}
|
|
100
375
|
}
|
|
@@ -105,31 +380,29 @@ function rightmostKey(selector) {
|
|
|
105
380
|
let i = 0;
|
|
106
381
|
while (i < compound.length) {
|
|
107
382
|
const c = compound[i];
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
cls = compound.slice(i + 1, end);
|
|
118
|
-
i = end;
|
|
383
|
+
// Names as the matcher reads them, escapes resolved: `.md\:flex` is
|
|
384
|
+
// the class `md:flex`, and filed under its first half it never matched.
|
|
385
|
+
if (c === '#' || c === '.') {
|
|
386
|
+
const name = readIdent(compound, i + 1);
|
|
387
|
+
if (c === '#' && !id)
|
|
388
|
+
id = name.value;
|
|
389
|
+
if (c === '.' && !cls)
|
|
390
|
+
cls = name.value;
|
|
391
|
+
i = Math.max(name.end, i + 1);
|
|
119
392
|
}
|
|
120
393
|
else if (c === '[') {
|
|
121
394
|
i = balancedEnd(compound, i, '[', ']');
|
|
122
395
|
}
|
|
123
396
|
else if (c === ':') {
|
|
124
397
|
const skip = compound[i + 1] === ':' ? 2 : 1;
|
|
125
|
-
const end =
|
|
398
|
+
const end = Math.max(readIdent(compound, i + skip).end, i + skip);
|
|
126
399
|
i = compound[end] === '(' ? balancedEnd(compound, end, '(', ')') : end;
|
|
127
400
|
}
|
|
128
|
-
else if (
|
|
129
|
-
const
|
|
401
|
+
else if (startsIdent(compound, i)) {
|
|
402
|
+
const name = readIdent(compound, i);
|
|
130
403
|
if (!tag)
|
|
131
|
-
tag =
|
|
132
|
-
i = end;
|
|
404
|
+
tag = name.value.toLowerCase();
|
|
405
|
+
i = name.end;
|
|
133
406
|
}
|
|
134
407
|
else {
|
|
135
408
|
i += 1;
|
|
@@ -143,12 +416,6 @@ function rightmostKey(selector) {
|
|
|
143
416
|
return { kind: 'tag', name: tag };
|
|
144
417
|
return { kind: 'any', name: '' };
|
|
145
418
|
}
|
|
146
|
-
function identEnd(text, from) {
|
|
147
|
-
let i = from;
|
|
148
|
-
while (i < text.length && /[a-zA-Z0-9_\-\\]/.test(text[i]))
|
|
149
|
-
i += 1;
|
|
150
|
-
return i;
|
|
151
|
-
}
|
|
152
419
|
function balancedEnd(text, from, open, close) {
|
|
153
420
|
let depth = 0;
|
|
154
421
|
for (let i = from; i < text.length; i += 1) {
|
|
@@ -163,13 +430,50 @@ function balancedEnd(text, from, open, close) {
|
|
|
163
430
|
return text.length;
|
|
164
431
|
}
|
|
165
432
|
const NO_POINTER = { hovered: new Set(), active: new Set() };
|
|
433
|
+
function faceOf(style) {
|
|
434
|
+
return {
|
|
435
|
+
family: style.fontFamily,
|
|
436
|
+
size: style.fontSize,
|
|
437
|
+
weight: style.fontWeight,
|
|
438
|
+
style: style.fontStyle,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
function faceKey(style) {
|
|
442
|
+
return `${style.fontFamily}\u0001${style.fontSize}\u0001${style.fontWeight}\u0001${style.fontStyle}`;
|
|
443
|
+
}
|
|
166
444
|
/**
|
|
167
445
|
* A cascade over a fixed set of stylesheets. Rebuilt when the sheets change;
|
|
168
446
|
* re-run when the DOM, the viewport band or the pointer state does.
|
|
169
447
|
*/
|
|
170
448
|
export class Cascade {
|
|
171
449
|
_index = new RuleIndex();
|
|
450
|
+
/** The rules for pseudo-elements, kept apart: they never style the
|
|
451
|
+
* element itself, and a document with none of them asks nothing. */
|
|
452
|
+
_pseudo = {
|
|
453
|
+
before: new RuleIndex(),
|
|
454
|
+
after: new RuleIndex(),
|
|
455
|
+
'first-letter': new RuleIndex(),
|
|
456
|
+
'first-line': new RuleIndex(),
|
|
457
|
+
marker: new RuleIndex(),
|
|
458
|
+
};
|
|
172
459
|
_adapter;
|
|
460
|
+
/** The compounds of the selectors that test the pointer, each without
|
|
461
|
+
* its `:hover` or `:active` (`pointerCompounds`), and their matchers,
|
|
462
|
+
* compiled when a pointer move first asks (`hoverTouches`). */
|
|
463
|
+
_hoverCompounds = new Set();
|
|
464
|
+
_hoverMatchers = null;
|
|
465
|
+
/** Whether a pointer move can be restyled where it happened
|
|
466
|
+
* (`HtmlViewNode._hoverInPlace`): false where a selector tests the
|
|
467
|
+
* pointer inside a functional pseudo-class, which reaches elements no
|
|
468
|
+
* compound names. */
|
|
469
|
+
hoverLocal = true;
|
|
470
|
+
/** Whether a compound that tests the pointer is followed by a sibling
|
|
471
|
+
* combinator, so an element's later siblings restyle with it. */
|
|
472
|
+
hoverSiblings = false;
|
|
473
|
+
/** The compounds whose `:has()` tests the pointer, each without it, and
|
|
474
|
+
* whether its argument starts at a sibling (`hoverAnchors`). */
|
|
475
|
+
_hoverAnchors = new Map();
|
|
476
|
+
_anchorMatchers = null;
|
|
173
477
|
_pointer = NO_POINTER;
|
|
174
478
|
initial;
|
|
175
479
|
look;
|
|
@@ -183,20 +487,74 @@ export class Cascade {
|
|
|
183
487
|
/** Every width at which some `@media` rule changes its mind, in CSS
|
|
184
488
|
* pixels — the unit the author wrote them in. */
|
|
185
489
|
breakpoints;
|
|
186
|
-
|
|
490
|
+
/** The counter styles the sheets define, over the predefined ones. */
|
|
491
|
+
counterStyles;
|
|
492
|
+
/** A face's x-height, for `ex`, where the fonts can say. */
|
|
493
|
+
_xHeightOf;
|
|
494
|
+
_xHeights = new Map();
|
|
495
|
+
/** The advance of a face's "0", for `ch`, likewise. */
|
|
496
|
+
_zeroWidthOf;
|
|
497
|
+
_zeroWidths = new Map();
|
|
498
|
+
/** A face's own line height, for `lh` where `line-height` is `normal`,
|
|
499
|
+
* likewise. */
|
|
500
|
+
_normalLineOf;
|
|
501
|
+
_normalLines = new Map();
|
|
502
|
+
/** Whether any declaration sets a custom property or reads one: without
|
|
503
|
+
* one, no element's style asks about them. */
|
|
504
|
+
_vars = false;
|
|
505
|
+
/** Whether any declaration is in a unit of the viewport's width — `vw`,
|
|
506
|
+
* `vmin`, `vmax` — or of its height, `vh` and the same two: a style
|
|
507
|
+
* holds such a length as a number, so it is computed again when that
|
|
508
|
+
* side of the viewport moves (`HtmlViewNode._update`). */
|
|
509
|
+
readsViewportWidth = false;
|
|
510
|
+
readsViewportHeight = false;
|
|
511
|
+
/** The families the document loads itself (`fonts.ts`), or null for a
|
|
512
|
+
* document with no `@font-face`. */
|
|
513
|
+
_families;
|
|
514
|
+
_mapFamilies;
|
|
515
|
+
/** Whether any declaration has a length in `lh` or `rlh`: only then is
|
|
516
|
+
* the line height settled ahead of the declarations that read it. */
|
|
517
|
+
_lh = false;
|
|
518
|
+
constructor(sheets, look, viewportWidth, viewportHeight, scale = 1, xHeight = null, zeroWidth = null, normalLine = null, families = null) {
|
|
519
|
+
this._xHeightOf = xHeight;
|
|
520
|
+
this._zeroWidthOf = zeroWidth;
|
|
521
|
+
this._normalLineOf = normalLine;
|
|
522
|
+
this._families = families;
|
|
523
|
+
this._mapFamilies = families
|
|
524
|
+
? (list) => families.map(list)
|
|
525
|
+
: undefined;
|
|
187
526
|
this.look = look;
|
|
188
|
-
this.initial = initialStyle(look);
|
|
527
|
+
this.initial = initialStyle(look, scale);
|
|
189
528
|
this.viewportWidth = viewportWidth;
|
|
190
529
|
this.viewportHeight = viewportHeight;
|
|
191
530
|
this.scale = scale;
|
|
192
531
|
const breakpoints = new Set();
|
|
532
|
+
const counterStyles = new Map();
|
|
193
533
|
for (const sheet of sheets) {
|
|
194
|
-
|
|
195
|
-
|
|
534
|
+
// a counter style's rule whole over any before it of its name
|
|
535
|
+
for (const { prelude, declarations } of sheet.counterStyles ?? []) {
|
|
536
|
+
const style = counterStyleRule(prelude, declarations);
|
|
537
|
+
if (style)
|
|
538
|
+
counterStyles.set(style.name, style.rule);
|
|
539
|
+
}
|
|
540
|
+
for (const rule of sheet.rules) {
|
|
541
|
+
if (!this._vars && usesVars(rule.declarations))
|
|
542
|
+
this._vars = true;
|
|
543
|
+
this._noteViewportUnits(rule.declarations);
|
|
544
|
+
if (!this._lh && usesLh(rule.declarations))
|
|
545
|
+
this._lh = true;
|
|
546
|
+
const pseudo = splitPseudoElement(rule);
|
|
547
|
+
if (pseudo)
|
|
548
|
+
this._pseudo[pseudo.which].add(pseudo.rule);
|
|
549
|
+
else
|
|
550
|
+
this._index.add(rule);
|
|
551
|
+
this._noteHover((pseudo?.rule ?? rule).selector);
|
|
552
|
+
}
|
|
196
553
|
for (const bp of sheet.breakpoints)
|
|
197
554
|
breakpoints.add(bp);
|
|
198
555
|
}
|
|
199
556
|
this.breakpoints = [...breakpoints].sort((a, b) => a - b);
|
|
557
|
+
this.counterStyles = new CounterStyles(counterStyles);
|
|
200
558
|
// css-select's default adapter is domutils; `isHovered` and `isActive`
|
|
201
559
|
// are its documented hooks for exactly this, so `:hover` costs an
|
|
202
560
|
// adapter field rather than a fork of the matcher.
|
|
@@ -207,18 +565,124 @@ export class Cascade {
|
|
|
207
565
|
this._adapter = {
|
|
208
566
|
...DomUtils,
|
|
209
567
|
isTag,
|
|
568
|
+
// a type selector sees `tagOf`'s name — XHTML's `<svg:svg>` is an
|
|
569
|
+
// `svg` — asked only of a name that could be one: this runs for every
|
|
570
|
+
// type selector tried, and the parser has lowercased the rest
|
|
571
|
+
getName: (el) => el.name.endsWith(':svg') ? tagOf(el) : el.name,
|
|
210
572
|
isHovered: (el) => this._pointer.hovered.has(el),
|
|
211
573
|
isActive: (el) => this._pointer.active.has(el),
|
|
212
574
|
isVisited: () => false,
|
|
213
575
|
};
|
|
214
576
|
}
|
|
577
|
+
/** Whether declarations read the viewport's width or height (`vw`,
|
|
578
|
+
* `vh`, `vmin`, `vmax`), noted on the cascade. */
|
|
579
|
+
_noteViewportUnits(declarations) {
|
|
580
|
+
if (this.readsViewportWidth && this.readsViewportHeight)
|
|
581
|
+
return;
|
|
582
|
+
for (const d of declarations) {
|
|
583
|
+
if (!VIEWPORT_UNIT.test(d.value))
|
|
584
|
+
continue;
|
|
585
|
+
for (const m of d.value.matchAll(VIEWPORT_UNITS)) {
|
|
586
|
+
const unit = m[1].toLowerCase();
|
|
587
|
+
if (unit !== 'vh')
|
|
588
|
+
this.readsViewportWidth = true;
|
|
589
|
+
if (unit !== 'vw')
|
|
590
|
+
this.readsViewportHeight = true;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
215
594
|
/** Whether a pointer move can change what this cascade produces. */
|
|
216
595
|
get hoverSensitive() {
|
|
217
|
-
return this._index.hoverSensitive
|
|
596
|
+
return (this._index.hoverSensitive ||
|
|
597
|
+
this._pseudo.before.hoverSensitive ||
|
|
598
|
+
this._pseudo.after.hoverSensitive ||
|
|
599
|
+
this._pseudo['first-letter'].hoverSensitive ||
|
|
600
|
+
this._pseudo['first-line'].hoverSensitive ||
|
|
601
|
+
this._pseudo.marker.hoverSensitive);
|
|
218
602
|
}
|
|
219
603
|
setPointer(pointer) {
|
|
220
604
|
this._pointer = pointer;
|
|
221
605
|
}
|
|
606
|
+
/**
|
|
607
|
+
* Whether the pointer entering or leaving `el` can change a style: one of
|
|
608
|
+
* the compounds a selector tests the pointer in matches it, the pointer
|
|
609
|
+
* aside. A move between two paragraphs of a page whose only such rule is
|
|
610
|
+
* `a:hover` touches nothing, and restyles nothing.
|
|
611
|
+
*/
|
|
612
|
+
hoverTouches(el) {
|
|
613
|
+
this._hoverMatchers ??= [...this._hoverCompounds].flatMap((c) => {
|
|
614
|
+
const match = this._compile(c);
|
|
615
|
+
return match ? [match] : [];
|
|
616
|
+
});
|
|
617
|
+
for (const match of this._hoverMatchers)
|
|
618
|
+
if (match(el))
|
|
619
|
+
return true;
|
|
620
|
+
return false;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* The elements whose `:has()` may have changed its answer as `el` was
|
|
624
|
+
* hovered or left: the ancestors of it a compound whose `:has()` tests
|
|
625
|
+
* the pointer names, and their earlier siblings and its own where the
|
|
626
|
+
* argument starts at a sibling — a superset, which is restyled and found
|
|
627
|
+
* the same where it did not. Into `into`.
|
|
628
|
+
*/
|
|
629
|
+
hoverAnchors(el, into) {
|
|
630
|
+
if (!this._hoverAnchors.size)
|
|
631
|
+
return;
|
|
632
|
+
this._anchorMatchers ??= [...this._hoverAnchors].flatMap(([anchor, siblings]) => {
|
|
633
|
+
const match = this._compile(anchor);
|
|
634
|
+
return match ? [{ match, siblings }] : [];
|
|
635
|
+
});
|
|
636
|
+
const siblings = this._anchorMatchers.some((m) => m.siblings);
|
|
637
|
+
for (let at = el; at;) {
|
|
638
|
+
if (at !== el) {
|
|
639
|
+
for (const { match } of this._anchorMatchers) {
|
|
640
|
+
if (match(at)) {
|
|
641
|
+
into.push(at);
|
|
642
|
+
break;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
if (siblings) {
|
|
647
|
+
for (let s = at.prev; s; s = s.prev) {
|
|
648
|
+
if (!isTag(s))
|
|
649
|
+
continue;
|
|
650
|
+
for (const { match, siblings: apart } of this._anchorMatchers) {
|
|
651
|
+
if (apart && match(s)) {
|
|
652
|
+
into.push(s);
|
|
653
|
+
break;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
const parent = at.parent;
|
|
659
|
+
at = parent && isTag(parent) ? parent : null;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
_noteHover(selector) {
|
|
663
|
+
if (!/:(?:hover|active)/i.test(selector))
|
|
664
|
+
return;
|
|
665
|
+
const found = pointerCompounds(selector);
|
|
666
|
+
if (found.nested)
|
|
667
|
+
this.hoverLocal = false;
|
|
668
|
+
if (found.siblings)
|
|
669
|
+
this.hoverSiblings = true;
|
|
670
|
+
for (const c of found.compounds)
|
|
671
|
+
this._hoverCompounds.add(c);
|
|
672
|
+
for (const { anchor, siblings } of found.has) {
|
|
673
|
+
this._hoverAnchors.set(anchor, siblings || (this._hoverAnchors.get(anchor) ?? false));
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
/** A selector compiled as a rule's is, or null where css-select refuses
|
|
677
|
+
* it, as a rule it refuses drops out of the cascade. */
|
|
678
|
+
_compile(selector) {
|
|
679
|
+
try {
|
|
680
|
+
return compileSelector(selector, this._adapter);
|
|
681
|
+
}
|
|
682
|
+
catch {
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
222
686
|
/** Which media band a device-pixel width falls in. Two widths in the same
|
|
223
687
|
* band produce identical styles, which is what lets a resize skip
|
|
224
688
|
* restyling. */
|
|
@@ -233,14 +697,323 @@ export class Cascade {
|
|
|
233
697
|
}
|
|
234
698
|
return band;
|
|
235
699
|
}
|
|
700
|
+
/** Computed styles by sharing key, for one build (`sharedStyleFor`): one
|
|
701
|
+
* map for the elements shared without matching, one for the elements
|
|
702
|
+
* shared by what they matched. */
|
|
703
|
+
_shared = new Map();
|
|
704
|
+
_sharedByMatch = new Map();
|
|
705
|
+
_nextShareKey = 1;
|
|
706
|
+
/** Custom property sets by what made them, for one build (`_customFor`). */
|
|
707
|
+
_customs = new Map();
|
|
708
|
+
_ids = new WeakMap();
|
|
709
|
+
_nextId = 1;
|
|
710
|
+
/** A box tree is about to be built: the styles shared in the last build
|
|
711
|
+
* were computed against a pointer and a viewport that may have moved. */
|
|
712
|
+
beginSharing() {
|
|
713
|
+
this._shared.clear();
|
|
714
|
+
this._sharedByMatch.clear();
|
|
715
|
+
this._customs.clear();
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* An element's custom properties: its parent's, or its own over them —
|
|
719
|
+
* shared by every element whose parent has the same ones and whose own
|
|
720
|
+
* come from the same declarations. Tailwind 4 sets thirty-five of them on
|
|
721
|
+
* every element (`*, ::before, ::after { --tw-shadow: 0 0 #0000; … }`),
|
|
722
|
+
* and a set per element was a fifth of building the boxes; it also kept
|
|
723
|
+
* each element's `var()`s from being replaced once for its siblings,
|
|
724
|
+
* which `substituteIn` remembers by the set they were read against.
|
|
725
|
+
*/
|
|
726
|
+
_customFor(parentStyle, candidates) {
|
|
727
|
+
let key = '';
|
|
728
|
+
for (const c of candidates) {
|
|
729
|
+
if (!this._hasCustom(c))
|
|
730
|
+
continue;
|
|
731
|
+
key += `${this._idOf(c.declarations)}:${c.only},`;
|
|
732
|
+
}
|
|
733
|
+
const parent = parentStyle.custom;
|
|
734
|
+
if (!key)
|
|
735
|
+
return parent;
|
|
736
|
+
key = `${parent ? this._idOf(parent) : 0}|${key}`;
|
|
737
|
+
const hit = this._customs.get(key);
|
|
738
|
+
if (hit)
|
|
739
|
+
return hit;
|
|
740
|
+
const own = new Map();
|
|
741
|
+
for (const c of candidates) {
|
|
742
|
+
for (const d of pick(c))
|
|
743
|
+
if (d.custom)
|
|
744
|
+
own.set(d.prop, d.value);
|
|
745
|
+
}
|
|
746
|
+
const made = customProperties(own, parent);
|
|
747
|
+
this._customs.set(key, made);
|
|
748
|
+
return made;
|
|
749
|
+
}
|
|
750
|
+
/** Whether a candidate sets a custom property. */
|
|
751
|
+
_hasCustom(c) {
|
|
752
|
+
if (c.only >= 0)
|
|
753
|
+
return !!c.declarations[c.only].custom;
|
|
754
|
+
let has = CUSTOM_IN.get(c.declarations);
|
|
755
|
+
if (has === undefined) {
|
|
756
|
+
has = c.declarations.some((d) => !!d.custom);
|
|
757
|
+
CUSTOM_IN.set(c.declarations, has);
|
|
758
|
+
}
|
|
759
|
+
return has;
|
|
760
|
+
}
|
|
761
|
+
/** A number for an object, to key a string by. */
|
|
762
|
+
_idOf(of) {
|
|
763
|
+
let id = this._ids.get(of);
|
|
764
|
+
if (id === undefined) {
|
|
765
|
+
id = this._nextId++;
|
|
766
|
+
this._ids.set(of, id);
|
|
767
|
+
}
|
|
768
|
+
return id;
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* `styleFor`, shared between the elements that must compute the same
|
|
772
|
+
* style, with the key this element's children share under.
|
|
773
|
+
*
|
|
774
|
+
* A style is a function of the parent's style, the rules that match, the
|
|
775
|
+
* presentational attributes, the inline style and whether the parent is a
|
|
776
|
+
* flex container. Outside the rules `UNSHAREABLE` names, what matches
|
|
777
|
+
* depends only on the element's tag and attributes and its ancestors', and
|
|
778
|
+
* the hints read nothing else either. So the key is the parent's key, the
|
|
779
|
+
* flex flag, the tag and every attribute — plus the pointer state where a
|
|
780
|
+
* rule asks for it — and an element whose key has been computed in this
|
|
781
|
+
* build takes that style object, matching nothing. A long document is a
|
|
782
|
+
* few kinds of element many times over: the benchmark's 600 KB report is
|
|
783
|
+
* 9,039 elements and 110 keys, and computing every style again was a third
|
|
784
|
+
* of an edit.
|
|
785
|
+
*
|
|
786
|
+
* An element a rule `UNSHAREABLE` could reach is matched, since where it
|
|
787
|
+
* sits decides what matches — and then shared by what matched: the same
|
|
788
|
+
* parent, attributes and rules make the same style. That is what keeps a
|
|
789
|
+
* striped table from being a style per row, and it keeps the key its
|
|
790
|
+
* children share under, which an element-per-key would have taken from the
|
|
791
|
+
* whole subtree.
|
|
792
|
+
*
|
|
793
|
+
* The style is handed out shared, so nothing may write to it — nothing
|
|
794
|
+
* does after the cascade, and `rootStyle` does not go through here.
|
|
795
|
+
*/
|
|
796
|
+
sharedStyleFor(el, parentStyle, parentKey, inFlexContainer) {
|
|
797
|
+
let key = `${parentKey}\u0001${inFlexContainer ? 1 : 0}`;
|
|
798
|
+
const tag = tagOf(el);
|
|
799
|
+
key += `\u0001${tag.length}:${tag}`;
|
|
800
|
+
if (this._index.hoverSensitive) {
|
|
801
|
+
if (this._pointer.hovered.has(el))
|
|
802
|
+
key += '\u0001:hover';
|
|
803
|
+
if (this._pointer.active.has(el))
|
|
804
|
+
key += '\u0001:active';
|
|
805
|
+
}
|
|
806
|
+
const attribs = el.attribs;
|
|
807
|
+
for (const name in attribs) {
|
|
808
|
+
const value = attribs[name];
|
|
809
|
+
key += `\u0001${name.length}:${name}=${value.length}:${value}`;
|
|
810
|
+
}
|
|
811
|
+
if (!this._shareable(el)) {
|
|
812
|
+
const matched = [];
|
|
813
|
+
const candidates = this._candidates(el, matched);
|
|
814
|
+
key += `\u0001${matched.join(',')}`;
|
|
815
|
+
let shared = this._sharedByMatch.get(key);
|
|
816
|
+
if (shared === undefined) {
|
|
817
|
+
shared = {
|
|
818
|
+
style: this._computeStyle(el, parentStyle, inFlexContainer, candidates),
|
|
819
|
+
key: this._nextShareKey++,
|
|
820
|
+
};
|
|
821
|
+
this._sharedByMatch.set(key, shared);
|
|
822
|
+
}
|
|
823
|
+
return shared;
|
|
824
|
+
}
|
|
825
|
+
let shared = this._shared.get(key);
|
|
826
|
+
if (shared === undefined) {
|
|
827
|
+
shared = {
|
|
828
|
+
style: this.styleFor(el, parentStyle, inFlexContainer),
|
|
829
|
+
key: this._nextShareKey++,
|
|
830
|
+
};
|
|
831
|
+
this._shared.set(key, shared);
|
|
832
|
+
}
|
|
833
|
+
return shared;
|
|
834
|
+
}
|
|
835
|
+
/** Whether no rule `UNSHAREABLE` names could reach this element: the same
|
|
836
|
+
* buckets `_candidates` looks in. */
|
|
837
|
+
_shareable(el) {
|
|
838
|
+
const index = this._index;
|
|
839
|
+
if (index.ownStyleEverywhere)
|
|
840
|
+
return false;
|
|
841
|
+
if (index.ownStyleTags.size && index.ownStyleTags.has(tagOf(el))) {
|
|
842
|
+
return false;
|
|
843
|
+
}
|
|
844
|
+
if (index.ownStyleIds.size) {
|
|
845
|
+
const id = attr(el, 'id');
|
|
846
|
+
if (id && index.ownStyleIds.has(id))
|
|
847
|
+
return false;
|
|
848
|
+
}
|
|
849
|
+
if (index.ownStyleClasses.size) {
|
|
850
|
+
const className = attr(el, 'class');
|
|
851
|
+
if (className) {
|
|
852
|
+
for (const name of className.split(/\s+/)) {
|
|
853
|
+
if (name && index.ownStyleClasses.has(name))
|
|
854
|
+
return false;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return true;
|
|
859
|
+
}
|
|
236
860
|
/**
|
|
237
|
-
* The computed style for one element, given its parent's.
|
|
238
|
-
*
|
|
239
|
-
*
|
|
861
|
+
* The computed style for one element, given its parent's. The box builder
|
|
862
|
+
* asks for every element in document order, through `sharedStyleFor`, so
|
|
863
|
+
* a style is computed only for the elements with none to share.
|
|
240
864
|
*/
|
|
241
865
|
styleFor(el, parentStyle, inFlexContainer) {
|
|
866
|
+
return this._computeStyle(el, parentStyle, inFlexContainer, this._candidates(el));
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* The style of an element's `::before` or `::after`, or null when it has
|
|
870
|
+
* none: no rule reaches it, or the rules that do leave `content` at
|
|
871
|
+
* `normal` or `none`, which make no box (CSS 2.1 12.2). It inherits from
|
|
872
|
+
* the element's own style, as a pseudo-element does, and a flex
|
|
873
|
+
* container's are flex items. Not shared: few elements have one, and where
|
|
874
|
+
* a rule gives every element one — a clearfix — the style is the cost of
|
|
875
|
+
* the box it makes.
|
|
876
|
+
*/
|
|
877
|
+
pseudoStyleFor(el, which, elementStyle) {
|
|
878
|
+
const index = this._pseudo[which];
|
|
879
|
+
if (!index.size || !index.reaches(el))
|
|
880
|
+
return null;
|
|
881
|
+
const candidates = [];
|
|
882
|
+
this._matchInto(index, el, candidates);
|
|
883
|
+
if (!candidates.length)
|
|
884
|
+
return null;
|
|
885
|
+
// One that no rule gives a `content` is none, whatever else reaches it —
|
|
886
|
+
// `content` is not inherited, and its initial `normal` is nothing here.
|
|
887
|
+
// Tailwind's `*, ::before, ::after` reaches both of every element's.
|
|
888
|
+
if (!candidates.some(setsContent))
|
|
889
|
+
return null;
|
|
890
|
+
candidates.sort(byCascade);
|
|
891
|
+
const style = this._computeStyle(el, elementStyle, elementStyle.display === 'flex' || elementStyle.display === 'inline-flex', candidates);
|
|
892
|
+
return style.content === 'normal' || style.content === 'none'
|
|
893
|
+
? null
|
|
894
|
+
: style;
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* The rules for an element's `::first-letter`, or null when none reaches
|
|
898
|
+
* it. They are matched against the element here, and its style computed
|
|
899
|
+
* later by `firstLetterStyle`, because the pseudo-element inherits from
|
|
900
|
+
* the box its letter turns out to be in — a `<span>` the block opens with,
|
|
901
|
+
* a `::before` — which the builder has not reached yet.
|
|
902
|
+
*/
|
|
903
|
+
firstLetterRules(el) {
|
|
904
|
+
const index = this._pseudo['first-letter'];
|
|
905
|
+
if (!index.size || !index.reaches(el))
|
|
906
|
+
return null;
|
|
907
|
+
const candidates = [];
|
|
908
|
+
this._matchInto(index, el, candidates);
|
|
909
|
+
if (!candidates.length)
|
|
910
|
+
return null;
|
|
911
|
+
candidates.sort(byCascade);
|
|
912
|
+
return { el, candidates };
|
|
913
|
+
}
|
|
914
|
+
/** Whether any rule styles a `::first-line`: a document with none asks
|
|
915
|
+
* nothing more of its blocks. */
|
|
916
|
+
get hasFirstLine() {
|
|
917
|
+
return this._pseudo['first-line'].size > 0;
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* A list item's `::marker` style, inheriting from its own, or null when no
|
|
921
|
+
* rule reaches it (CSS Lists 3, 3.1): the colour and the font a bullet or
|
|
922
|
+
* a number is set in, and a `content` it is set as instead.
|
|
923
|
+
*/
|
|
924
|
+
markerStyle(el, style) {
|
|
925
|
+
const index = this._pseudo.marker;
|
|
926
|
+
if (!index.size || !index.reaches(el))
|
|
927
|
+
return null;
|
|
928
|
+
const candidates = [];
|
|
929
|
+
this._matchInto(index, el, candidates);
|
|
930
|
+
if (!candidates.length)
|
|
931
|
+
return null;
|
|
932
|
+
candidates.sort(byCascade);
|
|
933
|
+
const out = this._computeStyle(el, style, false, candidates);
|
|
934
|
+
// a marker's direction is its own unless a rule says otherwise (the
|
|
935
|
+
// HTML style sheet's `::marker { unicode-bidi: isolate }`)
|
|
936
|
+
const set = candidates.some((c) => c.declarations.some((d) => d.prop === 'unicode-bidi'));
|
|
937
|
+
if (!set)
|
|
938
|
+
out.unicodeBidi = 'isolate';
|
|
939
|
+
return out;
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* An element's `::first-line` style, inheriting from its own, or null
|
|
943
|
+
* when no rule reaches it (CSS 2.1 5.12.1).
|
|
944
|
+
*/
|
|
945
|
+
firstLineStyle(el, style) {
|
|
946
|
+
const index = this._pseudo['first-line'];
|
|
947
|
+
if (!index.size)
|
|
948
|
+
return null;
|
|
949
|
+
const candidates = [];
|
|
950
|
+
this._matchInto(index, el, candidates);
|
|
951
|
+
if (!candidates.length)
|
|
952
|
+
return null;
|
|
953
|
+
candidates.sort(byCascade);
|
|
954
|
+
return this._computeStyle(el, style, false, candidates);
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* The style of a `::first-letter` inside a box of `parentStyle`. It is an
|
|
958
|
+
* inline box, or a float where it floats, whatever the rules say of its
|
|
959
|
+
* `display` or its `position` (CSS 2.1 5.12.2).
|
|
960
|
+
*/
|
|
961
|
+
firstLetterStyle(rules, parentStyle) {
|
|
962
|
+
const style = this._computeStyle(rules.el, parentStyle, false, rules.candidates);
|
|
963
|
+
style.display = style.float === 'none' ? 'inline' : 'block';
|
|
964
|
+
style.position = 'static';
|
|
965
|
+
return style;
|
|
966
|
+
}
|
|
967
|
+
/** The x-height of a style's font: the font's own, asked once per face,
|
|
968
|
+
* or half an em. */
|
|
969
|
+
_exOf(style) {
|
|
970
|
+
const key = faceKey(style);
|
|
971
|
+
let ex = this._xHeights.get(key);
|
|
972
|
+
if (ex === undefined) {
|
|
973
|
+
ex = this._xHeightOf?.(faceOf(style)) ?? NaN;
|
|
974
|
+
if (!(ex > 0))
|
|
975
|
+
ex = style.fontSize * 0.5;
|
|
976
|
+
this._xHeights.set(key, ex);
|
|
977
|
+
}
|
|
978
|
+
return ex;
|
|
979
|
+
}
|
|
980
|
+
/** The advance of a style's font's "0": the font's own, asked once per
|
|
981
|
+
* face, or half an em. */
|
|
982
|
+
_chOf(style) {
|
|
983
|
+
const key = faceKey(style);
|
|
984
|
+
let ch = this._zeroWidths.get(key);
|
|
985
|
+
if (ch === undefined) {
|
|
986
|
+
ch = this._zeroWidthOf?.(faceOf(style)) ?? NaN;
|
|
987
|
+
if (!(ch > 0))
|
|
988
|
+
ch = style.fontSize * 0.5;
|
|
989
|
+
this._zeroWidths.set(key, ch);
|
|
990
|
+
}
|
|
991
|
+
return ch;
|
|
992
|
+
}
|
|
993
|
+
/** A style's computed line height as a length, for `lh`: `normal` as
|
|
994
|
+
* its font's own, asked once per face, or 1.2em. */
|
|
995
|
+
_lineHeightOf(style) {
|
|
996
|
+
const set = style.lineHeight;
|
|
997
|
+
if (set !== 'normal') {
|
|
998
|
+
return style.lineHeightIsLength ? set : set * style.fontSize;
|
|
999
|
+
}
|
|
1000
|
+
const key = faceKey(style);
|
|
1001
|
+
let line = this._normalLines.get(key);
|
|
1002
|
+
if (line === undefined) {
|
|
1003
|
+
line = this._normalLineOf?.(faceOf(style)) ?? NaN;
|
|
1004
|
+
if (!(line > 0))
|
|
1005
|
+
line = style.fontSize * 1.2;
|
|
1006
|
+
this._normalLines.set(key, line);
|
|
1007
|
+
}
|
|
1008
|
+
return line;
|
|
1009
|
+
}
|
|
1010
|
+
/** `styleFor`, from the rules and hints already gathered for `el`. */
|
|
1011
|
+
_computeStyle(el, parentStyle, inFlexContainer, candidates) {
|
|
242
1012
|
const style = inherit(parentStyle, this.initial);
|
|
243
|
-
|
|
1013
|
+
// custom properties first, in cascade order, so every `var()` in the
|
|
1014
|
+
// declarations below finds the one that wins
|
|
1015
|
+
if (this._vars)
|
|
1016
|
+
style.custom = this._customFor(parentStyle, candidates);
|
|
244
1017
|
// The unit context has to be built twice: once with the parent's font
|
|
245
1018
|
// size, so a `font-size: 1.2em` in the cascade resolves against the
|
|
246
1019
|
// right em, and again after the font size is settled so every *other*
|
|
@@ -248,28 +1021,150 @@ export class Cascade {
|
|
|
248
1021
|
const ctxParent = {
|
|
249
1022
|
em: parentStyle.fontSize,
|
|
250
1023
|
rem: this.initial.fontSize,
|
|
1024
|
+
initial: this.initial,
|
|
251
1025
|
vw: this.viewportWidth,
|
|
252
1026
|
vh: this.viewportHeight,
|
|
253
1027
|
scale: this.scale,
|
|
1028
|
+
ex: () => this._exOf(parentStyle),
|
|
1029
|
+
ch: () => this._chOf(parentStyle),
|
|
1030
|
+
families: this._mapFamilies,
|
|
1031
|
+
lh: () => this._lineHeightOf(parentStyle),
|
|
1032
|
+
rlh: () => this._lineHeightOf(this.initial),
|
|
254
1033
|
};
|
|
1034
|
+
// The family, the weight and the slant go with the size: together they
|
|
1035
|
+
// pick the face an `ex`, a `ch` or an `lh` in any declaration is
|
|
1036
|
+
// measured in, however the declarations are ordered. A `width: 10ex`
|
|
1037
|
+
// in a sheet under an inline `font-weight: 900` was measured in the
|
|
1038
|
+
// family's regular face.
|
|
1039
|
+
let sized = false;
|
|
1040
|
+
let keyword = false;
|
|
255
1041
|
for (const c of candidates) {
|
|
256
1042
|
for (const d of pick(c)) {
|
|
257
|
-
if (d.prop === 'font-
|
|
258
|
-
|
|
1043
|
+
if (d.prop === 'font-family' ||
|
|
1044
|
+
d.prop === 'font-weight' ||
|
|
1045
|
+
d.prop === 'font-style') {
|
|
1046
|
+
this._apply(style, parentStyle, d, ctxParent);
|
|
1047
|
+
}
|
|
1048
|
+
else if (d.prop === 'font-size' || d.prop === 'font') {
|
|
1049
|
+
// NaN until a size is set, so one the declaration did not take
|
|
1050
|
+
// leaves the size where it was, and says nothing of it
|
|
1051
|
+
const was = style.fontSize;
|
|
1052
|
+
style.fontSize = NaN;
|
|
1053
|
+
this._apply(style, parentStyle, d, ctxParent);
|
|
1054
|
+
if (Number.isNaN(style.fontSize)) {
|
|
1055
|
+
style.fontSize = was;
|
|
1056
|
+
}
|
|
1057
|
+
else {
|
|
1058
|
+
sized = true;
|
|
1059
|
+
keyword = !d.vars && sizeKeyword(d.prop, d.value);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
// The generic `monospace` on its own has a smaller size than the rest,
|
|
1065
|
+
// 13 pixels to their 16 (the "fixed" font size every browser keeps):
|
|
1066
|
+
// an element whose family becomes it, or stops being it, scales the
|
|
1067
|
+
// size it inherits by that, and a keyword size is read from the
|
|
1068
|
+
// smaller scale — the size it sets itself stays its own. Blink's
|
|
1069
|
+
// CheckForGenericFamilyChange, and why a `<pre>` in a browser is 13px.
|
|
1070
|
+
const mono = monospaceOnly(style.fontFamily);
|
|
1071
|
+
if (sized ? keyword && mono : mono !== monospaceOnly(parentStyle.fontFamily)) {
|
|
1072
|
+
style.fontSize *= mono ? FIXED_SIZE : 1 / FIXED_SIZE;
|
|
1073
|
+
}
|
|
1074
|
+
// The face as the first pass settled it. The second applies every
|
|
1075
|
+
// declaration again in cascade order, the font's among them, so the
|
|
1076
|
+
// style passes through the fonts of every rule on the way: read from
|
|
1077
|
+
// it, the `10ex` in `div { font-family: foo; width: 10ex }` was `foo`'s
|
|
1078
|
+
// under an inline `font-family: Ahem` that came after it.
|
|
1079
|
+
const face = {
|
|
1080
|
+
fontFamily: style.fontFamily,
|
|
1081
|
+
fontSize: style.fontSize,
|
|
1082
|
+
fontWeight: style.fontWeight,
|
|
1083
|
+
fontStyle: style.fontStyle,
|
|
1084
|
+
};
|
|
1085
|
+
let line = null;
|
|
1086
|
+
const ctx = {
|
|
1087
|
+
...ctxParent,
|
|
1088
|
+
em: style.fontSize,
|
|
1089
|
+
ex: () => this._exOf(face),
|
|
1090
|
+
ch: () => this._chOf(face),
|
|
1091
|
+
lh: () => this._lineHeightOf(line ?? style),
|
|
1092
|
+
};
|
|
1093
|
+
// the line height, which an `lh` in any other declaration reads, ahead
|
|
1094
|
+
// of them — a `font` sets one too — and read as it is then, for the
|
|
1095
|
+
// same reason as the face: set again with the rest, in its place among
|
|
1096
|
+
// them. A `font` sets the size as well, which the first pass settled.
|
|
1097
|
+
if (this._lh) {
|
|
1098
|
+
for (const c of candidates) {
|
|
1099
|
+
for (const d of pick(c)) {
|
|
1100
|
+
if (d.prop === 'line-height' || d.prop === 'font') {
|
|
1101
|
+
this._apply(style, parentStyle, d, ctx);
|
|
1102
|
+
}
|
|
259
1103
|
}
|
|
260
1104
|
}
|
|
1105
|
+
style.fontSize = face.fontSize;
|
|
1106
|
+
line = {
|
|
1107
|
+
...face,
|
|
1108
|
+
lineHeight: style.lineHeight,
|
|
1109
|
+
lineHeightIsLength: style.lineHeightIsLength,
|
|
1110
|
+
};
|
|
261
1111
|
}
|
|
262
|
-
const
|
|
1112
|
+
const settled = style.fontSize;
|
|
263
1113
|
for (const c of candidates) {
|
|
264
1114
|
for (const d of pick(c)) {
|
|
265
|
-
if (d.prop === 'font-size')
|
|
1115
|
+
if (d.prop === 'font-size' || d.custom)
|
|
266
1116
|
continue;
|
|
267
|
-
|
|
1117
|
+
this._apply(style, parentStyle, d, ctx);
|
|
268
1118
|
}
|
|
269
1119
|
}
|
|
1120
|
+
// A `font` is applied again, to keep its other longhands in cascade
|
|
1121
|
+
// order, and it sets the size it names as well: the size is the first
|
|
1122
|
+
// pass's, which the declarations that outrank the `font` had their say
|
|
1123
|
+
// in, and the scale after them. `span { font: 15px/1 Ahem }` under
|
|
1124
|
+
// `.b > span { font-size: 3.75em }` was 15px, its `em`s 3.75 of its
|
|
1125
|
+
// parent's.
|
|
1126
|
+
style.fontSize = settled;
|
|
1127
|
+
// A table never keeps HTML's alignment, `-webkit-center` and its kin:
|
|
1128
|
+
// the `<td align="center">` every mail centres its body table in
|
|
1129
|
+
// centres the table, and the text in its cells stays at their start —
|
|
1130
|
+
// as Blink resets it ("tables never support the -webkit-* values for
|
|
1131
|
+
// text-align"). An author's own `text-align: center` is not HTML's, and
|
|
1132
|
+
// is inherited into the table as it always was.
|
|
1133
|
+
if (style.alignBlocks !== null && tagOf(el) === 'table') {
|
|
1134
|
+
style.textAlign = 'start';
|
|
1135
|
+
style.alignBlocks = null;
|
|
1136
|
+
}
|
|
1137
|
+
settleClamp(style, parentStyle);
|
|
1138
|
+
settleOverflow(style);
|
|
1139
|
+
settleContentVisibility(style);
|
|
270
1140
|
blockify(style, inFlexContainer);
|
|
1141
|
+
decorate(style);
|
|
1142
|
+
// which faces of the document's own families this family, weight and
|
|
1143
|
+
// slant ask for — known only now, with all three computed
|
|
1144
|
+
this._families?.note(style);
|
|
271
1145
|
return style;
|
|
272
1146
|
}
|
|
1147
|
+
/** One declaration, its `var()`s replaced first. One that names a
|
|
1148
|
+
* custom property with no value, and has no fallback, is invalid at
|
|
1149
|
+
* computed-value time, and the property is as though `unset`. */
|
|
1150
|
+
_apply(style, parentStyle, d, ctx) {
|
|
1151
|
+
if (!d.vars) {
|
|
1152
|
+
applyDeclaration(style, parentStyle, d.prop, d.value, ctx);
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
// unset first: a value that does not parse once it is substituted is
|
|
1156
|
+
// invalid at computed-value time, and does not leave the property what
|
|
1157
|
+
// an earlier declaration gave it
|
|
1158
|
+
if (isInherited(d.prop)) {
|
|
1159
|
+
applyDeclaration(style, parentStyle, d.prop, 'inherit', ctx);
|
|
1160
|
+
}
|
|
1161
|
+
else {
|
|
1162
|
+
initialOne(style, this.initial, d.prop);
|
|
1163
|
+
}
|
|
1164
|
+
const value = substituteIn(d.value, style.custom);
|
|
1165
|
+
if (value !== null)
|
|
1166
|
+
applyDeclaration(style, parentStyle, d.prop, value, ctx);
|
|
1167
|
+
}
|
|
273
1168
|
/**
|
|
274
1169
|
* The root's style — nothing above it to inherit from.
|
|
275
1170
|
*
|
|
@@ -278,24 +1173,44 @@ export class Cascade {
|
|
|
278
1173
|
* a `<body>` would have had: the UA sheet's margin and font, and any
|
|
279
1174
|
* author `body { … }` rule. Without it a fragment renders hard against the
|
|
280
1175
|
* left edge while the same markup inside `<html><body>` does not, which
|
|
281
|
-
* reads as a bug in the renderer rather than as a missing element.
|
|
1176
|
+
* reads as a bug in the renderer rather than as a missing element. With
|
|
1177
|
+
* no `<html>` either, the body inherits from an `<html>` that author
|
|
1178
|
+
* `html { … }` rules have styled, as the one a browser implies would be.
|
|
1179
|
+
*
|
|
1180
|
+
* A document with a `<body>` and no `<html>` — the usual shape of a page
|
|
1181
|
+
* that starts `<!DOCTYPE html><title>` — has the root box standing in for
|
|
1182
|
+
* that implied `<html>` instead, so an `html { font-size }` still reaches
|
|
1183
|
+
* the body. Taken as the initial style, the rule matched nothing and the
|
|
1184
|
+
* whole page came out at the theme's size.
|
|
1185
|
+
*
|
|
1186
|
+
* `html` is the implied `<html>`'s own style where the root box stands in
|
|
1187
|
+
* for the body inside it, and null otherwise: what an `html { … }` or a
|
|
1188
|
+
* `:root { … }` rule gives it that is not inherited has no box to be
|
|
1189
|
+
* drawn on, and its background is the canvas's (`paintDocument`).
|
|
282
1190
|
*/
|
|
283
|
-
rootStyle(hasBody) {
|
|
284
|
-
const style =
|
|
1191
|
+
rootStyle(hasBody, hasHtml = true) {
|
|
1192
|
+
const style = copyStyle(this.initial);
|
|
285
1193
|
style.display = 'block';
|
|
286
|
-
if (hasBody)
|
|
287
|
-
return style;
|
|
1194
|
+
if (hasBody && hasHtml)
|
|
1195
|
+
return { style, html: null };
|
|
288
1196
|
const synthetic = new DomElement('body', {}, []);
|
|
289
|
-
|
|
1197
|
+
let parent = style;
|
|
1198
|
+
let html = null;
|
|
1199
|
+
if (!hasHtml) {
|
|
1200
|
+
const element = new DomElement('html', {}, hasBody ? [] : [synthetic]);
|
|
1201
|
+
synthetic.parent = element;
|
|
1202
|
+
parent = this.styleFor(element, style, false);
|
|
1203
|
+
if (hasBody)
|
|
1204
|
+
return { style: asRoot(parent), html: null };
|
|
1205
|
+
html = parent;
|
|
1206
|
+
}
|
|
290
1207
|
// Only the box the body would have drawn is taken, not its layout role:
|
|
291
1208
|
// the root is still the initial containing block.
|
|
292
|
-
|
|
293
|
-
bodyStyle.position = 'static';
|
|
294
|
-
bodyStyle.float = 'none';
|
|
295
|
-
return bodyStyle;
|
|
1209
|
+
return { style: asRoot(this.styleFor(synthetic, parent, false)), html };
|
|
296
1210
|
}
|
|
297
|
-
|
|
298
|
-
|
|
1211
|
+
/** The rules of `index` that match `el`, pushed onto `out` as candidates,
|
|
1212
|
+
* and their ids onto `matched` in the order they were tried. */
|
|
1213
|
+
_matchInto(index, el, out, matched) {
|
|
299
1214
|
// A media query's width is CSS pixels; the viewport is kept in device.
|
|
300
1215
|
const width = this.viewportWidth / this.scale;
|
|
301
1216
|
const consider = (bucket) => {
|
|
@@ -308,10 +1223,7 @@ export class Cascade {
|
|
|
308
1223
|
if (!indexed.compiled) {
|
|
309
1224
|
indexed.compiled = true;
|
|
310
1225
|
try {
|
|
311
|
-
indexed.match =
|
|
312
|
-
adapter: this._adapter,
|
|
313
|
-
xmlMode: false,
|
|
314
|
-
});
|
|
1226
|
+
indexed.match = compileSelector(rule.selector, this._adapter);
|
|
315
1227
|
}
|
|
316
1228
|
catch {
|
|
317
1229
|
// A selector this matcher does not know (`::-moz-…`, a CSS4 form
|
|
@@ -322,26 +1234,35 @@ export class Cascade {
|
|
|
322
1234
|
}
|
|
323
1235
|
if (!indexed.match || !indexed.match(el))
|
|
324
1236
|
continue;
|
|
1237
|
+
matched?.push(indexed.id);
|
|
325
1238
|
const origin = rule.order < 0 ? Origin.UserAgent : Origin.Author;
|
|
326
1239
|
pushRule(out, rule, origin);
|
|
327
1240
|
}
|
|
328
1241
|
};
|
|
329
1242
|
const id = attr(el, 'id');
|
|
330
1243
|
if (id)
|
|
331
|
-
consider(
|
|
1244
|
+
consider(index.byId.get(id));
|
|
332
1245
|
const className = attr(el, 'class');
|
|
333
1246
|
if (className) {
|
|
334
1247
|
for (const name of className.split(/\s+/)) {
|
|
335
1248
|
if (name)
|
|
336
|
-
consider(
|
|
1249
|
+
consider(index.byClass.get(name));
|
|
337
1250
|
}
|
|
338
1251
|
}
|
|
339
|
-
consider(
|
|
340
|
-
consider(
|
|
1252
|
+
consider(index.byTag.get(tagOf(el)));
|
|
1253
|
+
consider(index.universal);
|
|
1254
|
+
}
|
|
1255
|
+
/** Every rule and hint that applies to `el`, in cascade order — and, into
|
|
1256
|
+
* `matched` when it is passed, the ids of the rules, in the order they
|
|
1257
|
+
* were tried. */
|
|
1258
|
+
_candidates(el, matched) {
|
|
1259
|
+
const out = [];
|
|
1260
|
+
this._matchInto(this._index, el, out, matched);
|
|
341
1261
|
const hints = presentationHints(el);
|
|
342
1262
|
if (hints.length) {
|
|
343
1263
|
out.push({
|
|
344
1264
|
origin: Origin.Presentation,
|
|
1265
|
+
layer: null,
|
|
345
1266
|
specificity: 0,
|
|
346
1267
|
order: 0,
|
|
347
1268
|
declarations: hints,
|
|
@@ -351,11 +1272,17 @@ export class Cascade {
|
|
|
351
1272
|
const inline = attr(el, 'style');
|
|
352
1273
|
if (inline) {
|
|
353
1274
|
const declarations = parseDeclarations(inline);
|
|
1275
|
+
if (!this._vars && usesVars(declarations))
|
|
1276
|
+
this._vars = true;
|
|
1277
|
+
this._noteViewportUnits(declarations);
|
|
1278
|
+
if (!this._lh && usesLh(declarations))
|
|
1279
|
+
this._lh = true;
|
|
354
1280
|
const normal = declarations.filter((d) => !d.important);
|
|
355
1281
|
const important = declarations.filter((d) => d.important);
|
|
356
1282
|
if (normal.length) {
|
|
357
1283
|
out.push({
|
|
358
1284
|
origin: Origin.Inline,
|
|
1285
|
+
layer: null,
|
|
359
1286
|
specificity: 0,
|
|
360
1287
|
order: 0,
|
|
361
1288
|
declarations: normal,
|
|
@@ -365,6 +1292,7 @@ export class Cascade {
|
|
|
365
1292
|
if (important.length) {
|
|
366
1293
|
out.push({
|
|
367
1294
|
origin: Origin.InlineImportant,
|
|
1295
|
+
layer: null,
|
|
368
1296
|
specificity: 0,
|
|
369
1297
|
order: 0,
|
|
370
1298
|
declarations: important,
|
|
@@ -376,6 +1304,144 @@ export class Cascade {
|
|
|
376
1304
|
return out;
|
|
377
1305
|
}
|
|
378
1306
|
}
|
|
1307
|
+
/** An implied element's style as the root box's: its look, not its role —
|
|
1308
|
+
* the root is still a block, in flow, and the initial containing block. */
|
|
1309
|
+
function asRoot(style) {
|
|
1310
|
+
style.display = 'block';
|
|
1311
|
+
style.position = 'static';
|
|
1312
|
+
style.float = 'none';
|
|
1313
|
+
return style;
|
|
1314
|
+
}
|
|
1315
|
+
/** `:root` is the `<html>` element: the one a browser implies around a
|
|
1316
|
+
* fragment, whose style the root box takes (`rootStyle`), and never a
|
|
1317
|
+
* fragment's top-level elements, which css-select would take for it. */
|
|
1318
|
+
const PSEUDOS = {
|
|
1319
|
+
root: (el) => el.name === 'html' && !(el.parent && isTag(el.parent)),
|
|
1320
|
+
// css-select's, but its ranges and tags lower-cased as ASCII has it, and
|
|
1321
|
+
// no other script (CSS 2.1 4.1.3): Unicode's took `:lang(\u212Al)`, a
|
|
1322
|
+
// Kelvin sign for the K, for `:lang(kl)`
|
|
1323
|
+
lang: (el, code) => {
|
|
1324
|
+
const ranges = (code ?? '')
|
|
1325
|
+
.split(',')
|
|
1326
|
+
.map((range) => range.trim().replace(/^['"]|['"]$/g, ''))
|
|
1327
|
+
.filter((range) => range.length > 0)
|
|
1328
|
+
.map((range) => asciiLower(range).split('-'));
|
|
1329
|
+
let root = el;
|
|
1330
|
+
for (let node = el; node;) {
|
|
1331
|
+
const value = node.attribs['xml:lang'] ?? node.attribs.lang;
|
|
1332
|
+
if (value != null) {
|
|
1333
|
+
if (!value)
|
|
1334
|
+
return ranges.some((range) => range[0] === '');
|
|
1335
|
+
const tag = asciiLower(value).split('-');
|
|
1336
|
+
return ranges.some((range) => langRangeMatches(tag, range));
|
|
1337
|
+
}
|
|
1338
|
+
root = node;
|
|
1339
|
+
const parent = node.parent;
|
|
1340
|
+
node = parent && isTag(parent) ? parent : null;
|
|
1341
|
+
}
|
|
1342
|
+
// with no element saying, the document's, as its `<meta>` sets it —
|
|
1343
|
+
// searched from the document, where a fragment's `<meta>` is a
|
|
1344
|
+
// sibling of what it covers
|
|
1345
|
+
const pragma = pragmaLanguage(root.parent ?? root);
|
|
1346
|
+
if (!pragma)
|
|
1347
|
+
return ranges.some((range) => range[0] === '');
|
|
1348
|
+
const tag = asciiLower(pragma).split('-');
|
|
1349
|
+
return ranges.some((range) => langRangeMatches(tag, range));
|
|
1350
|
+
},
|
|
1351
|
+
};
|
|
1352
|
+
/** A length in a unit of the viewport: a number, then the unit, and no
|
|
1353
|
+
* more of a name after it. */
|
|
1354
|
+
const VIEWPORT_UNIT = /\d(?:vw|vh|vmin|vmax)(?![\w-])/i;
|
|
1355
|
+
const VIEWPORT_UNITS = /\d(vw|vh|vmin|vmax)(?![\w-])/gi;
|
|
1356
|
+
/**
|
|
1357
|
+
* A selector with its `[attr~=""]` made one that matches nothing: an empty
|
|
1358
|
+
* string is no word of a list, and such a selector represents nothing
|
|
1359
|
+
* (Selectors 3, 6.3.1) — which the matcher's `~=` is not told, taking the
|
|
1360
|
+
* empty word for one between two spaces, or at either end of none.
|
|
1361
|
+
*/
|
|
1362
|
+
function noEmptyWords(selector) {
|
|
1363
|
+
if (!selector.includes('~='))
|
|
1364
|
+
return selector;
|
|
1365
|
+
return selector.replace(/\[[^\]"']*~=\s*(?:""|'')\s*(?:[is]\s*)?\]/gi, ':not(*)');
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* A document's language as a `<meta http-equiv="content-language">` sets
|
|
1369
|
+
* it — HTML's pragma-set default language, the last such `<meta>`'s
|
|
1370
|
+
* `content` up to its first white space, and none where it lists more
|
|
1371
|
+
* than one — by the document's root element, found once.
|
|
1372
|
+
*/
|
|
1373
|
+
function pragmaLanguage(root) {
|
|
1374
|
+
let lang = PRAGMA_LANGUAGE.get(root);
|
|
1375
|
+
if (lang !== undefined)
|
|
1376
|
+
return lang;
|
|
1377
|
+
lang = '';
|
|
1378
|
+
const stack = [root];
|
|
1379
|
+
while (stack.length) {
|
|
1380
|
+
const node = stack.pop();
|
|
1381
|
+
if (isTag(node) &&
|
|
1382
|
+
node.name === 'meta' &&
|
|
1383
|
+
node.attribs['http-equiv']?.trim().toLowerCase() === 'content-language') {
|
|
1384
|
+
const content = node.attribs.content;
|
|
1385
|
+
if (content !== undefined && !content.includes(',')) {
|
|
1386
|
+
const candidate = content.trim().split(/[\t\n\f\r ]/)[0];
|
|
1387
|
+
if (candidate)
|
|
1388
|
+
lang = candidate;
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
// in document order: the last one pushed is taken first
|
|
1392
|
+
for (let i = node.children.length - 1; i >= 0; i -= 1) {
|
|
1393
|
+
const child = node.children[i];
|
|
1394
|
+
if (isTag(child))
|
|
1395
|
+
stack.push(child);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
PRAGMA_LANGUAGE.set(root, lang);
|
|
1399
|
+
return lang;
|
|
1400
|
+
}
|
|
1401
|
+
const PRAGMA_LANGUAGE = new WeakMap();
|
|
1402
|
+
/** RFC 4647's extended filtering, of a tag's subtags by a range's, as
|
|
1403
|
+
* css-select does it. */
|
|
1404
|
+
function langRangeMatches(tag, range) {
|
|
1405
|
+
if (range[0] !== '*' && range[0] !== tag[0])
|
|
1406
|
+
return false;
|
|
1407
|
+
let at = 1;
|
|
1408
|
+
for (let r = 1; r < range.length; r += 1) {
|
|
1409
|
+
if (range[r] === '*')
|
|
1410
|
+
continue;
|
|
1411
|
+
while (at < tag.length && tag[at] !== range[r]) {
|
|
1412
|
+
if (tag[at++].length <= 1)
|
|
1413
|
+
return false;
|
|
1414
|
+
}
|
|
1415
|
+
if (at >= tag.length)
|
|
1416
|
+
return false;
|
|
1417
|
+
at += 1;
|
|
1418
|
+
}
|
|
1419
|
+
return true;
|
|
1420
|
+
}
|
|
1421
|
+
/** Whether any of these declarations sets a custom property or reads one. */
|
|
1422
|
+
function usesVars(declarations) {
|
|
1423
|
+
for (const d of declarations)
|
|
1424
|
+
if (d.custom || d.vars)
|
|
1425
|
+
return true;
|
|
1426
|
+
return false;
|
|
1427
|
+
}
|
|
1428
|
+
/** Whether any of the declarations has a length in `lh` or `rlh`. */
|
|
1429
|
+
function usesLh(declarations) {
|
|
1430
|
+
for (const d of declarations)
|
|
1431
|
+
if (LH.test(d.value))
|
|
1432
|
+
return true;
|
|
1433
|
+
return false;
|
|
1434
|
+
}
|
|
1435
|
+
const LH = /\d\.?r?lh\b/i;
|
|
1436
|
+
/** Whether a candidate declares `content`. */
|
|
1437
|
+
function setsContent(c) {
|
|
1438
|
+
for (const d of pick(c))
|
|
1439
|
+
if (d.prop === 'content')
|
|
1440
|
+
return true;
|
|
1441
|
+
return false;
|
|
1442
|
+
}
|
|
1443
|
+
/** Whether a rule's declarations set a custom property, by the array. */
|
|
1444
|
+
const CUSTOM_IN = new WeakMap();
|
|
379
1445
|
function pick(c) {
|
|
380
1446
|
return c.only < 0 ? c.declarations : [c.declarations[c.only]];
|
|
381
1447
|
}
|
|
@@ -390,6 +1456,7 @@ function pushRule(out, rule, origin) {
|
|
|
390
1456
|
if (!hasImportant) {
|
|
391
1457
|
out.push({
|
|
392
1458
|
origin,
|
|
1459
|
+
layer: rule.layer,
|
|
393
1460
|
specificity: rule.specificity,
|
|
394
1461
|
order: rule.order,
|
|
395
1462
|
declarations: rule.declarations,
|
|
@@ -407,6 +1474,7 @@ function pushRule(out, rule, origin) {
|
|
|
407
1474
|
? Origin.UserAgent
|
|
408
1475
|
: Origin.AuthorImportant
|
|
409
1476
|
: origin,
|
|
1477
|
+
layer: rule.layer,
|
|
410
1478
|
specificity: rule.specificity,
|
|
411
1479
|
order: rule.order,
|
|
412
1480
|
declarations: rule.declarations,
|
|
@@ -417,10 +1485,34 @@ function pushRule(out, rule, origin) {
|
|
|
417
1485
|
function byCascade(a, b) {
|
|
418
1486
|
if (a.origin !== b.origin)
|
|
419
1487
|
return a.origin - b.origin;
|
|
1488
|
+
if (a.layer !== b.layer) {
|
|
1489
|
+
// a later layer wins over an earlier one whatever the specificity, and
|
|
1490
|
+
// for `!important` an earlier one does (CSS Cascade 5, 6.4)
|
|
1491
|
+
const by = compareLayers(a.layer, b.layer);
|
|
1492
|
+
if (by !== 0)
|
|
1493
|
+
return a.origin >= Origin.AuthorImportant ? -by : by;
|
|
1494
|
+
}
|
|
420
1495
|
if (a.specificity !== b.specificity)
|
|
421
1496
|
return a.specificity - b.specificity;
|
|
422
1497
|
return a.order - b.order;
|
|
423
1498
|
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Which of two layers wins for a normal declaration: a later one over an
|
|
1501
|
+
* earlier one, and a rule in no layer over any, as a rule directly in a
|
|
1502
|
+
* layer is over the layers inside it.
|
|
1503
|
+
*/
|
|
1504
|
+
function compareLayers(a, b) {
|
|
1505
|
+
if (a === null)
|
|
1506
|
+
return b === null ? 0 : 1;
|
|
1507
|
+
if (b === null)
|
|
1508
|
+
return -1;
|
|
1509
|
+
const n = Math.min(a.length, b.length);
|
|
1510
|
+
for (let i = 0; i < n; i += 1) {
|
|
1511
|
+
if (a[i] !== b[i])
|
|
1512
|
+
return a[i] - b[i];
|
|
1513
|
+
}
|
|
1514
|
+
return b.length - a.length;
|
|
1515
|
+
}
|
|
424
1516
|
/**
|
|
425
1517
|
* The presentational attributes, as declarations. They sit above the UA
|
|
426
1518
|
* sheet and below every author rule, which is where HTML says they go — and
|
|
@@ -437,9 +1529,44 @@ function presentationHints(el) {
|
|
|
437
1529
|
const align = attr(el, 'align');
|
|
438
1530
|
if (align) {
|
|
439
1531
|
const v = align.toLowerCase();
|
|
440
|
-
|
|
1532
|
+
const side = v === 'middle' ? 'center' : v;
|
|
1533
|
+
if ((tag === 'img' || tag === 'table') && (v === 'left' || v === 'right')) {
|
|
441
1534
|
push('float', v);
|
|
442
|
-
|
|
1535
|
+
}
|
|
1536
|
+
else if (tag === 'img') {
|
|
1537
|
+
// an image's other alignments are its line's
|
|
1538
|
+
const va = IMAGE_ALIGN[v];
|
|
1539
|
+
if (va)
|
|
1540
|
+
push('vertical-align', va);
|
|
1541
|
+
}
|
|
1542
|
+
else if (tag === 'hr') {
|
|
1543
|
+
// a rule narrower than its line stands where it is aligned
|
|
1544
|
+
if (v === 'left') {
|
|
1545
|
+
push('margin-left', '0');
|
|
1546
|
+
push('margin-right', 'auto');
|
|
1547
|
+
}
|
|
1548
|
+
else if (v === 'right') {
|
|
1549
|
+
push('margin-left', 'auto');
|
|
1550
|
+
push('margin-right', '0');
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
else if (tag === 'table') {
|
|
1554
|
+
// a table's `align` places the table and leaves its text alone: set
|
|
1555
|
+
// as its text's, `<table align="center">` — the frame of nearly
|
|
1556
|
+
// every mail — stood at the left with its cells' text centred
|
|
1557
|
+
if (side === 'center') {
|
|
1558
|
+
push('margin-left', 'auto');
|
|
1559
|
+
push('margin-right', 'auto');
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
else if (ALIGNS_BLOCKS.has(tag) &&
|
|
1563
|
+
(side === 'center' || side === 'left' || side === 'right')) {
|
|
1564
|
+
// these align the blocks in them as well as their text (HTML's
|
|
1565
|
+
// rendering, "align descendants"): the table a `<td align="center">`
|
|
1566
|
+
// or a `<div align="center">` holds is centred in it
|
|
1567
|
+
push('text-align', `-webkit-${side}`);
|
|
1568
|
+
}
|
|
1569
|
+
else if (side === 'center')
|
|
443
1570
|
push('text-align', 'center');
|
|
444
1571
|
else if (v === 'left' || v === 'right' || v === 'justify')
|
|
445
1572
|
push('text-align', v);
|
|
@@ -447,9 +1574,42 @@ function presentationHints(el) {
|
|
|
447
1574
|
const valign = attr(el, 'valign');
|
|
448
1575
|
if (valign)
|
|
449
1576
|
push('vertical-align', valign.toLowerCase());
|
|
1577
|
+
// HTML's `dir` is its element's `direction`: `<table dir="rtl">` starts
|
|
1578
|
+
// at the right, and a Hebrew or an Arabic message is written this way
|
|
1579
|
+
const dir = attr(el, 'dir')?.toLowerCase();
|
|
1580
|
+
if (dir === 'rtl' || dir === 'ltr')
|
|
1581
|
+
push('direction', dir);
|
|
1582
|
+
// and it isolates the element from the text around it, or with `auto`
|
|
1583
|
+
// takes its first strong letter's direction (HTML's UA sheet: `[dir]`,
|
|
1584
|
+
// `[dir=auto i]`, `bdo[dir]`)
|
|
1585
|
+
if (dir !== undefined) {
|
|
1586
|
+
push('unicode-bidi', tag === 'bdo'
|
|
1587
|
+
? 'isolate-override'
|
|
1588
|
+
: dir === 'auto'
|
|
1589
|
+
? 'plaintext'
|
|
1590
|
+
: 'isolate');
|
|
1591
|
+
}
|
|
450
1592
|
const bgcolor = attr(el, 'bgcolor');
|
|
451
1593
|
if (bgcolor)
|
|
452
1594
|
push('background-color', bgcolor);
|
|
1595
|
+
if (BACKGROUNDS.has(tag)) {
|
|
1596
|
+
const background = attr(el, 'background')?.trim();
|
|
1597
|
+
if (background) {
|
|
1598
|
+
push('background-image', `url("${background.replace(/["\\\n]/g, '')}")`);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
if (tag === 'body') {
|
|
1602
|
+
// the text's colour, and the links'
|
|
1603
|
+
const text = attr(el, 'text');
|
|
1604
|
+
if (text)
|
|
1605
|
+
push('color', text);
|
|
1606
|
+
}
|
|
1607
|
+
else if (tag === 'a' && attr(el, 'href') !== undefined) {
|
|
1608
|
+
const body = closestBody(el);
|
|
1609
|
+
const link = body ? attr(body, 'link') : undefined;
|
|
1610
|
+
if (link)
|
|
1611
|
+
push('color', link);
|
|
1612
|
+
}
|
|
453
1613
|
const color = attr(el, 'color');
|
|
454
1614
|
if (color && (tag === 'font' || tag === 'basefont'))
|
|
455
1615
|
push('color', color);
|
|
@@ -472,6 +1632,27 @@ function presentationHints(el) {
|
|
|
472
1632
|
const height = attr(el, 'height');
|
|
473
1633
|
if (height)
|
|
474
1634
|
push('height', lengthAttr(height));
|
|
1635
|
+
// and, both numbers, an image's the ratio it has before it loads, or
|
|
1636
|
+
// where it has none of its own (HTML 15.4.3, "map to the aspect-ratio
|
|
1637
|
+
// property")
|
|
1638
|
+
if (width && height && RATIO_SIZED.has(tag)) {
|
|
1639
|
+
const w = parseFloat(width);
|
|
1640
|
+
const h = parseFloat(height);
|
|
1641
|
+
if (w > 0 && h > 0 && !/%/.test(width + height)) {
|
|
1642
|
+
push('aspect-ratio', `auto ${w} / ${h}`);
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
else if (tag === 'svg') {
|
|
1647
|
+
// an SVG's are CSS lengths of their own, units and all (SVG 2, 5.1.1)
|
|
1648
|
+
const width = attr(el, 'width');
|
|
1649
|
+
const w = width ? svgSizeHint(width) : null;
|
|
1650
|
+
if (w)
|
|
1651
|
+
push('width', w);
|
|
1652
|
+
const height = attr(el, 'height');
|
|
1653
|
+
const h = height ? svgSizeHint(height) : null;
|
|
1654
|
+
if (h)
|
|
1655
|
+
push('height', h);
|
|
475
1656
|
}
|
|
476
1657
|
if (tag === 'table') {
|
|
477
1658
|
const border = attr(el, 'border');
|
|
@@ -496,15 +1677,54 @@ function presentationHints(el) {
|
|
|
496
1677
|
const noshade = attr(el, 'noshade');
|
|
497
1678
|
if (noshade !== undefined)
|
|
498
1679
|
push('border-top-width', '2px');
|
|
1680
|
+
// the rule's colour and its thickness
|
|
1681
|
+
const color = attr(el, 'color');
|
|
1682
|
+
if (color)
|
|
1683
|
+
push('border-top-color', color);
|
|
1684
|
+
const size = attr(el, 'size');
|
|
1685
|
+
if (size && Number(size) > 0)
|
|
1686
|
+
push('border-top-width', `${Number(size)}px`);
|
|
1687
|
+
}
|
|
1688
|
+
if ((tag === 'td' || tag === 'th') && attr(el, 'nowrap') !== undefined) {
|
|
1689
|
+
push('white-space', 'nowrap');
|
|
1690
|
+
}
|
|
1691
|
+
if (tag === 'br') {
|
|
1692
|
+
// below the floats: `<br clear="all">` after a floated image
|
|
1693
|
+
const clear = attr(el, 'clear')?.toLowerCase();
|
|
1694
|
+
if (clear === 'all' || clear === 'both')
|
|
1695
|
+
push('clear', 'both');
|
|
1696
|
+
else if (clear === 'left' || clear === 'right')
|
|
1697
|
+
push('clear', clear);
|
|
499
1698
|
}
|
|
500
1699
|
if (tag === 'ol') {
|
|
501
1700
|
const type = attr(el, 'type');
|
|
502
1701
|
const mapped = OL_TYPES[type ?? ''];
|
|
503
1702
|
if (mapped)
|
|
504
1703
|
push('list-style-type', mapped);
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
1704
|
+
// the number a list starts at is its `list-item` counter's, one before
|
|
1705
|
+
// it, or counting down one after it (HTML's rendering, "Lists")
|
|
1706
|
+
const start = htmlInteger(attr(el, 'start'));
|
|
1707
|
+
if (start !== null) {
|
|
1708
|
+
push('counter-reset', attr(el, 'reversed') !== undefined
|
|
1709
|
+
? `reversed(list-item) ${start + 1}`
|
|
1710
|
+
: `list-item ${start - 1}`);
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
if (tag === 'ul') {
|
|
1714
|
+
const type = attr(el, 'type')?.toLowerCase();
|
|
1715
|
+
if (type && BULLETS.has(type))
|
|
1716
|
+
push('list-style-type', type);
|
|
1717
|
+
}
|
|
1718
|
+
if (tag === 'li') {
|
|
1719
|
+
// an item's `value` is the number it goes on from
|
|
1720
|
+
const value = htmlInteger(attr(el, 'value'));
|
|
1721
|
+
if (value !== null)
|
|
1722
|
+
push('counter-set', `list-item ${value}`);
|
|
1723
|
+
const type = attr(el, 'type');
|
|
1724
|
+
const mapped = OL_TYPES[type ?? ''] ??
|
|
1725
|
+
(type && BULLETS.has(type.toLowerCase()) ? type.toLowerCase() : null);
|
|
1726
|
+
if (mapped)
|
|
1727
|
+
push('list-style-type', mapped);
|
|
508
1728
|
}
|
|
509
1729
|
if (tag === 'img' || tag === 'object') {
|
|
510
1730
|
const hspace = attr(el, 'hspace');
|
|
@@ -520,6 +1740,51 @@ function presentationHints(el) {
|
|
|
520
1740
|
}
|
|
521
1741
|
return out;
|
|
522
1742
|
}
|
|
1743
|
+
/** An image's `align` other than a side, as its `vertical-align`. */
|
|
1744
|
+
const IMAGE_ALIGN = {
|
|
1745
|
+
top: 'top',
|
|
1746
|
+
texttop: 'text-top',
|
|
1747
|
+
middle: 'middle',
|
|
1748
|
+
absmiddle: 'middle',
|
|
1749
|
+
center: 'middle',
|
|
1750
|
+
bottom: 'baseline',
|
|
1751
|
+
baseline: 'baseline',
|
|
1752
|
+
absbottom: 'bottom',
|
|
1753
|
+
};
|
|
1754
|
+
/** The elements whose `align` aligns the blocks in them too. */
|
|
1755
|
+
const ALIGNS_BLOCKS = new Set([
|
|
1756
|
+
'div',
|
|
1757
|
+
'caption',
|
|
1758
|
+
'thead',
|
|
1759
|
+
'tbody',
|
|
1760
|
+
'tfoot',
|
|
1761
|
+
'tr',
|
|
1762
|
+
'td',
|
|
1763
|
+
'th',
|
|
1764
|
+
]);
|
|
1765
|
+
/** The elements a `background` attribute gives a background image. */
|
|
1766
|
+
const BACKGROUNDS = new Set([
|
|
1767
|
+
'body',
|
|
1768
|
+
'table',
|
|
1769
|
+
'thead',
|
|
1770
|
+
'tbody',
|
|
1771
|
+
'tfoot',
|
|
1772
|
+
'tr',
|
|
1773
|
+
'td',
|
|
1774
|
+
'th',
|
|
1775
|
+
]);
|
|
1776
|
+
function closestBody(el) {
|
|
1777
|
+
let node = el.parent;
|
|
1778
|
+
while (node) {
|
|
1779
|
+
if (node.type === 'tag' && node.name === 'body') {
|
|
1780
|
+
return node;
|
|
1781
|
+
}
|
|
1782
|
+
node = node.parent;
|
|
1783
|
+
}
|
|
1784
|
+
return null;
|
|
1785
|
+
}
|
|
1786
|
+
/** What the `width` and `height` attributes give a ratio as well. */
|
|
1787
|
+
const RATIO_SIZED = new Set(['img', 'video']);
|
|
523
1788
|
const SIZED = new Set([
|
|
524
1789
|
'img',
|
|
525
1790
|
'table',
|
|
@@ -529,7 +1794,6 @@ const SIZED = new Set([
|
|
|
529
1794
|
'colgroup',
|
|
530
1795
|
'iframe',
|
|
531
1796
|
'video',
|
|
532
|
-
'canvas',
|
|
533
1797
|
'object',
|
|
534
1798
|
'embed',
|
|
535
1799
|
'hr',
|
|
@@ -541,6 +1805,17 @@ const OL_TYPES = {
|
|
|
541
1805
|
i: 'lower-roman',
|
|
542
1806
|
I: 'upper-roman',
|
|
543
1807
|
};
|
|
1808
|
+
/** What a `<ul type>` or an `<li type>` names that is not a number. */
|
|
1809
|
+
const BULLETS = new Set(['disc', 'circle', 'square', 'none']);
|
|
1810
|
+
/** An attribute read as HTML reads an integer: its leading digits, signed,
|
|
1811
|
+
* whatever follows them; null where it has none. A counter is a 32-bit
|
|
1812
|
+
* integer in a browser, and one past that is kept to it. */
|
|
1813
|
+
function htmlInteger(value) {
|
|
1814
|
+
const match = value === undefined ? null : /^\s*([+-]?\d+)/.exec(value);
|
|
1815
|
+
if (!match)
|
|
1816
|
+
return null;
|
|
1817
|
+
return Math.max(-2147483648, Math.min(2147483647, Number(match[1])));
|
|
1818
|
+
}
|
|
544
1819
|
const FONT_SIZE_STEPS = [1, 0.63, 0.82, 1, 1.13, 1.5, 2, 3];
|
|
545
1820
|
/** A presentational length: bare numbers are pixels, `50%` stays a percent. */
|
|
546
1821
|
function lengthAttr(value) {
|
|
@@ -559,4 +1834,35 @@ function closestTable(el) {
|
|
|
559
1834
|
}
|
|
560
1835
|
return null;
|
|
561
1836
|
}
|
|
1837
|
+
/** The generic fixed-width family's size to everyone else's: 13 to 16. */
|
|
1838
|
+
const FIXED_SIZE = 13 / 16;
|
|
1839
|
+
/** Whether a family list is the generic `monospace` and nothing else,
|
|
1840
|
+
* which has the smaller size; a list with a fallback after it does not,
|
|
1841
|
+
* so `monospace, monospace` keeps the size it had. */
|
|
1842
|
+
function monospaceOnly(family) {
|
|
1843
|
+
return family.length === 9 && family.toLowerCase() === 'monospace';
|
|
1844
|
+
}
|
|
1845
|
+
/** Whether a `font-size`, or the size in a `font`, is an absolute-size
|
|
1846
|
+
* keyword, or `initial`, which is `medium`. */
|
|
1847
|
+
function sizeKeyword(prop, value) {
|
|
1848
|
+
const words = value.trim().toLowerCase();
|
|
1849
|
+
if (prop === 'font-size')
|
|
1850
|
+
return ABSOLUTE_SIZES.has(words);
|
|
1851
|
+
for (const word of words.split(/[\s/]+/)) {
|
|
1852
|
+
if (ABSOLUTE_SIZES.has(word))
|
|
1853
|
+
return true;
|
|
1854
|
+
}
|
|
1855
|
+
return false;
|
|
1856
|
+
}
|
|
1857
|
+
const ABSOLUTE_SIZES = new Set([
|
|
1858
|
+
'xx-small',
|
|
1859
|
+
'x-small',
|
|
1860
|
+
'small',
|
|
1861
|
+
'medium',
|
|
1862
|
+
'large',
|
|
1863
|
+
'x-large',
|
|
1864
|
+
'xx-large',
|
|
1865
|
+
'xxx-large',
|
|
1866
|
+
'initial',
|
|
1867
|
+
]);
|
|
562
1868
|
//# sourceMappingURL=cascade.js.map
|