@react-x11/components 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -4
- package/dist/charts/node.d.ts +11 -1
- package/dist/charts/node.d.ts.map +1 -1
- package/dist/charts/node.js +44 -14
- package/dist/charts/node.js.map +1 -1
- package/dist/charts/render.d.ts +12 -3
- package/dist/charts/render.d.ts.map +1 -1
- package/dist/charts/render.js +94 -25
- package/dist/charts/render.js.map +1 -1
- package/dist/code/index.d.ts.map +1 -1
- package/dist/code/index.js +27 -24
- package/dist/code/index.js.map +1 -1
- package/dist/code-editor/completion.d.ts.map +1 -1
- package/dist/code-editor/completion.js +3 -2
- package/dist/code-editor/completion.js.map +1 -1
- package/dist/code-editor/index.d.ts.map +1 -1
- package/dist/code-editor/index.js +19 -0
- package/dist/code-editor/index.js.map +1 -1
- package/dist/code-editor/node.d.ts +177 -7
- package/dist/code-editor/node.d.ts.map +1 -1
- package/dist/code-editor/node.js +1329 -164
- package/dist/code-editor/node.js.map +1 -1
- package/dist/code-language/index.d.ts +1 -1
- package/dist/code-language/index.d.ts.map +1 -1
- package/dist/code-language/index.js +1 -1
- package/dist/code-language/index.js.map +1 -1
- package/dist/code-language/languages/glsl.d.ts.map +1 -1
- package/dist/code-language/languages/glsl.js +10 -2
- package/dist/code-language/languages/glsl.js.map +1 -1
- package/dist/code-language/languages/javascript.d.ts.map +1 -1
- package/dist/code-language/languages/javascript.js +18 -3
- package/dist/code-language/languages/javascript.js.map +1 -1
- package/dist/code-language/languages/json.d.ts.map +1 -1
- package/dist/code-language/languages/json.js +10 -2
- package/dist/code-language/languages/json.js.map +1 -1
- package/dist/code-language/languages/shell.d.ts.map +1 -1
- package/dist/code-language/languages/shell.js +10 -2
- package/dist/code-language/languages/shell.js.map +1 -1
- package/dist/code-language/languages/sql.d.ts.map +1 -1
- package/dist/code-language/languages/sql.js +20 -2
- package/dist/code-language/languages/sql.js.map +1 -1
- package/dist/code-language/runs.d.ts +31 -0
- package/dist/code-language/runs.d.ts.map +1 -1
- package/dist/code-language/runs.js +105 -0
- package/dist/code-language/runs.js.map +1 -1
- package/dist/code-language/stream.d.ts +22 -0
- package/dist/code-language/stream.d.ts.map +1 -1
- package/dist/code-language/stream.js +259 -9
- package/dist/code-language/stream.js.map +1 -1
- package/dist/code-language/types.d.ts +5 -4
- package/dist/code-language/types.d.ts.map +1 -1
- package/dist/codeblock/index.d.ts +26 -2
- package/dist/codeblock/index.d.ts.map +1 -1
- package/dist/codeblock/index.js +57 -4
- package/dist/codeblock/index.js.map +1 -1
- package/dist/flow/draw.d.ts +50 -0
- package/dist/flow/draw.d.ts.map +1 -1
- package/dist/flow/draw.js +132 -33
- package/dist/flow/draw.js.map +1 -1
- package/dist/flow/gl/color.d.ts +13 -0
- package/dist/flow/gl/color.d.ts.map +1 -0
- package/dist/flow/gl/color.js +82 -0
- package/dist/flow/gl/color.js.map +1 -0
- package/dist/flow/gl/index.d.ts +60 -0
- package/dist/flow/gl/index.d.ts.map +1 -0
- package/dist/flow/gl/index.js +283 -0
- package/dist/flow/gl/index.js.map +1 -0
- package/dist/flow/gl/pack.d.ts +133 -0
- package/dist/flow/gl/pack.d.ts.map +1 -0
- package/dist/flow/gl/pack.js +408 -0
- package/dist/flow/gl/pack.js.map +1 -0
- package/dist/flow/gl/renderer.d.ts +95 -0
- package/dist/flow/gl/renderer.d.ts.map +1 -0
- package/dist/flow/gl/renderer.js +459 -0
- package/dist/flow/gl/renderer.js.map +1 -0
- package/dist/flow/gl/shaders.d.ts +79 -0
- package/dist/flow/gl/shaders.d.ts.map +1 -0
- package/dist/flow/gl/shaders.js +346 -0
- package/dist/flow/gl/shaders.js.map +1 -0
- package/dist/flow/gl/text.d.ts +318 -0
- package/dist/flow/gl/text.d.ts.map +1 -0
- package/dist/flow/gl/text.js +1103 -0
- package/dist/flow/gl/text.js.map +1 -0
- package/dist/flow/index.d.ts +1 -1
- package/dist/flow/index.d.ts.map +1 -1
- package/dist/flow/index.js +619 -64
- package/dist/flow/index.js.map +1 -1
- package/dist/flow/node.d.ts +621 -72
- package/dist/flow/node.d.ts.map +1 -1
- package/dist/flow/node.js +2253 -1018
- package/dist/flow/node.js.map +1 -1
- package/dist/flow/paint.d.ts +35 -0
- package/dist/flow/paint.d.ts.map +1 -0
- package/dist/flow/paint.js +393 -0
- package/dist/flow/paint.js.map +1 -0
- package/dist/flow/paths.d.ts +14 -0
- package/dist/flow/paths.d.ts.map +1 -1
- package/dist/flow/paths.js +45 -19
- package/dist/flow/paths.js.map +1 -1
- package/dist/flow/scene.d.ts +584 -0
- package/dist/flow/scene.d.ts.map +1 -0
- package/dist/flow/scene.js +1453 -0
- package/dist/flow/scene.js.map +1 -0
- package/dist/flow/types.d.ts +111 -1
- package/dist/flow/types.d.ts.map +1 -1
- package/dist/html/controls.d.ts +28 -0
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js +52 -2
- package/dist/html/controls.js.map +1 -1
- package/dist/html/css/calc.d.ts +14 -0
- package/dist/html/css/calc.d.ts.map +1 -0
- package/dist/html/css/calc.js +344 -0
- package/dist/html/css/calc.js.map +1 -0
- package/dist/html/css/cascade.d.ts +262 -6
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +1373 -67
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/color.d.ts +23 -0
- package/dist/html/css/color.d.ts.map +1 -0
- package/dist/html/css/color.js +740 -0
- package/dist/html/css/color.js.map +1 -0
- package/dist/html/css/content.d.ts +92 -0
- package/dist/html/css/content.d.ts.map +1 -0
- package/dist/html/css/content.js +388 -0
- package/dist/html/css/content.js.map +1 -0
- package/dist/html/css/counter-styles.d.ts +76 -0
- package/dist/html/css/counter-styles.d.ts.map +1 -0
- package/dist/html/css/counter-styles.js +893 -0
- package/dist/html/css/counter-styles.js.map +1 -0
- package/dist/html/css/decode.d.ts +12 -0
- package/dist/html/css/decode.d.ts.map +1 -0
- package/dist/html/css/decode.js +116 -0
- package/dist/html/css/decode.js.map +1 -0
- package/dist/html/css/parse.d.ts +110 -10
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +1473 -180
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/style.d.ts +501 -15
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +3729 -206
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/ua.d.ts.map +1 -1
- package/dist/html/css/ua.js +65 -16
- package/dist/html/css/ua.js.map +1 -1
- package/dist/html/css/values.d.ts +37 -3
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js +122 -48
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/css/vars.d.ts +52 -0
- package/dist/html/css/vars.d.ts.map +1 -0
- package/dist/html/css/vars.js +358 -0
- package/dist/html/css/vars.js.map +1 -0
- package/dist/html/dom.d.ts +30 -4
- package/dist/html/dom.d.ts.map +1 -1
- package/dist/html/dom.js +278 -17
- package/dist/html/dom.js.map +1 -1
- package/dist/html/fonts.d.ts +106 -0
- package/dist/html/fonts.d.ts.map +1 -0
- package/dist/html/fonts.js +565 -0
- package/dist/html/fonts.js.map +1 -0
- package/dist/html/gif.d.ts +15 -0
- package/dist/html/gif.d.ts.map +1 -0
- package/dist/html/gif.js +229 -0
- package/dist/html/gif.js.map +1 -0
- package/dist/html/index.d.ts +50 -11
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +115 -9
- package/dist/html/index.js.map +1 -1
- package/dist/html/layout/block.d.ts +226 -3
- package/dist/html/layout/block.d.ts.map +1 -1
- package/dist/html/layout/block.js +3077 -219
- package/dist/html/layout/block.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +367 -17
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +1742 -182
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/cache.d.ts +58 -0
- package/dist/html/layout/cache.d.ts.map +1 -0
- package/dist/html/layout/cache.js +224 -0
- package/dist/html/layout/cache.js.map +1 -0
- package/dist/html/layout/collapse.d.ts +45 -0
- package/dist/html/layout/collapse.d.ts.map +1 -0
- package/dist/html/layout/collapse.js +246 -0
- package/dist/html/layout/collapse.js.map +1 -0
- package/dist/html/layout/css-grid.d.ts +7 -0
- package/dist/html/layout/css-grid.d.ts.map +1 -0
- package/dist/html/layout/css-grid.js +900 -0
- package/dist/html/layout/css-grid.js.map +1 -0
- package/dist/html/layout/flex.d.ts.map +1 -1
- package/dist/html/layout/flex.js +1025 -89
- package/dist/html/layout/flex.js.map +1 -1
- package/dist/html/layout/floats.d.ts +45 -6
- package/dist/html/layout/floats.d.ts.map +1 -1
- package/dist/html/layout/floats.js +113 -14
- package/dist/html/layout/floats.js.map +1 -1
- package/dist/html/layout/grid-lines.d.ts +39 -0
- package/dist/html/layout/grid-lines.d.ts.map +1 -0
- package/dist/html/layout/grid-lines.js +119 -0
- package/dist/html/layout/grid-lines.js.map +1 -0
- package/dist/html/layout/grid.d.ts +53 -0
- package/dist/html/layout/grid.d.ts.map +1 -0
- package/dist/html/layout/grid.js +153 -0
- package/dist/html/layout/grid.js.map +1 -0
- package/dist/html/layout/inline.d.ts +154 -1
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +3598 -175
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/layout/shaping.d.ts +6 -0
- package/dist/html/layout/shaping.d.ts.map +1 -0
- package/dist/html/layout/shaping.js +100 -0
- package/dist/html/layout/shaping.js.map +1 -0
- package/dist/html/layout/table.d.ts +3 -0
- package/dist/html/layout/table.d.ts.map +1 -1
- package/dist/html/layout/table.js +681 -175
- package/dist/html/layout/table.js.map +1 -1
- package/dist/html/layout/tracks.d.ts +44 -0
- package/dist/html/layout/tracks.d.ts.map +1 -0
- package/dist/html/layout/tracks.js +349 -0
- package/dist/html/layout/tracks.js.map +1 -0
- package/dist/html/node.d.ts +169 -4
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +1429 -137
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +92 -3
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +3635 -107
- package/dist/html/paint.js.map +1 -1
- package/dist/html/resources.d.ts +60 -14
- package/dist/html/resources.d.ts.map +1 -1
- package/dist/html/resources.js +122 -36
- package/dist/html/resources.js.map +1 -1
- package/dist/html/surfaces.d.ts +23 -0
- package/dist/html/surfaces.d.ts.map +1 -0
- package/dist/html/surfaces.js +68 -0
- package/dist/html/surfaces.js.map +1 -0
- package/dist/html/svg.d.ts +80 -0
- package/dist/html/svg.d.ts.map +1 -0
- package/dist/html/svg.js +442 -0
- package/dist/html/svg.js.map +1 -0
- package/dist/html/url.d.ts +23 -0
- package/dist/html/url.d.ts.map +1 -0
- package/dist/html/url.js +80 -0
- package/dist/html/url.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/codelines.d.ts +42 -0
- package/dist/internal/codelines.d.ts.map +1 -0
- package/dist/internal/codelines.js +170 -0
- package/dist/internal/codelines.js.map +1 -0
- package/dist/internal/collate.d.ts +3 -0
- package/dist/internal/collate.d.ts.map +1 -0
- package/dist/internal/collate.js +11 -0
- package/dist/internal/collate.js.map +1 -0
- package/dist/internal/markdown/ast.d.ts +11 -0
- package/dist/internal/markdown/ast.d.ts.map +1 -1
- package/dist/internal/markdown/parse.d.ts.map +1 -1
- package/dist/internal/markdown/parse.js +109 -8
- package/dist/internal/markdown/parse.js.map +1 -1
- package/dist/internal/prewarm.d.ts +18 -0
- package/dist/internal/prewarm.d.ts.map +1 -0
- package/dist/internal/prewarm.js +42 -0
- package/dist/internal/prewarm.js.map +1 -0
- package/dist/internal/sdf.d.ts +20 -0
- package/dist/internal/sdf.d.ts.map +1 -0
- package/dist/internal/sdf.js +216 -0
- package/dist/internal/sdf.js.map +1 -0
- package/dist/internal/splice.d.ts +12 -0
- package/dist/internal/splice.d.ts.map +1 -0
- package/dist/internal/splice.js +23 -0
- package/dist/internal/splice.js.map +1 -0
- package/dist/internal/window.d.ts +12 -0
- package/dist/internal/window.d.ts.map +1 -1
- package/dist/internal/window.js +23 -6
- package/dist/internal/window.js.map +1 -1
- package/dist/maps/anchors.d.ts +6 -1
- package/dist/maps/anchors.d.ts.map +1 -1
- package/dist/maps/anchors.js +260 -1
- package/dist/maps/anchors.js.map +1 -1
- package/dist/maps/controller.d.ts +57 -0
- package/dist/maps/controller.d.ts.map +1 -1
- package/dist/maps/controller.js +97 -18
- package/dist/maps/controller.js.map +1 -1
- package/dist/maps/gl/buckets.d.ts +5 -1
- package/dist/maps/gl/buckets.d.ts.map +1 -1
- package/dist/maps/gl/buckets.js +5 -2
- package/dist/maps/gl/buckets.js.map +1 -1
- package/dist/maps/gl/build-worker.d.ts +2 -0
- package/dist/maps/gl/build-worker.d.ts.map +1 -1
- package/dist/maps/gl/build-worker.js +1 -1
- package/dist/maps/gl/build-worker.js.map +1 -1
- package/dist/maps/gl/cover.d.ts +23 -4
- package/dist/maps/gl/cover.d.ts.map +1 -1
- package/dist/maps/gl/cover.js +61 -48
- package/dist/maps/gl/cover.js.map +1 -1
- package/dist/maps/gl/placement.d.ts +21 -8
- package/dist/maps/gl/placement.d.ts.map +1 -1
- package/dist/maps/gl/placement.js +133 -58
- package/dist/maps/gl/placement.js.map +1 -1
- package/dist/maps/gl/renderer.d.ts +36 -4
- package/dist/maps/gl/renderer.d.ts.map +1 -1
- package/dist/maps/gl/renderer.js +81 -24
- package/dist/maps/gl/renderer.js.map +1 -1
- package/dist/maps/gl/shaders.d.ts +18 -17
- package/dist/maps/gl/shaders.d.ts.map +1 -1
- package/dist/maps/gl/shaders.js +34 -32
- package/dist/maps/gl/shaders.js.map +1 -1
- package/dist/maps/gl/store.d.ts +10 -0
- package/dist/maps/gl/store.d.ts.map +1 -1
- package/dist/maps/gl/store.js +47 -4
- package/dist/maps/gl/store.js.map +1 -1
- package/dist/maps/gl/text.d.ts +153 -24
- package/dist/maps/gl/text.d.ts.map +1 -1
- package/dist/maps/gl/text.js +379 -63
- package/dist/maps/gl/text.js.map +1 -1
- package/dist/maps/gl/view.d.ts +293 -2
- package/dist/maps/gl/view.d.ts.map +1 -1
- package/dist/maps/gl/view.js +317 -82
- package/dist/maps/gl/view.js.map +1 -1
- package/dist/maps/icons.d.ts +32 -0
- package/dist/maps/icons.d.ts.map +1 -0
- package/dist/maps/icons.js +151 -0
- package/dist/maps/icons.js.map +1 -0
- package/dist/maps/index.d.ts +2 -0
- package/dist/maps/index.d.ts.map +1 -1
- package/dist/maps/index.js +2 -0
- package/dist/maps/index.js.map +1 -1
- package/dist/maps/labels.d.ts +56 -4
- package/dist/maps/labels.d.ts.map +1 -1
- package/dist/maps/labels.js +213 -46
- package/dist/maps/labels.js.map +1 -1
- package/dist/maps/node.d.ts +17 -0
- package/dist/maps/node.d.ts.map +1 -1
- package/dist/maps/node.js +64 -30
- package/dist/maps/node.js.map +1 -1
- package/dist/maps/proj.d.ts +48 -0
- package/dist/maps/proj.d.ts.map +1 -1
- package/dist/maps/proj.js +73 -0
- package/dist/maps/proj.js.map +1 -1
- package/dist/maps/sources.d.ts +5 -3
- package/dist/maps/sources.d.ts.map +1 -1
- package/dist/maps/sources.js +5 -3
- package/dist/maps/sources.js.map +1 -1
- package/dist/maps/style.d.ts +35 -0
- package/dist/maps/style.d.ts.map +1 -1
- package/dist/maps/style.js.map +1 -1
- package/dist/maps/styles.d.ts +12 -0
- package/dist/maps/styles.d.ts.map +1 -1
- package/dist/maps/styles.js +120 -6
- package/dist/maps/styles.js.map +1 -1
- package/dist/maps/tiles.d.ts +31 -11
- package/dist/maps/tiles.d.ts.map +1 -1
- package/dist/maps/tiles.js +61 -27
- package/dist/maps/tiles.js.map +1 -1
- package/dist/maps/types.d.ts +28 -4
- package/dist/maps/types.d.ts.map +1 -1
- package/dist/markdown/index.d.ts.map +1 -1
- package/dist/markdown/index.js +209 -68
- package/dist/markdown/index.js.map +1 -1
- package/dist/markdown/spans.d.ts.map +1 -1
- package/dist/markdown/spans.js +6 -0
- package/dist/markdown/spans.js.map +1 -1
- package/dist/qml/containers.d.ts.map +1 -1
- package/dist/qml/containers.js +6 -1
- package/dist/qml/containers.js.map +1 -1
- package/dist/qml/interaction.d.ts.map +1 -1
- package/dist/qml/interaction.js +38 -5
- package/dist/qml/interaction.js.map +1 -1
- package/dist/qml/layouts.d.ts.map +1 -1
- package/dist/qml/layouts.js +21 -6
- package/dist/qml/layouts.js.map +1 -1
- package/dist/qml/qtquick.d.ts.map +1 -1
- package/dist/qml/qtquick.js +9 -2
- package/dist/qml/qtquick.js.map +1 -1
- package/dist/qml/react.d.ts.map +1 -1
- package/dist/qml/react.js +9 -7
- package/dist/qml/react.js.map +1 -1
- package/dist/reorder/clock.d.ts +7 -0
- package/dist/reorder/clock.d.ts.map +1 -0
- package/dist/reorder/clock.js +26 -0
- package/dist/reorder/clock.js.map +1 -0
- package/dist/reorder/index.d.ts +25 -3
- package/dist/reorder/index.d.ts.map +1 -1
- package/dist/reorder/index.js +64 -19
- package/dist/reorder/index.js.map +1 -1
- package/dist/rich-text-editor/index.d.ts +0 -11
- package/dist/rich-text-editor/index.d.ts.map +1 -1
- package/dist/rich-text-editor/index.js +38 -9
- package/dist/rich-text-editor/index.js.map +1 -1
- package/dist/rich-text-editor/keymap.d.ts.map +1 -1
- package/dist/rich-text-editor/keymap.js +2 -1
- package/dist/rich-text-editor/keymap.js.map +1 -1
- package/dist/rich-text-editor/keys.d.ts +17 -6
- package/dist/rich-text-editor/keys.d.ts.map +1 -1
- package/dist/rich-text-editor/keys.js +135 -26
- package/dist/rich-text-editor/keys.js.map +1 -1
- package/dist/rich-text-editor/markdown.d.ts.map +1 -1
- package/dist/rich-text-editor/markdown.js +30 -1
- package/dist/rich-text-editor/markdown.js.map +1 -1
- package/dist/rich-text-editor/marks.d.ts +9 -0
- package/dist/rich-text-editor/marks.d.ts.map +1 -0
- package/dist/rich-text-editor/marks.js +83 -0
- package/dist/rich-text-editor/marks.js.map +1 -0
- package/dist/rich-text-editor/render.d.ts.map +1 -1
- package/dist/rich-text-editor/render.js +28 -10
- package/dist/rich-text-editor/render.js.map +1 -1
- package/dist/rich-text-editor/replace.d.ts +13 -0
- package/dist/rich-text-editor/replace.d.ts.map +1 -0
- package/dist/rich-text-editor/replace.js +64 -0
- package/dist/rich-text-editor/replace.js.map +1 -0
- package/dist/rich-text-editor/toolbar.d.ts.map +1 -1
- package/dist/rich-text-editor/toolbar.js +1 -1
- package/dist/rich-text-editor/toolbar.js.map +1 -1
- package/dist/rich-text-editor/virtual.d.ts.map +1 -1
- package/dist/rich-text-editor/virtual.js +17 -0
- package/dist/rich-text-editor/virtual.js.map +1 -1
- package/dist/richtext/node.d.ts +46 -2
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +187 -4
- package/dist/richtext/node.js.map +1 -1
- package/dist/richtext/runs.d.ts +13 -8
- package/dist/richtext/runs.d.ts.map +1 -1
- package/dist/richtext/runs.js +18 -8
- package/dist/richtext/runs.js.map +1 -1
- package/dist/table/index.d.ts.map +1 -1
- package/dist/table/index.js +23 -0
- package/dist/table/index.js.map +1 -1
- package/dist/table/rows.d.ts +3 -2
- package/dist/table/rows.d.ts.map +1 -1
- package/dist/table/rows.js +20 -6
- package/dist/table/rows.js.map +1 -1
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +4 -0
- package/dist/terminal/index.js.map +1 -1
- package/dist/terminal/vt/pty.d.ts +13 -2
- package/dist/terminal/vt/pty.d.ts.map +1 -1
- package/dist/terminal/vt/pty.js +18 -3
- package/dist/terminal/vt/pty.js.map +1 -1
- package/dist/terminal-output/index.d.ts.map +1 -1
- package/dist/terminal-output/index.js +103 -23
- package/dist/terminal-output/index.js.map +1 -1
- package/dist/terminal-output/runs.d.ts +4 -1
- package/dist/terminal-output/runs.d.ts.map +1 -1
- package/dist/terminal-output/runs.js +5 -1
- package/dist/terminal-output/runs.js.map +1 -1
- package/dist/three/canvas.d.ts.map +1 -1
- package/dist/three/canvas.js +85 -7
- package/dist/three/canvas.js.map +1 -1
- package/dist/three/events.d.ts +22 -4
- package/dist/three/events.d.ts.map +1 -1
- package/dist/three/events.js +34 -4
- package/dist/three/events.js.map +1 -1
- package/dist/tree/index.d.ts.map +1 -1
- package/dist/tree/index.js +17 -0
- package/dist/tree/index.js.map +1 -1
- package/package.json +42 -33
- package/src/charts/node.ts +62 -26
- package/src/charts/render.ts +120 -30
- package/src/code/index.ts +36 -32
- package/src/code-editor/completion.ts +3 -2
- package/src/code-editor/index.ts +19 -0
- package/src/code-editor/node.ts +1574 -184
- package/src/code-language/index.ts +1 -1
- package/src/code-language/languages/glsl.ts +12 -2
- package/src/code-language/languages/javascript.ts +21 -4
- package/src/code-language/languages/json.ts +12 -2
- package/src/code-language/languages/shell.ts +12 -2
- package/src/code-language/languages/sql.ts +22 -2
- package/src/code-language/runs.ts +111 -1
- package/src/code-language/stream.ts +257 -17
- package/src/code-language/types.ts +5 -4
- package/src/codeblock/index.ts +68 -4
- package/src/flow/draw.ts +167 -41
- package/src/flow/gl/color.ts +85 -0
- package/src/flow/gl/index.ts +342 -0
- package/src/flow/gl/pack.ts +585 -0
- package/src/flow/gl/renderer.ts +679 -0
- package/src/flow/gl/shaders.ts +371 -0
- package/src/flow/gl/text.ts +1295 -0
- package/src/flow/index.ts +794 -67
- package/src/flow/node.ts +2496 -1256
- package/src/flow/paint.ts +511 -0
- package/src/flow/paths.ts +80 -15
- package/src/flow/scene.ts +2199 -0
- package/src/flow/types.ts +113 -1
- package/src/html/controls.ts +73 -2
- package/src/html/css/calc.ts +385 -0
- package/src/html/css/cascade.ts +1481 -62
- package/src/html/css/color.ts +755 -0
- package/src/html/css/content.ts +417 -0
- package/src/html/css/counter-styles.ts +973 -0
- package/src/html/css/decode.ts +130 -0
- package/src/html/css/parse.ts +1514 -160
- package/src/html/css/style.ts +4131 -223
- package/src/html/css/ua.ts +66 -17
- package/src/html/css/values.ts +150 -50
- package/src/html/css/vars.ts +348 -0
- package/src/html/dom.ts +284 -17
- package/src/html/fonts.ts +641 -0
- package/src/html/gif.ts +233 -0
- package/src/html/index.ts +180 -20
- package/src/html/layout/block.ts +3560 -208
- package/src/html/layout/boxes.ts +2141 -190
- package/src/html/layout/cache.ts +289 -0
- package/src/html/layout/collapse.ts +317 -0
- package/src/html/layout/css-grid.ts +1063 -0
- package/src/html/layout/flex.ts +1115 -106
- package/src/html/layout/floats.ts +128 -14
- package/src/html/layout/grid-lines.ts +141 -0
- package/src/html/layout/grid.ts +181 -0
- package/src/html/layout/inline.ts +4187 -192
- package/src/html/layout/shaping.ts +140 -0
- package/src/html/layout/table.ts +696 -186
- package/src/html/layout/tracks.ts +437 -0
- package/src/html/node.ts +1585 -156
- package/src/html/paint.ts +4582 -267
- package/src/html/resources.ts +161 -50
- package/src/html/surfaces.ts +81 -0
- package/src/html/svg.ts +504 -0
- package/src/html/url.ts +86 -0
- package/src/index.ts +2 -0
- package/src/internal/codelines.ts +200 -0
- package/src/internal/collate.ts +12 -0
- package/src/internal/markdown/ast.ts +11 -0
- package/src/internal/markdown/parse.ts +154 -11
- package/src/internal/prewarm.ts +45 -0
- package/src/internal/sdf.ts +227 -0
- package/src/internal/splice.ts +25 -0
- package/src/internal/window.ts +36 -5
- package/src/maps/anchors.ts +307 -1
- package/src/maps/controller.ts +116 -31
- package/src/maps/gl/buckets.ts +5 -1
- package/src/maps/gl/build-worker.ts +13 -2
- package/src/maps/gl/cover.ts +79 -44
- package/src/maps/gl/placement.ts +221 -69
- package/src/maps/gl/renderer.ts +104 -20
- package/src/maps/gl/shaders.ts +35 -32
- package/src/maps/gl/store.ts +66 -17
- package/src/maps/gl/text.ts +444 -71
- package/src/maps/gl/view.ts +361 -96
- package/src/maps/icons.ts +183 -0
- package/src/maps/index.ts +4 -0
- package/src/maps/labels.ts +269 -49
- package/src/maps/node.ts +82 -49
- package/src/maps/proj.ts +87 -0
- package/src/maps/sources.ts +5 -3
- package/src/maps/style.ts +32 -0
- package/src/maps/styles.ts +215 -4
- package/src/maps/tiles.ts +64 -31
- package/src/maps/types.ts +28 -4
- package/src/markdown/index.ts +293 -92
- package/src/markdown/spans.ts +5 -0
- package/src/qml/containers.tsx +6 -1
- package/src/qml/interaction.tsx +42 -5
- package/src/qml/layouts.tsx +21 -6
- package/src/qml/qtquick.tsx +9 -2
- package/src/qml/react.tsx +7 -5
- package/src/reorder/clock.ts +27 -0
- package/src/reorder/index.ts +100 -27
- package/src/rich-text-editor/index.ts +37 -12
- package/src/rich-text-editor/keymap.ts +1 -1
- package/src/rich-text-editor/keys.ts +135 -26
- package/src/rich-text-editor/markdown.ts +36 -1
- package/src/rich-text-editor/marks.ts +101 -0
- package/src/rich-text-editor/render.ts +49 -12
- package/src/rich-text-editor/replace.ts +85 -0
- package/src/rich-text-editor/toolbar.ts +1 -1
- package/src/rich-text-editor/virtual.ts +25 -0
- package/src/richtext/node.ts +235 -14
- package/src/richtext/runs.ts +23 -12
- package/src/table/index.ts +29 -0
- package/src/table/rows.ts +18 -8
- package/src/terminal/index.ts +4 -0
- package/src/terminal/vt/pty.ts +16 -2
- package/src/terminal-output/index.ts +129 -31
- package/src/terminal-output/runs.ts +16 -2
- package/src/three/canvas.ts +102 -8
- package/src/three/events.ts +49 -9
- package/src/tree/index.ts +19 -0
package/src/flow/index.ts
CHANGED
|
@@ -16,13 +16,14 @@
|
|
|
16
16
|
// constraint").
|
|
17
17
|
import React, {
|
|
18
18
|
useEffect,
|
|
19
|
+
useLayoutEffect,
|
|
19
20
|
useImperativeHandle,
|
|
20
21
|
useMemo,
|
|
21
22
|
useRef,
|
|
22
23
|
useState,
|
|
23
24
|
} from 'react';
|
|
24
25
|
import type { Dispatch, ReactElement, SetStateAction } from 'react';
|
|
25
|
-
import { Renderer } from 'react-x11';
|
|
26
|
+
import { Renderer, useApp, useScale, useSupports, useTheme } from 'react-x11';
|
|
26
27
|
import { registerElement, registeredElements } from 'react-x11/host';
|
|
27
28
|
import { createStyles, flattenStyle } from 'react-x11/style';
|
|
28
29
|
// Loads the module the JSX augmentation at the bottom targets: nothing in
|
|
@@ -31,7 +32,8 @@ import { createStyles, flattenStyle } from 'react-x11/style';
|
|
|
31
32
|
// addition. Type-only, so it is erased.
|
|
32
33
|
import type {} from 'react-x11/jsx-runtime';
|
|
33
34
|
|
|
34
|
-
import { applyEdgeChanges, applyNodeChanges } from './model.js';
|
|
35
|
+
import { applyEdgeChanges, applyNodeChanges, resolvePalette } from './model.js';
|
|
36
|
+
import { CULL_MARGIN } from './scene.js';
|
|
35
37
|
import { ELEMENT, FlowGraphNode, SELF_DAMAGED_PROPS } from './node.js';
|
|
36
38
|
import type {
|
|
37
39
|
EdgeChange,
|
|
@@ -41,8 +43,10 @@ import type {
|
|
|
41
43
|
FlowNodeData,
|
|
42
44
|
FlowNodeType,
|
|
43
45
|
FlowProps,
|
|
46
|
+
FlowRect,
|
|
44
47
|
NodeBodyRect,
|
|
45
48
|
NodeChange,
|
|
49
|
+
XYPosition,
|
|
46
50
|
} from './types.js';
|
|
47
51
|
|
|
48
52
|
if (!registeredElements().includes(ELEMENT)) {
|
|
@@ -75,6 +79,19 @@ const styles = createStyles({
|
|
|
75
79
|
pane: { flexGrow: 1, overflow: 'hidden' },
|
|
76
80
|
clip: { overflow: 'hidden' },
|
|
77
81
|
fill: { flexGrow: 1 },
|
|
82
|
+
// Over the pane, holding the bodies' layer and clipping it to the pane:
|
|
83
|
+
// a 2D pan carries the layer's pixels in its blit, and what the layer can
|
|
84
|
+
// paint outside the pane — in the border round it — would be repainted
|
|
85
|
+
// on every step (`_blitPan` in ./node.ts).
|
|
86
|
+
bodiesClip: {
|
|
87
|
+
position: 'absolute',
|
|
88
|
+
left: 0,
|
|
89
|
+
top: 0,
|
|
90
|
+
right: 0,
|
|
91
|
+
bottom: 0,
|
|
92
|
+
overflow: 'hidden',
|
|
93
|
+
pointerEvents: 'box-none',
|
|
94
|
+
},
|
|
78
95
|
});
|
|
79
96
|
|
|
80
97
|
/**
|
|
@@ -103,6 +120,163 @@ const flushSync: (fn: () => void) => void =
|
|
|
103
120
|
).flushSyncFromReconciler(fn)
|
|
104
121
|
: (fn) => fn();
|
|
105
122
|
|
|
123
|
+
/**
|
|
124
|
+
* The GL renderer's module, once it has loaded — reached by dynamic
|
|
125
|
+
* `import()` and never statically, so an application that never asks for
|
|
126
|
+
* `renderer="gl"` bundles none of it.
|
|
127
|
+
*/
|
|
128
|
+
type GlModule = typeof import('./gl/index.js');
|
|
129
|
+
|
|
130
|
+
let glModule: GlModule | null = null;
|
|
131
|
+
let glLoading: Promise<GlModule> | null = null;
|
|
132
|
+
|
|
133
|
+
/** Load the GL renderer, once per process however many panes ask. A failed
|
|
134
|
+
* load is forgotten, so the next pane to ask tries again. */
|
|
135
|
+
function loadGl(): Promise<GlModule> {
|
|
136
|
+
glLoading ??= import('./gl/index.js').then(
|
|
137
|
+
(module) => (glModule = module),
|
|
138
|
+
(error: unknown) => {
|
|
139
|
+
glLoading = null;
|
|
140
|
+
throw error;
|
|
141
|
+
},
|
|
142
|
+
);
|
|
143
|
+
return glLoading;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** How far a card's handles and grips ink outside its box — the canvas
|
|
147
|
+
* its card is painted on in the bodies' layer reaches that far round it. */
|
|
148
|
+
const CARD_INK = CULL_MARGIN;
|
|
149
|
+
|
|
150
|
+
/** The grid the bodies' layer grows to, in logical pixels. Every card is
|
|
151
|
+
* placed relative to the layer's corner, so a corner that followed the
|
|
152
|
+
* cards exactly moved — and moved every card with it — whenever the one
|
|
153
|
+
* being dragged was the outermost; grown to this grid it moves only when
|
|
154
|
+
* a card crosses a line of it. */
|
|
155
|
+
const EXTENT_STEP = 256;
|
|
156
|
+
|
|
157
|
+
/** A number per object, for a card's cache key: a style or a handle list
|
|
158
|
+
* that changed is a new object, and its card is painted again. */
|
|
159
|
+
const serials = new WeakMap<object, number>();
|
|
160
|
+
let serial = 0;
|
|
161
|
+
function serialOf(node: object): number {
|
|
162
|
+
let n = serials.get(node);
|
|
163
|
+
if (n === undefined) serials.set(node, (n = ++serial));
|
|
164
|
+
return n;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* What of a node its card draws, for the card's cache key: the label, the
|
|
169
|
+
* description, the style and the handles. A body's own data — a queue
|
|
170
|
+
* length, a chart's points — is none of it: keyed on the node object, a
|
|
171
|
+
* live body that patched its data repainted its card on every patch, the
|
|
172
|
+
* title's text shaped and drawn again for nothing. A type that paints its
|
|
173
|
+
* own card may draw anything of the node, so it is keyed on the node whole.
|
|
174
|
+
*/
|
|
175
|
+
function cardShows(
|
|
176
|
+
node: FlowNode<unknown>,
|
|
177
|
+
type: FlowNodeType<unknown>,
|
|
178
|
+
): string {
|
|
179
|
+
if (type.paint) return `n${serialOf(node)}`;
|
|
180
|
+
const data = node.data as FlowNodeData | undefined;
|
|
181
|
+
const style = node.style ? serialOf(node.style) : 0;
|
|
182
|
+
const handles = node.handles ? serialOf(node.handles) : 0;
|
|
183
|
+
return (
|
|
184
|
+
`${style}:${handles}:${String(data?.label ?? '')}` +
|
|
185
|
+
`\u0000${String(data?.description ?? '')}`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** What `forwardWheel` reads off a wheel that landed on a body. */
|
|
190
|
+
interface WheelLike {
|
|
191
|
+
x: number;
|
|
192
|
+
y: number;
|
|
193
|
+
deltaX: number;
|
|
194
|
+
deltaY: number;
|
|
195
|
+
defaultPrevented?: boolean;
|
|
196
|
+
preventDefault(): void;
|
|
197
|
+
target?: WheelTarget;
|
|
198
|
+
}
|
|
199
|
+
interface WheelTarget {
|
|
200
|
+
parent?: WheelTarget | null;
|
|
201
|
+
scale?: number;
|
|
202
|
+
kind?: string;
|
|
203
|
+
props?: Record<string, unknown>;
|
|
204
|
+
style?: { cursor?: string };
|
|
205
|
+
canScroll?(dx: number, dy: number): boolean;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** What `forwardPress` reads off a press, a drag step or a release. */
|
|
209
|
+
interface PressLike extends WheelLike {
|
|
210
|
+
button?: number;
|
|
211
|
+
capturePointer?(): void;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** The pane's half of a pointer gesture, as `forwardPress` drives it. */
|
|
215
|
+
interface PressSink {
|
|
216
|
+
scale?: number;
|
|
217
|
+
parent?: unknown;
|
|
218
|
+
defaultMouseDown?(ev: never): void;
|
|
219
|
+
defaultMouseDrag?(ev: never): void;
|
|
220
|
+
defaultMouseUp?(ev: never): void;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Roles a press means something to — the body keeps those presses. */
|
|
224
|
+
const INTERACTIVE_ROLES = new Set([
|
|
225
|
+
'button',
|
|
226
|
+
'checkbox',
|
|
227
|
+
'radio',
|
|
228
|
+
'switch',
|
|
229
|
+
'slider',
|
|
230
|
+
'spinbutton',
|
|
231
|
+
'textbox',
|
|
232
|
+
'searchbox',
|
|
233
|
+
'combobox',
|
|
234
|
+
'listbox',
|
|
235
|
+
'option',
|
|
236
|
+
'menuitem',
|
|
237
|
+
'tab',
|
|
238
|
+
'link',
|
|
239
|
+
'scrollbar',
|
|
240
|
+
]);
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Whether a press on `n` is the body's own: a control, something that
|
|
244
|
+
* listens for the press, something whose cursor says it can be clicked or
|
|
245
|
+
* typed into, or something that scrolls. Everything else in a body — its
|
|
246
|
+
* padding, a label, a progress bar — is the card, and a press there is the
|
|
247
|
+
* card's: it selects and drags the node, as it would on a card with no body.
|
|
248
|
+
*/
|
|
249
|
+
function interactive(n: WheelTarget): boolean {
|
|
250
|
+
const props = n.props ?? {};
|
|
251
|
+
if (
|
|
252
|
+
typeof props.onMouseDown === 'function' ||
|
|
253
|
+
typeof props.onClick === 'function' ||
|
|
254
|
+
typeof props.onPress === 'function' ||
|
|
255
|
+
typeof props.onChange === 'function' ||
|
|
256
|
+
typeof props.onMouseUp === 'function'
|
|
257
|
+
) {
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
if (typeof props.role === 'string' && INTERACTIVE_ROLES.has(props.role)) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
if (typeof props.tabIndex === 'number' && props.tabIndex >= 0) return true;
|
|
264
|
+
const cursor = n.style?.cursor;
|
|
265
|
+
if (cursor === 'pointer' || cursor === 'text') return true;
|
|
266
|
+
if (n.kind === 'textinput' || n.kind === 'textarea') return true;
|
|
267
|
+
return Boolean(n.canScroll?.(0, 1) || n.canScroll?.(1, 0));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** The event as the pane reads it: its coordinates taken out of the unit of
|
|
271
|
+
* the body they landed in (`scale`, the zoom) and into the window's. */
|
|
272
|
+
function inPaneUnits<E extends WheelLike>(ev: E, sink: PressSink): E {
|
|
273
|
+
const ratio = (ev.target?.scale ?? 1) / (sink.scale || 1);
|
|
274
|
+
return Object.assign(Object.create(ev) as E, {
|
|
275
|
+
x: ev.x * ratio,
|
|
276
|
+
y: ev.y * ratio,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
106
280
|
interface FlowNodeBodyProps {
|
|
107
281
|
type: FlowNodeType<unknown>;
|
|
108
282
|
node: FlowNode<unknown>;
|
|
@@ -114,6 +288,27 @@ interface FlowNodeBodyProps {
|
|
|
114
288
|
height: number;
|
|
115
289
|
}
|
|
116
290
|
|
|
291
|
+
/**
|
|
292
|
+
* The same node, as far as its body can tell: every field but `position`.
|
|
293
|
+
*
|
|
294
|
+
* Identity is not the test. A drag — and every commit of a controlled graph
|
|
295
|
+
* — hands the pane a *new* node object each step with only its position
|
|
296
|
+
* changed, so comparing identity called `render` on every step of every
|
|
297
|
+
* drag: 60 renders with unchanged `data` in a 60-step drag, counted by
|
|
298
|
+
* `examples/flow-stress.tsx`. Any other field that changes — `data`,
|
|
299
|
+
* `selected`, `style`, a size — still re-renders, as it must.
|
|
300
|
+
*/
|
|
301
|
+
function sameButPosition(a: FlowNode<unknown>, b: FlowNode<unknown>): boolean {
|
|
302
|
+
if (a === b) return true;
|
|
303
|
+
const keys = Object.keys(a) as (keyof FlowNode<unknown>)[];
|
|
304
|
+
if (keys.length !== Object.keys(b).length) return false;
|
|
305
|
+
for (const key of keys) {
|
|
306
|
+
if (key === 'position') continue;
|
|
307
|
+
if (!Object.is(a[key], b[key])) return false;
|
|
308
|
+
}
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
|
|
117
312
|
/**
|
|
118
313
|
* One mounted node body. Memoized so that a *move* re-renders nothing: a
|
|
119
314
|
* drag or a pan changes only the overlay box's `left`/`top` — the body's
|
|
@@ -141,13 +336,136 @@ const FlowNodeBody = React.memo(
|
|
|
141
336
|
},
|
|
142
337
|
(a, b) =>
|
|
143
338
|
a.type === b.type &&
|
|
144
|
-
a.node
|
|
339
|
+
sameButPosition(a.node, b.node) &&
|
|
145
340
|
a.selected === b.selected &&
|
|
146
341
|
a.zoom === b.zoom &&
|
|
147
342
|
a.width === b.width &&
|
|
148
343
|
a.height === b.height,
|
|
149
344
|
);
|
|
150
345
|
|
|
346
|
+
/** What one mounted card is drawn from — see {@link FlowBodyCard}. */
|
|
347
|
+
interface FlowBodyCardProps {
|
|
348
|
+
body: NodeBodyRect;
|
|
349
|
+
node: FlowNode<unknown>;
|
|
350
|
+
type: FlowNodeType<unknown>;
|
|
351
|
+
/** The card's box in the layer it sits in, on the device-pixel grid. */
|
|
352
|
+
left: number;
|
|
353
|
+
top: number;
|
|
354
|
+
width: number;
|
|
355
|
+
height: number;
|
|
356
|
+
/** The card's fill, which its body's box takes too. */
|
|
357
|
+
fill: string;
|
|
358
|
+
cacheKey: string;
|
|
359
|
+
/** One per card for as long as what paints cards holds (`drawCard`). */
|
|
360
|
+
onDraw: (ctx: unknown, info: { node: { abs: XYPosition } }) => void;
|
|
361
|
+
/** Where each card is the surface's child in its own right (no layer),
|
|
362
|
+
* where the layer would have put it, whether it sits a zoom out, and
|
|
363
|
+
* the forwarding it does for itself. */
|
|
364
|
+
offsetX?: number;
|
|
365
|
+
offsetY?: number;
|
|
366
|
+
hidden?: boolean;
|
|
367
|
+
handlers?: Record<string, (ev: unknown) => void>;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* One mounted node: its card, painted by the pane's own 2D painter
|
|
372
|
+
* (`FlowGraphNode.paintCard`), and its body over it. A component of its own
|
|
373
|
+
* so that React can skip it: every prop is a value or a reference that
|
|
374
|
+
* holds while the card does, and a drag re-renders the card that moved.
|
|
375
|
+
*/
|
|
376
|
+
const FlowBodyCard = React.memo(function FlowBodyCard(
|
|
377
|
+
props: FlowBodyCardProps,
|
|
378
|
+
): ReactElement {
|
|
379
|
+
const { body, node, type } = props;
|
|
380
|
+
const { card } = body;
|
|
381
|
+
// The two boxes are two units. The outer one is the pane's: it is
|
|
382
|
+
// positioned and clipped in the same logical window pixels the pane
|
|
383
|
+
// painted the card in, so the body lands on the card exactly. The inner
|
|
384
|
+
// one is the body's, and `scale` is what makes the difference between
|
|
385
|
+
// them the zoom (react-x11#449, core 2.6): every length under it is
|
|
386
|
+
// multiplied by that factor, so a body sized in graph units comes out at
|
|
387
|
+
// the size the card is drawn at, with its text shaped at that size rather
|
|
388
|
+
// than stretched.
|
|
389
|
+
const width = body.width / body.zoom;
|
|
390
|
+
const height = body.height / body.zoom;
|
|
391
|
+
const bodyBox = React.createElement(
|
|
392
|
+
'box',
|
|
393
|
+
{
|
|
394
|
+
key: 'body',
|
|
395
|
+
style: {
|
|
396
|
+
position: 'absolute',
|
|
397
|
+
left: body.x - card.x + CARD_INK,
|
|
398
|
+
top: body.y - card.y + CARD_INK,
|
|
399
|
+
width: body.width,
|
|
400
|
+
height: body.height,
|
|
401
|
+
// A body is free to overflow what it was given — a popup's
|
|
402
|
+
// fallback, a long line — and this is what stops it spilling over
|
|
403
|
+
// the graph.
|
|
404
|
+
overflow: 'hidden',
|
|
405
|
+
// Opaque, in the card's own fill: the card painted under it shows
|
|
406
|
+
// none of what a transparent body would let through.
|
|
407
|
+
backgroundColor: props.fill,
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
React.createElement(
|
|
411
|
+
'box',
|
|
412
|
+
{
|
|
413
|
+
scale: body.zoom,
|
|
414
|
+
// Sized in the unit it establishes, which is what makes it fill the
|
|
415
|
+
// outer box at every zoom.
|
|
416
|
+
style: { width, height },
|
|
417
|
+
},
|
|
418
|
+
React.createElement(FlowNodeBody, {
|
|
419
|
+
type,
|
|
420
|
+
node,
|
|
421
|
+
selected: body.selected,
|
|
422
|
+
zoom: body.zoom,
|
|
423
|
+
// Graph units, like everything else the body sees.
|
|
424
|
+
x: body.x / body.zoom,
|
|
425
|
+
y: body.y / body.zoom,
|
|
426
|
+
width,
|
|
427
|
+
height,
|
|
428
|
+
}),
|
|
429
|
+
),
|
|
430
|
+
);
|
|
431
|
+
// The card, just under its body: the bodies share one layer over every
|
|
432
|
+
// card the graph draws, so without it a body covered the header, border
|
|
433
|
+
// and handles of any card over its own.
|
|
434
|
+
const cardCanvas = React.createElement('canvas', {
|
|
435
|
+
key: 'card',
|
|
436
|
+
style: {
|
|
437
|
+
position: 'absolute',
|
|
438
|
+
left: 0,
|
|
439
|
+
top: 0,
|
|
440
|
+
width: card.width + CARD_INK * 2,
|
|
441
|
+
height: card.height + CARD_INK * 2,
|
|
442
|
+
pointerEvents: 'none',
|
|
443
|
+
},
|
|
444
|
+
cacheKey: props.cacheKey,
|
|
445
|
+
onDraw: props.onDraw,
|
|
446
|
+
});
|
|
447
|
+
return React.createElement(
|
|
448
|
+
'box',
|
|
449
|
+
{
|
|
450
|
+
style: {
|
|
451
|
+
position: 'absolute',
|
|
452
|
+
left: props.left + (props.offsetX ?? 0),
|
|
453
|
+
top: props.top + (props.offsetY ?? 0),
|
|
454
|
+
width: props.width,
|
|
455
|
+
height: props.height,
|
|
456
|
+
// the card's presses are the pane's; its body's are the body's
|
|
457
|
+
pointerEvents: 'box-none',
|
|
458
|
+
...(props.hidden === undefined
|
|
459
|
+
? null
|
|
460
|
+
: { display: props.hidden ? 'none' : 'flex' }),
|
|
461
|
+
},
|
|
462
|
+
...props.handlers,
|
|
463
|
+
},
|
|
464
|
+
cardCanvas,
|
|
465
|
+
bodyBox,
|
|
466
|
+
);
|
|
467
|
+
});
|
|
468
|
+
|
|
151
469
|
/**
|
|
152
470
|
* A directed graph.
|
|
153
471
|
*
|
|
@@ -188,10 +506,16 @@ export function Flow<N = FlowNodeData, E = unknown>(
|
|
|
188
506
|
onWheel,
|
|
189
507
|
style,
|
|
190
508
|
ref,
|
|
509
|
+
renderer,
|
|
510
|
+
onFrame,
|
|
511
|
+
onError,
|
|
191
512
|
...rest
|
|
192
513
|
} = props;
|
|
193
514
|
|
|
194
515
|
const pane = useRef<FlowGraphNode | null>(null);
|
|
516
|
+
// whether the surface draws the graph, as of the last render — read by a
|
|
517
|
+
// layout effect declared before the surface is decided
|
|
518
|
+
const drawsGlRef = useRef(false);
|
|
195
519
|
|
|
196
520
|
const [ownNodes, setOwnNodes] = useState<readonly FlowNode<N>[]>(
|
|
197
521
|
() => defaultNodes ?? [],
|
|
@@ -227,12 +551,20 @@ export function Flow<N = FlowNodeData, E = unknown>(
|
|
|
227
551
|
// it: the ref attaches after the commit that created the node, and a
|
|
228
552
|
// handle built once must still work for the whole mount.
|
|
229
553
|
getViewport: () => pane.current?.getViewport() ?? { x: 0, y: 0, zoom: 1 },
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
554
|
+
// the ones that move the viewport, as calls through the handle
|
|
555
|
+
// (`FlowGraphNode.fromHandle`): their bodies commit with the pan
|
|
556
|
+
setViewport: (viewport) =>
|
|
557
|
+
pane.current?.fromHandle(() => pane.current?.setViewport(viewport)),
|
|
558
|
+
zoomIn: (step) =>
|
|
559
|
+
pane.current?.fromHandle(() => pane.current?.zoomIn(step)),
|
|
560
|
+
zoomOut: (step) =>
|
|
561
|
+
pane.current?.fromHandle(() => pane.current?.zoomOut(step)),
|
|
562
|
+
zoomTo: (zoom) =>
|
|
563
|
+
pane.current?.fromHandle(() => pane.current?.zoomTo(zoom)),
|
|
564
|
+
fitView: (options) =>
|
|
565
|
+
pane.current?.fromHandle(() => pane.current?.fitView(options)),
|
|
566
|
+
setCenter: (x, y, options) =>
|
|
567
|
+
pane.current?.fromHandle(() => pane.current?.setCenter(x, y, options)),
|
|
236
568
|
screenToFlowPosition: (point) =>
|
|
237
569
|
pane.current?.screenToFlowPosition(point) ?? point,
|
|
238
570
|
flowToScreenPosition: (point) =>
|
|
@@ -280,23 +612,65 @@ export function Flow<N = FlowNodeData, E = unknown>(
|
|
|
280
612
|
|
|
281
613
|
// --- mounted node bodies ------------------------------------------------
|
|
282
614
|
//
|
|
283
|
-
// Only the
|
|
284
|
-
//
|
|
285
|
-
//
|
|
615
|
+
// Only the nodes whose type asked for one cost anything: with none in the
|
|
616
|
+
// graph the pane is never given `onNodeBodies`, never computes a rect, and
|
|
617
|
+
// this half of the component is one `useState` that stays empty. Asked of
|
|
618
|
+
// the nodes and not of the registry, because the registry is an app's
|
|
619
|
+
// whole vocabulary: a type with a body that no node uses is not a body,
|
|
620
|
+
// and it cost a graph of plain cards the GL surface on XQuartz (below) —
|
|
621
|
+
// the stress example registers its widget types for every scene, and its
|
|
622
|
+
// lattices drew in 2D there, a node dragged at 20 fps where GL drags it
|
|
623
|
+
// at 75. A scan per render of the nodes, a few microseconds at 2,000.
|
|
286
624
|
const { nodeTypes } = rest;
|
|
625
|
+
const bodyTypes = useMemo(() => {
|
|
626
|
+
if (!nodeTypes) return null;
|
|
627
|
+
const names = Object.keys(nodeTypes).filter(
|
|
628
|
+
(name) => nodeTypes[name]?.render != null,
|
|
629
|
+
);
|
|
630
|
+
return names.length > 0 ? new Set(names) : null;
|
|
631
|
+
}, [nodeTypes]);
|
|
287
632
|
const mounts = useMemo(
|
|
288
633
|
() =>
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
[nodeTypes],
|
|
634
|
+
bodyTypes != null &&
|
|
635
|
+
currentNodes.some((node) => bodyTypes.has(node.type ?? 'default')),
|
|
636
|
+
[bodyTypes, currentNodes],
|
|
293
637
|
);
|
|
294
638
|
const [bodies, setBodies] = useState<readonly NodeBodyRect[]>([]);
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
639
|
+
// Where the graph's origin sits in the pane. The bodies are laid out in
|
|
640
|
+
// one box placed here, so a pan — which moves this and nothing else — is
|
|
641
|
+
// one style change rather than a render of every body.
|
|
642
|
+
const [origin, setOrigin] = useState<XYPosition>({ x: 0, y: 0 });
|
|
643
|
+
// Hidden while a zoom moves, and nothing else about them touched — see
|
|
644
|
+
// `_holdBodies` in ./node.ts for what re-scaling them every step cost.
|
|
645
|
+
const [held, setHeld] = useState(false);
|
|
646
|
+
// Where the minimap and controls are, painted over the bodies when there
|
|
647
|
+
// are any to be over.
|
|
648
|
+
const [panels, setPanels] = useState<readonly FlowRect[]>([]);
|
|
649
|
+
const panelCanvases = useRef<
|
|
650
|
+
({
|
|
651
|
+
invalidate(layout: boolean, damage: unknown, reason: string): void;
|
|
652
|
+
} | null)[]
|
|
653
|
+
>([]);
|
|
654
|
+
// Gesture-time emissions commit inline (see `flushSync` above), and so do a
|
|
655
|
+
// handle's — a programmatic pan (`FlowGraphNode.fromHandle`). One made
|
|
656
|
+
// while React is already committing, a pan from a layout effect, is not
|
|
657
|
+
// flushed there: the reconciler runs it at sync priority as the commit
|
|
658
|
+
// ends. The rest — the first paint, what the pane's own frames emit — take
|
|
659
|
+
// the ordinary path.
|
|
660
|
+
const handleBodies = (
|
|
661
|
+
next: readonly NodeBodyRect[],
|
|
662
|
+
sync: boolean,
|
|
663
|
+
at: XYPosition,
|
|
664
|
+
hold: boolean,
|
|
665
|
+
): void => {
|
|
666
|
+
const apply = (): void => {
|
|
667
|
+
// the same array on a pan: React bails out of this update
|
|
668
|
+
setBodies(next);
|
|
669
|
+
setOrigin((was) => (was.x === at.x && was.y === at.y ? was : at));
|
|
670
|
+
setHeld(hold);
|
|
671
|
+
};
|
|
672
|
+
if (sync) flushSync(apply);
|
|
673
|
+
else apply();
|
|
300
674
|
};
|
|
301
675
|
const byId = useMemo(() => {
|
|
302
676
|
const map = new Map<string, FlowNode<N>>();
|
|
@@ -304,58 +678,394 @@ export function Flow<N = FlowNodeData, E = unknown>(
|
|
|
304
678
|
return map;
|
|
305
679
|
}, [mounts, currentNodes]);
|
|
306
680
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
681
|
+
// Every box the bodies are laid out in sits on the device-pixel grid.
|
|
682
|
+
// Layout rounds a box's two edges to whole device pixels separately, so at
|
|
683
|
+
// a fractional scale (1.25, 1.5) a box that moved by a fraction of a
|
|
684
|
+
// device pixel also changed size by one — and core moves a `<glarea>`
|
|
685
|
+
// child's pixels on its pane only when it moved and nothing else
|
|
686
|
+
// (sidorares/react-x11#644): a pan over bodies repainted every one of
|
|
687
|
+
// them, every step. On the grid, a pan moves the layer by whole pixels
|
|
688
|
+
// and every card in it by exactly as many.
|
|
689
|
+
const rootScale = useScale();
|
|
690
|
+
// the pane's own, where it is mounted: a `scale` prop above it counts
|
|
691
|
+
const deviceScale = pane.current?.scale ?? rootScale;
|
|
692
|
+
const snap = (v: number): number => Math.round(v * deviceScale) / deviceScale;
|
|
693
|
+
|
|
694
|
+
// The box the bodies are laid out in covers exactly them. It has to have a
|
|
695
|
+
// real size: core culls a child whose *own* box is off screen or outside
|
|
696
|
+
// a clipping ancestor before it looks at the child's subtree, and a 0×0
|
|
697
|
+
// box at the graph's origin is off screen whenever the graph has been
|
|
698
|
+
// panned past the pane's top-left — which took every body with it.
|
|
699
|
+
const extent = useMemo(() => {
|
|
700
|
+
if (bodies.length === 0) return { x: 0, y: 0, width: 0, height: 0 };
|
|
701
|
+
let x0 = Infinity;
|
|
702
|
+
let y0 = Infinity;
|
|
703
|
+
let x1 = -Infinity;
|
|
704
|
+
let y1 = -Infinity;
|
|
705
|
+
for (const { card } of bodies) {
|
|
706
|
+
x0 = Math.min(x0, card.x - CARD_INK);
|
|
707
|
+
y0 = Math.min(y0, card.y - CARD_INK);
|
|
708
|
+
x1 = Math.max(x1, card.x + card.width + CARD_INK);
|
|
709
|
+
y1 = Math.max(y1, card.y + card.height + CARD_INK);
|
|
710
|
+
}
|
|
711
|
+
const out = (v: number, up: boolean): number =>
|
|
712
|
+
snap((up ? Math.ceil : Math.floor)(v / EXTENT_STEP) * EXTENT_STEP);
|
|
713
|
+
x0 = out(x0, false);
|
|
714
|
+
y0 = out(y0, false);
|
|
715
|
+
x1 = out(x1, true);
|
|
716
|
+
y1 = out(y1, true);
|
|
717
|
+
return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
|
|
718
|
+
}, [bodies, deviceScale]);
|
|
719
|
+
|
|
720
|
+
// The fill a card is drawn in, which its body's box takes too.
|
|
721
|
+
const theme = useTheme();
|
|
722
|
+
const nodeFill = resolvePalette(
|
|
723
|
+
theme as unknown as Record<string, unknown> | null,
|
|
724
|
+
rest.palette,
|
|
725
|
+
).nodeBackground;
|
|
726
|
+
|
|
727
|
+
// One `onDraw` per card for as long as what paints cards holds: core
|
|
728
|
+
// repaints a canvas whose `onDraw` is a new function (react-x11
|
|
729
|
+
// src/nodes/canvas.js), and a closure made per render made every step of
|
|
730
|
+
// a drag repaint every card on screen and every body over them — 36
|
|
731
|
+
// claims, past the frame's rect cap, one rect the size of the pane. What a
|
|
732
|
+
// card shows is in its `cacheKey`; the palette, the theme and the node
|
|
733
|
+
// types are what paint it, and a change to any of them starts over.
|
|
734
|
+
const cardPaint = useMemo(
|
|
735
|
+
() => ({
|
|
736
|
+
drawers: new Map<
|
|
737
|
+
string,
|
|
738
|
+
(ctx: unknown, info: { node: { abs: XYPosition } }) => void
|
|
739
|
+
>(),
|
|
740
|
+
}),
|
|
741
|
+
[theme, rest.palette, nodeTypes],
|
|
742
|
+
);
|
|
743
|
+
const drawCard = (
|
|
744
|
+
id: string,
|
|
745
|
+
): ((ctx: unknown, info: { node: { abs: XYPosition } }) => void) => {
|
|
746
|
+
let draw = cardPaint.drawers.get(id);
|
|
747
|
+
if (!draw) {
|
|
748
|
+
draw = (ctx, info) => pane.current?.paintCard(id, ctx, info.node.abs);
|
|
749
|
+
cardPaint.drawers.set(id, draw);
|
|
750
|
+
}
|
|
751
|
+
return draw;
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
// One card per body, each a memoized component: a drag step moves one
|
|
755
|
+
// card and hands the others the same props they had — the same body
|
|
756
|
+
// object (`_emitBodies` reuses it), the same node object, the same
|
|
757
|
+
// `onDraw` — so React re-renders the card that moved and bails out of the
|
|
758
|
+
// rest. Built as one element list per render, which a pan does not
|
|
759
|
+
// trigger: the box they sit in moves, and nothing here is asked.
|
|
760
|
+
const cards = useMemo(() => {
|
|
761
|
+
if (!mounts) return null;
|
|
762
|
+
const out: FlowBodyCardProps[] = [];
|
|
763
|
+
for (const body of bodies) {
|
|
764
|
+
const node = byId.get(body.id);
|
|
765
|
+
const type = node && nodeTypes?.[node.type ?? 'default'];
|
|
766
|
+
if (!node || !type?.render) continue;
|
|
767
|
+
const { card } = body;
|
|
768
|
+
// on the grid, like the layer (`snap` above)
|
|
769
|
+
const left = snap(card.x - CARD_INK);
|
|
770
|
+
const top = snap(card.y - CARD_INK);
|
|
771
|
+
out.push({
|
|
772
|
+
body,
|
|
773
|
+
node: node as FlowNode<unknown>,
|
|
774
|
+
type: type as FlowNodeType<unknown>,
|
|
775
|
+
left: left - extent.x,
|
|
776
|
+
top: top - extent.y,
|
|
777
|
+
// Sized from the card alone, not as the gap between two edges each
|
|
778
|
+
// put on the grid: at 1.25x a card dragged a fraction of a pixel
|
|
779
|
+
// grew or shrank by one as its edges rounded apart, and a box that
|
|
780
|
+
// changed size is no longer a box that only moved — every step of
|
|
781
|
+
// a drag measured the content floors and repainted the card where
|
|
782
|
+
// core would have moved it. The box draws nothing and takes no
|
|
783
|
+
// pointer; the canvas and the body inside it keep sizes of their
|
|
784
|
+
// own.
|
|
785
|
+
width: snap(card.width + CARD_INK * 2),
|
|
786
|
+
height: snap(card.height + CARD_INK * 2),
|
|
787
|
+
fill:
|
|
788
|
+
(node.style as { background?: string } | undefined)?.background ??
|
|
789
|
+
nodeFill,
|
|
790
|
+
// Cached until something it shows changes (`cardShows`): a new
|
|
791
|
+
// label or style repaints it, a body's own data does not.
|
|
792
|
+
cacheKey:
|
|
793
|
+
`${body.id}:${cardShows(node as FlowNode<unknown>, type as FlowNodeType<unknown>)}:` +
|
|
794
|
+
`${card.width}x${card.height}:` +
|
|
795
|
+
`${body.zoom}:${body.selected}:${body.hovered}:` +
|
|
796
|
+
`${serialOf(cardPaint)}`,
|
|
797
|
+
onDraw: drawCard(body.id),
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
return out;
|
|
801
|
+
}, [
|
|
802
|
+
mounts,
|
|
803
|
+
bodies,
|
|
804
|
+
extent,
|
|
805
|
+
byId,
|
|
806
|
+
nodeTypes,
|
|
807
|
+
nodeFill,
|
|
808
|
+
deviceScale,
|
|
809
|
+
cardPaint,
|
|
810
|
+
]);
|
|
811
|
+
const overlays = cards?.map((props) =>
|
|
812
|
+
React.createElement(FlowBodyCard, { key: props.body.id, ...props }),
|
|
813
|
+
);
|
|
814
|
+
// A wheel over a body is a wheel over the graph. Core runs the wheel's
|
|
815
|
+
// default action on the node under the pointer and scrolls up from there,
|
|
816
|
+
// and the bodies are the pane's siblings, not its children — so over a
|
|
817
|
+
// card's body the pane never heard it, and zooming a graph whose cards
|
|
818
|
+
// are mostly bodies stalled wherever the pointer rested. Forwarded unless
|
|
819
|
+
// something between the pointer and the pane can scroll that way itself:
|
|
820
|
+
// a list inside a card keeps its wheel.
|
|
821
|
+
const forwardWheel = useMemo(
|
|
822
|
+
() =>
|
|
823
|
+
(ev: unknown): void => {
|
|
824
|
+
const node = pane.current;
|
|
825
|
+
const wheel = ev as WheelLike;
|
|
826
|
+
if (!node || wheel.defaultPrevented) return;
|
|
827
|
+
const stop = node.parent;
|
|
828
|
+
for (
|
|
829
|
+
let n: WheelTarget | null | undefined = wheel.target;
|
|
830
|
+
n && n !== (stop as unknown);
|
|
831
|
+
n = n.parent
|
|
832
|
+
) {
|
|
833
|
+
if (n.canScroll?.(wheel.deltaX, wheel.deltaY)) return;
|
|
834
|
+
}
|
|
835
|
+
node.defaultWheel(inPaneUnits(wheel, node) as never);
|
|
836
|
+
wheel.preventDefault();
|
|
837
|
+
},
|
|
838
|
+
[],
|
|
839
|
+
);
|
|
840
|
+
// A press on a body's card-like part is a press on the card. Core runs a
|
|
841
|
+
// press's default actions — select, drag, and the drag's steps and
|
|
842
|
+
// release — on the node that took it, so a body took them all: the cards
|
|
843
|
+
// of a graph whose nodes are mostly body could not be selected or dragged
|
|
844
|
+
// by most of their area. A press that bubbles up here from something that
|
|
845
|
+
// is not a control is the pane's instead: its default is vetoed on the
|
|
846
|
+
// body, the pointer captured so the drag and the release come back here
|
|
847
|
+
// wherever they wander, and each step handed to the pane.
|
|
848
|
+
const pressing = useRef(false);
|
|
849
|
+
const forwardPress = useMemo(() => {
|
|
850
|
+
// From the pressed node up to the bodies' box — which listens for the
|
|
851
|
+
// press itself, and is where the walk stops.
|
|
852
|
+
const within = (ev: PressLike, sink: PressSink): boolean => {
|
|
853
|
+
for (
|
|
854
|
+
let n: WheelTarget | null | undefined = ev.target;
|
|
855
|
+
n && n !== (sink.parent as unknown);
|
|
856
|
+
n = n.parent
|
|
857
|
+
) {
|
|
858
|
+
if (n.props?.onMouseDown === handlers.onMouseDown) return true;
|
|
859
|
+
if (interactive(n)) return false;
|
|
860
|
+
}
|
|
861
|
+
return true;
|
|
862
|
+
};
|
|
863
|
+
const handlers = {
|
|
864
|
+
onMouseDown: (ev: unknown): void => {
|
|
865
|
+
const press = ev as PressLike;
|
|
866
|
+
const sink = pane.current as unknown as PressSink | null;
|
|
867
|
+
if (!sink || press.defaultPrevented || (press.button ?? 1) !== 1)
|
|
868
|
+
return;
|
|
869
|
+
if (!within(press, sink)) return;
|
|
870
|
+
pressing.current = true;
|
|
871
|
+
press.preventDefault();
|
|
872
|
+
press.capturePointer?.();
|
|
873
|
+
sink.defaultMouseDown?.(inPaneUnits(press, sink) as never);
|
|
874
|
+
},
|
|
875
|
+
onMouseMove: (ev: unknown): void => {
|
|
876
|
+
if (!pressing.current) return;
|
|
877
|
+
const sink = pane.current as unknown as PressSink | null;
|
|
878
|
+
sink?.defaultMouseDrag?.(inPaneUnits(ev as PressLike, sink) as never);
|
|
879
|
+
},
|
|
880
|
+
onMouseUp: (ev: unknown): void => {
|
|
881
|
+
if (!pressing.current) return;
|
|
882
|
+
pressing.current = false;
|
|
883
|
+
const sink = pane.current as unknown as PressSink | null;
|
|
884
|
+
sink?.defaultMouseUp?.(inPaneUnits(ev as PressLike, sink) as never);
|
|
885
|
+
},
|
|
886
|
+
};
|
|
887
|
+
return handlers;
|
|
888
|
+
}, []);
|
|
889
|
+
// what each card forwards on its own where it is the surface's child
|
|
890
|
+
const directHandlers = useMemo(
|
|
891
|
+
() => ({ onWheel: forwardWheel, ...forwardPress }),
|
|
892
|
+
[forwardWheel, forwardPress],
|
|
893
|
+
);
|
|
894
|
+
const bodiesLayer = useRef<unknown>(null);
|
|
895
|
+
const layer =
|
|
896
|
+
overlays && overlays.length > 0
|
|
897
|
+
? React.createElement(
|
|
323
898
|
'box',
|
|
324
899
|
{
|
|
325
|
-
key:
|
|
900
|
+
key: 'bodies',
|
|
901
|
+
ref: bodiesLayer,
|
|
326
902
|
style: {
|
|
327
903
|
position: 'absolute',
|
|
328
|
-
left:
|
|
329
|
-
top:
|
|
330
|
-
width:
|
|
331
|
-
height:
|
|
332
|
-
//
|
|
333
|
-
//
|
|
334
|
-
//
|
|
335
|
-
|
|
904
|
+
left: snap(origin.x) + extent.x,
|
|
905
|
+
top: snap(origin.y) + extent.y,
|
|
906
|
+
width: extent.width,
|
|
907
|
+
height: extent.height,
|
|
908
|
+
// The box spans every body, the gaps between them and the
|
|
909
|
+
// cards' headers with them — taking the pointer itself, it ate
|
|
910
|
+
// every press in that span: no pan, no pane click, no selecting
|
|
911
|
+
// a node by its header. Its bodies take the pointer; it does not.
|
|
912
|
+
pointerEvents: 'box-none',
|
|
913
|
+
// held through a zoom gesture: see `_holdBodies` in ./node.ts
|
|
914
|
+
display: held ? 'none' : 'flex',
|
|
336
915
|
},
|
|
916
|
+
onWheel: forwardWheel,
|
|
917
|
+
...forwardPress,
|
|
337
918
|
},
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
919
|
+
overlays,
|
|
920
|
+
)
|
|
921
|
+
: null;
|
|
922
|
+
|
|
923
|
+
// The box a 2D pan carries along with the pane's pixels (`_blitPan`).
|
|
924
|
+
useLayoutEffect(() => {
|
|
925
|
+
pane.current?.setBodiesLayer(
|
|
926
|
+
drawsGlRef.current ? null : bodiesLayer.current,
|
|
927
|
+
);
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
// The cards whose canvases are on screen, told to the pane once they are,
|
|
931
|
+
// so the 2D pane stops drawing them itself — and the empty set while
|
|
932
|
+
// bodies are held out of a zoom, when their cards are the pane's again.
|
|
933
|
+
// The GL world draws every card whatever this says (`_cardInLayer`).
|
|
934
|
+
useLayoutEffect(() => {
|
|
935
|
+
const shown = new Set<string>();
|
|
936
|
+
if (mounts && !held) for (const body of bodies) shown.add(body.id);
|
|
937
|
+
pane.current?.setShownBodies(shown);
|
|
938
|
+
}, [mounts, held, bodies]);
|
|
939
|
+
|
|
940
|
+
// The minimap and the controls over the bodies: the bodies' layer is over
|
|
941
|
+
// the graph, so panels the graph drew went under any card that reached
|
|
942
|
+
// them. Painted by the pane (`paintPanels`) on canvases after the layer,
|
|
943
|
+
// which take no pointer — a press on a button is the pane's, as before.
|
|
944
|
+
const panelLayer =
|
|
945
|
+
mounts && panels.length > 0
|
|
946
|
+
? panels.map((rect, i) =>
|
|
947
|
+
React.createElement('canvas', {
|
|
948
|
+
key: `panel-${i}`,
|
|
949
|
+
ref: (
|
|
950
|
+
node: {
|
|
951
|
+
invalidate(
|
|
952
|
+
layout: boolean,
|
|
953
|
+
damage: unknown,
|
|
954
|
+
reason: string,
|
|
955
|
+
): void;
|
|
956
|
+
} | null,
|
|
957
|
+
) => {
|
|
958
|
+
panelCanvases.current[i] = node;
|
|
959
|
+
},
|
|
960
|
+
style: {
|
|
961
|
+
position: 'absolute',
|
|
962
|
+
left: rect.x,
|
|
963
|
+
top: rect.y,
|
|
964
|
+
width: rect.width,
|
|
965
|
+
height: rect.height,
|
|
966
|
+
pointerEvents: 'none',
|
|
345
967
|
},
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
968
|
+
onDraw: (ctx: unknown, info: { node: { abs: FlowRect } }) =>
|
|
969
|
+
pane.current?.paintPanels(ctx, info.node.abs),
|
|
970
|
+
}),
|
|
971
|
+
)
|
|
972
|
+
: null;
|
|
973
|
+
useLayoutEffect(() => {
|
|
974
|
+
const live = panelCanvases.current
|
|
975
|
+
.slice(0, panelLayer?.length ?? 0)
|
|
976
|
+
.filter((c) => c != null);
|
|
977
|
+
pane.current?.setPanelCanvases(live);
|
|
978
|
+
}, [panelLayer?.length, panels]);
|
|
979
|
+
|
|
980
|
+
// On X11 a <glarea>'s children are not composited over its frame: each
|
|
981
|
+
// child gets an opaque child window, as big as the region it reaches,
|
|
982
|
+
// filled with the surface's clear colour (react-x11's src/gloverlay.js).
|
|
983
|
+
// The bodies' one box reaches every card and the gaps between them, so it
|
|
984
|
+
// became one window over the whole view: cards and bodies, and not one
|
|
985
|
+
// edge. There each card is the surface's child in its own right, placed
|
|
986
|
+
// at the origin itself, and a pane covers a card and nothing more. Where
|
|
987
|
+
// panes composite (Cocoa) the one box stays — a pan moves it alone.
|
|
988
|
+
const app = useApp() as { createOverlayPane?: unknown } | null;
|
|
989
|
+
const composited = typeof app?.createOverlayPane === 'function';
|
|
990
|
+
// …and on XQuartz not shown at all: the macOS window server composites
|
|
991
|
+
// every GL surface there above everything the X server draws, panes
|
|
992
|
+
// included. Core says so (`useSupports('glOverlay')` false, from the first
|
|
993
|
+
// render — sidorares/react-x11#653), and there a graph with nodes whose
|
|
994
|
+
// types mount bodies draws with the 2D renderer: for as long as it has
|
|
995
|
+
// one, not per zoom, so the surface does not come and go as bodies mount.
|
|
996
|
+
const overlaySupported = useSupports('glOverlay');
|
|
997
|
+
const cardsDirect: ReactElement[] = [];
|
|
998
|
+
if (cards && !composited) {
|
|
999
|
+
const offsetX = snap(origin.x) + extent.x;
|
|
1000
|
+
const offsetY = snap(origin.y) + extent.y;
|
|
1001
|
+
for (const props of cards) {
|
|
1002
|
+
cardsDirect.push(
|
|
1003
|
+
React.createElement(FlowBodyCard, {
|
|
1004
|
+
key: props.body.id,
|
|
1005
|
+
...props,
|
|
1006
|
+
offsetX,
|
|
1007
|
+
offsetY,
|
|
1008
|
+
hidden: held,
|
|
1009
|
+
handlers: directHandlers,
|
|
1010
|
+
}),
|
|
1011
|
+
);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// --- the GL surface -----------------------------------------------------
|
|
1016
|
+
//
|
|
1017
|
+
// Loaded when it is asked for and not before — see `./gl/index.ts` for why
|
|
1018
|
+
// the import is dynamic. Until it arrives, and for good once it has failed,
|
|
1019
|
+
// the pane draws itself: `renderer` reaches the element only while a
|
|
1020
|
+
// surface is there to draw, so there is never a frame with neither.
|
|
1021
|
+
const wantGl = renderer === 'gl';
|
|
1022
|
+
const [gl, setGl] = useState<GlModule | null>(glModule);
|
|
1023
|
+
const [glFailed, setGlFailed] = useState(false);
|
|
1024
|
+
const latestError = useRef(onError);
|
|
1025
|
+
latestError.current = onError;
|
|
1026
|
+
const failGl = useMemo(
|
|
1027
|
+
() =>
|
|
1028
|
+
(error: Error): void => {
|
|
1029
|
+
setGlFailed(true);
|
|
1030
|
+
latestError.current?.(error);
|
|
1031
|
+
},
|
|
1032
|
+
[],
|
|
1033
|
+
);
|
|
1034
|
+
useEffect(() => {
|
|
1035
|
+
if (!wantGl || gl || glFailed) return;
|
|
1036
|
+
let live = true;
|
|
1037
|
+
loadGl().then(
|
|
1038
|
+
(module) => {
|
|
1039
|
+
if (live) setGl(module);
|
|
1040
|
+
},
|
|
1041
|
+
(error: unknown) => {
|
|
1042
|
+
if (live)
|
|
1043
|
+
failGl(error instanceof Error ? error : new Error(String(error)));
|
|
1044
|
+
},
|
|
1045
|
+
);
|
|
1046
|
+
return () => {
|
|
1047
|
+
live = false;
|
|
1048
|
+
};
|
|
1049
|
+
}, [wantGl, gl, glFailed]);
|
|
1050
|
+
const drawsGl =
|
|
1051
|
+
wantGl && gl != null && !glFailed && !(mounts && !overlaySupported);
|
|
1052
|
+
drawsGlRef.current = drawsGl;
|
|
1053
|
+
const surface = drawsGl
|
|
1054
|
+
? React.createElement(gl.FlowGlSurface, {
|
|
1055
|
+
key: 'gl',
|
|
1056
|
+
pane,
|
|
1057
|
+
clearColor: resolvePalette(
|
|
1058
|
+
theme as unknown as Record<string, unknown> | null,
|
|
1059
|
+
rest.palette,
|
|
1060
|
+
).background,
|
|
1061
|
+
onFrame: onFrame,
|
|
1062
|
+
onError: failGl,
|
|
1063
|
+
// A `<glarea>`'s children are drawn over its surface, so that is
|
|
1064
|
+
// where the bodies go under GL — beside the pane, they would be
|
|
1065
|
+
// under it.
|
|
1066
|
+
children: composited
|
|
1067
|
+
? [layer, panelLayer]
|
|
1068
|
+
: [cardsDirect.length > 0 ? cardsDirect : null, panelLayer],
|
|
359
1069
|
})
|
|
360
1070
|
: null;
|
|
361
1071
|
|
|
@@ -380,11 +1090,26 @@ export function Flow<N = FlowNodeData, E = unknown>(
|
|
|
380
1090
|
// `<flowgraph>` element zooms and hovers on its own.
|
|
381
1091
|
onWheel,
|
|
382
1092
|
onNodeBodies: mounts ? handleBodies : undefined,
|
|
1093
|
+
onPanels: mounts ? setPanels : undefined,
|
|
1094
|
+
renderer: drawsGl ? 'gl' : undefined,
|
|
1095
|
+
// the element reports the 2D renderer's frames, the surface the GL
|
|
1096
|
+
// one's — one callback either way
|
|
1097
|
+
onFrame,
|
|
383
1098
|
style: styles.fill,
|
|
384
1099
|
role: 'group',
|
|
385
1100
|
'aria-label': rest['aria-label'] ?? 'Flow graph',
|
|
386
1101
|
}),
|
|
387
|
-
|
|
1102
|
+
// After the pane, so the surface covers exactly its box — and with the
|
|
1103
|
+
// bodies inside it under GL, or beside the pane without.
|
|
1104
|
+
surface,
|
|
1105
|
+
drawsGl || !layer
|
|
1106
|
+
? null
|
|
1107
|
+
: React.createElement(
|
|
1108
|
+
'box',
|
|
1109
|
+
{ key: 'bodies-clip', style: styles.bodiesClip },
|
|
1110
|
+
layer,
|
|
1111
|
+
),
|
|
1112
|
+
drawsGl ? null : panelLayer,
|
|
388
1113
|
);
|
|
389
1114
|
}
|
|
390
1115
|
|
|
@@ -453,6 +1178,8 @@ export type {
|
|
|
453
1178
|
EdgeType,
|
|
454
1179
|
FitViewOptions,
|
|
455
1180
|
FlowEdge,
|
|
1181
|
+
FlowBodyBudget,
|
|
1182
|
+
FlowFrameStats,
|
|
456
1183
|
FlowInstance,
|
|
457
1184
|
FlowNode,
|
|
458
1185
|
FlowNodeData,
|