@react-x11/components 0.8.0 → 0.10.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 +105 -38
- package/dist/charts/node.d.ts +12 -2
- package/dist/charts/node.d.ts.map +1 -1
- package/dist/charts/node.js +50 -16
- 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 +3 -1
- 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/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/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 +13 -2
- package/dist/codeblock/index.d.ts.map +1 -1
- package/dist/codeblock/index.js +20 -3
- package/dist/codeblock/index.js.map +1 -1
- package/dist/embed/client.d.ts +48 -3
- package/dist/embed/client.d.ts.map +1 -1
- package/dist/embed/client.js +79 -5
- package/dist/embed/client.js.map +1 -1
- package/dist/embed/index.d.ts +1 -1
- package/dist/embed/index.d.ts.map +1 -1
- package/dist/embed/index.js +1 -1
- package/dist/embed/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 +240 -6
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +1327 -66
- 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 +498 -15
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +3698 -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 +57 -11
- 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 +2937 -197
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +340 -17
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +1714 -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 +151 -1
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +3375 -174
- 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 +172 -5
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +1336 -103
- 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 +3503 -141
- 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 +435 -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 +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- 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/{markdown → internal/markdown}/ast.d.ts +23 -0
- package/dist/internal/markdown/ast.d.ts.map +1 -0
- package/dist/internal/markdown/ast.js +22 -0
- package/dist/internal/markdown/ast.js.map +1 -0
- package/dist/internal/markdown/parse.d.ts.map +1 -0
- package/dist/{markdown → internal/markdown}/parse.js +221 -30
- package/dist/internal/markdown/parse.js.map +1 -0
- package/dist/internal/markdown/stringify.d.ts +4 -0
- package/dist/internal/markdown/stringify.d.ts.map +1 -0
- package/dist/internal/markdown/stringify.js +684 -0
- package/dist/internal/markdown/stringify.js.map +1 -0
- package/dist/internal/markdown/tags.d.ts.map +1 -0
- package/dist/internal/markdown/tags.js.map +1 -0
- 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/scroll.d.ts +3 -2
- package/dist/internal/scroll.d.ts.map +1 -1
- package/dist/internal/scroll.js +1 -0
- package/dist/internal/scroll.js.map +1 -1
- 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 +103 -0
- package/dist/maps/anchors.d.ts.map +1 -0
- package/dist/maps/anchors.js +790 -0
- package/dist/maps/anchors.js.map +1 -0
- package/dist/maps/controller.d.ts +340 -0
- package/dist/maps/controller.d.ts.map +1 -0
- package/dist/maps/controller.js +822 -0
- package/dist/maps/controller.js.map +1 -0
- package/dist/maps/gl/buckets.d.ts +99 -0
- package/dist/maps/gl/buckets.d.ts.map +1 -0
- package/dist/maps/gl/buckets.js +365 -0
- package/dist/maps/gl/buckets.js.map +1 -0
- package/dist/maps/gl/build-worker.d.ts +15 -0
- package/dist/maps/gl/build-worker.d.ts.map +1 -0
- package/dist/maps/gl/build-worker.js +44 -0
- package/dist/maps/gl/build-worker.js.map +1 -0
- package/dist/maps/gl/color.d.ts +8 -0
- package/dist/maps/gl/color.d.ts.map +1 -0
- package/dist/maps/gl/color.js +57 -0
- package/dist/maps/gl/color.js.map +1 -0
- package/dist/maps/gl/cover.d.ts +70 -0
- package/dist/maps/gl/cover.d.ts.map +1 -0
- package/dist/maps/gl/cover.js +137 -0
- package/dist/maps/gl/cover.js.map +1 -0
- package/dist/maps/gl/index.d.ts +3 -0
- package/dist/maps/gl/index.d.ts.map +1 -0
- package/dist/maps/gl/index.js +20 -0
- package/dist/maps/gl/index.js.map +1 -0
- package/dist/maps/gl/markers.d.ts +28 -0
- package/dist/maps/gl/markers.d.ts.map +1 -0
- package/dist/maps/gl/markers.js +60 -0
- package/dist/maps/gl/markers.js.map +1 -0
- package/dist/maps/gl/overlays.d.ts +68 -0
- package/dist/maps/gl/overlays.d.ts.map +1 -0
- package/dist/maps/gl/overlays.js +300 -0
- package/dist/maps/gl/overlays.js.map +1 -0
- package/dist/maps/gl/pane.d.ts +12 -0
- package/dist/maps/gl/pane.d.ts.map +1 -0
- package/dist/maps/gl/pane.js +37 -0
- package/dist/maps/gl/pane.js.map +1 -0
- package/dist/maps/gl/placement.d.ts +124 -0
- package/dist/maps/gl/placement.d.ts.map +1 -0
- package/dist/maps/gl/placement.js +642 -0
- package/dist/maps/gl/placement.js.map +1 -0
- package/dist/maps/gl/renderer.d.ts +384 -0
- package/dist/maps/gl/renderer.d.ts.map +1 -0
- package/dist/maps/gl/renderer.js +1184 -0
- package/dist/maps/gl/renderer.js.map +1 -0
- package/dist/maps/gl/shaders.d.ts +121 -0
- package/dist/maps/gl/shaders.d.ts.map +1 -0
- package/dist/maps/gl/shaders.js +453 -0
- package/dist/maps/gl/shaders.js.map +1 -0
- package/dist/maps/gl/store.d.ts +125 -0
- package/dist/maps/gl/store.d.ts.map +1 -0
- package/dist/maps/gl/store.js +512 -0
- package/dist/maps/gl/store.js.map +1 -0
- package/dist/maps/gl/text.d.ts +283 -0
- package/dist/maps/gl/text.d.ts.map +1 -0
- package/dist/maps/gl/text.js +698 -0
- package/dist/maps/gl/text.js.map +1 -0
- package/dist/maps/gl/view.d.ts +345 -0
- package/dist/maps/gl/view.d.ts.map +1 -0
- package/dist/maps/gl/view.js +1209 -0
- package/dist/maps/gl/view.js.map +1 -0
- 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 +3 -1
- package/dist/maps/index.d.ts.map +1 -1
- package/dist/maps/index.js +218 -52
- package/dist/maps/index.js.map +1 -1
- package/dist/maps/labels.d.ts +91 -18
- package/dist/maps/labels.d.ts.map +1 -1
- package/dist/maps/labels.js +376 -140
- package/dist/maps/labels.js.map +1 -1
- package/dist/maps/node.d.ts +179 -56
- package/dist/maps/node.d.ts.map +1 -1
- package/dist/maps/node.js +663 -537
- package/dist/maps/node.js.map +1 -1
- package/dist/maps/overlay.d.ts +72 -9
- package/dist/maps/overlay.d.ts.map +1 -1
- package/dist/maps/overlay.js +108 -28
- package/dist/maps/overlay.js.map +1 -1
- package/dist/maps/paint.d.ts +3 -0
- package/dist/maps/paint.d.ts.map +1 -1
- package/dist/maps/paint.js.map +1 -1
- package/dist/maps/proj.d.ts +62 -0
- package/dist/maps/proj.d.ts.map +1 -1
- package/dist/maps/proj.js +101 -0
- package/dist/maps/proj.js.map +1 -1
- package/dist/maps/renderer.d.ts +69 -0
- package/dist/maps/renderer.d.ts.map +1 -0
- package/dist/maps/renderer.js +66 -0
- package/dist/maps/renderer.js.map +1 -0
- package/dist/maps/sources.d.ts +30 -6
- package/dist/maps/sources.d.ts.map +1 -1
- package/dist/maps/sources.js +22 -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/theme.d.ts +19 -0
- package/dist/maps/theme.d.ts.map +1 -0
- package/dist/maps/theme.js +44 -0
- package/dist/maps/theme.js.map +1 -0
- package/dist/maps/tiles.d.ts +147 -27
- package/dist/maps/tiles.d.ts.map +1 -1
- package/dist/maps/tiles.js +221 -54
- package/dist/maps/tiles.js.map +1 -1
- package/dist/maps/types.d.ts +213 -21
- package/dist/maps/types.d.ts.map +1 -1
- package/dist/markdown/expressions.d.ts +1 -1
- package/dist/markdown/expressions.d.ts.map +1 -1
- package/dist/markdown/expressions.js.map +1 -1
- package/dist/markdown/index.d.ts +7 -6
- package/dist/markdown/index.d.ts.map +1 -1
- package/dist/markdown/index.js +121 -50
- package/dist/markdown/index.js.map +1 -1
- package/dist/markdown/spans.d.ts +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/media-player/index.d.ts +11 -3
- package/dist/media-player/index.d.ts.map +1 -1
- package/dist/media-player/index.js +13 -2
- package/dist/media-player/index.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/clipboard.d.ts +23 -0
- package/dist/rich-text-editor/clipboard.d.ts.map +1 -0
- package/dist/rich-text-editor/clipboard.js +307 -0
- package/dist/rich-text-editor/clipboard.js.map +1 -0
- package/dist/rich-text-editor/collab.d.ts +32 -0
- package/dist/rich-text-editor/collab.d.ts.map +1 -0
- package/dist/rich-text-editor/collab.js +55 -0
- package/dist/rich-text-editor/collab.js.map +1 -0
- package/dist/rich-text-editor/commands.d.ts +50 -0
- package/dist/rich-text-editor/commands.d.ts.map +1 -0
- package/dist/rich-text-editor/commands.js +376 -0
- package/dist/rich-text-editor/commands.js.map +1 -0
- package/dist/rich-text-editor/drag.d.ts +68 -0
- package/dist/rich-text-editor/drag.d.ts.map +1 -0
- package/dist/rich-text-editor/drag.js +148 -0
- package/dist/rich-text-editor/drag.js.map +1 -0
- package/dist/rich-text-editor/html.d.ts +145 -0
- package/dist/rich-text-editor/html.d.ts.map +1 -0
- package/dist/rich-text-editor/html.js +516 -0
- package/dist/rich-text-editor/html.js.map +1 -0
- package/dist/rich-text-editor/index.d.ts +252 -0
- package/dist/rich-text-editor/index.d.ts.map +1 -0
- package/dist/rich-text-editor/index.js +856 -0
- package/dist/rich-text-editor/index.js.map +1 -0
- package/dist/rich-text-editor/inline.d.ts +94 -0
- package/dist/rich-text-editor/inline.d.ts.map +1 -0
- package/dist/rich-text-editor/inline.js +252 -0
- package/dist/rich-text-editor/inline.js.map +1 -0
- package/dist/rich-text-editor/keymap.d.ts +71 -0
- package/dist/rich-text-editor/keymap.d.ts.map +1 -0
- package/dist/rich-text-editor/keymap.js +394 -0
- package/dist/rich-text-editor/keymap.js.map +1 -0
- package/dist/rich-text-editor/keys.d.ts +40 -0
- package/dist/rich-text-editor/keys.d.ts.map +1 -0
- package/dist/rich-text-editor/keys.js +202 -0
- package/dist/rich-text-editor/keys.js.map +1 -0
- package/dist/rich-text-editor/look.d.ts +71 -0
- package/dist/rich-text-editor/look.d.ts.map +1 -0
- package/dist/rich-text-editor/look.js +342 -0
- package/dist/rich-text-editor/look.js.map +1 -0
- package/dist/rich-text-editor/markdown.d.ts +18 -0
- package/dist/rich-text-editor/markdown.d.ts.map +1 -0
- package/dist/rich-text-editor/markdown.js +496 -0
- package/dist/rich-text-editor/markdown.js.map +1 -0
- 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/nodes.d.ts +135 -0
- package/dist/rich-text-editor/nodes.d.ts.map +1 -0
- package/dist/rich-text-editor/nodes.js +397 -0
- package/dist/rich-text-editor/nodes.js.map +1 -0
- package/dist/rich-text-editor/render.d.ts +68 -0
- package/dist/rich-text-editor/render.d.ts.map +1 -0
- package/dist/rich-text-editor/render.js +518 -0
- package/dist/rich-text-editor/render.js.map +1 -0
- package/dist/rich-text-editor/schema.d.ts +16 -0
- package/dist/rich-text-editor/schema.d.ts.map +1 -0
- package/dist/rich-text-editor/schema.js +386 -0
- package/dist/rich-text-editor/schema.js.map +1 -0
- package/dist/rich-text-editor/store.d.ts +11 -0
- package/dist/rich-text-editor/store.d.ts.map +1 -0
- package/dist/rich-text-editor/store.js +43 -0
- package/dist/rich-text-editor/store.js.map +1 -0
- package/dist/rich-text-editor/suggest.d.ts +127 -0
- package/dist/rich-text-editor/suggest.d.ts.map +1 -0
- package/dist/rich-text-editor/suggest.js +0 -0
- package/dist/rich-text-editor/suggest.js.map +1 -0
- package/dist/rich-text-editor/tables.d.ts +41 -0
- package/dist/rich-text-editor/tables.d.ts.map +1 -0
- package/dist/rich-text-editor/tables.js +204 -0
- package/dist/rich-text-editor/tables.js.map +1 -0
- package/dist/rich-text-editor/toolbar.d.ts +58 -0
- package/dist/rich-text-editor/toolbar.d.ts.map +1 -0
- package/dist/rich-text-editor/toolbar.js +548 -0
- package/dist/rich-text-editor/toolbar.js.map +1 -0
- package/dist/rich-text-editor/view.d.ts +368 -0
- package/dist/rich-text-editor/view.d.ts.map +1 -0
- package/dist/rich-text-editor/view.js +1968 -0
- package/dist/rich-text-editor/view.js.map +1 -0
- package/dist/rich-text-editor/virtual.d.ts +54 -0
- package/dist/rich-text-editor/virtual.d.ts.map +1 -0
- package/dist/rich-text-editor/virtual.js +279 -0
- package/dist/rich-text-editor/virtual.js.map +1 -0
- package/dist/richtext/node.d.ts +71 -4
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +233 -28
- 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/backends.d.ts +4 -1
- package/dist/terminal/backends.d.ts.map +1 -1
- package/dist/terminal/backends.js.map +1 -1
- package/dist/terminal/index.d.ts +18 -7
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +32 -11
- 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 +6 -1
- package/dist/terminal-output/index.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 +59 -31
- package/src/charts/node.ts +68 -28
- package/src/charts/render.ts +120 -30
- package/src/code/index.ts +3 -1
- 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/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/stream.ts +257 -17
- package/src/code-language/types.ts +5 -4
- package/src/codeblock/index.ts +20 -3
- package/src/embed/client.ts +102 -8
- package/src/embed/index.ts +2 -0
- 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 +1403 -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 +4102 -222
- package/src/html/css/ua.ts +58 -12
- 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 +3456 -230
- package/src/html/layout/boxes.ts +2100 -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 +3943 -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 +1486 -121
- package/src/html/paint.ts +4293 -169
- package/src/html/resources.ts +161 -50
- package/src/html/surfaces.ts +81 -0
- package/src/html/svg.ts +493 -0
- package/src/html/url.ts +86 -0
- package/src/index.ts +4 -0
- package/src/internal/collate.ts +12 -0
- package/src/{markdown → internal/markdown}/ast.ts +35 -7
- package/src/{markdown → internal/markdown}/parse.ts +288 -35
- package/src/internal/markdown/stringify.ts +772 -0
- package/src/internal/prewarm.ts +45 -0
- package/src/internal/scroll.ts +5 -3
- 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 +913 -0
- package/src/maps/controller.ts +1084 -0
- package/src/maps/gl/buckets.ts +461 -0
- package/src/maps/gl/build-worker.ts +66 -0
- package/src/maps/gl/color.ts +62 -0
- package/src/maps/gl/cover.ts +205 -0
- package/src/maps/gl/index.ts +23 -0
- package/src/maps/gl/markers.ts +83 -0
- package/src/maps/gl/overlays.ts +379 -0
- package/src/maps/gl/pane.ts +42 -0
- package/src/maps/gl/placement.ts +968 -0
- package/src/maps/gl/renderer.ts +1660 -0
- package/src/maps/gl/shaders.ts +489 -0
- package/src/maps/gl/store.ts +615 -0
- package/src/maps/gl/text.ts +868 -0
- package/src/maps/gl/view.ts +1489 -0
- package/src/maps/icons.ts +183 -0
- package/src/maps/index.ts +274 -81
- package/src/maps/labels.ts +457 -144
- package/src/maps/node.ts +832 -665
- package/src/maps/overlay.ts +148 -43
- package/src/maps/paint.ts +3 -0
- package/src/maps/proj.ts +118 -0
- package/src/maps/renderer.ts +155 -0
- package/src/maps/sources.ts +43 -6
- package/src/maps/style.ts +32 -0
- package/src/maps/styles.ts +215 -4
- package/src/maps/theme.ts +51 -0
- package/src/maps/tiles.ts +253 -62
- package/src/maps/types.ts +213 -21
- package/src/markdown/expressions.ts +5 -1
- package/src/markdown/index.ts +163 -78
- package/src/markdown/spans.ts +6 -1
- package/src/media-player/index.ts +18 -4
- 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/clipboard.ts +439 -0
- package/src/rich-text-editor/collab.ts +91 -0
- package/src/rich-text-editor/commands.ts +448 -0
- package/src/rich-text-editor/dom-globals.d.ts +23 -0
- package/src/rich-text-editor/drag.ts +211 -0
- package/src/rich-text-editor/html.ts +619 -0
- package/src/rich-text-editor/index.ts +1364 -0
- package/src/rich-text-editor/inline.ts +345 -0
- package/src/rich-text-editor/keymap.ts +510 -0
- package/src/rich-text-editor/keys.ts +228 -0
- package/src/rich-text-editor/look.ts +427 -0
- package/src/rich-text-editor/markdown.ts +653 -0
- package/src/rich-text-editor/marks.ts +101 -0
- package/src/rich-text-editor/nodes.ts +497 -0
- package/src/rich-text-editor/render.ts +837 -0
- package/src/rich-text-editor/schema.ts +431 -0
- package/src/rich-text-editor/store.ts +39 -0
- package/src/rich-text-editor/suggest.ts +597 -0
- package/src/rich-text-editor/tables.ts +272 -0
- package/src/rich-text-editor/toolbar.ts +724 -0
- package/src/rich-text-editor/view.ts +2287 -0
- package/src/rich-text-editor/virtual.ts +372 -0
- package/src/richtext/node.ts +294 -44
- package/src/richtext/runs.ts +23 -12
- package/src/table/index.ts +29 -0
- package/src/table/rows.ts +18 -8
- package/src/terminal/backends.ts +4 -1
- package/src/terminal/index.ts +47 -15
- package/src/terminal/vt/pty.ts +16 -2
- package/src/terminal-output/index.ts +6 -1
- package/src/three/canvas.ts +102 -8
- package/src/three/events.ts +49 -9
- package/src/tree/index.ts +19 -0
- package/dist/markdown/ast.d.ts.map +0 -1
- package/dist/markdown/ast.js +0 -17
- package/dist/markdown/ast.js.map +0 -1
- package/dist/markdown/parse.d.ts.map +0 -1
- package/dist/markdown/parse.js.map +0 -1
- package/dist/markdown/tags.d.ts.map +0 -1
- package/dist/markdown/tags.js.map +0 -1
- /package/dist/{markdown → internal/markdown}/parse.d.ts +0 -0
- /package/dist/{markdown → internal/markdown}/tags.d.ts +0 -0
- /package/dist/{markdown → internal/markdown}/tags.js +0 -0
- /package/src/{markdown → internal/markdown}/tags.ts +0 -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) {
|
|
@@ -169,7 +436,33 @@ const NO_POINTER = { hovered: new Set(), active: new Set() };
|
|
|
169
436
|
*/
|
|
170
437
|
export class Cascade {
|
|
171
438
|
_index = new RuleIndex();
|
|
439
|
+
/** The rules for pseudo-elements, kept apart: they never style the
|
|
440
|
+
* element itself, and a document with none of them asks nothing. */
|
|
441
|
+
_pseudo = {
|
|
442
|
+
before: new RuleIndex(),
|
|
443
|
+
after: new RuleIndex(),
|
|
444
|
+
'first-letter': new RuleIndex(),
|
|
445
|
+
'first-line': new RuleIndex(),
|
|
446
|
+
marker: new RuleIndex(),
|
|
447
|
+
};
|
|
172
448
|
_adapter;
|
|
449
|
+
/** The compounds of the selectors that test the pointer, each without
|
|
450
|
+
* its `:hover` or `:active` (`pointerCompounds`), and their matchers,
|
|
451
|
+
* compiled when a pointer move first asks (`hoverTouches`). */
|
|
452
|
+
_hoverCompounds = new Set();
|
|
453
|
+
_hoverMatchers = null;
|
|
454
|
+
/** Whether a pointer move can be restyled where it happened
|
|
455
|
+
* (`HtmlViewNode._hoverInPlace`): false where a selector tests the
|
|
456
|
+
* pointer inside a functional pseudo-class, which reaches elements no
|
|
457
|
+
* compound names. */
|
|
458
|
+
hoverLocal = true;
|
|
459
|
+
/** Whether a compound that tests the pointer is followed by a sibling
|
|
460
|
+
* combinator, so an element's later siblings restyle with it. */
|
|
461
|
+
hoverSiblings = false;
|
|
462
|
+
/** The compounds whose `:has()` tests the pointer, each without it, and
|
|
463
|
+
* whether its argument starts at a sibling (`hoverAnchors`). */
|
|
464
|
+
_hoverAnchors = new Map();
|
|
465
|
+
_anchorMatchers = null;
|
|
173
466
|
_pointer = NO_POINTER;
|
|
174
467
|
initial;
|
|
175
468
|
look;
|
|
@@ -183,20 +476,74 @@ export class Cascade {
|
|
|
183
476
|
/** Every width at which some `@media` rule changes its mind, in CSS
|
|
184
477
|
* pixels — the unit the author wrote them in. */
|
|
185
478
|
breakpoints;
|
|
186
|
-
|
|
479
|
+
/** The counter styles the sheets define, over the predefined ones. */
|
|
480
|
+
counterStyles;
|
|
481
|
+
/** A font's x-height at a size, for `ex`, where the fonts can say. */
|
|
482
|
+
_xHeightOf;
|
|
483
|
+
_xHeights = new Map();
|
|
484
|
+
/** The advance of a font's "0" at a size, for `ch`, likewise. */
|
|
485
|
+
_zeroWidthOf;
|
|
486
|
+
_zeroWidths = new Map();
|
|
487
|
+
/** A font's own line height at a size, for `lh` where `line-height` is
|
|
488
|
+
* `normal`, likewise. */
|
|
489
|
+
_normalLineOf;
|
|
490
|
+
_normalLines = new Map();
|
|
491
|
+
/** Whether any declaration sets a custom property or reads one: without
|
|
492
|
+
* one, no element's style asks about them. */
|
|
493
|
+
_vars = false;
|
|
494
|
+
/** Whether any declaration is in a unit of the viewport's width — `vw`,
|
|
495
|
+
* `vmin`, `vmax` — or of its height, `vh` and the same two: a style
|
|
496
|
+
* holds such a length as a number, so it is computed again when that
|
|
497
|
+
* side of the viewport moves (`HtmlViewNode._update`). */
|
|
498
|
+
readsViewportWidth = false;
|
|
499
|
+
readsViewportHeight = false;
|
|
500
|
+
/** The families the document loads itself (`fonts.ts`), or null for a
|
|
501
|
+
* document with no `@font-face`. */
|
|
502
|
+
_families;
|
|
503
|
+
_mapFamilies;
|
|
504
|
+
/** Whether any declaration has a length in `lh` or `rlh`: only then is
|
|
505
|
+
* the line height settled ahead of the declarations that read it. */
|
|
506
|
+
_lh = false;
|
|
507
|
+
constructor(sheets, look, viewportWidth, viewportHeight, scale = 1, xHeight = null, zeroWidth = null, normalLine = null, families = null) {
|
|
508
|
+
this._xHeightOf = xHeight;
|
|
509
|
+
this._zeroWidthOf = zeroWidth;
|
|
510
|
+
this._normalLineOf = normalLine;
|
|
511
|
+
this._families = families;
|
|
512
|
+
this._mapFamilies = families
|
|
513
|
+
? (list) => families.map(list)
|
|
514
|
+
: undefined;
|
|
187
515
|
this.look = look;
|
|
188
|
-
this.initial = initialStyle(look);
|
|
516
|
+
this.initial = initialStyle(look, scale);
|
|
189
517
|
this.viewportWidth = viewportWidth;
|
|
190
518
|
this.viewportHeight = viewportHeight;
|
|
191
519
|
this.scale = scale;
|
|
192
520
|
const breakpoints = new Set();
|
|
521
|
+
const counterStyles = new Map();
|
|
193
522
|
for (const sheet of sheets) {
|
|
194
|
-
|
|
195
|
-
|
|
523
|
+
// a counter style's rule whole over any before it of its name
|
|
524
|
+
for (const { prelude, declarations } of sheet.counterStyles ?? []) {
|
|
525
|
+
const style = counterStyleRule(prelude, declarations);
|
|
526
|
+
if (style)
|
|
527
|
+
counterStyles.set(style.name, style.rule);
|
|
528
|
+
}
|
|
529
|
+
for (const rule of sheet.rules) {
|
|
530
|
+
if (!this._vars && usesVars(rule.declarations))
|
|
531
|
+
this._vars = true;
|
|
532
|
+
this._noteViewportUnits(rule.declarations);
|
|
533
|
+
if (!this._lh && usesLh(rule.declarations))
|
|
534
|
+
this._lh = true;
|
|
535
|
+
const pseudo = splitPseudoElement(rule);
|
|
536
|
+
if (pseudo)
|
|
537
|
+
this._pseudo[pseudo.which].add(pseudo.rule);
|
|
538
|
+
else
|
|
539
|
+
this._index.add(rule);
|
|
540
|
+
this._noteHover((pseudo?.rule ?? rule).selector);
|
|
541
|
+
}
|
|
196
542
|
for (const bp of sheet.breakpoints)
|
|
197
543
|
breakpoints.add(bp);
|
|
198
544
|
}
|
|
199
545
|
this.breakpoints = [...breakpoints].sort((a, b) => a - b);
|
|
546
|
+
this.counterStyles = new CounterStyles(counterStyles);
|
|
200
547
|
// css-select's default adapter is domutils; `isHovered` and `isActive`
|
|
201
548
|
// are its documented hooks for exactly this, so `:hover` costs an
|
|
202
549
|
// adapter field rather than a fork of the matcher.
|
|
@@ -207,18 +554,124 @@ export class Cascade {
|
|
|
207
554
|
this._adapter = {
|
|
208
555
|
...DomUtils,
|
|
209
556
|
isTag,
|
|
557
|
+
// a type selector sees `tagOf`'s name — XHTML's `<svg:svg>` is an
|
|
558
|
+
// `svg` — asked only of a name that could be one: this runs for every
|
|
559
|
+
// type selector tried, and the parser has lowercased the rest
|
|
560
|
+
getName: (el) => el.name.endsWith(':svg') ? tagOf(el) : el.name,
|
|
210
561
|
isHovered: (el) => this._pointer.hovered.has(el),
|
|
211
562
|
isActive: (el) => this._pointer.active.has(el),
|
|
212
563
|
isVisited: () => false,
|
|
213
564
|
};
|
|
214
565
|
}
|
|
566
|
+
/** Whether declarations read the viewport's width or height (`vw`,
|
|
567
|
+
* `vh`, `vmin`, `vmax`), noted on the cascade. */
|
|
568
|
+
_noteViewportUnits(declarations) {
|
|
569
|
+
if (this.readsViewportWidth && this.readsViewportHeight)
|
|
570
|
+
return;
|
|
571
|
+
for (const d of declarations) {
|
|
572
|
+
if (!VIEWPORT_UNIT.test(d.value))
|
|
573
|
+
continue;
|
|
574
|
+
for (const m of d.value.matchAll(VIEWPORT_UNITS)) {
|
|
575
|
+
const unit = m[1].toLowerCase();
|
|
576
|
+
if (unit !== 'vh')
|
|
577
|
+
this.readsViewportWidth = true;
|
|
578
|
+
if (unit !== 'vw')
|
|
579
|
+
this.readsViewportHeight = true;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
215
583
|
/** Whether a pointer move can change what this cascade produces. */
|
|
216
584
|
get hoverSensitive() {
|
|
217
|
-
return this._index.hoverSensitive
|
|
585
|
+
return (this._index.hoverSensitive ||
|
|
586
|
+
this._pseudo.before.hoverSensitive ||
|
|
587
|
+
this._pseudo.after.hoverSensitive ||
|
|
588
|
+
this._pseudo['first-letter'].hoverSensitive ||
|
|
589
|
+
this._pseudo['first-line'].hoverSensitive ||
|
|
590
|
+
this._pseudo.marker.hoverSensitive);
|
|
218
591
|
}
|
|
219
592
|
setPointer(pointer) {
|
|
220
593
|
this._pointer = pointer;
|
|
221
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* Whether the pointer entering or leaving `el` can change a style: one of
|
|
597
|
+
* the compounds a selector tests the pointer in matches it, the pointer
|
|
598
|
+
* aside. A move between two paragraphs of a page whose only such rule is
|
|
599
|
+
* `a:hover` touches nothing, and restyles nothing.
|
|
600
|
+
*/
|
|
601
|
+
hoverTouches(el) {
|
|
602
|
+
this._hoverMatchers ??= [...this._hoverCompounds].flatMap((c) => {
|
|
603
|
+
const match = this._compile(c);
|
|
604
|
+
return match ? [match] : [];
|
|
605
|
+
});
|
|
606
|
+
for (const match of this._hoverMatchers)
|
|
607
|
+
if (match(el))
|
|
608
|
+
return true;
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* The elements whose `:has()` may have changed its answer as `el` was
|
|
613
|
+
* hovered or left: the ancestors of it a compound whose `:has()` tests
|
|
614
|
+
* the pointer names, and their earlier siblings and its own where the
|
|
615
|
+
* argument starts at a sibling — a superset, which is restyled and found
|
|
616
|
+
* the same where it did not. Into `into`.
|
|
617
|
+
*/
|
|
618
|
+
hoverAnchors(el, into) {
|
|
619
|
+
if (!this._hoverAnchors.size)
|
|
620
|
+
return;
|
|
621
|
+
this._anchorMatchers ??= [...this._hoverAnchors].flatMap(([anchor, siblings]) => {
|
|
622
|
+
const match = this._compile(anchor);
|
|
623
|
+
return match ? [{ match, siblings }] : [];
|
|
624
|
+
});
|
|
625
|
+
const siblings = this._anchorMatchers.some((m) => m.siblings);
|
|
626
|
+
for (let at = el; at;) {
|
|
627
|
+
if (at !== el) {
|
|
628
|
+
for (const { match } of this._anchorMatchers) {
|
|
629
|
+
if (match(at)) {
|
|
630
|
+
into.push(at);
|
|
631
|
+
break;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
if (siblings) {
|
|
636
|
+
for (let s = at.prev; s; s = s.prev) {
|
|
637
|
+
if (!isTag(s))
|
|
638
|
+
continue;
|
|
639
|
+
for (const { match, siblings: apart } of this._anchorMatchers) {
|
|
640
|
+
if (apart && match(s)) {
|
|
641
|
+
into.push(s);
|
|
642
|
+
break;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
const parent = at.parent;
|
|
648
|
+
at = parent && isTag(parent) ? parent : null;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
_noteHover(selector) {
|
|
652
|
+
if (!/:(?:hover|active)/i.test(selector))
|
|
653
|
+
return;
|
|
654
|
+
const found = pointerCompounds(selector);
|
|
655
|
+
if (found.nested)
|
|
656
|
+
this.hoverLocal = false;
|
|
657
|
+
if (found.siblings)
|
|
658
|
+
this.hoverSiblings = true;
|
|
659
|
+
for (const c of found.compounds)
|
|
660
|
+
this._hoverCompounds.add(c);
|
|
661
|
+
for (const { anchor, siblings } of found.has) {
|
|
662
|
+
this._hoverAnchors.set(anchor, siblings || (this._hoverAnchors.get(anchor) ?? false));
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
/** A selector compiled as a rule's is, or null where css-select refuses
|
|
666
|
+
* it, as a rule it refuses drops out of the cascade. */
|
|
667
|
+
_compile(selector) {
|
|
668
|
+
try {
|
|
669
|
+
return compileSelector(selector, this._adapter);
|
|
670
|
+
}
|
|
671
|
+
catch {
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
222
675
|
/** Which media band a device-pixel width falls in. Two widths in the same
|
|
223
676
|
* band produce identical styles, which is what lets a resize skip
|
|
224
677
|
* restyling. */
|
|
@@ -233,14 +686,323 @@ export class Cascade {
|
|
|
233
686
|
}
|
|
234
687
|
return band;
|
|
235
688
|
}
|
|
689
|
+
/** Computed styles by sharing key, for one build (`sharedStyleFor`): one
|
|
690
|
+
* map for the elements shared without matching, one for the elements
|
|
691
|
+
* shared by what they matched. */
|
|
692
|
+
_shared = new Map();
|
|
693
|
+
_sharedByMatch = new Map();
|
|
694
|
+
_nextShareKey = 1;
|
|
695
|
+
/** Custom property sets by what made them, for one build (`_customFor`). */
|
|
696
|
+
_customs = new Map();
|
|
697
|
+
_ids = new WeakMap();
|
|
698
|
+
_nextId = 1;
|
|
699
|
+
/** A box tree is about to be built: the styles shared in the last build
|
|
700
|
+
* were computed against a pointer and a viewport that may have moved. */
|
|
701
|
+
beginSharing() {
|
|
702
|
+
this._shared.clear();
|
|
703
|
+
this._sharedByMatch.clear();
|
|
704
|
+
this._customs.clear();
|
|
705
|
+
}
|
|
236
706
|
/**
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
707
|
+
* An element's custom properties: its parent's, or its own over them —
|
|
708
|
+
* shared by every element whose parent has the same ones and whose own
|
|
709
|
+
* come from the same declarations. Tailwind 4 sets thirty-five of them on
|
|
710
|
+
* every element (`*, ::before, ::after { --tw-shadow: 0 0 #0000; … }`),
|
|
711
|
+
* and a set per element was a fifth of building the boxes; it also kept
|
|
712
|
+
* each element's `var()`s from being replaced once for its siblings,
|
|
713
|
+
* which `substituteIn` remembers by the set they were read against.
|
|
714
|
+
*/
|
|
715
|
+
_customFor(parentStyle, candidates) {
|
|
716
|
+
let key = '';
|
|
717
|
+
for (const c of candidates) {
|
|
718
|
+
if (!this._hasCustom(c))
|
|
719
|
+
continue;
|
|
720
|
+
key += `${this._idOf(c.declarations)}:${c.only},`;
|
|
721
|
+
}
|
|
722
|
+
const parent = parentStyle.custom;
|
|
723
|
+
if (!key)
|
|
724
|
+
return parent;
|
|
725
|
+
key = `${parent ? this._idOf(parent) : 0}|${key}`;
|
|
726
|
+
const hit = this._customs.get(key);
|
|
727
|
+
if (hit)
|
|
728
|
+
return hit;
|
|
729
|
+
const own = new Map();
|
|
730
|
+
for (const c of candidates) {
|
|
731
|
+
for (const d of pick(c))
|
|
732
|
+
if (d.custom)
|
|
733
|
+
own.set(d.prop, d.value);
|
|
734
|
+
}
|
|
735
|
+
const made = customProperties(own, parent);
|
|
736
|
+
this._customs.set(key, made);
|
|
737
|
+
return made;
|
|
738
|
+
}
|
|
739
|
+
/** Whether a candidate sets a custom property. */
|
|
740
|
+
_hasCustom(c) {
|
|
741
|
+
if (c.only >= 0)
|
|
742
|
+
return !!c.declarations[c.only].custom;
|
|
743
|
+
let has = CUSTOM_IN.get(c.declarations);
|
|
744
|
+
if (has === undefined) {
|
|
745
|
+
has = c.declarations.some((d) => !!d.custom);
|
|
746
|
+
CUSTOM_IN.set(c.declarations, has);
|
|
747
|
+
}
|
|
748
|
+
return has;
|
|
749
|
+
}
|
|
750
|
+
/** A number for an object, to key a string by. */
|
|
751
|
+
_idOf(of) {
|
|
752
|
+
let id = this._ids.get(of);
|
|
753
|
+
if (id === undefined) {
|
|
754
|
+
id = this._nextId++;
|
|
755
|
+
this._ids.set(of, id);
|
|
756
|
+
}
|
|
757
|
+
return id;
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* `styleFor`, shared between the elements that must compute the same
|
|
761
|
+
* style, with the key this element's children share under.
|
|
762
|
+
*
|
|
763
|
+
* A style is a function of the parent's style, the rules that match, the
|
|
764
|
+
* presentational attributes, the inline style and whether the parent is a
|
|
765
|
+
* flex container. Outside the rules `UNSHAREABLE` names, what matches
|
|
766
|
+
* depends only on the element's tag and attributes and its ancestors', and
|
|
767
|
+
* the hints read nothing else either. So the key is the parent's key, the
|
|
768
|
+
* flex flag, the tag and every attribute — plus the pointer state where a
|
|
769
|
+
* rule asks for it — and an element whose key has been computed in this
|
|
770
|
+
* build takes that style object, matching nothing. A long document is a
|
|
771
|
+
* few kinds of element many times over: the benchmark's 600 KB report is
|
|
772
|
+
* 9,039 elements and 110 keys, and computing every style again was a third
|
|
773
|
+
* of an edit.
|
|
774
|
+
*
|
|
775
|
+
* An element a rule `UNSHAREABLE` could reach is matched, since where it
|
|
776
|
+
* sits decides what matches — and then shared by what matched: the same
|
|
777
|
+
* parent, attributes and rules make the same style. That is what keeps a
|
|
778
|
+
* striped table from being a style per row, and it keeps the key its
|
|
779
|
+
* children share under, which an element-per-key would have taken from the
|
|
780
|
+
* whole subtree.
|
|
781
|
+
*
|
|
782
|
+
* The style is handed out shared, so nothing may write to it — nothing
|
|
783
|
+
* does after the cascade, and `rootStyle` does not go through here.
|
|
784
|
+
*/
|
|
785
|
+
sharedStyleFor(el, parentStyle, parentKey, inFlexContainer) {
|
|
786
|
+
let key = `${parentKey}\u0001${inFlexContainer ? 1 : 0}`;
|
|
787
|
+
const tag = tagOf(el);
|
|
788
|
+
key += `\u0001${tag.length}:${tag}`;
|
|
789
|
+
if (this._index.hoverSensitive) {
|
|
790
|
+
if (this._pointer.hovered.has(el))
|
|
791
|
+
key += '\u0001:hover';
|
|
792
|
+
if (this._pointer.active.has(el))
|
|
793
|
+
key += '\u0001:active';
|
|
794
|
+
}
|
|
795
|
+
const attribs = el.attribs;
|
|
796
|
+
for (const name in attribs) {
|
|
797
|
+
const value = attribs[name];
|
|
798
|
+
key += `\u0001${name.length}:${name}=${value.length}:${value}`;
|
|
799
|
+
}
|
|
800
|
+
if (!this._shareable(el)) {
|
|
801
|
+
const matched = [];
|
|
802
|
+
const candidates = this._candidates(el, matched);
|
|
803
|
+
key += `\u0001${matched.join(',')}`;
|
|
804
|
+
let shared = this._sharedByMatch.get(key);
|
|
805
|
+
if (shared === undefined) {
|
|
806
|
+
shared = {
|
|
807
|
+
style: this._computeStyle(el, parentStyle, inFlexContainer, candidates),
|
|
808
|
+
key: this._nextShareKey++,
|
|
809
|
+
};
|
|
810
|
+
this._sharedByMatch.set(key, shared);
|
|
811
|
+
}
|
|
812
|
+
return shared;
|
|
813
|
+
}
|
|
814
|
+
let shared = this._shared.get(key);
|
|
815
|
+
if (shared === undefined) {
|
|
816
|
+
shared = {
|
|
817
|
+
style: this.styleFor(el, parentStyle, inFlexContainer),
|
|
818
|
+
key: this._nextShareKey++,
|
|
819
|
+
};
|
|
820
|
+
this._shared.set(key, shared);
|
|
821
|
+
}
|
|
822
|
+
return shared;
|
|
823
|
+
}
|
|
824
|
+
/** Whether no rule `UNSHAREABLE` names could reach this element: the same
|
|
825
|
+
* buckets `_candidates` looks in. */
|
|
826
|
+
_shareable(el) {
|
|
827
|
+
const index = this._index;
|
|
828
|
+
if (index.ownStyleEverywhere)
|
|
829
|
+
return false;
|
|
830
|
+
if (index.ownStyleTags.size && index.ownStyleTags.has(tagOf(el))) {
|
|
831
|
+
return false;
|
|
832
|
+
}
|
|
833
|
+
if (index.ownStyleIds.size) {
|
|
834
|
+
const id = attr(el, 'id');
|
|
835
|
+
if (id && index.ownStyleIds.has(id))
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
838
|
+
if (index.ownStyleClasses.size) {
|
|
839
|
+
const className = attr(el, 'class');
|
|
840
|
+
if (className) {
|
|
841
|
+
for (const name of className.split(/\s+/)) {
|
|
842
|
+
if (name && index.ownStyleClasses.has(name))
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
return true;
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* The computed style for one element, given its parent's. The box builder
|
|
851
|
+
* asks for every element in document order, through `sharedStyleFor`, so
|
|
852
|
+
* a style is computed only for the elements with none to share.
|
|
240
853
|
*/
|
|
241
854
|
styleFor(el, parentStyle, inFlexContainer) {
|
|
855
|
+
return this._computeStyle(el, parentStyle, inFlexContainer, this._candidates(el));
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* The style of an element's `::before` or `::after`, or null when it has
|
|
859
|
+
* none: no rule reaches it, or the rules that do leave `content` at
|
|
860
|
+
* `normal` or `none`, which make no box (CSS 2.1 12.2). It inherits from
|
|
861
|
+
* the element's own style, as a pseudo-element does, and a flex
|
|
862
|
+
* container's are flex items. Not shared: few elements have one, and where
|
|
863
|
+
* a rule gives every element one — a clearfix — the style is the cost of
|
|
864
|
+
* the box it makes.
|
|
865
|
+
*/
|
|
866
|
+
pseudoStyleFor(el, which, elementStyle) {
|
|
867
|
+
const index = this._pseudo[which];
|
|
868
|
+
if (!index.size || !index.reaches(el))
|
|
869
|
+
return null;
|
|
870
|
+
const candidates = [];
|
|
871
|
+
this._matchInto(index, el, candidates);
|
|
872
|
+
if (!candidates.length)
|
|
873
|
+
return null;
|
|
874
|
+
// One that no rule gives a `content` is none, whatever else reaches it —
|
|
875
|
+
// `content` is not inherited, and its initial `normal` is nothing here.
|
|
876
|
+
// Tailwind's `*, ::before, ::after` reaches both of every element's.
|
|
877
|
+
if (!candidates.some(setsContent))
|
|
878
|
+
return null;
|
|
879
|
+
candidates.sort(byCascade);
|
|
880
|
+
const style = this._computeStyle(el, elementStyle, elementStyle.display === 'flex' || elementStyle.display === 'inline-flex', candidates);
|
|
881
|
+
return style.content === 'normal' || style.content === 'none'
|
|
882
|
+
? null
|
|
883
|
+
: style;
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* The rules for an element's `::first-letter`, or null when none reaches
|
|
887
|
+
* it. They are matched against the element here, and its style computed
|
|
888
|
+
* later by `firstLetterStyle`, because the pseudo-element inherits from
|
|
889
|
+
* the box its letter turns out to be in — a `<span>` the block opens with,
|
|
890
|
+
* a `::before` — which the builder has not reached yet.
|
|
891
|
+
*/
|
|
892
|
+
firstLetterRules(el) {
|
|
893
|
+
const index = this._pseudo['first-letter'];
|
|
894
|
+
if (!index.size || !index.reaches(el))
|
|
895
|
+
return null;
|
|
896
|
+
const candidates = [];
|
|
897
|
+
this._matchInto(index, el, candidates);
|
|
898
|
+
if (!candidates.length)
|
|
899
|
+
return null;
|
|
900
|
+
candidates.sort(byCascade);
|
|
901
|
+
return { el, candidates };
|
|
902
|
+
}
|
|
903
|
+
/** Whether any rule styles a `::first-line`: a document with none asks
|
|
904
|
+
* nothing more of its blocks. */
|
|
905
|
+
get hasFirstLine() {
|
|
906
|
+
return this._pseudo['first-line'].size > 0;
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* A list item's `::marker` style, inheriting from its own, or null when no
|
|
910
|
+
* rule reaches it (CSS Lists 3, 3.1): the colour and the font a bullet or
|
|
911
|
+
* a number is set in, and a `content` it is set as instead.
|
|
912
|
+
*/
|
|
913
|
+
markerStyle(el, style) {
|
|
914
|
+
const index = this._pseudo.marker;
|
|
915
|
+
if (!index.size || !index.reaches(el))
|
|
916
|
+
return null;
|
|
917
|
+
const candidates = [];
|
|
918
|
+
this._matchInto(index, el, candidates);
|
|
919
|
+
if (!candidates.length)
|
|
920
|
+
return null;
|
|
921
|
+
candidates.sort(byCascade);
|
|
922
|
+
const out = this._computeStyle(el, style, false, candidates);
|
|
923
|
+
// a marker's direction is its own unless a rule says otherwise (the
|
|
924
|
+
// HTML style sheet's `::marker { unicode-bidi: isolate }`)
|
|
925
|
+
const set = candidates.some((c) => c.declarations.some((d) => d.prop === 'unicode-bidi'));
|
|
926
|
+
if (!set)
|
|
927
|
+
out.unicodeBidi = 'isolate';
|
|
928
|
+
return out;
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* An element's `::first-line` style, inheriting from its own, or null
|
|
932
|
+
* when no rule reaches it (CSS 2.1 5.12.1).
|
|
933
|
+
*/
|
|
934
|
+
firstLineStyle(el, style) {
|
|
935
|
+
const index = this._pseudo['first-line'];
|
|
936
|
+
if (!index.size)
|
|
937
|
+
return null;
|
|
938
|
+
const candidates = [];
|
|
939
|
+
this._matchInto(index, el, candidates);
|
|
940
|
+
if (!candidates.length)
|
|
941
|
+
return null;
|
|
942
|
+
candidates.sort(byCascade);
|
|
943
|
+
return this._computeStyle(el, style, false, candidates);
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* The style of a `::first-letter` inside a box of `parentStyle`. It is an
|
|
947
|
+
* inline box, or a float where it floats, whatever the rules say of its
|
|
948
|
+
* `display` or its `position` (CSS 2.1 5.12.2).
|
|
949
|
+
*/
|
|
950
|
+
firstLetterStyle(rules, parentStyle) {
|
|
951
|
+
const style = this._computeStyle(rules.el, parentStyle, false, rules.candidates);
|
|
952
|
+
style.display = style.float === 'none' ? 'inline' : 'block';
|
|
953
|
+
style.position = 'static';
|
|
954
|
+
return style;
|
|
955
|
+
}
|
|
956
|
+
/** The x-height of a style's font: the font's own, asked once per face
|
|
957
|
+
* and size, or half an em. */
|
|
958
|
+
_exOf(style) {
|
|
959
|
+
const key = `${style.fontFamily}\u0001${style.fontSize}`;
|
|
960
|
+
let ex = this._xHeights.get(key);
|
|
961
|
+
if (ex === undefined) {
|
|
962
|
+
ex = this._xHeightOf?.(style.fontFamily, style.fontSize) ?? NaN;
|
|
963
|
+
if (!(ex > 0))
|
|
964
|
+
ex = style.fontSize * 0.5;
|
|
965
|
+
this._xHeights.set(key, ex);
|
|
966
|
+
}
|
|
967
|
+
return ex;
|
|
968
|
+
}
|
|
969
|
+
/** The advance of a style's font's "0": the font's own, asked once per
|
|
970
|
+
* face and size, or half an em. */
|
|
971
|
+
_chOf(style) {
|
|
972
|
+
const key = `${style.fontFamily}\u0001${style.fontSize}`;
|
|
973
|
+
let ch = this._zeroWidths.get(key);
|
|
974
|
+
if (ch === undefined) {
|
|
975
|
+
ch = this._zeroWidthOf?.(style.fontFamily, style.fontSize) ?? NaN;
|
|
976
|
+
if (!(ch > 0))
|
|
977
|
+
ch = style.fontSize * 0.5;
|
|
978
|
+
this._zeroWidths.set(key, ch);
|
|
979
|
+
}
|
|
980
|
+
return ch;
|
|
981
|
+
}
|
|
982
|
+
/** A style's computed line height as a length, for `lh`: `normal` as
|
|
983
|
+
* its font's own, asked once per face and size, or 1.2em. */
|
|
984
|
+
_lineHeightOf(style) {
|
|
985
|
+
const set = style.lineHeight;
|
|
986
|
+
if (set !== 'normal') {
|
|
987
|
+
return style.lineHeightIsLength ? set : set * style.fontSize;
|
|
988
|
+
}
|
|
989
|
+
const key = `${style.fontFamily}\u0001${style.fontSize}`;
|
|
990
|
+
let line = this._normalLines.get(key);
|
|
991
|
+
if (line === undefined) {
|
|
992
|
+
line = this._normalLineOf?.(style.fontFamily, style.fontSize) ?? NaN;
|
|
993
|
+
if (!(line > 0))
|
|
994
|
+
line = style.fontSize * 1.2;
|
|
995
|
+
this._normalLines.set(key, line);
|
|
996
|
+
}
|
|
997
|
+
return line;
|
|
998
|
+
}
|
|
999
|
+
/** `styleFor`, from the rules and hints already gathered for `el`. */
|
|
1000
|
+
_computeStyle(el, parentStyle, inFlexContainer, candidates) {
|
|
242
1001
|
const style = inherit(parentStyle, this.initial);
|
|
243
|
-
|
|
1002
|
+
// custom properties first, in cascade order, so every `var()` in the
|
|
1003
|
+
// declarations below finds the one that wins
|
|
1004
|
+
if (this._vars)
|
|
1005
|
+
style.custom = this._customFor(parentStyle, candidates);
|
|
244
1006
|
// The unit context has to be built twice: once with the parent's font
|
|
245
1007
|
// size, so a `font-size: 1.2em` in the cascade resolves against the
|
|
246
1008
|
// right em, and again after the font size is settled so every *other*
|
|
@@ -248,28 +1010,123 @@ export class Cascade {
|
|
|
248
1010
|
const ctxParent = {
|
|
249
1011
|
em: parentStyle.fontSize,
|
|
250
1012
|
rem: this.initial.fontSize,
|
|
1013
|
+
initial: this.initial,
|
|
251
1014
|
vw: this.viewportWidth,
|
|
252
1015
|
vh: this.viewportHeight,
|
|
253
1016
|
scale: this.scale,
|
|
1017
|
+
ex: () => this._exOf(parentStyle),
|
|
1018
|
+
ch: () => this._chOf(parentStyle),
|
|
1019
|
+
families: this._mapFamilies,
|
|
1020
|
+
lh: () => this._lineHeightOf(parentStyle),
|
|
1021
|
+
rlh: () => this._lineHeightOf(this.initial),
|
|
254
1022
|
};
|
|
1023
|
+
// the family goes with the size, so an `ex` after it is its font's
|
|
1024
|
+
let sized = false;
|
|
1025
|
+
let keyword = false;
|
|
255
1026
|
for (const c of candidates) {
|
|
256
1027
|
for (const d of pick(c)) {
|
|
257
|
-
if (d.prop === 'font-
|
|
258
|
-
|
|
1028
|
+
if (d.prop === 'font-family') {
|
|
1029
|
+
this._apply(style, parentStyle, d, ctxParent);
|
|
1030
|
+
}
|
|
1031
|
+
else if (d.prop === 'font-size' || d.prop === 'font') {
|
|
1032
|
+
// NaN until a size is set, so one the declaration did not take
|
|
1033
|
+
// leaves the size where it was, and says nothing of it
|
|
1034
|
+
const was = style.fontSize;
|
|
1035
|
+
style.fontSize = NaN;
|
|
1036
|
+
this._apply(style, parentStyle, d, ctxParent);
|
|
1037
|
+
if (Number.isNaN(style.fontSize)) {
|
|
1038
|
+
style.fontSize = was;
|
|
1039
|
+
}
|
|
1040
|
+
else {
|
|
1041
|
+
sized = true;
|
|
1042
|
+
keyword = !d.vars && sizeKeyword(d.prop, d.value);
|
|
1043
|
+
}
|
|
259
1044
|
}
|
|
260
1045
|
}
|
|
261
1046
|
}
|
|
262
|
-
|
|
1047
|
+
// The generic `monospace` on its own has a smaller size than the rest,
|
|
1048
|
+
// 13 pixels to their 16 (the "fixed" font size every browser keeps):
|
|
1049
|
+
// an element whose family becomes it, or stops being it, scales the
|
|
1050
|
+
// size it inherits by that, and a keyword size is read from the
|
|
1051
|
+
// smaller scale — the size it sets itself stays its own. Blink's
|
|
1052
|
+
// CheckForGenericFamilyChange, and why a `<pre>` in a browser is 13px.
|
|
1053
|
+
const mono = monospaceOnly(style.fontFamily);
|
|
1054
|
+
if (sized ? keyword && mono : mono !== monospaceOnly(parentStyle.fontFamily)) {
|
|
1055
|
+
style.fontSize *= mono ? FIXED_SIZE : 1 / FIXED_SIZE;
|
|
1056
|
+
}
|
|
1057
|
+
const ctx = {
|
|
1058
|
+
...ctxParent,
|
|
1059
|
+
em: style.fontSize,
|
|
1060
|
+
ex: () => this._exOf(style),
|
|
1061
|
+
ch: () => this._chOf(style),
|
|
1062
|
+
lh: () => this._lineHeightOf(style),
|
|
1063
|
+
};
|
|
1064
|
+
// the line height, which an `lh` in any other declaration reads, ahead
|
|
1065
|
+
// of them: set again with the rest, in its place among them
|
|
1066
|
+
if (this._lh) {
|
|
1067
|
+
for (const c of candidates) {
|
|
1068
|
+
for (const d of pick(c)) {
|
|
1069
|
+
if (d.prop === 'line-height')
|
|
1070
|
+
this._apply(style, parentStyle, d, ctx);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
const settled = style.fontSize;
|
|
263
1075
|
for (const c of candidates) {
|
|
264
1076
|
for (const d of pick(c)) {
|
|
265
|
-
if (d.prop === 'font-size')
|
|
1077
|
+
if (d.prop === 'font-size' || d.custom)
|
|
266
1078
|
continue;
|
|
267
|
-
|
|
1079
|
+
this._apply(style, parentStyle, d, ctx);
|
|
268
1080
|
}
|
|
269
1081
|
}
|
|
1082
|
+
// A `font` is applied again, to keep its other longhands in cascade
|
|
1083
|
+
// order, and it sets the size it names as well: the size is the first
|
|
1084
|
+
// pass's, which the declarations that outrank the `font` had their say
|
|
1085
|
+
// in, and the scale after them. `span { font: 15px/1 Ahem }` under
|
|
1086
|
+
// `.b > span { font-size: 3.75em }` was 15px, its `em`s 3.75 of its
|
|
1087
|
+
// parent's.
|
|
1088
|
+
style.fontSize = settled;
|
|
1089
|
+
// A table never keeps HTML's alignment, `-webkit-center` and its kin:
|
|
1090
|
+
// the `<td align="center">` every mail centres its body table in
|
|
1091
|
+
// centres the table, and the text in its cells stays at their start —
|
|
1092
|
+
// as Blink resets it ("tables never support the -webkit-* values for
|
|
1093
|
+
// text-align"). An author's own `text-align: center` is not HTML's, and
|
|
1094
|
+
// is inherited into the table as it always was.
|
|
1095
|
+
if (style.alignBlocks !== null && tagOf(el) === 'table') {
|
|
1096
|
+
style.textAlign = 'start';
|
|
1097
|
+
style.alignBlocks = null;
|
|
1098
|
+
}
|
|
1099
|
+
settleClamp(style, parentStyle);
|
|
1100
|
+
settleOverflow(style);
|
|
1101
|
+
settleContentVisibility(style);
|
|
270
1102
|
blockify(style, inFlexContainer);
|
|
1103
|
+
decorate(style);
|
|
1104
|
+
// which faces of the document's own families this family, weight and
|
|
1105
|
+
// slant ask for — known only now, with all three computed
|
|
1106
|
+
this._families?.note(style);
|
|
271
1107
|
return style;
|
|
272
1108
|
}
|
|
1109
|
+
/** One declaration, its `var()`s replaced first. One that names a
|
|
1110
|
+
* custom property with no value, and has no fallback, is invalid at
|
|
1111
|
+
* computed-value time, and the property is as though `unset`. */
|
|
1112
|
+
_apply(style, parentStyle, d, ctx) {
|
|
1113
|
+
if (!d.vars) {
|
|
1114
|
+
applyDeclaration(style, parentStyle, d.prop, d.value, ctx);
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
// unset first: a value that does not parse once it is substituted is
|
|
1118
|
+
// invalid at computed-value time, and does not leave the property what
|
|
1119
|
+
// an earlier declaration gave it
|
|
1120
|
+
if (isInherited(d.prop)) {
|
|
1121
|
+
applyDeclaration(style, parentStyle, d.prop, 'inherit', ctx);
|
|
1122
|
+
}
|
|
1123
|
+
else {
|
|
1124
|
+
initialOne(style, this.initial, d.prop);
|
|
1125
|
+
}
|
|
1126
|
+
const value = substituteIn(d.value, style.custom);
|
|
1127
|
+
if (value !== null)
|
|
1128
|
+
applyDeclaration(style, parentStyle, d.prop, value, ctx);
|
|
1129
|
+
}
|
|
273
1130
|
/**
|
|
274
1131
|
* The root's style — nothing above it to inherit from.
|
|
275
1132
|
*
|
|
@@ -278,24 +1135,37 @@ export class Cascade {
|
|
|
278
1135
|
* a `<body>` would have had: the UA sheet's margin and font, and any
|
|
279
1136
|
* author `body { … }` rule. Without it a fragment renders hard against the
|
|
280
1137
|
* 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.
|
|
1138
|
+
* reads as a bug in the renderer rather than as a missing element. With
|
|
1139
|
+
* no `<html>` either, the body inherits from an `<html>` that author
|
|
1140
|
+
* `html { … }` rules have styled, as the one a browser implies would be.
|
|
1141
|
+
*
|
|
1142
|
+
* A document with a `<body>` and no `<html>` — the usual shape of a page
|
|
1143
|
+
* that starts `<!DOCTYPE html><title>` — has the root box standing in for
|
|
1144
|
+
* that implied `<html>` instead, so an `html { font-size }` still reaches
|
|
1145
|
+
* the body. Taken as the initial style, the rule matched nothing and the
|
|
1146
|
+
* whole page came out at the theme's size.
|
|
282
1147
|
*/
|
|
283
|
-
rootStyle(hasBody) {
|
|
284
|
-
const style =
|
|
1148
|
+
rootStyle(hasBody, hasHtml = true) {
|
|
1149
|
+
const style = copyStyle(this.initial);
|
|
285
1150
|
style.display = 'block';
|
|
286
|
-
if (hasBody)
|
|
1151
|
+
if (hasBody && hasHtml)
|
|
287
1152
|
return style;
|
|
288
1153
|
const synthetic = new DomElement('body', {}, []);
|
|
289
|
-
|
|
1154
|
+
let parent = style;
|
|
1155
|
+
if (!hasHtml) {
|
|
1156
|
+
const html = new DomElement('html', {}, hasBody ? [] : [synthetic]);
|
|
1157
|
+
synthetic.parent = html;
|
|
1158
|
+
parent = this.styleFor(html, style, false);
|
|
1159
|
+
if (hasBody)
|
|
1160
|
+
return asRoot(parent);
|
|
1161
|
+
}
|
|
290
1162
|
// Only the box the body would have drawn is taken, not its layout role:
|
|
291
1163
|
// the root is still the initial containing block.
|
|
292
|
-
|
|
293
|
-
bodyStyle.position = 'static';
|
|
294
|
-
bodyStyle.float = 'none';
|
|
295
|
-
return bodyStyle;
|
|
1164
|
+
return asRoot(this.styleFor(synthetic, parent, false));
|
|
296
1165
|
}
|
|
297
|
-
|
|
298
|
-
|
|
1166
|
+
/** The rules of `index` that match `el`, pushed onto `out` as candidates,
|
|
1167
|
+
* and their ids onto `matched` in the order they were tried. */
|
|
1168
|
+
_matchInto(index, el, out, matched) {
|
|
299
1169
|
// A media query's width is CSS pixels; the viewport is kept in device.
|
|
300
1170
|
const width = this.viewportWidth / this.scale;
|
|
301
1171
|
const consider = (bucket) => {
|
|
@@ -308,10 +1178,7 @@ export class Cascade {
|
|
|
308
1178
|
if (!indexed.compiled) {
|
|
309
1179
|
indexed.compiled = true;
|
|
310
1180
|
try {
|
|
311
|
-
indexed.match =
|
|
312
|
-
adapter: this._adapter,
|
|
313
|
-
xmlMode: false,
|
|
314
|
-
});
|
|
1181
|
+
indexed.match = compileSelector(rule.selector, this._adapter);
|
|
315
1182
|
}
|
|
316
1183
|
catch {
|
|
317
1184
|
// A selector this matcher does not know (`::-moz-…`, a CSS4 form
|
|
@@ -322,26 +1189,35 @@ export class Cascade {
|
|
|
322
1189
|
}
|
|
323
1190
|
if (!indexed.match || !indexed.match(el))
|
|
324
1191
|
continue;
|
|
1192
|
+
matched?.push(indexed.id);
|
|
325
1193
|
const origin = rule.order < 0 ? Origin.UserAgent : Origin.Author;
|
|
326
1194
|
pushRule(out, rule, origin);
|
|
327
1195
|
}
|
|
328
1196
|
};
|
|
329
1197
|
const id = attr(el, 'id');
|
|
330
1198
|
if (id)
|
|
331
|
-
consider(
|
|
1199
|
+
consider(index.byId.get(id));
|
|
332
1200
|
const className = attr(el, 'class');
|
|
333
1201
|
if (className) {
|
|
334
1202
|
for (const name of className.split(/\s+/)) {
|
|
335
1203
|
if (name)
|
|
336
|
-
consider(
|
|
1204
|
+
consider(index.byClass.get(name));
|
|
337
1205
|
}
|
|
338
1206
|
}
|
|
339
|
-
consider(
|
|
340
|
-
consider(
|
|
1207
|
+
consider(index.byTag.get(tagOf(el)));
|
|
1208
|
+
consider(index.universal);
|
|
1209
|
+
}
|
|
1210
|
+
/** Every rule and hint that applies to `el`, in cascade order — and, into
|
|
1211
|
+
* `matched` when it is passed, the ids of the rules, in the order they
|
|
1212
|
+
* were tried. */
|
|
1213
|
+
_candidates(el, matched) {
|
|
1214
|
+
const out = [];
|
|
1215
|
+
this._matchInto(this._index, el, out, matched);
|
|
341
1216
|
const hints = presentationHints(el);
|
|
342
1217
|
if (hints.length) {
|
|
343
1218
|
out.push({
|
|
344
1219
|
origin: Origin.Presentation,
|
|
1220
|
+
layer: null,
|
|
345
1221
|
specificity: 0,
|
|
346
1222
|
order: 0,
|
|
347
1223
|
declarations: hints,
|
|
@@ -351,11 +1227,17 @@ export class Cascade {
|
|
|
351
1227
|
const inline = attr(el, 'style');
|
|
352
1228
|
if (inline) {
|
|
353
1229
|
const declarations = parseDeclarations(inline);
|
|
1230
|
+
if (!this._vars && usesVars(declarations))
|
|
1231
|
+
this._vars = true;
|
|
1232
|
+
this._noteViewportUnits(declarations);
|
|
1233
|
+
if (!this._lh && usesLh(declarations))
|
|
1234
|
+
this._lh = true;
|
|
354
1235
|
const normal = declarations.filter((d) => !d.important);
|
|
355
1236
|
const important = declarations.filter((d) => d.important);
|
|
356
1237
|
if (normal.length) {
|
|
357
1238
|
out.push({
|
|
358
1239
|
origin: Origin.Inline,
|
|
1240
|
+
layer: null,
|
|
359
1241
|
specificity: 0,
|
|
360
1242
|
order: 0,
|
|
361
1243
|
declarations: normal,
|
|
@@ -365,6 +1247,7 @@ export class Cascade {
|
|
|
365
1247
|
if (important.length) {
|
|
366
1248
|
out.push({
|
|
367
1249
|
origin: Origin.InlineImportant,
|
|
1250
|
+
layer: null,
|
|
368
1251
|
specificity: 0,
|
|
369
1252
|
order: 0,
|
|
370
1253
|
declarations: important,
|
|
@@ -376,6 +1259,144 @@ export class Cascade {
|
|
|
376
1259
|
return out;
|
|
377
1260
|
}
|
|
378
1261
|
}
|
|
1262
|
+
/** An implied element's style as the root box's: its look, not its role —
|
|
1263
|
+
* the root is still a block, in flow, and the initial containing block. */
|
|
1264
|
+
function asRoot(style) {
|
|
1265
|
+
style.display = 'block';
|
|
1266
|
+
style.position = 'static';
|
|
1267
|
+
style.float = 'none';
|
|
1268
|
+
return style;
|
|
1269
|
+
}
|
|
1270
|
+
/** `:root` is the `<html>` element: the one a browser implies around a
|
|
1271
|
+
* fragment, whose style the root box takes (`rootStyle`), and never a
|
|
1272
|
+
* fragment's top-level elements, which css-select would take for it. */
|
|
1273
|
+
const PSEUDOS = {
|
|
1274
|
+
root: (el) => el.name === 'html' && !(el.parent && isTag(el.parent)),
|
|
1275
|
+
// css-select's, but its ranges and tags lower-cased as ASCII has it, and
|
|
1276
|
+
// no other script (CSS 2.1 4.1.3): Unicode's took `:lang(\u212Al)`, a
|
|
1277
|
+
// Kelvin sign for the K, for `:lang(kl)`
|
|
1278
|
+
lang: (el, code) => {
|
|
1279
|
+
const ranges = (code ?? '')
|
|
1280
|
+
.split(',')
|
|
1281
|
+
.map((range) => range.trim().replace(/^['"]|['"]$/g, ''))
|
|
1282
|
+
.filter((range) => range.length > 0)
|
|
1283
|
+
.map((range) => asciiLower(range).split('-'));
|
|
1284
|
+
let root = el;
|
|
1285
|
+
for (let node = el; node;) {
|
|
1286
|
+
const value = node.attribs['xml:lang'] ?? node.attribs.lang;
|
|
1287
|
+
if (value != null) {
|
|
1288
|
+
if (!value)
|
|
1289
|
+
return ranges.some((range) => range[0] === '');
|
|
1290
|
+
const tag = asciiLower(value).split('-');
|
|
1291
|
+
return ranges.some((range) => langRangeMatches(tag, range));
|
|
1292
|
+
}
|
|
1293
|
+
root = node;
|
|
1294
|
+
const parent = node.parent;
|
|
1295
|
+
node = parent && isTag(parent) ? parent : null;
|
|
1296
|
+
}
|
|
1297
|
+
// with no element saying, the document's, as its `<meta>` sets it —
|
|
1298
|
+
// searched from the document, where a fragment's `<meta>` is a
|
|
1299
|
+
// sibling of what it covers
|
|
1300
|
+
const pragma = pragmaLanguage(root.parent ?? root);
|
|
1301
|
+
if (!pragma)
|
|
1302
|
+
return ranges.some((range) => range[0] === '');
|
|
1303
|
+
const tag = asciiLower(pragma).split('-');
|
|
1304
|
+
return ranges.some((range) => langRangeMatches(tag, range));
|
|
1305
|
+
},
|
|
1306
|
+
};
|
|
1307
|
+
/** A length in a unit of the viewport: a number, then the unit, and no
|
|
1308
|
+
* more of a name after it. */
|
|
1309
|
+
const VIEWPORT_UNIT = /\d(?:vw|vh|vmin|vmax)(?![\w-])/i;
|
|
1310
|
+
const VIEWPORT_UNITS = /\d(vw|vh|vmin|vmax)(?![\w-])/gi;
|
|
1311
|
+
/**
|
|
1312
|
+
* A selector with its `[attr~=""]` made one that matches nothing: an empty
|
|
1313
|
+
* string is no word of a list, and such a selector represents nothing
|
|
1314
|
+
* (Selectors 3, 6.3.1) — which the matcher's `~=` is not told, taking the
|
|
1315
|
+
* empty word for one between two spaces, or at either end of none.
|
|
1316
|
+
*/
|
|
1317
|
+
function noEmptyWords(selector) {
|
|
1318
|
+
if (!selector.includes('~='))
|
|
1319
|
+
return selector;
|
|
1320
|
+
return selector.replace(/\[[^\]"']*~=\s*(?:""|'')\s*(?:[is]\s*)?\]/gi, ':not(*)');
|
|
1321
|
+
}
|
|
1322
|
+
/**
|
|
1323
|
+
* A document's language as a `<meta http-equiv="content-language">` sets
|
|
1324
|
+
* it — HTML's pragma-set default language, the last such `<meta>`'s
|
|
1325
|
+
* `content` up to its first white space, and none where it lists more
|
|
1326
|
+
* than one — by the document's root element, found once.
|
|
1327
|
+
*/
|
|
1328
|
+
function pragmaLanguage(root) {
|
|
1329
|
+
let lang = PRAGMA_LANGUAGE.get(root);
|
|
1330
|
+
if (lang !== undefined)
|
|
1331
|
+
return lang;
|
|
1332
|
+
lang = '';
|
|
1333
|
+
const stack = [root];
|
|
1334
|
+
while (stack.length) {
|
|
1335
|
+
const node = stack.pop();
|
|
1336
|
+
if (isTag(node) &&
|
|
1337
|
+
node.name === 'meta' &&
|
|
1338
|
+
node.attribs['http-equiv']?.trim().toLowerCase() === 'content-language') {
|
|
1339
|
+
const content = node.attribs.content;
|
|
1340
|
+
if (content !== undefined && !content.includes(',')) {
|
|
1341
|
+
const candidate = content.trim().split(/[\t\n\f\r ]/)[0];
|
|
1342
|
+
if (candidate)
|
|
1343
|
+
lang = candidate;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
// in document order: the last one pushed is taken first
|
|
1347
|
+
for (let i = node.children.length - 1; i >= 0; i -= 1) {
|
|
1348
|
+
const child = node.children[i];
|
|
1349
|
+
if (isTag(child))
|
|
1350
|
+
stack.push(child);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
PRAGMA_LANGUAGE.set(root, lang);
|
|
1354
|
+
return lang;
|
|
1355
|
+
}
|
|
1356
|
+
const PRAGMA_LANGUAGE = new WeakMap();
|
|
1357
|
+
/** RFC 4647's extended filtering, of a tag's subtags by a range's, as
|
|
1358
|
+
* css-select does it. */
|
|
1359
|
+
function langRangeMatches(tag, range) {
|
|
1360
|
+
if (range[0] !== '*' && range[0] !== tag[0])
|
|
1361
|
+
return false;
|
|
1362
|
+
let at = 1;
|
|
1363
|
+
for (let r = 1; r < range.length; r += 1) {
|
|
1364
|
+
if (range[r] === '*')
|
|
1365
|
+
continue;
|
|
1366
|
+
while (at < tag.length && tag[at] !== range[r]) {
|
|
1367
|
+
if (tag[at++].length <= 1)
|
|
1368
|
+
return false;
|
|
1369
|
+
}
|
|
1370
|
+
if (at >= tag.length)
|
|
1371
|
+
return false;
|
|
1372
|
+
at += 1;
|
|
1373
|
+
}
|
|
1374
|
+
return true;
|
|
1375
|
+
}
|
|
1376
|
+
/** Whether any of these declarations sets a custom property or reads one. */
|
|
1377
|
+
function usesVars(declarations) {
|
|
1378
|
+
for (const d of declarations)
|
|
1379
|
+
if (d.custom || d.vars)
|
|
1380
|
+
return true;
|
|
1381
|
+
return false;
|
|
1382
|
+
}
|
|
1383
|
+
/** Whether any of the declarations has a length in `lh` or `rlh`. */
|
|
1384
|
+
function usesLh(declarations) {
|
|
1385
|
+
for (const d of declarations)
|
|
1386
|
+
if (LH.test(d.value))
|
|
1387
|
+
return true;
|
|
1388
|
+
return false;
|
|
1389
|
+
}
|
|
1390
|
+
const LH = /\d\.?r?lh\b/i;
|
|
1391
|
+
/** Whether a candidate declares `content`. */
|
|
1392
|
+
function setsContent(c) {
|
|
1393
|
+
for (const d of pick(c))
|
|
1394
|
+
if (d.prop === 'content')
|
|
1395
|
+
return true;
|
|
1396
|
+
return false;
|
|
1397
|
+
}
|
|
1398
|
+
/** Whether a rule's declarations set a custom property, by the array. */
|
|
1399
|
+
const CUSTOM_IN = new WeakMap();
|
|
379
1400
|
function pick(c) {
|
|
380
1401
|
return c.only < 0 ? c.declarations : [c.declarations[c.only]];
|
|
381
1402
|
}
|
|
@@ -390,6 +1411,7 @@ function pushRule(out, rule, origin) {
|
|
|
390
1411
|
if (!hasImportant) {
|
|
391
1412
|
out.push({
|
|
392
1413
|
origin,
|
|
1414
|
+
layer: rule.layer,
|
|
393
1415
|
specificity: rule.specificity,
|
|
394
1416
|
order: rule.order,
|
|
395
1417
|
declarations: rule.declarations,
|
|
@@ -407,6 +1429,7 @@ function pushRule(out, rule, origin) {
|
|
|
407
1429
|
? Origin.UserAgent
|
|
408
1430
|
: Origin.AuthorImportant
|
|
409
1431
|
: origin,
|
|
1432
|
+
layer: rule.layer,
|
|
410
1433
|
specificity: rule.specificity,
|
|
411
1434
|
order: rule.order,
|
|
412
1435
|
declarations: rule.declarations,
|
|
@@ -417,10 +1440,34 @@ function pushRule(out, rule, origin) {
|
|
|
417
1440
|
function byCascade(a, b) {
|
|
418
1441
|
if (a.origin !== b.origin)
|
|
419
1442
|
return a.origin - b.origin;
|
|
1443
|
+
if (a.layer !== b.layer) {
|
|
1444
|
+
// a later layer wins over an earlier one whatever the specificity, and
|
|
1445
|
+
// for `!important` an earlier one does (CSS Cascade 5, 6.4)
|
|
1446
|
+
const by = compareLayers(a.layer, b.layer);
|
|
1447
|
+
if (by !== 0)
|
|
1448
|
+
return a.origin >= Origin.AuthorImportant ? -by : by;
|
|
1449
|
+
}
|
|
420
1450
|
if (a.specificity !== b.specificity)
|
|
421
1451
|
return a.specificity - b.specificity;
|
|
422
1452
|
return a.order - b.order;
|
|
423
1453
|
}
|
|
1454
|
+
/**
|
|
1455
|
+
* Which of two layers wins for a normal declaration: a later one over an
|
|
1456
|
+
* earlier one, and a rule in no layer over any, as a rule directly in a
|
|
1457
|
+
* layer is over the layers inside it.
|
|
1458
|
+
*/
|
|
1459
|
+
function compareLayers(a, b) {
|
|
1460
|
+
if (a === null)
|
|
1461
|
+
return b === null ? 0 : 1;
|
|
1462
|
+
if (b === null)
|
|
1463
|
+
return -1;
|
|
1464
|
+
const n = Math.min(a.length, b.length);
|
|
1465
|
+
for (let i = 0; i < n; i += 1) {
|
|
1466
|
+
if (a[i] !== b[i])
|
|
1467
|
+
return a[i] - b[i];
|
|
1468
|
+
}
|
|
1469
|
+
return b.length - a.length;
|
|
1470
|
+
}
|
|
424
1471
|
/**
|
|
425
1472
|
* The presentational attributes, as declarations. They sit above the UA
|
|
426
1473
|
* sheet and below every author rule, which is where HTML says they go — and
|
|
@@ -437,9 +1484,44 @@ function presentationHints(el) {
|
|
|
437
1484
|
const align = attr(el, 'align');
|
|
438
1485
|
if (align) {
|
|
439
1486
|
const v = align.toLowerCase();
|
|
440
|
-
|
|
1487
|
+
const side = v === 'middle' ? 'center' : v;
|
|
1488
|
+
if ((tag === 'img' || tag === 'table') && (v === 'left' || v === 'right')) {
|
|
441
1489
|
push('float', v);
|
|
442
|
-
|
|
1490
|
+
}
|
|
1491
|
+
else if (tag === 'img') {
|
|
1492
|
+
// an image's other alignments are its line's
|
|
1493
|
+
const va = IMAGE_ALIGN[v];
|
|
1494
|
+
if (va)
|
|
1495
|
+
push('vertical-align', va);
|
|
1496
|
+
}
|
|
1497
|
+
else if (tag === 'hr') {
|
|
1498
|
+
// a rule narrower than its line stands where it is aligned
|
|
1499
|
+
if (v === 'left') {
|
|
1500
|
+
push('margin-left', '0');
|
|
1501
|
+
push('margin-right', 'auto');
|
|
1502
|
+
}
|
|
1503
|
+
else if (v === 'right') {
|
|
1504
|
+
push('margin-left', 'auto');
|
|
1505
|
+
push('margin-right', '0');
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
else if (tag === 'table') {
|
|
1509
|
+
// a table's `align` places the table and leaves its text alone: set
|
|
1510
|
+
// as its text's, `<table align="center">` — the frame of nearly
|
|
1511
|
+
// every mail — stood at the left with its cells' text centred
|
|
1512
|
+
if (side === 'center') {
|
|
1513
|
+
push('margin-left', 'auto');
|
|
1514
|
+
push('margin-right', 'auto');
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
else if (ALIGNS_BLOCKS.has(tag) &&
|
|
1518
|
+
(side === 'center' || side === 'left' || side === 'right')) {
|
|
1519
|
+
// these align the blocks in them as well as their text (HTML's
|
|
1520
|
+
// rendering, "align descendants"): the table a `<td align="center">`
|
|
1521
|
+
// or a `<div align="center">` holds is centred in it
|
|
1522
|
+
push('text-align', `-webkit-${side}`);
|
|
1523
|
+
}
|
|
1524
|
+
else if (side === 'center')
|
|
443
1525
|
push('text-align', 'center');
|
|
444
1526
|
else if (v === 'left' || v === 'right' || v === 'justify')
|
|
445
1527
|
push('text-align', v);
|
|
@@ -447,9 +1529,42 @@ function presentationHints(el) {
|
|
|
447
1529
|
const valign = attr(el, 'valign');
|
|
448
1530
|
if (valign)
|
|
449
1531
|
push('vertical-align', valign.toLowerCase());
|
|
1532
|
+
// HTML's `dir` is its element's `direction`: `<table dir="rtl">` starts
|
|
1533
|
+
// at the right, and a Hebrew or an Arabic message is written this way
|
|
1534
|
+
const dir = attr(el, 'dir')?.toLowerCase();
|
|
1535
|
+
if (dir === 'rtl' || dir === 'ltr')
|
|
1536
|
+
push('direction', dir);
|
|
1537
|
+
// and it isolates the element from the text around it, or with `auto`
|
|
1538
|
+
// takes its first strong letter's direction (HTML's UA sheet: `[dir]`,
|
|
1539
|
+
// `[dir=auto i]`, `bdo[dir]`)
|
|
1540
|
+
if (dir !== undefined) {
|
|
1541
|
+
push('unicode-bidi', tag === 'bdo'
|
|
1542
|
+
? 'isolate-override'
|
|
1543
|
+
: dir === 'auto'
|
|
1544
|
+
? 'plaintext'
|
|
1545
|
+
: 'isolate');
|
|
1546
|
+
}
|
|
450
1547
|
const bgcolor = attr(el, 'bgcolor');
|
|
451
1548
|
if (bgcolor)
|
|
452
1549
|
push('background-color', bgcolor);
|
|
1550
|
+
if (BACKGROUNDS.has(tag)) {
|
|
1551
|
+
const background = attr(el, 'background')?.trim();
|
|
1552
|
+
if (background) {
|
|
1553
|
+
push('background-image', `url("${background.replace(/["\\\n]/g, '')}")`);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
if (tag === 'body') {
|
|
1557
|
+
// the text's colour, and the links'
|
|
1558
|
+
const text = attr(el, 'text');
|
|
1559
|
+
if (text)
|
|
1560
|
+
push('color', text);
|
|
1561
|
+
}
|
|
1562
|
+
else if (tag === 'a' && attr(el, 'href') !== undefined) {
|
|
1563
|
+
const body = closestBody(el);
|
|
1564
|
+
const link = body ? attr(body, 'link') : undefined;
|
|
1565
|
+
if (link)
|
|
1566
|
+
push('color', link);
|
|
1567
|
+
}
|
|
453
1568
|
const color = attr(el, 'color');
|
|
454
1569
|
if (color && (tag === 'font' || tag === 'basefont'))
|
|
455
1570
|
push('color', color);
|
|
@@ -472,6 +1587,27 @@ function presentationHints(el) {
|
|
|
472
1587
|
const height = attr(el, 'height');
|
|
473
1588
|
if (height)
|
|
474
1589
|
push('height', lengthAttr(height));
|
|
1590
|
+
// and, both numbers, an image's the ratio it has before it loads, or
|
|
1591
|
+
// where it has none of its own (HTML 15.4.3, "map to the aspect-ratio
|
|
1592
|
+
// property")
|
|
1593
|
+
if (width && height && RATIO_SIZED.has(tag)) {
|
|
1594
|
+
const w = parseFloat(width);
|
|
1595
|
+
const h = parseFloat(height);
|
|
1596
|
+
if (w > 0 && h > 0 && !/%/.test(width + height)) {
|
|
1597
|
+
push('aspect-ratio', `auto ${w} / ${h}`);
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
else if (tag === 'svg') {
|
|
1602
|
+
// an SVG's are CSS lengths of their own, units and all (SVG 2, 5.1.1)
|
|
1603
|
+
const width = attr(el, 'width');
|
|
1604
|
+
const w = width ? svgSizeHint(width) : null;
|
|
1605
|
+
if (w)
|
|
1606
|
+
push('width', w);
|
|
1607
|
+
const height = attr(el, 'height');
|
|
1608
|
+
const h = height ? svgSizeHint(height) : null;
|
|
1609
|
+
if (h)
|
|
1610
|
+
push('height', h);
|
|
475
1611
|
}
|
|
476
1612
|
if (tag === 'table') {
|
|
477
1613
|
const border = attr(el, 'border');
|
|
@@ -496,15 +1632,54 @@ function presentationHints(el) {
|
|
|
496
1632
|
const noshade = attr(el, 'noshade');
|
|
497
1633
|
if (noshade !== undefined)
|
|
498
1634
|
push('border-top-width', '2px');
|
|
1635
|
+
// the rule's colour and its thickness
|
|
1636
|
+
const color = attr(el, 'color');
|
|
1637
|
+
if (color)
|
|
1638
|
+
push('border-top-color', color);
|
|
1639
|
+
const size = attr(el, 'size');
|
|
1640
|
+
if (size && Number(size) > 0)
|
|
1641
|
+
push('border-top-width', `${Number(size)}px`);
|
|
1642
|
+
}
|
|
1643
|
+
if ((tag === 'td' || tag === 'th') && attr(el, 'nowrap') !== undefined) {
|
|
1644
|
+
push('white-space', 'nowrap');
|
|
1645
|
+
}
|
|
1646
|
+
if (tag === 'br') {
|
|
1647
|
+
// below the floats: `<br clear="all">` after a floated image
|
|
1648
|
+
const clear = attr(el, 'clear')?.toLowerCase();
|
|
1649
|
+
if (clear === 'all' || clear === 'both')
|
|
1650
|
+
push('clear', 'both');
|
|
1651
|
+
else if (clear === 'left' || clear === 'right')
|
|
1652
|
+
push('clear', clear);
|
|
499
1653
|
}
|
|
500
1654
|
if (tag === 'ol') {
|
|
501
1655
|
const type = attr(el, 'type');
|
|
502
1656
|
const mapped = OL_TYPES[type ?? ''];
|
|
503
1657
|
if (mapped)
|
|
504
1658
|
push('list-style-type', mapped);
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
1659
|
+
// the number a list starts at is its `list-item` counter's, one before
|
|
1660
|
+
// it, or counting down one after it (HTML's rendering, "Lists")
|
|
1661
|
+
const start = htmlInteger(attr(el, 'start'));
|
|
1662
|
+
if (start !== null) {
|
|
1663
|
+
push('counter-reset', attr(el, 'reversed') !== undefined
|
|
1664
|
+
? `reversed(list-item) ${start + 1}`
|
|
1665
|
+
: `list-item ${start - 1}`);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
if (tag === 'ul') {
|
|
1669
|
+
const type = attr(el, 'type')?.toLowerCase();
|
|
1670
|
+
if (type && BULLETS.has(type))
|
|
1671
|
+
push('list-style-type', type);
|
|
1672
|
+
}
|
|
1673
|
+
if (tag === 'li') {
|
|
1674
|
+
// an item's `value` is the number it goes on from
|
|
1675
|
+
const value = htmlInteger(attr(el, 'value'));
|
|
1676
|
+
if (value !== null)
|
|
1677
|
+
push('counter-set', `list-item ${value}`);
|
|
1678
|
+
const type = attr(el, 'type');
|
|
1679
|
+
const mapped = OL_TYPES[type ?? ''] ??
|
|
1680
|
+
(type && BULLETS.has(type.toLowerCase()) ? type.toLowerCase() : null);
|
|
1681
|
+
if (mapped)
|
|
1682
|
+
push('list-style-type', mapped);
|
|
508
1683
|
}
|
|
509
1684
|
if (tag === 'img' || tag === 'object') {
|
|
510
1685
|
const hspace = attr(el, 'hspace');
|
|
@@ -520,6 +1695,51 @@ function presentationHints(el) {
|
|
|
520
1695
|
}
|
|
521
1696
|
return out;
|
|
522
1697
|
}
|
|
1698
|
+
/** An image's `align` other than a side, as its `vertical-align`. */
|
|
1699
|
+
const IMAGE_ALIGN = {
|
|
1700
|
+
top: 'top',
|
|
1701
|
+
texttop: 'text-top',
|
|
1702
|
+
middle: 'middle',
|
|
1703
|
+
absmiddle: 'middle',
|
|
1704
|
+
center: 'middle',
|
|
1705
|
+
bottom: 'baseline',
|
|
1706
|
+
baseline: 'baseline',
|
|
1707
|
+
absbottom: 'bottom',
|
|
1708
|
+
};
|
|
1709
|
+
/** The elements whose `align` aligns the blocks in them too. */
|
|
1710
|
+
const ALIGNS_BLOCKS = new Set([
|
|
1711
|
+
'div',
|
|
1712
|
+
'caption',
|
|
1713
|
+
'thead',
|
|
1714
|
+
'tbody',
|
|
1715
|
+
'tfoot',
|
|
1716
|
+
'tr',
|
|
1717
|
+
'td',
|
|
1718
|
+
'th',
|
|
1719
|
+
]);
|
|
1720
|
+
/** The elements a `background` attribute gives a background image. */
|
|
1721
|
+
const BACKGROUNDS = new Set([
|
|
1722
|
+
'body',
|
|
1723
|
+
'table',
|
|
1724
|
+
'thead',
|
|
1725
|
+
'tbody',
|
|
1726
|
+
'tfoot',
|
|
1727
|
+
'tr',
|
|
1728
|
+
'td',
|
|
1729
|
+
'th',
|
|
1730
|
+
]);
|
|
1731
|
+
function closestBody(el) {
|
|
1732
|
+
let node = el.parent;
|
|
1733
|
+
while (node) {
|
|
1734
|
+
if (node.type === 'tag' && node.name === 'body') {
|
|
1735
|
+
return node;
|
|
1736
|
+
}
|
|
1737
|
+
node = node.parent;
|
|
1738
|
+
}
|
|
1739
|
+
return null;
|
|
1740
|
+
}
|
|
1741
|
+
/** What the `width` and `height` attributes give a ratio as well. */
|
|
1742
|
+
const RATIO_SIZED = new Set(['img', 'video']);
|
|
523
1743
|
const SIZED = new Set([
|
|
524
1744
|
'img',
|
|
525
1745
|
'table',
|
|
@@ -529,7 +1749,6 @@ const SIZED = new Set([
|
|
|
529
1749
|
'colgroup',
|
|
530
1750
|
'iframe',
|
|
531
1751
|
'video',
|
|
532
|
-
'canvas',
|
|
533
1752
|
'object',
|
|
534
1753
|
'embed',
|
|
535
1754
|
'hr',
|
|
@@ -541,6 +1760,17 @@ const OL_TYPES = {
|
|
|
541
1760
|
i: 'lower-roman',
|
|
542
1761
|
I: 'upper-roman',
|
|
543
1762
|
};
|
|
1763
|
+
/** What a `<ul type>` or an `<li type>` names that is not a number. */
|
|
1764
|
+
const BULLETS = new Set(['disc', 'circle', 'square', 'none']);
|
|
1765
|
+
/** An attribute read as HTML reads an integer: its leading digits, signed,
|
|
1766
|
+
* whatever follows them; null where it has none. A counter is a 32-bit
|
|
1767
|
+
* integer in a browser, and one past that is kept to it. */
|
|
1768
|
+
function htmlInteger(value) {
|
|
1769
|
+
const match = value === undefined ? null : /^\s*([+-]?\d+)/.exec(value);
|
|
1770
|
+
if (!match)
|
|
1771
|
+
return null;
|
|
1772
|
+
return Math.max(-2147483648, Math.min(2147483647, Number(match[1])));
|
|
1773
|
+
}
|
|
544
1774
|
const FONT_SIZE_STEPS = [1, 0.63, 0.82, 1, 1.13, 1.5, 2, 3];
|
|
545
1775
|
/** A presentational length: bare numbers are pixels, `50%` stays a percent. */
|
|
546
1776
|
function lengthAttr(value) {
|
|
@@ -559,4 +1789,35 @@ function closestTable(el) {
|
|
|
559
1789
|
}
|
|
560
1790
|
return null;
|
|
561
1791
|
}
|
|
1792
|
+
/** The generic fixed-width family's size to everyone else's: 13 to 16. */
|
|
1793
|
+
const FIXED_SIZE = 13 / 16;
|
|
1794
|
+
/** Whether a family list is the generic `monospace` and nothing else,
|
|
1795
|
+
* which has the smaller size; a list with a fallback after it does not,
|
|
1796
|
+
* so `monospace, monospace` keeps the size it had. */
|
|
1797
|
+
function monospaceOnly(family) {
|
|
1798
|
+
return family.length === 9 && family.toLowerCase() === 'monospace';
|
|
1799
|
+
}
|
|
1800
|
+
/** Whether a `font-size`, or the size in a `font`, is an absolute-size
|
|
1801
|
+
* keyword, or `initial`, which is `medium`. */
|
|
1802
|
+
function sizeKeyword(prop, value) {
|
|
1803
|
+
const words = value.trim().toLowerCase();
|
|
1804
|
+
if (prop === 'font-size')
|
|
1805
|
+
return ABSOLUTE_SIZES.has(words);
|
|
1806
|
+
for (const word of words.split(/[\s/]+/)) {
|
|
1807
|
+
if (ABSOLUTE_SIZES.has(word))
|
|
1808
|
+
return true;
|
|
1809
|
+
}
|
|
1810
|
+
return false;
|
|
1811
|
+
}
|
|
1812
|
+
const ABSOLUTE_SIZES = new Set([
|
|
1813
|
+
'xx-small',
|
|
1814
|
+
'x-small',
|
|
1815
|
+
'small',
|
|
1816
|
+
'medium',
|
|
1817
|
+
'large',
|
|
1818
|
+
'x-large',
|
|
1819
|
+
'xx-large',
|
|
1820
|
+
'xxx-large',
|
|
1821
|
+
'initial',
|
|
1822
|
+
]);
|
|
562
1823
|
//# sourceMappingURL=cascade.js.map
|