aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package-lock.json641
-rw-r--r--package.json20
-rw-r--r--src/client/util/CaptureManager.tsx4
-rw-r--r--src/client/util/CurrentUserUtils.ts9
-rw-r--r--src/client/util/Scripting.ts1
-rw-r--r--src/client/views/DocComponent.tsx6
-rw-r--r--src/client/views/DocumentDecorations.tsx81
-rw-r--r--src/client/views/InkStrokeProperties.ts191
-rw-r--r--src/client/views/InkingStroke.tsx91
-rw-r--r--src/client/views/LightboxView.tsx15
-rw-r--r--src/client/views/MainView.tsx35
-rw-r--r--src/client/views/MarqueeAnnotator.tsx6
-rw-r--r--src/client/views/PropertiesView.tsx4
-rw-r--r--src/client/views/SidebarAnnos.tsx2
-rw-r--r--src/client/views/StyleProvider.scss10
-rw-r--r--src/client/views/StyleProvider.tsx105
-rw-r--r--src/client/views/collections/CollectionCarousel3DView.tsx41
-rw-r--r--src/client/views/collections/CollectionCarouselView.scss15
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx77
-rw-r--r--src/client/views/collections/CollectionMenu.scss2
-rw-r--r--src/client/views/collections/CollectionMenu.tsx12
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.scss1
-rw-r--r--src/client/views/collections/CollectionStackedTimeline.tsx4
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx2
-rw-r--r--src/client/views/collections/TabDocView.tsx18
-rw-r--r--src/client/views/collections/TreeView.scss18
-rw-r--r--src/client/views/collections/TreeView.tsx7
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx6
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx2
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx29
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx33
-rw-r--r--src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx27
-rw-r--r--src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx27
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx15
-rw-r--r--src/client/views/nodes/ColorBox.tsx2
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx44
-rw-r--r--src/client/views/nodes/DocumentView.scss7
-rw-r--r--src/client/views/nodes/DocumentView.tsx70
-rw-r--r--src/client/views/nodes/FieldView.tsx4
-rw-r--r--src/client/views/nodes/FilterBox.tsx47
-rw-r--r--src/client/views/nodes/ImageBox.tsx50
-rw-r--r--src/client/views/nodes/PDFBox.tsx4
-rw-r--r--src/client/views/nodes/ScreenshotBox.scss7
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx181
-rw-r--r--src/client/views/nodes/VideoBox.scss1
-rw-r--r--src/client/views/nodes/VideoBox.tsx47
-rw-r--r--src/client/views/nodes/WebBox.tsx3
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx44
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx4
-rw-r--r--src/client/views/pdf/PDFViewer.tsx2
-rw-r--r--src/fields/Doc.ts4
-rw-r--r--src/fields/Schema.ts32
-rw-r--r--webpack.config.js4
53 files changed, 1284 insertions, 830 deletions
diff --git a/package-lock.json b/package-lock.json
index fa8f7259b..3637b14ac 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -512,6 +512,42 @@
"react-is": "^16.8.0"
}
},
+ "@react-three/fiber": {
+ "version": "6.0.16",
+ "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-6.0.16.tgz",
+ "integrity": "sha512-oKMYNJOd5t+V4o18aRMhaRhcDQ1NeeCDy52yJvXpu7zrsR04YZtXD4RacW0FDH0KnwkOLDst95LCCphm3Thk/A==",
+ "requires": {
+ "@babel/runtime": "^7.13.10",
+ "react-merge-refs": "^1.1.0",
+ "react-reconciler": "^0.26.2",
+ "react-three-fiber": "0.0.0-deprecated",
+ "react-use-measure": "^2.0.4",
+ "resize-observer-polyfill": "^1.5.1",
+ "scheduler": "^0.20.2",
+ "use-asset": "^1.0.4",
+ "utility-types": "^3.10.0",
+ "zustand": "^3.3.3"
+ },
+ "dependencies": {
+ "@babel/runtime": {
+ "version": "7.13.17",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.17.tgz",
+ "integrity": "sha512-NCdgJEelPTSh+FEFylhnP1ylq848l1z9t9N0j1Lfbcw0+KXGjsTvUmkxy+voLLXB5SOKMbLLx4jxYliGrYQseA==",
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
+ "scheduler": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
+ "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ }
+ }
+ },
"@rkusa/linebreak": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rkusa/linebreak/-/linebreak-1.0.0.tgz",
@@ -683,6 +719,37 @@
"@types/express": "*"
}
},
+ "@types/d3-axis": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-2.0.0.tgz",
+ "integrity": "sha512-gUdlEwGBLl3tXGiBnBNmNzph9W3bCfa4tBgWZD60Z1eDQKTY4zyCAcZ3LksignGfKawYatmDYcBdjJ5h/54sqA==",
+ "requires": {
+ "@types/d3-selection": "*"
+ }
+ },
+ "@types/d3-color": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-2.0.1.tgz",
+ "integrity": "sha512-u7LTCL7RnaavFSmob2rIAJLNwu50i6gFwY9cHFr80BrQURYQBRkJ+Yv47nA3Fm7FeRhdWTiVTeqvSeOuMAOzBQ=="
+ },
+ "@types/d3-scale": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-3.2.2.tgz",
+ "integrity": "sha512-qpQe8G02tzUwt9sdWX1h8A/W0Q1+N48wMnYXVOkrzeLUkCfvzJYV9Ee3aORCS4dN4ONRLFmMvaXdziQ29XGLjQ==",
+ "requires": {
+ "@types/d3-time": "*"
+ }
+ },
+ "@types/d3-selection": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-2.0.0.tgz",
+ "integrity": "sha512-EF0lWZ4tg7oDFg4YQFlbOU3936e3a9UmoQ2IXlBy1+cv2c2Pv7knhKUzGlH5Hq2sF/KeDTH1amiRPey2rrLMQA=="
+ },
+ "@types/d3-time": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-2.0.0.tgz",
+ "integrity": "sha512-Abz8bTzy8UWDeYs9pCa3D37i29EWDjNTjemdk0ei1ApYVNqulYlGUKip/jLOpogkPSsPz/GvZCYiC7MFlEk0iQ=="
+ },
"@types/dotenv": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz",
@@ -845,9 +912,9 @@
"dev": true
},
"@types/memory-fs": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@types/memory-fs/-/memory-fs-0.3.2.tgz",
- "integrity": "sha512-j5AcZo7dbMxHoOimcHEIh0JZe5e1b8q8AqGSpZJrYc7xOgCIP79cIjTdx5jSDLtySnQDwkDTqwlC7Xw7uXw7qg==",
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@types/memory-fs/-/memory-fs-0.3.3.tgz",
+ "integrity": "sha512-rLEYzl1xODshz+Lm+YX8NYws8Xw7/qcYbQInMkotl96VpLZmUvoCfYYGxfajMSiugANV02QO5Fc+R98KKeE4gQ==",
"dev": true,
"requires": {
"@types/node": "*"
@@ -1195,6 +1262,14 @@
"@types/react": "*"
}
},
+ "@types/react-reconciler": {
+ "version": "0.26.1",
+ "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.1.tgz",
+ "integrity": "sha512-jeizEH5o/k6tv42RYNbaulR9KvoSM4RAUq1Q2SXd2HZ7dqgTxN9OIf+GU/sErT7CohB/mUxy9hSjaRLiCPGF5w==",
+ "requires": {
+ "@types/react": "*"
+ }
+ },
"@types/react-select": {
"version": "3.0.13",
"resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-3.0.13.tgz",
@@ -1337,11 +1412,16 @@
"dev": true
},
"@types/tapable": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz",
- "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==",
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.7.tgz",
+ "integrity": "sha512-0VBprVqfgFD7Ehb2vd8Lh9TG3jP98gvr8rgehQqzztZNI7o8zS8Ad4jyZneKELphpuE212D8J70LnSNQSyO6bQ==",
"dev": true
},
+ "@types/three": {
+ "version": "0.126.2",
+ "resolved": "https://registry.npmjs.org/@types/three/-/three-0.126.2.tgz",
+ "integrity": "sha512-6JqTgijtfXcTJik8NtiNxr2L90ex6ElM00qilOGeUcrEsJLOdzLJSIkXHUYS+KPAYQYtRJQKD6XaXds3HjS+gg=="
+ },
"@types/tough-cookie": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz",
@@ -1358,9 +1438,9 @@
}
},
"@types/uglify-js": {
- "version": "3.9.2",
- "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.9.2.tgz",
- "integrity": "sha512-d6dIfpPbF+8B7WiCi2ELY7m0w1joD8cRW4ms88Emdb2w062NeEpbNCeWwVCgzLRpVG+5e74VFSg4rgJ2xXjEiQ==",
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.0.tgz",
+ "integrity": "sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==",
"dev": true,
"requires": {
"source-map": "^0.6.1"
@@ -1387,14 +1467,14 @@
"dev": true
},
"@types/webpack": {
- "version": "4.41.18",
- "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.18.tgz",
- "integrity": "sha512-mQm2R8vV2BZE/qIDVYqmBVLfX73a8muwjs74SpjEyJWJxeXBbsI9L65Pcia9XfYLYWzD1c1V8m+L0p30y2N7MA==",
+ "version": "4.41.27",
+ "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.27.tgz",
+ "integrity": "sha512-wK/oi5gcHi72VMTbOaQ70VcDxSQ1uX8S2tukBK9ARuGXrYM/+u4ou73roc7trXDNmCxCoerE8zruQqX/wuHszA==",
"dev": true,
"requires": {
"@types/anymatch": "*",
"@types/node": "*",
- "@types/tapable": "*",
+ "@types/tapable": "^1",
"@types/uglify-js": "*",
"@types/webpack-sources": "*",
"source-map": "^0.6.0"
@@ -1409,30 +1489,31 @@
}
},
"@types/webpack-dev-middleware": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@types/webpack-dev-middleware/-/webpack-dev-middleware-2.0.5.tgz",
- "integrity": "sha512-B/1X0xAYz62rtjn3gYWaYLRISKzjWehpjndCvpCNuv0OJi4TbIV6QQt9xq/moVxB83u2RjsG8E8S6U/Efg/Vvw==",
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/webpack-dev-middleware/-/webpack-dev-middleware-2.0.7.tgz",
+ "integrity": "sha512-pArv7YnqpbSCOBWiRlR1KgqVorlzkIiwto66hI8Gdgp5ATQAC+Ug4QVz69ZI1dP+D5Rs8QWnbT81tE4tcMuTag==",
"dev": true,
"requires": {
"@types/connect": "*",
"@types/memory-fs": "*",
- "@types/webpack": "*"
+ "@types/webpack": "^4",
+ "loglevel": "^1.6.2"
}
},
"@types/webpack-hot-middleware": {
- "version": "2.25.3",
- "resolved": "https://registry.npmjs.org/@types/webpack-hot-middleware/-/webpack-hot-middleware-2.25.3.tgz",
- "integrity": "sha512-zGkTzrwQnhSadIXGYGZLu7tpXQwn4+6y9nGeql+5UeRtW/k54Jp4SnzB0Qw00ednw0ZFoZOvqTFfXSbFXohc5Q==",
+ "version": "2.25.4",
+ "resolved": "https://registry.npmjs.org/@types/webpack-hot-middleware/-/webpack-hot-middleware-2.25.4.tgz",
+ "integrity": "sha512-6tQb9EBKIANZYUVLQYWiWfDFVe7FhXSj4bB2EF5QB7VtYWL3HDR+y/zqjZPAnCorv0spLqVMRqjRK8AmhfocMw==",
"dev": true,
"requires": {
"@types/connect": "*",
- "@types/webpack": "*"
+ "@types/webpack": "^4"
}
},
"@types/webpack-sources": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-1.4.0.tgz",
- "integrity": "sha512-c88dKrpSle9BtTqR6ifdaxu1Lvjsl3C5OsfvuUbUwdXymshv1TkufUAXBajCCUM/f/TmnkZC/Esb03MinzSiXQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz",
+ "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==",
"dev": true,
"requires": {
"@types/node": "*",
@@ -2133,14 +2214,23 @@
}
},
"asn1.js": {
- "version": "4.10.1",
- "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
- "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
+ "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
"dev": true,
"requires": {
"bn.js": "^4.0.0",
"inherits": "^2.0.1",
- "minimalistic-assert": "^1.0.0"
+ "minimalistic-assert": "^1.0.0",
+ "safer-buffer": "^2.1.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
}
},
"assert": {
@@ -2592,9 +2682,9 @@
"integrity": "sha512-6sTGh1OiUmuH8ftAYvUzALivoOmcnahinGmjZFI4puZVowXoKTn/bXtth7N1skW5AlezEOfjgFH4lNXHeNRQog=="
},
"bn.js": {
- "version": "4.11.8",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
- "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
+ "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==",
"dev": true
},
"body-parser": {
@@ -2788,28 +2878,38 @@
}
},
"browserify-rsa": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
- "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
+ "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
"dev": true,
"requires": {
- "bn.js": "^4.1.0",
+ "bn.js": "^5.0.0",
"randombytes": "^2.0.1"
}
},
"browserify-sign": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
- "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
+ "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
"dev": true,
"requires": {
- "bn.js": "^4.1.1",
- "browserify-rsa": "^4.0.0",
- "create-hash": "^1.1.0",
- "create-hmac": "^1.1.2",
- "elliptic": "^6.0.0",
- "inherits": "^2.0.1",
- "parse-asn1": "^5.0.0"
+ "bn.js": "^5.1.1",
+ "browserify-rsa": "^4.0.1",
+ "create-hash": "^1.2.0",
+ "create-hmac": "^1.1.7",
+ "elliptic": "^6.5.3",
+ "inherits": "^2.0.4",
+ "parse-asn1": "^5.1.5",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true
+ }
}
},
"browserify-zlib": {
@@ -3675,13 +3775,10 @@
}
},
"chrome-trace-event": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz",
- "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==",
- "dev": true,
- "requires": {
- "tslib": "^1.9.0"
- }
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
+ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
+ "dev": true
},
"ci-info": {
"version": "1.6.0",
@@ -4336,13 +4433,21 @@
}
},
"create-ecdh": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
- "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
+ "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
"dev": true,
"requires": {
"bn.js": "^4.1.0",
- "elliptic": "^6.0.0"
+ "elliptic": "^6.5.3"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
}
},
"create-emotion": {
@@ -4828,6 +4933,11 @@
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
"integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0="
},
+ "debounce": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
+ "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug=="
+ },
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
@@ -5313,6 +5423,14 @@
"bn.js": "^4.1.0",
"miller-rabin": "^4.0.0",
"randombytes": "^2.0.0"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
}
},
"dir-glob": {
@@ -5522,18 +5640,26 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"elliptic": {
- "version": "6.5.2",
- "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
- "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
+ "version": "6.5.4",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
+ "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
"dev": true,
"requires": {
- "bn.js": "^4.4.0",
- "brorand": "^1.0.1",
+ "bn.js": "^4.11.9",
+ "brorand": "^1.1.0",
"hash.js": "^1.0.0",
- "hmac-drbg": "^1.0.0",
- "inherits": "^2.0.1",
- "minimalistic-assert": "^1.0.0",
- "minimalistic-crypto-utils": "^1.0.0"
+ "hmac-drbg": "^1.0.1",
+ "inherits": "^2.0.4",
+ "minimalistic-assert": "^1.0.1",
+ "minimalistic-crypto-utils": "^1.0.1"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
}
},
"emoji-regex": {
@@ -5811,12 +5937,20 @@
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"esrecurse": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
- "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
"requires": {
- "estraverse": "^4.1.0"
+ "estraverse": "^5.2.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
}
},
"estraverse": {
@@ -5847,9 +5981,9 @@
"dev": true
},
"events": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz",
- "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"dev": true
},
"eventsource": {
@@ -7241,13 +7375,22 @@
}
},
"hash-base": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
- "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+ "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
"dev": true,
"requires": {
- "inherits": "^2.0.1",
- "safe-buffer": "^5.0.1"
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.6.0",
+ "safe-buffer": "^5.2.0"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true
+ }
}
},
"hash.js": {
@@ -9180,6 +9323,14 @@
"requires": {
"bn.js": "^4.0.0",
"brorand": "^1.0.1"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
}
},
"mime": {
@@ -13477,14 +13628,13 @@
}
},
"parse-asn1": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz",
- "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==",
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
+ "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
"dev": true,
"requires": {
- "asn1.js": "^4.0.0",
+ "asn1.js": "^5.2.0",
"browserify-aes": "^1.0.0",
- "create-hash": "^1.1.0",
"evp_bytestokey": "^1.0.0",
"pbkdf2": "^3.0.3",
"safe-buffer": "^5.1.1"
@@ -13640,9 +13790,9 @@
"integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
},
"pbkdf2": {
- "version": "3.0.17",
- "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
- "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
+ "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
"dev": true,
"requires": {
"create-hash": "^1.1.2",
@@ -14164,6 +14314,14 @@
"parse-asn1": "^5.0.0",
"randombytes": "^2.0.1",
"safe-buffer": "^5.1.2"
+ },
+ "dependencies": {
+ "bn.js": {
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
+ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
+ "dev": true
+ }
}
},
"pug": {
@@ -14726,6 +14884,11 @@
"resize-observer-polyfill": "^1.5.0"
}
},
+ "react-merge-refs": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz",
+ "integrity": "sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ=="
+ },
"react-modal": {
"version": "3.11.2",
"resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.11.2.tgz",
@@ -14785,6 +14948,27 @@
}
}
},
+ "react-reconciler": {
+ "version": "0.26.2",
+ "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.26.2.tgz",
+ "integrity": "sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "scheduler": "^0.20.2"
+ },
+ "dependencies": {
+ "scheduler": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
+ "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ }
+ }
+ },
"react-redux": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.0.tgz",
@@ -14881,6 +15065,11 @@
}
}
},
+ "react-three-fiber": {
+ "version": "0.0.0-deprecated",
+ "resolved": "https://registry.npmjs.org/react-three-fiber/-/react-three-fiber-0.0.0-deprecated.tgz",
+ "integrity": "sha512-EblIqTAsIpkYeM8bZtC4lcpTE0A2zCEGipFB52RgcQq/q+0oryrk7Sxt+sqhIjUu6xMNEVywV8dr74lz5yWO6A=="
+ },
"react-transition-group": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
@@ -14892,6 +15081,14 @@
"react-lifecycles-compat": "^3.0.4"
}
},
+ "react-use-measure": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.0.4.tgz",
+ "integrity": "sha512-7K2HIGaPMl3Q9ZQiEVjen3tRXl4UDda8LiTPy/QxP8dP2rl5gPBhf7mMH6MVjjRNv3loU7sNzey/ycPNnHVTxQ==",
+ "requires": {
+ "debounce": "^1.2.0"
+ }
+ },
"reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
@@ -16768,9 +16965,9 @@
}
},
"terser": {
- "version": "4.6.12",
- "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.12.tgz",
- "integrity": "sha512-fnIwuaKjFPANG6MAixC/k1TDtnl1YlPLUlLVIxxGZUn1gfUx2+l3/zGNB72wya+lgsb50QBi2tUV75RiODwnww==",
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
+ "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
"dev": true,
"requires": {
"commander": "^2.20.0",
@@ -16787,16 +16984,16 @@
}
},
"terser-webpack-plugin": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
- "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz",
+ "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==",
"dev": true,
"requires": {
"cacache": "^12.0.2",
"find-cache-dir": "^2.1.0",
"is-wsl": "^1.1.0",
"schema-utils": "^1.0.0",
- "serialize-javascript": "^2.1.2",
+ "serialize-javascript": "^4.0.0",
"source-map": "^0.6.1",
"terser": "^4.1.2",
"webpack-sources": "^1.4.0",
@@ -16883,23 +17080,15 @@
"glob": "^7.1.3"
}
},
- "schema-utils": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
- "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
+ "serialize-javascript": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
+ "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
"dev": true,
"requires": {
- "ajv": "^6.1.0",
- "ajv-errors": "^1.0.0",
- "ajv-keywords": "^3.1.0"
+ "randombytes": "^2.1.0"
}
},
- "serialize-javascript": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
- "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
- "dev": true
- },
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -16907,9 +17096,9 @@
"dev": true
},
"ssri": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
- "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
+ "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
"dev": true,
"requires": {
"figgy-pudding": "^3.5.1"
@@ -16922,6 +17111,11 @@
"resolved": "https://registry.npmjs.org/textarea-caret/-/textarea-caret-3.1.0.tgz",
"integrity": "sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q=="
},
+ "three": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/three/-/three-0.127.0.tgz",
+ "integrity": "sha512-wtgrn+mhYUbobxT7QN3GPdu3SRpSBQvwY6uOzLChWS7QE//f7paDU/+wlzbg+ngeIvBBqjBHSRuywTh8A99Jng=="
+ },
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
@@ -16966,9 +17160,9 @@
"integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8="
},
"timers-browserify": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz",
- "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==",
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
+ "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
"dev": true,
"requires": {
"setimmediate": "^1.0.4"
@@ -17489,9 +17683,9 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"typescript": {
- "version": "3.9.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz",
- "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==",
+ "version": "3.9.9",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
+ "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
"dev": true
},
"typescript-collections": {
@@ -17887,6 +18081,21 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
},
+ "use-asset": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/use-asset/-/use-asset-1.0.4.tgz",
+ "integrity": "sha512-7/hqDrWa0iMnCoET9W1T07EmD4Eg/Wmoj/X8TGBc++ECRK4m5yTsjP4O6s0yagbxfqIOuUkIxe2/sA+VR2GxZA==",
+ "requires": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "dependencies": {
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ }
+ }
+ },
"use-memo-one": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.1.tgz",
@@ -17914,6 +18123,11 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
+ "utility-types": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz",
+ "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg=="
+ },
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -18061,14 +18275,136 @@
}
},
"watchpack": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz",
- "integrity": "sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA==",
+ "version": "1.7.5",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
+ "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==",
"dev": true,
"requires": {
- "chokidar": "^2.1.8",
+ "chokidar": "^3.4.1",
"graceful-fs": "^4.1.2",
- "neo-async": "^2.5.0"
+ "neo-async": "^2.5.0",
+ "watchpack-chokidar2": "^2.0.1"
+ },
+ "dependencies": {
+ "anymatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+ "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true,
+ "optional": true
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "chokidar": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
+ "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "anymatch": "~3.1.1",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.1",
+ "glob-parent": "~5.1.0",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.5.0"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true
+ },
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "optional": true
+ },
+ "readdirp": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
+ "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ }
+ }
+ },
+ "watchpack-chokidar2": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz",
+ "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "chokidar": "^2.1.8"
}
},
"wbuf": {
@@ -18095,9 +18431,9 @@
"dev": true
},
"webpack": {
- "version": "4.43.0",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.43.0.tgz",
- "integrity": "sha512-GW1LjnPipFW2Y78OOab8NJlCflB7EFskMih2AHdvjbpKMeDJqEgSx24cXXXiPS65+WSwVyxtDsJH6jGX2czy+g==",
+ "version": "4.46.0",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz",
+ "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==",
"dev": true,
"requires": {
"@webassemblyjs/ast": "1.9.0",
@@ -18108,7 +18444,7 @@
"ajv": "^6.10.2",
"ajv-keywords": "^3.4.1",
"chrome-trace-event": "^1.0.2",
- "enhanced-resolve": "^4.1.0",
+ "enhanced-resolve": "^4.5.0",
"eslint-scope": "^4.0.3",
"json-parse-better-errors": "^1.0.2",
"loader-runner": "^2.4.0",
@@ -18121,16 +18457,39 @@
"schema-utils": "^1.0.0",
"tapable": "^1.1.3",
"terser-webpack-plugin": "^1.4.3",
- "watchpack": "^1.6.1",
+ "watchpack": "^1.7.4",
"webpack-sources": "^1.4.1"
},
"dependencies": {
"acorn": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
- "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
+ "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
"dev": true
},
+ "enhanced-resolve": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
+ "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "memory-fs": "^0.5.0",
+ "tapable": "^1.0.0"
+ },
+ "dependencies": {
+ "memory-fs": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
+ "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
+ "dev": true,
+ "requires": {
+ "errno": "^0.1.3",
+ "readable-stream": "^2.0.1"
+ }
+ }
+ }
+ },
"memory-fs": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
@@ -18155,17 +18514,6 @@
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
- },
- "schema-utils": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
- "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
- "dev": true,
- "requires": {
- "ajv": "^6.1.0",
- "ajv-errors": "^1.0.0",
- "ajv-keywords": "^3.1.0"
- }
}
}
},
@@ -18219,9 +18567,9 @@
}
},
"webpack-dev-middleware": {
- "version": "3.7.2",
- "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz",
- "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==",
+ "version": "3.7.3",
+ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz",
+ "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==",
"dev": true,
"requires": {
"memory-fs": "^0.4.1",
@@ -18242,9 +18590,9 @@
}
},
"mime": {
- "version": "2.4.4",
- "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
- "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==",
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
+ "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==",
"dev": true
},
"readable-stream": {
@@ -18816,6 +19164,11 @@
"compress-commons": "^2.1.1",
"readable-stream": "^3.4.0"
}
+ },
+ "zustand": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.4.1.tgz",
+ "integrity": "sha512-Kb91vSjy5vwBQ/PQ1a5GE6naS3gCxCgpkujT9zqZSO85+gnvmzgqraMW3ao1I0jR4PwHBXtLTf26r9j7EXoUiQ=="
}
}
}
diff --git a/package.json b/package.json
index 7ea6fdc6f..6cbde9e1f 100644
--- a/package.json
+++ b/package.json
@@ -85,9 +85,9 @@
"@types/typescript": "^2.0.0",
"@types/uuid": "^3.4.6",
"@types/valid-url": "^1.0.3",
- "@types/webpack": "^4.41.18",
- "@types/webpack-dev-middleware": "^2.0.5",
- "@types/webpack-hot-middleware": "^2.25.3",
+ "@types/webpack": "^4.41.27",
+ "@types/webpack-dev-middleware": "^2.0.7",
+ "@types/webpack-hot-middleware": "^2.25.4",
"@types/xregexp": "^4.3.0",
"@types/youtube": "0.0.39",
"awesome-typescript-loader": "^5.2.1",
@@ -108,10 +108,10 @@
"ts-node-dev": "^1.0.0-pre.49",
"tslint": "^5.20.1",
"tslint-loader": "^3.6.0",
- "typescript": "^3.9.5",
- "webpack": "^4.41.5",
+ "typescript": "^3.9.9",
+ "webpack": "^4.46.0",
"webpack-cli": "^3.3.12",
- "webpack-dev-middleware": "^3.7.2",
+ "webpack-dev-middleware": "^3.7.3",
"webpack-dev-server": "^3.11.0",
"webpack-hot-middleware": "^2.24.3"
},
@@ -125,9 +125,16 @@
"@hig/theme-context": "^2.1.3",
"@hig/theme-data": "^2.16.1",
"@material-ui/core": "^4.11.0",
+ "@react-three/fiber": "^6.0.16",
"@types/cors": "^2.8.8",
+ "@types/d3-axis": "^2.0.0",
+ "@types/d3-color": "^2.0.1",
+ "@types/d3-scale": "^3.2.2",
+ "@types/d3-selection": "^2.0.0",
"@types/google-maps": "^3.2.2",
+ "@types/react-reconciler": "^0.26.1",
"@types/reveal": "^3.3.33",
+ "@types/three": "^0.126.2",
"@types/webscopeio__react-textarea-autocomplete": "^4.6.1",
"@webscopeio/react-textarea-autocomplete": "^4.7.0",
"adm-zip": "^0.4.16",
@@ -254,6 +261,7 @@
"standard-http-error": "^2.0.1",
"styled-components": "^4.4.1",
"textarea-caret": "^3.1.0",
+ "three": "^0.127.0",
"translate-google-api": "^1.0.4",
"typescript-collections": "^1.3.3",
"typescript-language-server": "^0.4.0",
diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx
index c38337c91..c247afa26 100644
--- a/src/client/util/CaptureManager.tsx
+++ b/src/client/util/CaptureManager.tsx
@@ -99,7 +99,7 @@ export class CaptureManager extends React.Component<{}> {
Cancel
</div>
</div>
- </div>
+ </div>;
}
@@ -135,6 +135,6 @@ export class CaptureManager extends React.Component<{}> {
dialogueBoxStyle={{ width: "500px", height: "350px", border: "none", background: "whitesmoke" }}
overlayStyle={{ background: "black" }}
overlayDisplayedOpacity={0.6}
- />
+ />;
}
} \ No newline at end of file
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 9bf78b186..5dbded00e 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -425,6 +425,10 @@ export class CurrentUserUtils {
if (doc.emptyScreenshot === undefined) {
doc.emptyScreenshot = Docs.Create.ScreenshotDocument("empty screenshot", { _fitWidth: true, _width: 400, _height: 200, system: true, cloneFieldFilter: new List<string>(["system"]) });
}
+ if (doc.emptyWall === undefined) {
+ doc.emptyWall = Docs.Create.ScreenshotDocument("", { _fitWidth: true, _width: 400, _height: 200, title: "screen snapshot", system: true, cloneFieldFilter: new List<string>(["system"]) });
+ (doc.emptyWall as Doc).videoWall = true;
+ }
if (doc.emptyAudio === undefined) {
doc.emptyAudio = Docs.Create.AudioDocument(nullAudio, { _width: 200, title: "audio recording", system: true, cloneFieldFilter: new List<string>(["system"]) });
((doc.emptyAudio as Doc).proto as Doc)["dragFactory-count"] = 0;
@@ -454,6 +458,7 @@ export class CurrentUserUtils {
{ toolTip: "Tap to create a cat image in a new pane, drag for a cat image", title: "Image", icon: "cat", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyImage as Doc },
{ toolTip: "Tap to create a comparison box in a new pane, drag for a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyComparison as Doc, noviceMode: true },
{ toolTip: "Tap to create a screen grabber in a new pane, drag for a screen grabber", title: "Grab", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScreenshot as Doc, noviceMode: true },
+ { toolTip: "Tap to create a videoWall", title: "Wall", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWall as Doc },
{ toolTip: "Tap to create an audio recorder in a new pane, drag for an audio recorder", title: "Audio", icon: "microphone", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyAudio as Doc, noviceMode: true },
{ toolTip: "Tap to create a button in a new pane, drag for a button", title: "Button", icon: "bolt", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyButton as Doc },
{ toolTip: "Tap to create a presentation in a new pane, drag for a presentation", title: "Trails", icon: "pres-trail", click: 'openOnRight(Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory))', drag: `Doc.UserDoc().activePresentation = copyDragFactory(this.dragFactory)`, dragFactory: doc.emptyPresentation as Doc, noviceMode: true },
@@ -1248,4 +1253,6 @@ Scripting.addGlobal(function shareDashboard(dashboard: Doc) {
},
"opens sharing dialog for Dashboard");
Scripting.addGlobal(function addToDashboards(dashboard: Doc) { Doc.AddDocToList(CurrentUserUtils.MyDashboards, "data", dashboard); },
- "adds Dashboard to set of Dashboards"); \ No newline at end of file
+ "adds Dashboard to set of Dashboards");
+Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; },
+ "toggle between regular rendeing and an informal sketch/comic style");
diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index cb0a4bea0..c3c3083be 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -1,5 +1,6 @@
import * as ts from "typescript";
export { ts };
+
// export const ts = (window as any).ts;
// // @ts-ignore
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 677e5ad01..f1042de0f 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -124,8 +124,8 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name, scale: "number" })?.script.run({ self: this.rootDoc, this: this.layoutDoc, scale }).result as string || "";
};
divKeys.map((prop: string) => {
- const p = (this.props as any)[prop] as string;
- p && (style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer));
+ const p = (this.props as any)[prop];
+ typeof p === "string" && (style[prop] = p?.replace(/{([^.'][^}']+)}/g, replacer));
});
return style;
}
@@ -182,7 +182,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
addDocument(doc: Doc | Doc[], annotationKey?: string): boolean {
const docs = doc instanceof Doc ? [doc] : doc;
if (this.props.filterAddDocument?.(docs) === false ||
- docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document))) {
+ docs.find(doc => Doc.AreProtosEqual(doc, this.props.Document) && Doc.LayoutField(doc) === Doc.LayoutField(this.props.Document))) {
return false;
}
const targetDataDoc = this.props.Document[DataSym];
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e23374cea..bf939d57c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -8,7 +8,7 @@ import { Document } from '../../fields/documentSchemas';
import { HtmlField } from '../../fields/HtmlField';
import { InkField } from "../../fields/InkField";
import { ScriptField } from '../../fields/ScriptField';
-import { Cast, NumCast } from "../../fields/Types";
+import { Cast, NumCast, StrCast } from "../../fields/Types";
import { GetEffectiveAcl } from '../../fields/util';
import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils";
import { Docs, DocUtils } from "../documents/Documents";
@@ -26,6 +26,7 @@ import { InkStrokeProperties } from './InkStrokeProperties';
import { LightboxView } from './LightboxView';
import { DocumentView } from "./nodes/DocumentView";
import React = require("react");
+import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
@observer
export class DocumentDecorations extends React.Component<{ boundsLeft: number, boundsTop: number }, { value: string }> {
@@ -83,7 +84,21 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
UndoManager.RunInBatch(() => titleFieldKey && SelectionManager.Views().forEach(d => {
titleFieldKey === "title" && (d.dataDoc["title-custom"] = !this._accumulatedTitle.startsWith("-"));
//@ts-ignore
- Doc.SetInPlace(d.rootDoc, titleFieldKey, +this._accumulatedTitle === this._accumulatedTitle ? +this._accumulatedTitle : this._accumulatedTitle, true);
+ const titleField = (+this._accumulatedTitle === this._accumulatedTitle ? +this._accumulatedTitle : this._accumulatedTitle);
+ Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true);
+
+ if (d.rootDoc.syncLayoutFieldWithTitle) {
+ const title = titleField.toString();
+ const curKey = Doc.LayoutFieldKey(d.rootDoc);
+ if (curKey !== title && d.dataDoc[title] === undefined) {
+ d.rootDoc.layout = FormattedTextBox.LayoutString(title);
+ setTimeout(() => {
+ const val = d.dataDoc[curKey];
+ d.dataDoc[curKey] = undefined;
+ d.dataDoc[title] = val;
+ });
+ }
+ }
}), "title blur");
}
}
@@ -126,6 +141,17 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
SelectionManager.DeselectAll();
selected.map(dv => dv.props.removeDocument?.(dv.props.Document));
}
+ onMaximizeDown = (e: React.PointerEvent) => {
+ setupMoveUpEvents(this, e, () => {
+ DragManager.StartWindowDrag?.({
+ pageX: e.pageX,
+ pageY: e.pageY,
+ preventDefault: emptyFunction,
+ button: 0
+ }, [SelectionManager.Views().lastElement().rootDoc]);
+ return true;
+ }, emptyFunction, this.onMaximizeClick, false, false);
+ }
@undoBatch
@action
onMaximizeClick = (e: any): void => {
@@ -171,8 +197,15 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
@action
onRotateDown = (e: React.PointerEvent): void => {
this._rotateUndo = UndoManager.StartBatch("rotatedown");
-
- setupMoveUpEvents(this, e, this.onRotateMove, () => this._rotateUndo?.end(), emptyFunction);
+ setupMoveUpEvents(this, e,
+ (e: PointerEvent, down: number[], delta: number[]) => {
+ const movement = { X: delta[0], Y: e.clientY - down[1] };
+ const angle = Math.max(1, Math.abs(movement.Y / 10));
+ InkStrokeProperties.Instance?.rotate(2 * movement.X / angle * (Math.PI / 180));
+ return false;
+ },
+ () => this._rotateUndo?.end(),
+ emptyFunction);
this._prevY = e.clientY;
this._inkCenterPts = SelectionManager.Views()
.filter(dv => dv.rootDoc.type === DocumentType.INK)
@@ -181,26 +214,6 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
}
@action
- onRotateMove = (e: PointerEvent, down: number[]): boolean => {
- const distance = Math.abs(this._prevY - e.clientY);
- const angle = e.clientY > this._prevY ? distance * (Math.PI / 180) : e.clientY < this._prevY ? - distance * (Math.PI / 180) : 0;
- this._prevY = e.clientY;
- this._inkCenterPts.map(({ doc, X, Y }) => ({ doc, X, Y, inkData: Cast(doc.data, InkField)?.inkData }))
- .forEach(pair => {
- const newPoints = pair.inkData?.map(ink => ({
- X: Math.cos(angle) * (ink.X - pair.X) - Math.sin(angle) * (ink.Y - pair.Y) + pair.X,
- Y: Math.sin(angle) * (ink.X - pair.X) + Math.cos(angle) * (ink.Y - pair.Y) + pair.Y
- })) || [];
- Doc.GetProto(pair.doc).data = new InkField(newPoints);
-
- pair.doc._width = ((xs) => (Math.max(...xs) - Math.min(...xs)))(newPoints.map(p => p.X) || [0]);
- pair.doc._height = ((ys) => (Math.max(...ys) - Math.min(...ys)))(newPoints.map(p => p.Y) || [0]);
- pair.doc.rotation = NumCast(pair.doc.rotation) + angle;
- });
- return false;
- }
-
- @action
onPointerDown = (e: React.PointerEvent): void => {
DragManager.docsBeingDragged = SelectionManager.Views().map(dv => dv.rootDoc);
this._inkDragDocs = DragManager.docsBeingDragged
@@ -376,10 +389,10 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
this._inkDragDocs.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
.forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => {
Doc.GetProto(doc).data = new InkField(inkPts.map(ipt => // (new x — oldx) + newWidth * (oldxpoint /oldWidth)
- ({
- X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width,
- Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height
- })));
+ ({
+ X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width,
+ Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height
+ })));
Doc.SetNativeWidth(doc, undefined);
Doc.SetNativeHeight(doc, undefined);
});
@@ -412,10 +425,10 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
return (!docView.rootDoc._stayInCollection || docView.rootDoc.isInkMask) &&
(collectionAcl === AclAdmin || collectionAcl === AclEdit || GetEffectiveAcl(docView.rootDoc) === AclAdmin);
});
- const topBtn = (key: string, icon: string, click: (e: any) => void, title: string) => (
+ const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
<Tooltip key={key} title={<div className="dash-tooltip">{title}</div>} placement="top">
<div className={`documentDecorations-${key}Button`} onContextMenu={e => e.preventDefault()}
- onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, click, emptyFunction)} >
+ onPointerDown={pointerDown ?? (e => setupMoveUpEvents(this, e, returnFalse, click!, emptyFunction))} >
<FontAwesomeIcon icon={icon as any} />
</div>
</Tooltip>);
@@ -456,13 +469,13 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
left: bounds.x - this._resizeBorderWidth / 2,
top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight,
}}>
- {!canDelete ? <div /> : topBtn("close", "times", this.onCloseClick, "Close")}
+ {!canDelete ? <div /> : topBtn("close", "times", undefined, this.onCloseClick, "Close")}
{seldoc.props.hideDecorationTitle || seldoc.props.Document.type === DocumentType.EQUATION ? (null) : titleArea}
{seldoc.props.hideResizeHandles || seldoc.props.Document.type === DocumentType.EQUATION ? (null) :
<>
{SelectionManager.Views().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) :
- topBtn("iconify", `window-${seldoc.finalLayoutKey.includes("icon") ? "restore" : "minimize"}`, this.onIconifyClick, `${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`)}
- {!canOpen ? (null) : topBtn("open", "external-link-alt", this.onMaximizeClick, "Open in Tab (ctrl: as alias, shift: in new collection)")}
+ topBtn("iconify", `window-${seldoc.finalLayoutKey.includes("icon") ? "restore" : "minimize"}`, undefined, this.onIconifyClick, `${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`)}
+ {!canOpen ? (null) : topBtn("open", "external-link-alt", this.onMaximizeDown, undefined, "Open in Tab (ctrl: as alias, shift: in new collection)")}
<div key="tl" className="documentDecorations-topLeftResizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} />
<div key="t" className="documentDecorations-topResizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} />
<div key="tr" className="documentDecorations-topRightResizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} />
@@ -474,7 +487,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
<div key="br" className="documentDecorations-bottomRightResizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} />
{seldoc.props.renderDepth <= 1 || !seldoc.props.ContainingCollectionView ? (null) :
- topBtn("selector", "arrow-alt-circle-up", this.onSelectorClick, "tap to select containing document")}
+ topBtn("selector", "arrow-alt-circle-up", undefined, this.onSelectorClick, "tap to select containing document")}
<div key="rot" className={`documentDecorations-${useRotation ? "rotation" : "borderRadius"}`}
onPointerDown={useRotation ? this.onRotateDown : this.onRadiusDown} onContextMenu={(e) => e.preventDefault()}>{useRotation && "⟲"}</div>
</>
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index 9257ee4e6..b13b04f68 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -2,11 +2,12 @@ import { action, computed, observable } from "mobx";
import { ColorState } from 'react-color';
import { Doc, Field, Opt } from "../../fields/Doc";
import { Document } from "../../fields/documentSchemas";
-import { InkField } from "../../fields/InkField";
+import { InkField, InkData } from "../../fields/InkField";
import { Cast, NumCast } from "../../fields/Types";
import { DocumentType } from "../documents/DocumentTypes";
import { SelectionManager } from "../util/SelectionManager";
import { undoBatch } from "../util/UndoManager";
+import { bool } from "sharp";
export class InkStrokeProperties {
static Instance: InkStrokeProperties | undefined;
@@ -114,139 +115,99 @@ export class InkStrokeProperties {
}));
}
- @undoBatch
- @action
- deletePoints = () => {
+ applyFunction = (func: (doc: Doc, ink: InkData, ptsXscale: number, ptsYscale: number) => { X: number, Y: number }[] | undefined, requireCurrPoint: boolean = false) => {
+ var appliedFunc = false;
this.selectedInk?.forEach(action(inkView => {
- if (this.selectedInk?.length === 1 && this._currPoint !== -1) {
+ if (this.selectedInk?.length === 1 && (!requireCurrPoint || this._currPoint !== -1)) {
const doc = Document(inkView.rootDoc);
- if (doc.type === DocumentType.INK) {
+ if (doc.type === DocumentType.INK && doc.width && doc.height) {
const ink = Cast(doc.data, InkField)?.inkData;
- if (ink && ink.length > 4) {
- const newPoints: { X: number, Y: number }[] = [];
- const toRemove = Math.floor(((this._currPoint + 2) / 4));
- for (var i = 0; i < ink.length; i++) {
- if (Math.floor((i + 2) / 4) !== toRemove) {
- newPoints.push({ X: ink[i].X, Y: ink[i].Y });
- }
- }
- this._currPoint = -1;
- Doc.GetProto(doc).data = new InkField(newPoints);
- if (newPoints.length === 4) {
- const newerPoints: { X: number, Y: number }[] = [];
- newerPoints.push({ X: newPoints[0].X, Y: newPoints[0].Y });
- newerPoints.push({ X: newPoints[0].X, Y: newPoints[0].Y });
- newerPoints.push({ X: newPoints[3].X, Y: newPoints[3].Y });
- newerPoints.push({ X: newPoints[3].X, Y: newPoints[3].Y });
- Doc.GetProto(doc).data = new InkField(newerPoints);
-
+ if (ink) {
+ const oldXrange = (xs => ({ coord: NumCast(doc.x), min: Math.min(...xs), max: Math.max(...xs) }))(ink.map(p => p.X));
+ const oldYrange = (ys => ({ coord: NumCast(doc.y), min: Math.min(...ys), max: Math.max(...ys) }))(ink.map(p => p.Y));
+ const ptsXscale = NumCast(doc._width) / (oldXrange.max - oldXrange.min);
+ const ptsYscale = NumCast(doc._height) / (oldYrange.max - oldYrange.min);
+ const newPoints = func(doc, ink, ptsXscale, ptsYscale);
+ if (newPoints) {
+ const newXrange = (xs => ({ min: Math.min(...xs), max: Math.max(...xs) }))(newPoints.map(p => p.X));
+ const newYrange = (ys => ({ min: Math.min(...ys), max: Math.max(...ys) }))(newPoints.map(p => p.Y));
+ doc._width = (newXrange.max - newXrange.min) * ptsXscale;
+ doc._height = (newYrange.max - newYrange.min) * ptsYscale;
+ doc.x = (oldXrange.coord + (newXrange.min - oldXrange.min) * ptsXscale);
+ doc.y = (oldYrange.coord + (newYrange.min - oldYrange.min) * ptsYscale);
+ Doc.GetProto(doc).data = new InkField(newPoints);
+ appliedFunc = true;
}
}
}
}
}));
+ return appliedFunc;
}
@undoBatch
@action
- rotate = (angle: number) => {
- const _centerPoints: { X: number, Y: number }[] = [];
- SelectionManager.Views().forEach(action(inkView => {
- const doc = Document(inkView.rootDoc);
- if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink) {
- const xs = ink.map(p => p.X);
- const ys = ink.map(p => p.Y);
- const left = Math.min(...xs);
- const top = Math.min(...ys);
- const right = Math.max(...xs);
- const bottom = Math.max(...ys);
- _centerPoints.push({ X: left, Y: top });
- }
+ deletePoints = () => this.applyFunction((doc: Doc, ink: InkData) => {
+ var newPoints: { X: number, Y: number }[] = [];
+ const toRemove = Math.floor(((this._currPoint + 2) / 4));
+ for (var i = 0; i < ink.length; i++) {
+ if (Math.floor((i + 2) / 4) !== toRemove && (toRemove !== 0 || i > 3)) {
+ newPoints.push({ X: ink[i].X, Y: ink[i].Y });
}
- }));
-
- var index = 0;
- SelectionManager.Views().forEach(action(inkView => {
- const doc = Document(inkView.rootDoc);
- if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
- doc.rotation = NumCast(doc.rotation) + angle;
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink) {
-
- const newPoints: { X: number, Y: number }[] = [];
- ink.forEach(i => {
- const newX = Math.cos(angle) * (i.X - _centerPoints[index].X) - Math.sin(angle) * (i.Y - _centerPoints[index].Y) + _centerPoints[index].X;
- const newY = Math.sin(angle) * (i.X - _centerPoints[index].X) + Math.cos(angle) * (i.Y - _centerPoints[index].Y) + _centerPoints[index].Y;
- newPoints.push({ X: newX, Y: newY });
- });
- Doc.GetProto(doc).data = new InkField(newPoints);
- const xs = newPoints.map(p => p.X);
- const ys = newPoints.map(p => p.Y);
- const left = Math.min(...xs);
- const top = Math.min(...ys);
- const right = Math.max(...xs);
- const bottom = Math.max(...ys);
+ }
+ this._currPoint = -1;
+ if (newPoints.length < 4) return undefined;
+ if (newPoints.length === 4) {
+ const newerPoints: { X: number, Y: number }[] = [];
+ newerPoints.push({ X: newPoints[0].X, Y: newPoints[0].Y });
+ newerPoints.push({ X: newPoints[0].X, Y: newPoints[0].Y });
+ newerPoints.push({ X: newPoints[3].X, Y: newPoints[3].Y });
+ newerPoints.push({ X: newPoints[3].X, Y: newPoints[3].Y });
+ return newerPoints;
+ }
+ return newPoints;
+ }, true);
- doc._height = (bottom - top);
- doc._width = (right - left);
- }
- index++;
- }
- }));
+ @undoBatch
+ @action
+ rotate = (angle: number) => {
+ this.applyFunction((doc: Doc, ink: InkData, ptsXscale: number, ptsYscale: number) => {
+ const oldXrange = (xs => ({ coord: NumCast(doc.x), min: Math.min(...xs), max: Math.max(...xs) }))(ink.map(p => p.X));
+ const oldYrange = (ys => ({ coord: NumCast(doc.y), min: Math.min(...ys), max: Math.max(...ys) }))(ink.map(p => p.Y));
+ const centerPoint = { X: (oldXrange.min + oldXrange.max) / 2, Y: (oldYrange.min + oldYrange.max) / 2 };
+ const newPoints: { X: number, Y: number }[] = [];
+ ink.map(i => ({ X: i.X - centerPoint.X, Y: i.Y - centerPoint.Y })).forEach(i => {
+ const newX = Math.cos(angle) * i.X - Math.sin(angle) * i.Y;
+ const newY = Math.sin(angle) * i.X + Math.cos(angle) * i.Y;
+ newPoints.push({ X: newX + centerPoint.X, Y: newY + centerPoint.Y });
+ });
+ doc.rotation = NumCast(doc.rotation) + angle;
+ return newPoints;
+ });
}
@undoBatch
@action
- control = (xDiff: number, yDiff: number, controlNum: number) => {
- this.selectedInk?.forEach(action(inkView => {
- if (this.selectedInk?.length === 1) {
- const doc = Document(inkView.rootDoc);
- if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink) {
- const newPoints: { X: number, Y: number }[] = [];
- const order = controlNum % 4;
- for (var i = 0; i < ink.length; i++) {
- newPoints.push(
- (controlNum === i ||
- (order === 0 && i === controlNum + 1) ||
- (order === 0 && controlNum !== 0 && i === controlNum - 2) ||
- (order === 0 && controlNum !== 0 && i === controlNum - 1) ||
- (order === 3 && i === controlNum - 1) ||
- (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 1) ||
- (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 2) ||
- ((ink[0].X === ink[ink.length - 1].X) && (ink[0].Y === ink[ink.length - 1].Y) && (i === 0 || i === ink.length - 1) && (controlNum === 0 || controlNum === ink.length - 1))
- ) ?
- { X: ink[i].X - xDiff, Y: ink[i].Y - yDiff } :
- { X: ink[i].X, Y: ink[i].Y });
- }
- const oldx = doc.x;
- const oldy = doc.y;
- const oldxs = ink.map(p => p.X);
- const oldys = ink.map(p => p.Y);
- const oldleft = Math.min(...oldxs);
- const oldtop = Math.min(...oldys);
- Doc.GetProto(doc).data = new InkField(newPoints);
- const newxs = newPoints.map(p => p.X);
- const newys = newPoints.map(p => p.Y);
- const newleft = Math.min(...newxs);
- const newtop = Math.min(...newys);
- const newright = Math.max(...newxs);
- const newbottom = Math.max(...newys);
-
- //if points move out of bounds
- doc._height = (newbottom - newtop) * inkView.props.ScreenToLocalTransform().Scale;
- doc._width = (newright - newleft) * inkView.props.ScreenToLocalTransform().Scale;
-
- doc.x = oldx - (oldleft - newleft) * inkView.props.ScreenToLocalTransform().Scale;
- doc.y = oldy - (oldtop - newtop) * inkView.props.ScreenToLocalTransform().Scale;
- }
- }
+ control = (xDiff: number, yDiff: number, controlNum: number) =>
+ this.applyFunction((doc: Doc, ink: InkData, ptsXscale: number, ptsYscale: number) => {
+ const newPoints: { X: number, Y: number }[] = [];
+ const order = controlNum % 4;
+ for (var i = 0; i < ink.length; i++) {
+ newPoints.push(
+ (controlNum === i ||
+ (order === 0 && i === controlNum + 1) ||
+ (order === 0 && controlNum !== 0 && i === controlNum - 2) ||
+ (order === 0 && controlNum !== 0 && i === controlNum - 1) ||
+ (order === 3 && i === controlNum - 1) ||
+ (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 1) ||
+ (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 2) ||
+ ((ink[0].X === ink[ink.length - 1].X) && (ink[0].Y === ink[ink.length - 1].Y) && (i === 0 || i === ink.length - 1) && (controlNum === 0 || controlNum === ink.length - 1))
+ ) ?
+ { X: ink[i].X - xDiff / ptsXscale, Y: ink[i].Y - yDiff / ptsYscale } :
+ { X: ink[i].X, Y: ink[i].Y });
}
- }));
- }
+ return newPoints;
+ });
@undoBatch
@action
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 966abc0e7..449019ca8 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -41,56 +41,41 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
inkDoc._stayInCollection = inkDoc.isInkMask ? true : undefined;
});
- public _prevX = 0;
- public _prevY = 0;
- private _controlNum = 0;
@action
- onControlDown = (e: React.PointerEvent, i: number): void => {
- //TODO:renew points before controlling
- InkStrokeProperties.Instance?.control(0.001, 0.001, 1);
- setupMoveUpEvents(this, e, this.onControlMove, this.onControlup, (e) => { });
- this._controlUndo = UndoManager.StartBatch("DocDecs set radius");
- this._prevX = e.clientX;
- this._prevY = e.clientY;
- this._controlNum = i;
+ onControlDown = (e: React.PointerEvent, controlNum: number): void => {
+ if (InkStrokeProperties.Instance) {
+ InkStrokeProperties.Instance.control(0, 0, 1);
+ const controlUndo = UndoManager.StartBatch("DocDecs set radius");
+ const screenScale = this.props.ScreenToLocalTransform().Scale;
+ setupMoveUpEvents(this, e,
+ (e: PointerEvent, down: number[], delta: number[]) => {
+ InkStrokeProperties.Instance?.control(-delta[0] * screenScale, -delta[1] * screenScale, controlNum);
+ return false;
+ },
+ () => controlUndo?.end(), emptyFunction);
+ }
}
@action
changeCurrPoint = (i: number) => {
- if (!InkStrokeProperties.Instance) return;
- InkStrokeProperties.Instance._currPoint = i;
- document.addEventListener("keydown", this.delPts, true);
- }
-
- @action
- onControlMove = (e: PointerEvent, down: number[]): boolean => {
- if (!InkStrokeProperties.Instance) return false;
- const xDiff = this._prevX - e.clientX;
- const yDiff = this._prevY - e.clientY;
- InkStrokeProperties.Instance.control(xDiff, yDiff, this._controlNum);
- this._prevX = e.clientX;
- this._prevY = e.clientY;
- return false;
+ if (InkStrokeProperties.Instance) {
+ InkStrokeProperties.Instance._currPoint = i;
+ document.addEventListener("keydown", this.delPts, true);
+ }
}
- onControlup = (e: PointerEvent) => {
- this._prevX = 0;
- this._prevY = 0;
- this._controlNum = 0;
- this._controlUndo?.end();
- this._controlUndo = undefined;
- }
@action
- delPts = (e: KeyboardEvent | React.PointerEvent | undefined) => {
- if (InkStrokeProperties.Instance && (e instanceof KeyboardEvent ? e.key === "-" : true)) {
- InkStrokeProperties.Instance.deletePoints();
+ delPts = (e: KeyboardEvent) => {
+ if (["-", "Backspace", "Delete"].includes(e.key)) {
+ if (InkStrokeProperties.Instance?.deletePoints()) e.stopPropagation();
}
}
onPointerDown = (e: React.PointerEvent) => {
- this.props.isSelected(true) && setupMoveUpEvents(this, e, returnFalse, emptyFunction, action((e: PointerEvent, doubleTap: boolean | undefined) => {
- doubleTap && InkStrokeProperties.Instance && (InkStrokeProperties.Instance._controlBtn = true);
- }));
+ if (this.props.isSelected(true)) {
+ setupMoveUpEvents(this, e, returnFalse, emptyFunction, action((e: PointerEvent, doubleTap: boolean | undefined) =>
+ doubleTap && InkStrokeProperties.Instance && (InkStrokeProperties.Instance._controlBtn = true)));
+ }
}
public static MaskDim = 50000;
@@ -152,6 +137,10 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
}
handleLine.push({ X1: data[data.length - 2].X, Y1: data[data.length - 2].Y, X2: data[data.length - 1].X, Y2: data[data.length - 1].Y, X3: data[data.length - 1].X, Y3: data[data.length - 1].Y, dot1: data.length - 1, dot2: data.length - 1 });
+ for (var i = 0; i <= data.length - 4; i += 4) {
+ handlePoints.push({ X: data[i + 1].X, Y: data[i + 1].Y, I: i + 1, dot1: i, dot2: i === 0 ? i : i - 1 });
+ handlePoints.push({ X: data[i + 2].X, Y: data[i + 2].Y, I: i + 2, dot1: i + 3, dot2: i === data.length ? i + 3 : i + 4 });
+ }
}
// if (data.length <= 4) {
// handlePoints = [];
@@ -162,33 +151,33 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
// }
// }
- const dotsize = String(Math.max(width * scaleX, height * scaleY) / 40);
+ const dotsize = Math.max(width * scaleX, height * scaleY) / 40;
const addpoints = apoints.map((pts, i) =>
<svg height="10" width="10" key={`add${i}`}>
- <circle cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={strokeWidth / 2} stroke="invisible" strokeWidth={String(Number(dotsize) / 2)} fill="invisible"
+ <circle cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={strokeWidth / 2} stroke="invisible" strokeWidth={dotsize / 2} fill="invisible"
onPointerDown={(e) => { formatInstance.addPoints(pts.X, pts.Y, apoints, i, controlPoints); }} pointerEvents="all" cursor="all-scroll"
/>
</svg>);
+ const handles = handlePoints.map((pts, i) =>
+ <svg height="10" width="10" key={`hdl${i}`}>
+ <circle cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={strokeWidth} strokeWidth={0} fill="green"
+ onPointerDown={(e) => this.onControlDown(e, pts.I)} pointerEvents="all" cursor="default" display={(pts.dot1 === formatInstance._currPoint || pts.dot2 === formatInstance._currPoint) ? "inherit" : "none"} />
+ </svg>);
const controls = controlPoints.map((pts, i) =>
<svg height="10" width="10" key={`ctrl${i}`}>
- <circle cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={strokeWidth / 2} stroke="black" strokeWidth={String(Number(dotsize) / 2)} fill="red"
- onPointerDown={(e) => { this.changeCurrPoint(pts.I); this.onControlDown(e, pts.I); }} pointerEvents="all" cursor="all-scroll"
+ <circle cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={strokeWidth / 2} strokeWidth={0} fill="red"
+ onPointerDown={(e) => { this.changeCurrPoint(pts.I); this.onControlDown(e, pts.I); }} pointerEvents="all" cursor="default"
/>
</svg>);
- const handles = handlePoints.map((pts, i) =>
- <svg height="10" width="10" key={`hdl${i}`}>
- <circle cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2} cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2} r={strokeWidth / 2} stroke="black" strokeWidth={String(Number(dotsize) / 2)} fill="green"
- onPointerDown={(e) => this.onControlDown(e, pts.I)} pointerEvents="all" cursor="all-scroll" display={(pts.dot1 === formatInstance._currPoint || pts.dot2 === formatInstance._currPoint) ? "inherit" : "none"} />
- </svg>);
const handleLines = handleLine.map((pts, i) =>
<svg height="100" width="100" key={`line${i}`} >
<line x1={(pts.X1 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} y1={(pts.Y1 - top - strokeWidth / 2) * scaleY + strokeWidth / 2}
- x2={(pts.X2 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} y2={(pts.Y2 - top - strokeWidth / 2) * scaleY + strokeWidth / 2} stroke="green" strokeWidth={String(Number(dotsize) / 2)}
+ x2={(pts.X2 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} y2={(pts.Y2 - top - strokeWidth / 2) * scaleY + strokeWidth / 2} stroke="green" strokeWidth={dotsize / 6}
display={(pts.dot1 === formatInstance._currPoint || pts.dot2 === formatInstance._currPoint) ? "inherit" : "none"} />
<line x1={(pts.X2 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} y1={(pts.Y2 - top - strokeWidth / 2) * scaleY + strokeWidth / 2}
- x2={(pts.X3 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} y2={(pts.Y3 - top - strokeWidth / 2) * scaleY + strokeWidth / 2} stroke="green" strokeWidth={String(Number(dotsize) / 2)}
+ x2={(pts.X3 - left - strokeWidth / 2) * scaleX + strokeWidth / 2} y2={(pts.Y3 - top - strokeWidth / 2) * scaleY + strokeWidth / 2} stroke="green" strokeWidth={dotsize / 6}
display={(pts.dot1 === formatInstance._currPoint || pts.dot2 === formatInstance._currPoint) ? "inherit" : "none"} />
</svg>);
@@ -216,9 +205,9 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
{hpoints}
{points}
{formatInstance._controlBtn && this.props.isSelected() ? addpoints : ""}
- {formatInstance._controlBtn && this.props.isSelected() ? controls : ""}
- {formatInstance._controlBtn && this.props.isSelected() ? handles : ""}
{formatInstance._controlBtn && this.props.isSelected() ? handleLines : ""}
+ {formatInstance._controlBtn && this.props.isSelected() ? handles : ""}
+ {formatInstance._controlBtn && this.props.isSelected() ? controls : ""}
</svg>
);
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index b26765fa7..ce36d9182 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -14,7 +14,7 @@ import { Transform } from '../util/Transform';
import { TabDocView } from './collections/TabDocView';
import "./LightboxView.scss";
import { DocumentView, ViewAdjustment } from './nodes/DocumentView';
-import { DefaultStyleProvider } from './StyleProvider';
+import { DefaultStyleProvider, wavyBorderPath } from './StyleProvider';
interface LightboxViewProps {
PanelWidth: number;
@@ -26,6 +26,8 @@ interface LightboxViewProps {
export class LightboxView extends React.Component<LightboxViewProps> {
@computed public static get LightboxDoc() { return this._doc; }
+ private static LightboxDocTemplate = () => LightboxView._layoutTemplate;
+ @observable private static _layoutTemplate: Opt<Doc>;
@observable private static _doc: Opt<Doc>;
@observable private static _docTarget: Opt<Doc>;
@observable private static _docFilters: string[] = []; // filters
@@ -35,7 +37,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
private static _future: Opt<Doc[]> = [];
private static _docView: Opt<DocumentView>;
static path: { doc: Opt<Doc>, target: Opt<Doc>, history: Opt<{ doc: Doc, target?: Doc }[]>, future: Opt<Doc[]>, saved: Opt<{ panX: Opt<number>, panY: Opt<number>, scale: Opt<number>, scrollTop: Opt<number> }> }[] = [];
- @action public static SetLightboxDoc(doc: Opt<Doc>, target?: Doc, future?: Doc[]) {
+ @action public static SetLightboxDoc(doc: Opt<Doc>, target?: Doc, future?: Doc[], layoutTemplate?: Doc) {
if (this.LightboxDoc && this.LightboxDoc !== doc && this._savedState) {
this.LightboxDoc._panX = this._savedState.panX;
this.LightboxDoc._panY = this._savedState.panY;
@@ -62,6 +64,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
this._future = future.slice().sort((a, b) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)).sort((a, b) => DocListCast(a.links).length - DocListCast(b.links).length);
}
this._doc = doc;
+ this._layoutTemplate = layoutTemplate;
this._docTarget = target || doc;
this._tourMap = DocListCast(doc?.links).map(link => {
const opp = LinkManager.getOppositeAnchor(link, doc!);
@@ -101,13 +104,13 @@ export class LightboxView extends React.Component<LightboxViewProps> {
this._docFilters = (f => this._docFilters ? [this._docFilters.push(f) as any, this._docFilters][1] : [f])(`cookies:${cookie}:provide`);
}
}
- public static AddDocTab = (doc: Doc, location: string) => {
+ public static AddDocTab = (doc: Doc, location: string, layoutTemplate?: Doc) => {
SelectionManager.DeselectAll();
return LightboxView.SetLightboxDoc(doc, undefined,
[...DocListCast(doc[Doc.LayoutFieldKey(doc)]),
...DocListCast(doc[Doc.LayoutFieldKey(doc) + "-annotations"]),
...(LightboxView._future ?? [])
- ].sort((a: Doc, b: Doc) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)));
+ ].sort((a: Doc, b: Doc) => NumCast(b._timecodeToShow) - NumCast(a._timecodeToShow)), layoutTemplate);
}
docFilters = () => LightboxView._docFilters || [];
addDocTab = LightboxView.AddDocTab;
@@ -214,7 +217,8 @@ export class LightboxView extends React.Component<LightboxViewProps> {
left: this.leftBorder,
top: this.topBorder,
width: this.lightboxWidth(),
- height: this.lightboxHeight()
+ height: this.lightboxHeight(),
+ clipPath: `path('${Doc.UserDoc().renderStyle === "comic" ? wavyBorderPath(this.lightboxWidth(), this.lightboxHeight()) : undefined}')`
}}>
<DocumentView ref={action((r: DocumentView | null) => {
LightboxView._docView = r !== null ? r : undefined;
@@ -229,6 +233,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
})}
Document={LightboxView.LightboxDoc}
DataDoc={undefined}
+ LayoutTemplate={LightboxView.LightboxDocTemplate}
addDocument={undefined}
fitContentsToDoc={this.fitToBox}
isDocumentActive={returnFalse}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index fa2a738c8..4eeb1fc95 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -180,8 +180,8 @@ export class MainView extends React.Component {
const targClass = targets[0].className.toString();
if (SearchBox.Instance._searchbarOpen || SearchBox.Instance.open) {
const check = targets.some((thing) =>
- (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" ||
- thing.className === "collectionSchema-header-menuOptions"));
+ (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" ||
+ thing.className === "collectionSchema-header-menuOptions"));
!check && SearchBox.Instance.resetSearch(true);
}
!targClass.includes("contextMenu") && ContextMenu.Instance.closeMenu();
@@ -309,32 +309,6 @@ export class MainView extends React.Component {
}
- /**
- * add lock and hide button decorations for the "Dashboards" flyout TreeView
- */
- DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps | DocumentViewProps>, property: string) {
- const toggleField = undoBatch(action((e: React.MouseEvent, doc: Doc, field: string) => {
- e.stopPropagation();
- doc[field] = doc[field] ? undefined : true;
- }));
- switch (property.split(":")[0]) {
- case StyleProp.Decorations:
- return !doc || property.includes(":afterHeader") || // bcz: Todo: afterHeader should be generalized into a renderPath that is a list of the documents rendered so far which would mimic much of CSS property selectors
- DocListCast((Doc.UserDoc().myDashboards as Doc).data).some(dash => dash === doc ||
- DocListCast(dash.data).some(tabset => tabset === doc)) ? (null) :
- <>
- <div className={`styleProvider-treeView-hide${doc.hidden ? "-active" : ""}`} onClick={e => toggleField(e, doc, "hidden")}>
- <FontAwesomeIcon icon={doc.hidden ? "eye-slash" : "eye"} size="sm" />
- </div>
- <div className={`styleProvider-treeView-lock${doc._lockedPosition ? "-active" : ""}`} onClick={e => toggleField(e, doc, "_lockedPosition")}>
- <FontAwesomeIcon icon={doc._lockedPosition ? "lock" : "unlock"} size="sm" />
- </div>
- </>;
- }
- return DefaultStyleProvider(doc, props, property);
- }
-
-
@computed get flyout() {
return !this._flyoutWidth ? <div key="flyout" className={`mainView-libraryFlyout-out`}>
{this.docButtons}
@@ -349,7 +323,7 @@ export class MainView extends React.Component {
pinToPres={emptyFunction}
docViewPath={returnEmptyDoclist}
layerProvider={undefined}
- styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards ? this.DashboardStyleProvider : DefaultStyleProvider}
+ styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards ? DashboardStyleProvider : DefaultStyleProvider}
rootSelected={returnTrue}
removeDocument={returnFalse}
ScreenToLocalTransform={this.mainContainerXf}
@@ -704,5 +678,4 @@ export class MainView extends React.Component {
}
}
-Scripting.addGlobal(function selectMainMenu(doc: Doc, title: string) { MainView.Instance.selectMenu(doc); });
-Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().fontFamily = "Comic Sans MS"; Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }); \ No newline at end of file
+Scripting.addGlobal(function selectMainMenu(doc: Doc, title: string) { MainView.Instance.selectMenu(doc); }); \ No newline at end of file
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index efdf7f9f5..d2074d653 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -32,7 +32,7 @@ export interface MarqueeAnnotatorProps {
addDocument: (doc: Doc) => boolean;
getPageFromScroll?: (top: number) => number;
finishMarquee: (x?: number, y?: number) => void;
- anchorMenuClick?: (anchor: Doc) => void;
+ anchorMenuClick?: () => undefined | ((anchor: Doc) => void);
}
@observer
export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
@@ -65,7 +65,9 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
doc.addEventListener("pointermove", this.onSelectMove);
doc.addEventListener("pointerup", this.onSelectEnd);
- AnchorMenu.Instance.OnClick = (e: PointerEvent) => this.props.anchorMenuClick?.(this.highlight("rgba(173, 216, 230, 0.75)", true));
+ AnchorMenu.Instance.OnClick = (e: PointerEvent) => {
+ this.props.anchorMenuClick?.()?.(this.highlight("rgba(173, 216, 230, 0.75)", true));
+ };
AnchorMenu.Instance.Highlight = this.highlight;
/**
* This function is used by the AnchorMenu to create an anchor highlight and a new linked text annotation.
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index bb0ad4c66..d09d949ff 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -328,7 +328,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
*/
@undoBatch
changePermissions = (e: any, user: string) => {
- const docs = SelectionManager.Views().length < 2 ? [this.selectedDoc!] : SelectionManager.Views().map(docView => docView.props.Document);
+ const docs = SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(docView => docView.props.Document);
SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs);
}
@@ -409,7 +409,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
// all selected docs
const docs = SelectionManager.Views().length < 2 ?
- [this.layoutDocAcls ? this.selectedDoc! : this.selectedDoc![DataSym]]
+ [this.layoutDocAcls ? this.selectedDoc : this.selectedDoc[DataSym]]
: SelectionManager.Views().map(docView => this.layoutDocAcls ? docView.props.Document : docView.props.Document[DataSym]);
const target = docs[0];
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 6c3eb1e95..bff4c95fc 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -113,8 +113,6 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
NativeHeight={returnZero}
PanelHeight={this.panelHeight}
PanelWidth={this.panelWidth}
- xMargin={0}
- yMargin={0}
styleProvider={this.sidebarStyleProvider}
docFilters={this.docFilters}
scaleField={this.sidebarKey() + "-scale"}
diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss
index 94001730c..f26ed1f2d 100644
--- a/src/client/views/StyleProvider.scss
+++ b/src/client/views/StyleProvider.scss
@@ -16,4 +16,14 @@
}
.styleProvider-lock:hover {
opacity:1;
+}
+
+.styleProvider-treeView-icon,
+.styleProvider-treeView-icon-active {
+ margin-left: 0.25rem;
+ margin-right: 0.25rem;
+}
+
+.styleProvider-treeView-icon {
+ display: none;
} \ No newline at end of file
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 9102b9fa4..9e61351c4 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -1,7 +1,8 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
import 'golden-layout/src/css/goldenlayout-base.css';
import 'golden-layout/src/css/goldenlayout-dark-theme.css';
-import { runInAction } from 'mobx';
+import { runInAction, action } from 'mobx';
import { Doc, Opt, StrListCast } from "../../fields/Doc";
import { List } from '../../fields/List';
import { listSpec } from '../../fields/Schema';
@@ -9,16 +10,16 @@ import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types";
import { DocumentType } from '../documents/DocumentTypes';
import { CurrentUserUtils } from '../util/CurrentUserUtils';
import { SnappingManager } from '../util/SnappingManager';
-import { UndoManager } from '../util/UndoManager';
+import { UndoManager, undoBatch } from '../util/UndoManager';
import { CollectionViewType } from './collections/CollectionView';
+import "./collections/TreeView.scss";
import { MainView } from './MainView';
import { DocumentViewProps } from "./nodes/DocumentView";
-import "./StyleProvider.scss";
-import "./collections/TreeView.scss";
+import { FieldViewProps } from './nodes/FieldView';
import "./nodes/FilterBox.scss";
+import "./StyleProvider.scss";
import React = require("react");
import Color = require('color');
-import { FieldViewProps } from './nodes/FieldView';
export enum StyleLayers {
Background = "background"
@@ -41,6 +42,9 @@ export enum StyleProp {
HeaderMargin = "headerMargin", // margin at top of documentview, typically for displaying a title -- doc contents will start below that
TitleHeight = "titleHeight", // Height of Title area
ShowTitle = "showTitle", // whether to display a title on a Document (optional :hover suffix)
+ JitterRotation = "jitterRotation", // whether documents should be randomly rotated
+ BorderPath = "customBorder", // border path for document view
+ FontSize = "fontSize", // size of text font
}
function darkScheme() { return BoolCast(CurrentUserUtils.ActiveDashboard?.darkScheme); }
@@ -60,7 +64,10 @@ export function testDocProps(toBeDetermined: any): toBeDetermined is DocumentVie
return (toBeDetermined?.isContentActive) ? toBeDetermined : undefined;
}
-//
+export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) {
+ return `M ${pw * .5} ${ph * inset} C ${pw * .6} ${ph * inset} ${pw * (1 - 2 * inset)} 0 ${pw * (1 - inset)} ${ph * inset} C ${pw} ${ph * (2 * inset)} ${pw * (1 - inset)} ${ph * .25} ${pw * (1 - inset)} ${ph * .3} C ${pw * (1 - inset)} ${ph * .4} ${pw} ${ph * (1 - 2 * inset)} ${pw * (1 - inset)} ${ph * (1 - inset)} C ${pw * (1 - 2 * inset)} ${ph} ${pw * .6} ${ph * (1 - inset)} ${pw * .5} ${ph * (1 - inset)} C ${pw * .3} ${ph * (1 - inset)} ${pw * (2 * inset)} ${ph} ${pw * inset} ${ph * (1 - inset)} C 0 ${ph * (1 - 2 * inset)} ${pw * inset} ${ph * .8} ${pw * inset} ${ph * .75} C ${pw * inset} ${ph * .7} 0 ${ph * (2 * inset)} ${pw * inset} ${ph * inset} C ${pw * (2 * inset)} 0 ${pw * .25} ${ph * inset} ${pw * .5} ${ph * inset}`;
+}
+
// a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab
//
export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any {
@@ -70,36 +77,43 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
const isAnchor = property.includes(":anchor");
const isAnnotated = property.includes(":annotated");
const isOpen = property.includes(":open");
+ const fieldKey = (props as any)?.fieldKey ? (props as any).fieldKey + "-" : isCaption ? "caption-" : "";
+ const comicStyle = () => doc && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === "comic";
const isBackground = () => StrListCast(doc?._layerTags).includes(StyleLayers.Background);
const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity);
const showTitle = () => props?.styleProvider?.(doc, props, StyleProp.ShowTitle);
-
+ const random = (min: number, max: number, x: number, y: number) => /* min should not be equal to max */ min + ((Math.abs(x * y) * 9301 + 49297) % 233280 / 233280) * (max - min);
switch (property.split(":")[0]) {
case StyleProp.TreeViewIcon: return Doc.toIcon(doc, isOpen);
case StyleProp.DocContents: return undefined;
case StyleProp.WidgetColor: return isAnnotated ? "lightBlue" : darkScheme() ? "lightgrey" : "dimgrey";
case StyleProp.Opacity: return Cast(doc?._opacity, "number", Cast(doc?.opacity, "number", null));
case StyleProp.HideLinkButton: return props?.hideLinkButton || (!selected && (doc?.isLinkButton || doc?.hideLinkButton));
+ case StyleProp.FontSize: return StrCast(doc?.[fieldKey + "fontSize"]);
case StyleProp.ShowTitle: return doc && !doc.presentationTargetDoc && StrCast(doc._showTitle,
!Doc.IsSystem(doc) && doc.type === DocumentType.RTF ?
(doc.author === Doc.CurrentUserEmail ? StrCast(Doc.UserDoc().showTitle) : "author;creationDate") : "") || "";
case StyleProp.Color:
- if (isCaption) return "white";
- const backColor = backgroundCol() || "black";
- const col = Color(backColor).rgb();
+ const docColor: Opt<string> = StrCast(doc?.[fieldKey + "color"], StrCast(doc?._color));
+ if (docColor) return docColor;
+ const backColor = backgroundCol();// || (darkScheme() ? "black" : "white");
+ if (!backColor) return undefined;
+ const nonAlphaColor = backColor.startsWith("#") ? (backColor as string).substring(0, 7) :
+ backColor.startsWith("rgba") ? backColor.replace(/,.[^,]*\)/, ")").replace("rgba", "rgb") : backColor
+ const col = Color(nonAlphaColor).rgb();
const colsum = (col.red() + col.green() + col.blue());
if (colsum / col.alpha() > 400 || col.alpha() < 0.25) return "black";
return "white";
case StyleProp.Hidden: return BoolCast(doc?._hidden);
- case StyleProp.BorderRounding: return StrCast(doc?._borderRounding);
+ case StyleProp.BorderRounding: return StrCast(doc?.[fieldKey + "borderRounding"]);
case StyleProp.TitleHeight: return 15;
+ case StyleProp.BorderPath: return comicStyle() && props?.renderDepth ? { path: wavyBorderPath(props?.PanelWidth?.() || 0, props?.PanelHeight?.() || 0), fill: wavyBorderPath(props?.PanelWidth?.() || 0, props?.PanelHeight?.() || 0, .08), width: 3 } : { path: undefined, width: 0 };
+ case StyleProp.JitterRotation: return comicStyle() ? random(-1, 1, NumCast(doc?.x), NumCast(doc?.y)) * ((props?.PanelWidth() || 0) > (props?.PanelHeight() || 0) ? 5 : 10) : 0;
case StyleProp.HeaderMargin: return ([CollectionViewType.Stacking, CollectionViewType.Masonry].includes(doc?._viewType as any) ||
doc?.type === DocumentType.RTF) && showTitle() && !StrCast(doc?.showTitle).includes(":hover") ? 15 : 0;
case StyleProp.BackgroundColor: {
- if (isCaption) return "rgba(0,0,0 ,0.4)";
- if (Doc.UserDoc().renderStyle === "comic") return "transparent";
- let docColor: Opt<string> = StrCast(doc?._backgroundColor);
+ let docColor: Opt<string> = StrCast(doc?.[fieldKey + "backgroundColor"], StrCast(doc?._backgroundColor, isCaption ? "rgba(0,0,0,0.4)" : ""));
if (MainView.Instance.LastButton === doc) return darkScheme() ? "dimgrey" : "lightgrey";
switch (doc?.type) {
case DocumentType.PRESELEMENT: docColor = docColor || (darkScheme() ? "" : ""); break;
@@ -114,6 +128,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
case DocumentType.BUTTON: docColor = docColor || (darkScheme() ? "#2d2d2d" : "lightgray"); break;
case DocumentType.LINKANCHOR: docColor = isAnchor ? "lightblue" : "transparent"; break;
case DocumentType.LINK: docColor = docColor || "transparent"; break;
+ case DocumentType.IMG:
case DocumentType.WEB:
case DocumentType.PDF:
case DocumentType.SCREENSHOT:
@@ -130,7 +145,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
Doc.UserDoc().activeCollectionBackground));
break;
//if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)";
- default: docColor = darkScheme() ? "black" : "white"; break;
+ default: docColor = docColor || (darkScheme() ? "black" : "white"); break;
}
if (docColor && (!doc || props?.layerProvider?.(doc) === false)) docColor = Color(docColor.toLowerCase()).fade(0.5).toString();
return docColor;
@@ -177,60 +192,30 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
}
}
-
-function toggleHidden(e: React.MouseEvent, doc: Doc) {
- UndoManager.RunInBatch(() => runInAction(() => {
- e.stopPropagation();
- doc.hidden = doc.hidden ? undefined : true;
- }), "toggleHidden");
-}
-
-function toggleLock(e: React.MouseEvent, doc: Doc) {
- UndoManager.RunInBatch(() => runInAction(() => {
- e.stopPropagation();
- doc.lockedPosition = doc.lockedPosition ? undefined : true;
- }), "toggleHidden");
+export function DashboardToggleButton(doc: Doc, field: string, onIcon: IconProp, offIcon: IconProp, clickFunc?: () => void) {
+ return <div className={`styleProvider-treeView-icon${doc[field] ? "-active" : ""}`}
+ onClick={undoBatch(action((e: React.MouseEvent) => {
+ e.stopPropagation();
+ clickFunc ? clickFunc() : (doc[field] = doc[field] ? undefined : true);
+ }))}>
+ <FontAwesomeIcon icon={(doc[field] ? onIcon as any : offIcon) as IconProp} size="sm" />
+ </div>;
}
-
/**
* add lock and hide button decorations for the "Dashboards" flyout TreeView
*/
export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps | DocumentViewProps>, property: string) {
- switch (property.split(":")[0]) {
- case StyleProp.Decorations:
- if (doc) {
- const hidden = doc.hidden;
- const locked = doc.lockedPosition;
- return doc._viewType === CollectionViewType.Docking || (Doc.IsSystem(doc) && Doc.UserDoc().noviceMode) ? (null) :
- <>
- <div className={`styleProvider-treeView-hide${hidden ? "-active" : ""}`} onClick={(e) => toggleHidden(e, doc)}>
- <FontAwesomeIcon icon={hidden ? "eye-slash" : "eye"} size="sm" />
- </div>
- <div className={`styleProvider-treeView-lock${locked ? "-active" : ""}`} onClick={(e) => toggleLock(e, doc)}>
- <FontAwesomeIcon icon={locked ? "lock" : "unlock"} size="sm" />
- </div>
- </>;
- }
- default: return DefaultStyleProvider(doc, props, property);
+ if (doc && property.split(":")[0] === StyleProp.Decorations) {
+ return doc._viewType === CollectionViewType.Docking ? (null) :
+ <>
+ {DashboardToggleButton(doc, "hidden", "eye-slash", "eye")}
+ {DashboardToggleButton(doc, "lockedPosition", "lock", "unlock")}
+ </>;
}
+ return DefaultStyleProvider(doc, props, property);
}
-function changeFilterBool(e: any, doc: Doc) {
- UndoManager.RunInBatch(() => runInAction(() => {
- //e.stopPropagation();
- //doc.lockedPosition = doc.lockedPosition ? undefined : true;
- }), "changeFilterBool");
-}
-
-function closeFilter(e: React.MouseEvent, doc: Doc) {
- UndoManager.RunInBatch(() => runInAction(() => {
- e.stopPropagation();
- //doc.lockedPosition = doc.lockedPosition ? undefined : true;
- }), "closeFilter");
-}
-
-
//
// a preliminary semantic-"layering/grouping" mechanism for determining interactive properties of documents
// currently, the provider tests whether the docuemnt's layer field matches the activeLayer field of the tab.
diff --git a/src/client/views/collections/CollectionCarousel3DView.tsx b/src/client/views/collections/CollectionCarousel3DView.tsx
index b2ae441d6..3c66faf0c 100644
--- a/src/client/views/collections/CollectionCarousel3DView.tsx
+++ b/src/client/views/collections/CollectionCarousel3DView.tsx
@@ -13,6 +13,7 @@ import { DragManager } from '../../util/DragManager';
import { DocumentView } from '../nodes/DocumentView';
import "./CollectionCarousel3DView.scss";
import { CollectionSubView } from './CollectionSubView';
+import { StyleProp } from '../StyleProvider';
type Carousel3DDocument = makeInterface<[typeof documentSchema, typeof collectionSchema]>;
const Carousel3DDocument = makeInterface(documentSchema, collectionSchema);
@@ -40,11 +41,8 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
@computed get content() {
const currentIndex = NumCast(this.layoutDoc._itemIndex);
const displayDoc = (childPair: { layout: Doc, data: Doc }) => {
- const script = ScriptField.MakeScript("this._showCaption = 'caption'", { this: Doc.name });
- const onChildClick = script && (() => script);
- return <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
+ return <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "childLayoutTemplate", "childLayoutString"]).omit}
onDoubleClick={this.onChildDoubleClick}
- onClick={onChildClick}
renderDepth={this.props.renderDepth + 1}
LayoutTemplate={this.props.childLayoutTemplate}
LayoutTemplateString={this.props.childLayoutString}
@@ -52,7 +50,6 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
DataDoc={childPair.data}
PanelWidth={this.panelWidth}
PanelHeight={this.panelHeight}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform}
bringToFront={returnFalse}
/>;
};
@@ -104,27 +101,6 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
}, 1500);
}
- _downX = 0;
- _downY = 0;
- onPointerDown = (e: React.PointerEvent) => {
- this._downX = e.clientX;
- this._downY = e.clientY;
- document.addEventListener("pointerup", this.onpointerup);
- }
- private _lastTap: number = 0;
- private _doubleTap = false;
- onpointerup = (e: PointerEvent) => {
- this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2);
- this._lastTap = Date.now();
- }
-
- onClick = (e: React.MouseEvent) => {
- if (this._doubleTap) {
- e.stopPropagation();
- this.props.Document.isLightboxOpen = true;
- }
- }
-
@computed get buttons() {
if (!this.props.isContentActive()) return null;
return <div className="arrow-buttons" >
@@ -157,17 +133,20 @@ export class CollectionCarousel3DView extends CollectionSubView(Carousel3DDocume
}
@computed get dots() {
- return (this.childLayoutPairs.map((_child, index) => {
- return <div key={Utils.GenerateGuid()} className={`dot${index === NumCast(this.layoutDoc._itemIndex) ? "-active" : ""}`}
- onClick={() => this.layoutDoc._itemIndex = index} />;
- }));
+ return (this.childLayoutPairs.map((_child, index) =>
+ <div key={Utils.GenerateGuid()} className={`dot${index === NumCast(this.layoutDoc._itemIndex) ? "-active" : ""}`}
+ onClick={() => this.layoutDoc._itemIndex = index} />));
}
render() {
const index = NumCast(this.layoutDoc._itemIndex);
const translateX = this.panelWidth() * (1 - index);
- return <div className="collectionCarousel3DView-outer" onClick={this.onClick} onPointerDown={this.onPointerDown} ref={this.createDashEventsTarget}>
+ return <div className="collectionCarousel3DView-outer" ref={this.createDashEventsTarget}
+ style={{
+ background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
+ color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
+ }} >
<div className="carousel-wrapper" style={{ transform: `translateX(${translateX}px)` }}>
{this.content}
</div>
diff --git a/src/client/views/collections/CollectionCarouselView.scss b/src/client/views/collections/CollectionCarouselView.scss
index a9a1898f5..8660113cd 100644
--- a/src/client/views/collections/CollectionCarouselView.scss
+++ b/src/client/views/collections/CollectionCarouselView.scss
@@ -1,13 +1,10 @@
.collectionCarouselView-outer {
- background: gray;
height : 100%;
.collectionCarouselView-caption {
- margin-left: 10%;
- margin-right: 10%;
height: 50;
display: inline-block;
- width: 80%;
+ width: 100%;
}
.collectionCarouselView-image {
height: calc(100% - 50px);
@@ -19,13 +16,17 @@
.carouselView-back, .carouselView-fwd {
position: absolute;
display: flex;
- top: 50%;
+ top: 42.5%;
width: 30;
- height: 30;
+ height: 15%;
align-items: center;
border-radius: 5px;
justify-content: center;
- background : rgba(255, 255, 255, 0.46);
+ color: rgba(255,255,255,0.5);
+ background : rgba(0,0,0, 0.1);
+ &:hover {
+ color:white;
+ }
}
.carouselView-fwd {
right: 0;
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index cc90b9134..6c2c27e8e 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -2,17 +2,17 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { computed } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Doc } from '../../../fields/Doc';
+import { Doc, Opt } from '../../../fields/Doc';
import { collectionSchema, documentSchema } from '../../../fields/documentSchemas';
import { makeInterface } from '../../../fields/Schema';
import { NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { OmitKeys, returnFalse } from '../../../Utils';
import { DragManager } from '../../util/DragManager';
-import { DocumentView } from '../nodes/DocumentView';
+import { DocumentView, DocumentViewProps } from '../nodes/DocumentView';
import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
import { StyleProp } from '../StyleProvider';
import "./CollectionCarouselView.scss";
-import { CollectionSubView } from './CollectionSubView';
+import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
type CarouselDocument = makeInterface<[typeof documentSchema, typeof collectionSchema]>;
const CarouselDocument = makeInterface(documentSchema, collectionSchema);
@@ -38,77 +38,72 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
e.stopPropagation();
this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length;
}
- panelHeight = () => this.props.PanelHeight() - 50;
+ captionStyleProvider = (doc: (Doc | undefined), captionProps: Opt<DocumentViewProps>, property: string): any => {
+ // first look for properties on the document in the carousel, then fallback to properties on the container
+ const childValue = doc?.["caption-" + property] ? this.props.styleProvider?.(doc, captionProps, property) : undefined;
+ return childValue ?? this.props.styleProvider?.(this.layoutDoc, captionProps, property);
+ }
+ panelHeight = () => this.props.PanelHeight() - (StrCast(this.layoutDoc._showCaption) ? 50 : 0);
onContentDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick);
onContentClick = () => ScriptCast(this.layoutDoc.onChildClick);
@computed get content() {
const index = NumCast(this.layoutDoc._itemIndex);
const curDoc = this.childLayoutPairs?.[index];
+ const captionProps = { ...this.props, fieldKey: "caption" };
+ const marginX = NumCast(this.layoutDoc["caption-xMargin"]);
+ const marginY = NumCast(this.layoutDoc["caption-yMargin"]);
+ const showCaptions = StrCast(this.layoutDoc._showCaption);
return !(curDoc?.layout instanceof Doc) ? (null) :
<>
<div className="collectionCarouselView-image" key="image">
- <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
+ <DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "childLayoutTemplate", "childLayoutString"]).omit}
onDoubleClick={this.onContentDoubleClick}
onClick={this.onContentClick}
+ hideCaptions={showCaptions ? true : false}
renderDepth={this.props.renderDepth + 1}
+ ContainingCollectionView={this}
LayoutTemplate={this.props.childLayoutTemplate}
LayoutTemplateString={this.props.childLayoutString}
Document={curDoc.layout}
- DataDoc={curDoc.data}
+ DataDoc={curDoc.layout.resolvedDataDoc as Doc}
PanelHeight={this.panelHeight}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform}
bringToFront={returnFalse}
/>
</div>
<div className="collectionCarouselView-caption" key="caption"
style={{
- background: StrCast(this.layoutDoc._captionBackgroundColor, this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BackgroundColor)),
- color: StrCast(this.layoutDoc._captionColor, StrCast(this.layoutDoc.color)),
- borderRadius: StrCast(this.layoutDoc._captionBorderRounding),
+ display: showCaptions ? undefined : "none",
+ borderRadius: this.props.styleProvider?.(this.layoutDoc, captionProps, StyleProp.BorderRounding),
+ marginRight: marginX, marginLeft: marginX,
+ width: `calc(100% - ${marginX * 2}px)`
}}>
- <FormattedTextBox key={index} {...this.props}
- xMargin={NumCast(this.layoutDoc["_carousel-caption-xMargin"])}
- yMargin={NumCast(this.layoutDoc["_carousel-caption-yMargin"])}
- Document={curDoc.layout} DataDoc={undefined} fieldKey={"caption"} />
+ <FormattedTextBox key={index} {...captionProps}
+ fieldKey={showCaptions}
+ styleProvider={this.captionStyleProvider}
+ Document={curDoc.layout}
+ DataDoc={undefined} />
</div>
</>;
}
@computed get buttons() {
return <>
- <div key="back" className="carouselView-back" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }} onClick={this.goback}>
- <FontAwesomeIcon icon={"caret-left"} size={"2x"} />
+ <div key="back" className="carouselView-back" onClick={this.goback}>
+ <FontAwesomeIcon icon={"chevron-left"} size={"2x"} />
</div>
- <div key="fwd" className="carouselView-fwd" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }} onClick={this.advance}>
- <FontAwesomeIcon icon={"caret-right"} size={"2x"} />
+ <div key="fwd" className="carouselView-fwd" onClick={this.advance}>
+ <FontAwesomeIcon icon={"chevron-right"} size={"2x"} />
</div>
</>;
}
- _downX = 0;
- _downY = 0;
- onPointerDown = (e: React.PointerEvent) => {
- this._downX = e.clientX;
- this._downY = e.clientY;
- document.addEventListener("pointerup", this.onpointerup);
- }
- private _lastTap: number = 0;
- private _doubleTap = false;
- onpointerup = (e: PointerEvent) => {
- this._doubleTap = (Date.now() - this._lastTap < 300 && e.button === 0 && Math.abs(e.clientX - this._downX) < 2 && Math.abs(e.clientY - this._downY) < 2);
- this._lastTap = Date.now();
- }
-
- onClick = (e: React.MouseEvent) => {
- if (this._doubleTap) {
- e.stopPropagation();
- this.props.Document.isLightboxOpen = true;
- }
- }
-
render() {
- return <div className="collectionCarouselView-outer" onClick={this.onClick} onPointerDown={this.onPointerDown} ref={this.createDashEventsTarget}>
+ return <div className="collectionCarouselView-outer" ref={this.createDashEventsTarget}
+ style={{
+ background: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
+ color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
+ }}>
{this.content}
- {!this.props.Document._chromeHidden ? (null) : this.buttons}
+ {this.props.Document._chromeHidden ? (null) : this.buttons}
</div>;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index 9eac75f4b..dc5231a3a 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -300,7 +300,7 @@
.collection3DCarouselViewChrome-scrollSpeed-cont {
justify-self: right;
align-items: center;
- display: grid;
+ display: flex;
grid-auto-columns: auto;
font-size: 75%;
letter-spacing: 2px;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index a26953ff6..6e6fabd0d 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -37,6 +37,7 @@ import { LightboxView } from "../LightboxView";
import { Docs } from "../../documents/Documents";
import { DocumentManager } from "../../util/DocumentManager";
import { CollectionDockingView } from "./CollectionDockingView";
+import { FormattedTextBox } from "../nodes/formattedText/FormattedTextBox";
@observer
export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -260,6 +261,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" {...this.props} />);
case CollectionViewType.Tree: return (<CollectionTreeViewChrome key="collchrome" {...this.props} />);
case CollectionViewType.Masonry: return (<CollectionStackingViewChrome key="collchrome" {...this.props} />);
+ case CollectionViewType.Carousel:
case CollectionViewType.Carousel3D: return (<Collection3DCarouselViewChrome key="collchrome" {...this.props} />);
case CollectionViewType.Grid: return (<CollectionGridViewChrome key="collchrome" {...this.props} />);
case CollectionViewType.Docking: return (<CollectionDockingChrome key="collchrome" {...this.props} />);
@@ -533,7 +535,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
<FontAwesomeIcon icon={["fab", "buffer"]} size={"lg"} />
</button>
</Tooltip>
- </>
+ </>;
}
render() {
@@ -552,7 +554,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
<div className="collectionMenu-divider" key="divider3"></div>
{this.lightboxButton}
{this.recordButton}
- {/* {!this._buttonizableCommands ? (null) : this.templateChrome} */}
+ {!this._buttonizableCommands ? (null) : this.templateChrome}
</div>
</div>
</div>
@@ -761,7 +763,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
render() {
return !this.props.docView.layoutDoc ? (null) :
<div className="collectionFreeFormMenu-cont">
-
+ <RichTextMenu key="rich" />
{!this.isText ?
<>
{this.drawButtons}
@@ -787,8 +789,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
</div>
</Tooltip>
</>}
- </> :
- <RichTextMenu />
+ </> : (null)
}
{!this.selectedDocumentView?.ComponentView?.menuControls ? (null) : this.selectedDocumentView?.ComponentView?.menuControls?.()}
</div>;
@@ -1021,6 +1022,7 @@ export class Collection3DCarouselViewChrome extends React.Component<CollectionMe
return (
<div className="collection3DCarouselViewChrome-cont">
<div className="collection3DCarouselViewChrome-scrollSpeed-cont">
+ {FormattedTextBox.Focused ? <RichTextMenu /> : (null)}
<div className="collectionStackingViewChrome-scrollSpeed-label">
AUTOSCROLL SPEED:
</div>
diff --git a/src/client/views/collections/CollectionStackedTimeline.scss b/src/client/views/collections/CollectionStackedTimeline.scss
index 19ad5cefa..e456c0664 100644
--- a/src/client/views/collections/CollectionStackedTimeline.scss
+++ b/src/client/views/collections/CollectionStackedTimeline.scss
@@ -62,6 +62,7 @@
.collectionStackedTimeline-waveform {
position: absolute;
width: 100%;
+ height: 100%;
top: 0;
left: 0;
pointer-events: none;
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index ab9c4aa2c..a2c95df6e 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -235,12 +235,12 @@ export class CollectionStackedTimeline extends CollectionSubView<PanZoomDocument
}
dictationHeightPercent = 50;
- dictationHeight = () => `${this.dictationHeightPercent}%`;
+ dictationHeight = () => this.props.PanelHeight() * (100 - this.dictationHeightPercent) / 100;
timelineContentHeight = () => this.props.PanelHeight() * this.dictationHeightPercent / 100;
dictationScreenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(0, -this.timelineContentHeight());
@computed get renderDictation() {
const dictation = Cast(this.dataDoc[this.props.dictationKey], Doc, null);
- return !dictation ? (null) : <div style={{ position: "absolute", height: this.dictationHeight(), top: this.timelineContentHeight(), background: "tan" }}>
+ return !dictation ? (null) : <div style={{ position: "absolute", height: "100%", top: this.timelineContentHeight(), background: "tan" }}>
<DocumentView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
Document={dictation}
PanelHeight={this.dictationHeight}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 1aed40bc3..30f8e0112 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -58,7 +58,7 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
@computed get filteredChildren() { return this.childLayoutPairs.filter(pair => (pair.layout instanceof Doc) && !pair.layout.hidden).map(pair => pair.layout); }
@computed get headerMargin() { return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin); }
@computed get xMargin() { return NumCast(this.layoutDoc._xMargin, 2 * Math.min(this.gridGap, .05 * this.props.PanelWidth())); }
- @computed get yMargin() { return this.props.yMargin || NumCast(this.layoutDoc._yMargin, 5); } // 2 * this.gridGap)); }
+ @computed get yMargin() { return this.props.yPadding || NumCast(this.layoutDoc._yMargin, 5); } // 2 * this.gridGap)); }
@computed get gridGap() { return NumCast(this.layoutDoc._gridGap, 10); }
@computed get isStackingView() { return (this.props.viewType ?? this.layoutDoc._viewType) === CollectionViewType.Stacking; }
@computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index f6aecbb14..7e2f7811e 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -9,7 +9,7 @@ import * as ReactDOM from 'react-dom';
import { DataSym, Doc, DocListCast, DocListCastAsync, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
import { Id } from '../../../fields/FieldSymbols';
import { FieldId } from "../../../fields/RefField";
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
+import { Cast, NumCast, StrCast, BoolCast } from "../../../fields/Types";
import { TraceMobx } from '../../../fields/util';
import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils";
import { DocServer } from "../../DocServer";
@@ -92,7 +92,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
};
tab.element[0].style.borderTopRightRadius = "8px";
tab.element[0].children[1].appendChild(toggle);
- tab._disposers.layerDisposer = reaction(() => ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }),
+ tab._disposers.layerDisposer = reaction(() =>
+ ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }),
({ layer, color }) => toggle.style.background = !layer ? color : "dimgrey", { fireImmediately: true });
}
// shifts the focus to this tab when another tab is dragged over it
@@ -298,6 +299,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
PanelHeight = () => this._panelHeight;
miniMapColor = () => this.tabColor;
tabView = () => this._view;
+ disableMinimap = () => !this._document || (this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform);
+ hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.hideMinimap);
@computed get layerProvider() { return this._document && DefaultLayerProvider(this._document); }
@computed get docView() {
@@ -329,13 +332,14 @@ export class TabDocView extends React.Component<TabDocViewProps> {
bringToFront={emptyFunction}
pinToPres={TabDocView.PinDoc} />
<TabMinimapView key="minimap"
+ hideMinimap={this.hideMinimap}
addDocTab={this.addDocTab}
PanelHeight={this.PanelHeight}
PanelWidth={this.PanelWidth}
background={this.miniMapColor}
document={this._document}
tabView={this.tabView} />
- <Tooltip style={{ display: this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform ? "none" : undefined }} key="ttip" title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
+ <Tooltip style={{ display: this.disableMinimap() ? "none" : undefined }} key="ttip" title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
<div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
<FontAwesomeIcon icon={"globe-asia"} size="lg" />
</div>
@@ -346,7 +350,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
render() {
this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab);
return (
- <div className="collectionDockingView-content" style={{ height: "100%", width: "100%" }} ref={ref => {
+ <div className="collectionDockingView-content" style={{
+ fontFamily: Doc.UserDoc().renderStyle === "comic" ? "Comic Sans MS" : undefined,
+ height: "100%", width: "100%"
+ }} ref={ref => {
if (this._mainCont = ref) {
(this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
DocServer.GetRefField(this.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document)));
@@ -360,6 +367,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
interface TabMinimapViewProps {
document: Doc;
+ hideMinimap: () => boolean;
tabView: () => DocumentView | undefined;
addDocTab: (doc: Doc, where: string) => boolean;
PanelWidth: () => number;
@@ -410,7 +418,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
const miniLeft = 50 + (NumCast(this.props.document._panX) - this.renderBounds.cx) / this.renderBounds.dim * 100 - miniWidth / 2;
const miniTop = 50 + (NumCast(this.props.document._panY) - this.renderBounds.cy) / this.renderBounds.dim * 100 - miniHeight / 2;
const miniSize = this.returnMiniSize();
- return this.props.document.hideMinimap ? (null) :
+ return this.props.hideMinimap() ? (null) :
<div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
<CollectionFreeFormView
Document={this.props.document}
diff --git a/src/client/views/collections/TreeView.scss b/src/client/views/collections/TreeView.scss
index 5b0c04f33..0239ae863 100644
--- a/src/client/views/collections/TreeView.scss
+++ b/src/client/views/collections/TreeView.scss
@@ -113,24 +113,18 @@
width: unset;
}
- .right-buttons-container {
+ .treeView-rightButtons {
display: flex;
align-items: center;
margin-left: 0.25rem;
opacity: 0.75;
- >svg,
- .styleProvider-treeView-lock,
- .styleProvider-treeView-hide,
- .styleProvider-treeView-lock-active,
- .styleProvider-treeView-hide-active {
+ >svg {
margin-left: 0.25rem;
margin-right: 0.25rem;
}
- >svg,
- .styleProvider-treeView-lock,
- .styleProvider-treeView-hide {
+ >svg {
display: none;
}
}
@@ -154,11 +148,9 @@
}
}
- .right-buttons-container {
-
+ .treeView-rightButtons {
>svg,
- .styleProvider-treeView-lock,
- .styleProvider-treeView-hide {
+ .styleProvider-treeView-icon {
display: inherit;
}
}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index e1fd78270..2e98fb508 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -626,6 +626,7 @@ export class TreeView extends React.Component<TreeViewProps> {
ContainingCollectionDoc={this.props.treeView.props.Document}
/>;
+ const buttons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ":afterHeader" : ""));
return <>
<div className={`docContainer${Doc.IsSystem(this.props.document) || this.props.document.isFolder ? "-system" : ""}`} ref={this._tref} title="click to edit title. Double Click or Drag to Open"
style={{
@@ -636,8 +637,8 @@ export class TreeView extends React.Component<TreeViewProps> {
}} >
{view}
</div >
- <div className={"right-buttons-container"}>
- {this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ":afterHeader" : ""))} {/* hide and lock buttons */}
+ <div className="treeView-rightButtons">
+ {buttons} {/* hide and lock buttons */}
{this.headerElements}
</div>
</>;
@@ -719,7 +720,7 @@ export class TreeView extends React.Component<TreeViewProps> {
}
@computed get renderBorder() {
- const sorting = this.doc[`${this.fieldKey}-sortCriteria`];
+ const sorting = this.doc[`${this.fieldKey}-sortCriterion`];
return <div className={`treeView-border${this.props.treeView.outlineMode ? "outline" : ""}`}
style={{ borderColor: sorting === undefined ? undefined : sorting === "up" ? "crimson" : sorting === "down" ? "blue" : "green" }}>
{!this.treeViewOpen ? (null) : this.renderContent}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 7a879ecde..a14ba036f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -805,8 +805,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
const localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y);
- if (localTransform.Scale >= 0.15 || localTransform.Scale > this.zoomScaling()) {
- const safeScale = Math.min(Math.max(0.15, localTransform.Scale), 20);
+ if (localTransform.Scale >= 0.05 || localTransform.Scale > this.zoomScaling()) {
+ const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20);
this.props.Document[this.scaleFieldKey] = Math.abs(safeScale);
this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale);
}
@@ -1051,7 +1051,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
dontRegisterView={this.props.dontRegisterView}
pointerEvents={this.backgroundActive || this.props.childPointerEvents ? "all" :
(this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : undefined}
- jitterRotation={NumCast(this.props.Document._jitterRotation) || ((Doc.UserDoc().renderStyle === "comic" ? 10 : 0))}
+ jitterRotation={this.props.styleProvider?.(childLayout, this.props, StyleProp.JitterRotation) || 0}
//fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)} // bcz: check this
/>;
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index a4f129b8c..b1f2750c3 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -155,7 +155,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
} else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this.props.childLayoutString ? e.key : "";
FormattedTextBox.LiveTextUndo = UndoManager.StartBatch("live text batch");
- this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100, this.props.xMargin === 0));
+ this.props.addLiveTextDocument(CurrentUserUtils.GetNewTextDoc("-typed text-", x, y, 200, 100, this.props.xPadding === 0));
e.stopPropagation();
}
}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 8b5c02b75..f3a39a262 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -49,6 +49,11 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, "*") === DimUnit.Ratio);
}
+ @computed
+ private get minimumDim() {
+ return Math.min(...this.ratioDefinedDocs.filter(layout => layout._dimMagnitude).map(layout => NumCast(layout._dimMagnitude)));
+ }
+
/**
* This loops through all childLayoutPairs and extracts the values for _dimUnit
* and _dimMagnitude, ignoring any that are malformed. Additionally, it then
@@ -63,7 +68,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
const widthSpecifiers: WidthSpecifier[] = [];
this.childLayoutPairs.map(pair => {
const unit = StrCast(pair.layout._dimUnit, "*");
- const magnitude = NumCast(pair.layout._dimMagnitude, 1);
+ const magnitude = NumCast(pair.layout._dimMagnitude, this.minimumDim);
if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
(unit === DimUnit.Ratio) && (starSum += magnitude);
widthSpecifiers.push({ magnitude, unit });
@@ -80,15 +85,15 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
* themselves to drift toward zero. Thus, whenever we change any of the values,
* we normalize everything (dividing by the smallest magnitude).
*/
- setTimeout(() => {
- const { ratioDefinedDocs } = this;
- if (this.childLayoutPairs.length) {
- const minimum = Math.min(...ratioDefinedDocs.map(doc => NumCast(doc._dimMagnitude, 1)));
- if (minimum !== 0) {
- ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum, 1);
- }
- }
- });
+ // setTimeout(() => {
+ // const { ratioDefinedDocs } = this;
+ // if (this.childLayoutPairs.length) {
+ // const minimum = this.minimumDim;
+ // if (minimum !== 0) {
+ // ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum, 1);
+ // }
+ // }
+ // });
return { widthSpecifiers, starSum };
}
@@ -161,7 +166,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
if (columnUnitLength === undefined) {
return 0; // we're still waiting on promises to resolve
}
- let width = NumCast(layout._dimMagnitude, 1);
+ let width = NumCast(layout._dimMagnitude, this.minimumDim);
if (StrCast(layout._dimUnit, "*") === DimUnit.Ratio) {
width *= columnUnitLength;
}
@@ -273,6 +278,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
<ResizeBar
width={resizerWidth}
key={"resizer" + i}
+ styleProvider={this.props.styleProvider}
+ isContentActive={this.props.isContentActive}
select={this.props.select}
columnUnitLength={this.getColumnUnitLength}
toLeft={layout}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 2c5e40d02..29cb3511a 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -49,6 +49,11 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
return this.childLayoutPairs.map(pair => pair.layout).filter(layout => StrCast(layout._dimUnit, "*") === DimUnit.Ratio);
}
+ @computed
+ private get minimumDim() {
+ return Math.min(...this.ratioDefinedDocs.filter(layout => layout._dimMagnitude).map(layout => NumCast(layout._dimMagnitude)));
+ }
+
/**
* This loops through all childLayoutPairs and extracts the values for _dimUnit
* and _dimUnit, ignoring any that are malformed. Additionally, it then
@@ -63,7 +68,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
const heightSpecifiers: HeightSpecifier[] = [];
this.childLayoutPairs.map(pair => {
const unit = StrCast(pair.layout._dimUnit, "*");
- const magnitude = NumCast(pair.layout._dimMagnitude, 1);
+ const magnitude = NumCast(pair.layout._dimMagnitude, this.minimumDim);
if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
(unit === DimUnit.Ratio) && (starSum += magnitude);
heightSpecifiers.push({ magnitude, unit });
@@ -80,15 +85,15 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
* themselves to drift toward zero. Thus, whenever we change any of the values,
* we normalize everything (dividing by the smallest magnitude).
*/
- setTimeout(() => {
- const { ratioDefinedDocs } = this;
- if (this.childLayoutPairs.length) {
- const minimum = Math.min(...ratioDefinedDocs.map(layout => NumCast(layout._dimMagnitude, 1)));
- if (minimum !== 0) {
- ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum);
- }
- }
- });
+ // setTimeout(() => {
+ // const { ratioDefinedDocs } = this;
+ // if (this.childLayoutPairs.length) {
+ // const minimum = Math.min(...ratioDefinedDocs.map(layout => NumCast(layout._dimMagnitude, 1)));
+ // if (minimum !== 0) {
+ // ratioDefinedDocs.forEach(layout => layout._dimMagnitude = NumCast(layout._dimMagnitude, 1) / minimum);
+ // }
+ // }
+ // });
return { heightSpecifiers, starSum };
}
@@ -161,7 +166,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
if (rowUnitLength === undefined) {
return 0; // we're still waiting on promises to resolve
}
- let height = NumCast(layout._dimMagnitude, 1);
+ let height = NumCast(layout._dimMagnitude, this.minimumDim);
if (StrCast(layout._dimUnit, "*") === DimUnit.Ratio) {
height *= rowUnitLength;
}
@@ -261,12 +266,16 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
const height = () => this.lookupPixels(layout);
const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
collector.push(
- <div className={"document-wrapper"} key={"wrapper" + i} >
+ <div className={"document-wrapper"}
+ style={{ height: height() }}
+ key={"wrapper" + i} >
{this.getDisplayDoc(layout, dxf, width, height)}
<HeightLabel layout={layout} collectionDoc={Document} />
</div>,
<ResizeBar
height={resizerHeight}
+ styleProvider={this.props.styleProvider}
+ isContentActive={this.props.isContentActive}
key={"resizer" + i}
columnUnitLength={this.getRowUnitLength}
toTop={layout}
diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
index 734915a93..9fe18d118 100644
--- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
+++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx
@@ -5,9 +5,13 @@ import { Doc } from "../../../../fields/Doc";
import { NumCast, StrCast } from "../../../../fields/Types";
import { DimUnit } from "./CollectionMulticolumnView";
import { UndoManager } from "../../../util/UndoManager";
+import { StyleProviderFunc } from "../../nodes/DocumentView";
+import { StyleProp } from "../../StyleProvider";
interface ResizerProps {
width: number;
+ styleProvider?: StyleProviderFunc;
+ isContentActive?: () => boolean;
columnUnitLength(): number | undefined;
toLeft?: Doc;
toRight?: Doc;
@@ -85,19 +89,16 @@ export default class ResizeBar extends React.Component<ResizerProps> {
}
render() {
- return (
- <div
- className={"multiColumnResizer"}
- style={{
- width: this.props.width,
- opacity: this.isActivated && this.isHoverActive ? resizerOpacity : 0
- }}
- onPointerEnter={action(() => this.isHoverActive = true)}
- onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))}
- >
- <div className={"multiColumnResizer-hdl"} onPointerDown={e => this.registerResizing(e)} />
- </div>
- );
+ return <div className="multiColumnResizer"
+ style={{
+ width: this.props.width,
+ backgroundColor: !this.props.isContentActive?.() ? "" : this.props.styleProvider?.(undefined, undefined, StyleProp.WidgetColor)
+ }}
+ onPointerEnter={action(() => this.isHoverActive = true)}
+ onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))}
+ >
+ <div className={"multiColumnResizer-hdl"} onPointerDown={e => this.registerResizing(e)} />
+ </div>;
}
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
index d0bc4d01c..5478bf709 100644
--- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
+++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx
@@ -5,9 +5,13 @@ import { Doc } from "../../../../fields/Doc";
import { NumCast, StrCast } from "../../../../fields/Types";
import { DimUnit } from "./CollectionMultirowView";
import { UndoManager } from "../../../util/UndoManager";
+import { StyleProp } from "../../StyleProvider";
+import { StyleProviderFunc } from "../../nodes/DocumentView";
interface ResizerProps {
height: number;
+ styleProvider?: StyleProviderFunc;
+ isContentActive?: () => boolean;
columnUnitLength(): number | undefined;
toTop?: Doc;
toBottom?: Doc;
@@ -83,19 +87,16 @@ export default class ResizeBar extends React.Component<ResizerProps> {
}
render() {
- return (
- <div
- className={"multiRowResizer"}
- style={{
- height: this.props.height,
- opacity: this.isActivated && this.isHoverActive ? resizerOpacity : 0
- }}
- onPointerEnter={action(() => this.isHoverActive = true)}
- onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))}
- >
- <div className={"multiRowResizer-hdl"} onPointerDown={e => this.registerResizing(e)} />
- </div>
- );
+ return <div className="multiRowResizer"
+ style={{
+ height: this.props.height,
+ backgroundColor: !this.props.isContentActive?.() ? "" : this.props.styleProvider?.(undefined, undefined, StyleProp.WidgetColor)
+ }}
+ onPointerEnter={action(() => this.isHoverActive = true)}
+ onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))}
+ >
+ <div className={"multiRowResizer-hdl"} onPointerDown={e => this.registerResizing(e)} />
+ </div>;
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 1fda4cc5e..092823603 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -37,10 +37,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
public static animFields = ["_height", "_width", "x", "y", "_scrollTop", "opacity"]; // fields that are configured to be animatable using animation frames
@observable _animPos: number[] | undefined = undefined;
@observable _contentView: DocumentView | undefined | null;
- random(min: number, max: number) { /* min should not be equal to max */ return min + ((Math.abs(this.X * this.Y) * 9301 + 49297) % 233280 / 233280) * (max - min); }
get displayName() { return "CollectionFreeFormDocumentView(" + this.rootDoc.title + ")"; } // this makes mobx trace() statements more descriptive
get maskCentering() { return this.props.Document.isInkMask ? InkingStroke.MaskDim / 2 : 0; }
- get transform() { return `translate(${this.X - this.maskCentering}px, ${this.Y - this.maskCentering}px) rotate(${this.random(-1, 1) * this.props.jitterRotation}deg)`; }
+ get transform() { return `translate(${this.X - this.maskCentering}px, ${this.Y - this.maskCentering}px) rotate(${this.props.jitterRotation}deg)`; }
get X() { return this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); }
get Y() { return this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); }
get ZInd() { return this.dataProvider ? this.dataProvider.zIndex : (this.Document.zIndex || 0); }
@@ -156,7 +155,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
returnThis = () => this;
render() {
TraceMobx();
- const backgroundColor = () => this.props.styleProvider?.(this.Document, this.props, StyleProp.BackgroundColor);
const divProps: DocumentViewProps = {
...this.props,
CollectionFreeFormDocumentView: this.returnThis,
@@ -175,17 +173,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
transition: this.props.dataTransition ? this.props.dataTransition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.dataTransition),
zIndex: this.ZInd,
mixBlendMode: StrCast(this.layoutDoc.mixBlendMode) as any,
- display: this.ZInd === -99 ? "none" : undefined,
+ display: this.ZInd === -99 ? "none" : undefined
}} >
-
- {Doc.UserDoc().renderStyle !== "comic" ? (null) :
- <div style={{ width: "100%", height: "100%", position: "absolute" }}>
- <svg style={{ transform: `scale(1,${this.props.PanelHeight() / this.props.PanelWidth()})`, transformOrigin: "top left", overflow: "visible" }} viewBox="0 0 12 14">
- <path d="M 7 0 C 9 -1 13 1 12 4 C 11 10 13 12 10 12 C 6 12 7 13 2 12 Q -1 11 0 8 C 1 4 0 4 0 2 C 0 0 1 0 1 0 C 3 0 3 1 7 0"
- style={{ stroke: "black", fill: backgroundColor(), strokeWidth: 0.2 }} />
- </svg>
- </div>}
-
<DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} />
</div>;
}
diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx
index 46c599abe..8da5cd1b1 100644
--- a/src/client/views/nodes/ColorBox.tsx
+++ b/src/client/views/nodes/ColorBox.tsx
@@ -41,7 +41,7 @@ export class ColorBox extends ViewBoxBaseComponent<FieldViewProps, ColorDocument
else if (RichTextMenu.Instance?.TextViewFieldKey && window.getSelection()?.toString() !== "") {
Doc.Layout(view.props.Document)[RichTextMenu.Instance.TextViewFieldKey + "-color"] = color.hex;
} else {
- Doc.Layout(view.props.Document)._backgroundColor = color.hex; // '_backgroundColor' is template specific. 'backgroundColor' would apply to all templates, but has no UI at the moment
+ Doc.Layout(view.props.Document)._backgroundColor = color.hex + (color.rgb.a ? Math.round(color.rgb.a * 255).toString(16) : ""); // '_backgroundColor' is template specific. 'backgroundColor' would apply to all templates, but has no UI at the moment
}
}
});
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index b53827371..f0a54e4ac 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -1,46 +1,45 @@
import { computed } from "mobx";
import { observer } from "mobx-react";
-import { Doc, Opt, Field, AclPrivate } from "../../../fields/Doc";
-import { Cast, StrCast, NumCast } from "../../../fields/Types";
-import { OmitKeys, Without, emptyPath } from "../../../Utils";
+import { AclPrivate, Doc, Opt } from "../../../fields/Doc";
+import { ScriptField } from "../../../fields/ScriptField";
+import { Cast, StrCast } from "../../../fields/Types";
+import { GetEffectiveAcl, TraceMobx } from "../../../fields/util";
+import { emptyPath, OmitKeys, Without } from "../../../Utils";
import { DirectoryImportBox } from "../../util/Import & Export/DirectoryImportBox";
import { CollectionDockingView } from "../collections/CollectionDockingView";
import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
import { CollectionSchemaView } from "../collections/CollectionSchemaView";
import { CollectionView } from "../collections/CollectionView";
+import { InkingStroke } from "../InkingStroke";
+import { PresElementBox } from "../presentationview/PresElementBox";
+import { SearchBox } from "../search/SearchBox";
+import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo";
import { YoutubeBox } from "./../../apis/youtube/YoutubeBox";
import { AudioBox } from "./AudioBox";
-import { LabelBox } from "./LabelBox";
-import { EquationBox } from "./EquationBox";
-import { FunctionPlotBox } from "./FunctionPlotBox";
-import { SliderBox } from "./SliderBox";
-import { LinkBox } from "./LinkBox";
-import { ScriptingBox } from "./ScriptingBox";
+import { ColorBox } from "./ColorBox";
+import { ComparisonBox } from "./ComparisonBox";
import { DocumentViewProps } from "./DocumentView";
import "./DocumentView.scss";
-import { FontIconBox } from "./FontIconBox";
+import { EquationBox } from "./EquationBox";
import { FieldView, FieldViewProps } from "./FieldView";
+import { FilterBox } from "./FilterBox";
+import { FontIconBox } from "./FontIconBox";
import { FormattedTextBox, FormattedTextBoxProps } from "./formattedText/FormattedTextBox";
+import { FunctionPlotBox } from "./FunctionPlotBox";
import { ImageBox } from "./ImageBox";
import { KeyValueBox } from "./KeyValueBox";
+import { LabelBox } from "./LabelBox";
+import { LinkAnchorBox } from "./LinkAnchorBox";
+import { LinkBox } from "./LinkBox";
import { PDFBox } from "./PDFBox";
import { PresBox } from "./PresBox";
-import { SearchBox } from "../search/SearchBox";
-import { FilterBox } from "./FilterBox";
-import { ColorBox } from "./ColorBox";
-import { DashWebRTCVideo } from "../webcam/DashWebRTCVideo";
-import { LinkAnchorBox } from "./LinkAnchorBox";
-import { PresElementBox } from "../presentationview/PresElementBox";
import { ScreenshotBox } from "./ScreenshotBox";
-import { ComparisonBox } from "./ComparisonBox";
+import { ScriptingBox } from "./ScriptingBox";
+import { SliderBox } from "./SliderBox";
import { VideoBox } from "./VideoBox";
import { WebBox } from "./WebBox";
-import { InkingStroke } from "../InkingStroke";
import React = require("react");
-import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
-import { ScriptField } from "../../../fields/ScriptField";
import XRegExp = require("xregexp");
-import { DocumentType } from "../../documents/DocumentTypes";
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
@@ -226,7 +225,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, SearchBox, FilterBox, FunctionPlotBox,
ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, LinkBox, ScriptingBox,
- ScreenshotBox, HTMLtag, ComparisonBox
+ ScreenshotBox,
+ HTMLtag, ComparisonBox
}}
bindings={bindings}
jsx={layoutFrame}
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 36572b861..bdbece621 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -4,6 +4,13 @@
border-radius: inherit;
}
+.documentView-customBorder {
+ width:100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+}
+
.documentView-node,
.documentView-node-topmost {
position: inherit;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8abcc3f6a..22bdfb1cf 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -47,6 +47,7 @@ import { PresBox } from './PresBox';
import { RadialMenu } from './RadialMenu';
import React = require("react");
import { ScriptingBox } from "./ScriptingBox";
+import { FormattedTextBox } from "./formattedText/FormattedTextBox";
const { Howl } = require('howler');
interface Window {
@@ -120,6 +121,7 @@ export interface DocumentViewSharedProps {
dropAction?: dropActionType;
dontRegisterView?: boolean;
hideLinkButton?: boolean;
+ hideCaptions?: boolean;
ignoreAutoHeight?: boolean;
disableDocBrushing?: boolean; // should highlighting for this view be disabled when same document in another view is hovered over.
pointerEvents?: string;
@@ -200,7 +202,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
@computed get finalLayoutKey() { return StrCast(this.Document.layoutKey, "layout"); }
@computed get nativeWidth() { return this.props.NativeWidth(); }
@computed get nativeHeight() { return this.props.NativeHeight(); }
- @computed get onClickHandler() { return this.props.onClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null)); }
+ @computed get onClickHandler() { return this.props.onClick?.() ?? Cast(this.Document.onfClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null)); }
@computed get onDoubleClickHandler() { return this.props.onDoubleClick?.() ?? (Cast(this.layoutDoc.onDoubleClick, ScriptField, null) ?? this.Document.onDoubleClick); }
@computed get onPointerDownHandler() { return this.props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown); }
@computed get onPointerUpHandler() { return this.props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp); }
@@ -385,7 +387,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
SelectionManager.DeselectAll();
}
- startDragging(x: number, y: number, dropAction: dropActionType) {
+ startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) {
if (this._mainCont.current) {
const dragData = new DragManager.DocumentDragData([this.props.Document]);
const [left, top] = this.props.ScreenToLocalTransform().scale(this.ContentScale).inverse().transformPoint(0, 0);
@@ -396,7 +398,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
dragData.moveDocument = this.props.moveDocument;
const ffview = this.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
ffview && runInAction(() => (ffview.ChildDrag = this.props.DocumentView()));
- DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: !dropAction && !this.layoutDoc.onDragStart },
+ DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: hideSource || (!dropAction && !this.layoutDoc.onDragStart) },
() => setTimeout(action(() => ffview && (ffview.ChildDrag = undefined)))); // this needs to happen after the drop event is processed.
}
}
@@ -453,10 +455,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
}, console.log);
UndoManager.RunInBatch(() => func().result?.select === true ? this.props.select(false) : "", "on double click");
} else if (!Doc.IsSystem(this.rootDoc)) {
- if (this.props.Document.type !== DocumentType.LABEL) {
- UndoManager.RunInBatch(() => this.props.addDocTab((this.rootDoc._fullScreenView as Doc) || this.rootDoc, "lightbox"), "double tap");
- SelectionManager.DeselectAll();
- }
+ UndoManager.RunInBatch(() =>
+ LightboxView.AddDocTab(this.rootDoc, "lightbox", this.props.LayoutTemplate?.())
+ //this.props.addDocTab((this.rootDoc._fullScreenView as Doc) || this.rootDoc, "lightbox")
+ , "double tap");
+ SelectionManager.DeselectAll();
Doc.UnBrushDoc(this.props.Document);
}
} else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes(ScriptingBox.name)) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
@@ -508,6 +511,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
// if this is part of a template, let the event go up to the tempalte root unless right/ctrl clicking
!(this.props.Document.rootDocument && !(e.ctrlKey || e.button > 0))) {
if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) &&
+ !this.Document.ignoreClick &&
!e.ctrlKey &&
(e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) &&
!CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
@@ -668,6 +672,20 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const appearance = cm.findByDescription("UI Controls...");
const appearanceItems: ContextMenuProps[] = appearance && "subitems" in appearance ? appearance.subitems : [];
!Doc.UserDoc().noviceMode && templateDoc && appearanceItems.push({ description: "Open Template ", event: () => this.props.addDocTab(templateDoc, "add:right"), icon: "eye" });
+ appearanceItems.push({
+ description: "Add a Field", event: () => {
+ const alias = Doc.MakeAlias(this.rootDoc);
+ alias.layout = FormattedTextBox.LayoutString("newfield");
+ alias.title = "newfield";
+ alias._yMargin = 10;
+ alias._height = 35;
+ alias._width = 100;
+ alias.syncLayoutFieldWithTitle = true;
+ alias.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc.width);
+ alias.y = NumCast(this.rootDoc.y);
+ this.props.addDocument?.(alias);
+ }, icon: "eye"
+ });
DocListCast(this.Document.links).length && appearanceItems.splice(0, 0, { description: `${this.layoutDoc.hideLinkButton ? "Show" : "Hide"} Link Button`, event: action(() => this.layoutDoc.hideLinkButton = !this.layoutDoc.hideLinkButton), icon: "eye" });
!appearance && cm.addItem({ description: "UI Controls...", subitems: appearanceItems, icon: "compass" });
@@ -890,22 +908,19 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
TraceMobx();
const showTitle = this.ShowTitle?.split(":")[0];
const showTitleHover = this.ShowTitle?.includes(":hover");
- const showCaption = StrCast(this.layoutDoc._showCaption);
+ const showCaption = !this.props.hideCaptions && this.Document._viewType !== CollectionViewType.Carousel ? StrCast(this.layoutDoc._showCaption) : undefined;
const captionView = !showCaption ? (null) :
- <div className="documentView-captionWrapper"
- style={{
- backgroundColor: StrCast(this.layoutDoc["caption-backgroundColor"]),
- color: StrCast(this.layoutDoc["caption-color"])
- }}>
- <DocumentContentsView {...OmitKeys(this.props, ['children']).omit}
- yMargin={10}
- xMargin={10}
+ <div className="documentView-captionWrapper">
+ <FormattedTextBox {...OmitKeys(this.props, ['children']).omit}
+ yPadding={10}
+ xPadding={10}
+ fieldKey={showCaption}
+ fontSize={Math.min(32, 12 * this.props.ScreenToLocalTransform().Scale)}
hideOnLeave={true}
styleProvider={this.captionStyleProvider}
dontRegisterView={true}
- LayoutTemplateString={`<FormattedTextBox {...props} fieldKey={'${showCaption}'}/>`}
onClick={this.onClickFunc}
- layoutKey={this.finalLayoutKey} />
+ />
</div>;
const titleView = !showTitle ? (null) :
<div className={`documentView-titleWrapper${showTitleHover ? "-hover" : ""}`} key="title" style={{
@@ -960,6 +975,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
let highlighting = !this.props.disableDocBrushing && highlightIndex && !excludeTypes.includes(this.layoutDoc.type as any) && this.layoutDoc._viewType !== CollectionViewType.Linear;
highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== "[pres element template]"; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way
+ const borderPath = this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BorderPath) || { path: undefined };
+ const internal = PresBox.EffectsProvider(this.layoutDoc, this.renderDoc) || this.renderDoc;
const boxShadow = highlighting && this.borderRounding && highlightStyle !== "dashed" ? `0 0 0 ${highlightIndex}px ${highlightColor}` :
this.boxShadow || (this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined);
return <div className={DocumentView.ROOT_DIV} ref={this._mainCont}
@@ -975,8 +992,21 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
outline: highlighting && !this.borderRounding ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : "solid 0px",
border: highlighting && this.borderRounding && highlightStyle === "dashed" ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined,
boxShadow,
+ clipPath: borderPath.path ? `path('${borderPath.path}')` : undefined
}}>
- {PresBox.EffectsProvider(this.layoutDoc, this.renderDoc) || this.renderDoc}
+ {!borderPath.path ? internal :
+ <>
+ {/* <div style={{ clipPath: `path('${borderPath.fill}')` }}>
+ {internal}
+ </div> */}
+ {internal}
+ <div key="border2" className="documentView-customBorder" style={{ pointerEvents: "none" }} >
+ <svg style={{ overflow: "visible" }} viewBox={`0 0 ${this.props.PanelWidth()} ${this.props.PanelHeight()}`}>
+ <path d={borderPath.path} style={{ stroke: "black", fill: "transparent", strokeWidth: borderPath.width }} />
+ </svg>
+ </div>
+ </>
+ }
</div>;
}
}
@@ -1076,6 +1106,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
}), 400);
});
+ startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this.docView?.startDragging(x, y, dropAction, hideSource);
+
docViewPathFunc = () => this.docViewPath;
isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
select = (extendSelection: boolean) => SelectionManager.SelectView(this, !SelectionManager.Views().some(v => v.props.Document === this.props.ContainingCollectionDoc) && extendSelection);
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 4f4df32b3..86250c9d1 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -32,8 +32,8 @@ export interface FieldViewProps extends DocumentViewSharedProps {
width?: number;
background?: string;
color?: string;
- xMargin?: number;
- yMargin?: number;
+ xPadding?: number;
+ yPadding?: number;
}
@observer
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index 090099dd8..c97de3402 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -1,8 +1,9 @@
import React = require("react");
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { computed, observable, action, reaction, runInAction } from "mobx";
+import { action, computed, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DocListCast, Field, Opt, DocListCastAsync, HeightSym } from "../../../fields/Doc";
+import Select from "react-select";
+import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
import { List } from "../../../fields/List";
import { RichTextField } from "../../../fields/RichTextField";
@@ -12,24 +13,22 @@ import { Cast, StrCast } from "../../../fields/Types";
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../../Utils";
import { Docs } from "../../documents/Documents";
import { DocumentType } from "../../documents/DocumentTypes";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
+import { UserOptions } from "../../util/GroupManager";
+import { Scripting } from "../../util/Scripting";
+import { SelectionManager } from "../../util/SelectionManager";
import { CollectionTreeView } from "../collections/CollectionTreeView";
+import { CollectionView } from "../collections/CollectionView";
import { ViewBoxBaseComponent } from "../DocComponent";
+import { EditableView } from "../EditableView";
import { SearchBox } from "../search/SearchBox";
+import { DashboardToggleButton, DefaultStyleProvider, StyleProp } from "../StyleProvider";
+import { DocumentViewProps } from "./DocumentView";
import { FieldView, FieldViewProps } from './FieldView';
import './FilterBox.scss';
-import { Scripting } from "../../util/Scripting";
-import { SelectionManager } from "../../util/SelectionManager";
-import { CollectionView } from "../collections/CollectionView";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
-import Select from "react-select";
-import { UserOptions } from "../../util/GroupManager";
-import { DocumentViewProps } from "./DocumentView";
-import { DefaultStyleProvider, StyleProp } from "../StyleProvider";
-import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { EditableView } from "../EditableView";
-import { undoBatch } from "../../util/UndoManager";
type FilterBoxDocument = makeInterface<[typeof documentSchema]>;
const FilterBoxDocument = makeInterface(documentSchema);
@@ -135,7 +134,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
}
gatherFieldValues(dashboard: Doc, facetKey: string) {
- const childDocs = DocListCast((dashboard.data as any)[0].data);
+ const childDocs = DocListCast(dashboard.data);
const valueSet = new Set<string>();
let rtFields = 0;
childDocs.forEach((d) => {
@@ -206,7 +205,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
let nonNumbers = 0;
let minVal = Number.MAX_VALUE, maxVal = -Number.MAX_VALUE;
facetValues.strings.map(val => {
- const num = Number(val);
+ const num = val ? Number(val) : Number.NaN;
if (Number.isNaN(num)) {
nonNumbers++;
} else {
@@ -217,8 +216,8 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
let newFacet: Opt<Doc>;
if (facetHeader === "text" || facetValues.rtFields / allCollectionDocs.length > 0.1) {
newFacet = Docs.Create.TextDocument("", {
- _width: 100, _height: 25, system: true, _stayInCollection: true, target: targetDoc,
- treeViewExpandedView: "layout", title: facetHeader, _treeViewOpen: true, _forceActive: true, ignoreClick: true
+ title: facetHeader, system: true, target: targetDoc, _width: 100, _height: 25, _stayInCollection: true,
+ treeViewExpandedView: "layout", _treeViewOpen: true, _forceActive: true, ignoreClick: true
});
Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
newFacet._textBoxPadding = 4;
@@ -226,7 +225,8 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
newFacet.onTextChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, text: "string" });
} else if (facetHeader !== "tags" && nonNumbers / facetValues.strings.length < .1) {
newFacet = Docs.Create.SliderDocument({
- title: facetHeader, _overflow: "visible", _fitWidth: true, target: targetDoc, _height: 40, _stayInCollection: true, treeViewExpandedView: "layout", _treeViewOpen: true
+ title: facetHeader, system: true, target: targetDoc, _fitWidth: true, _height: 40, _stayInCollection: true,
+ treeViewExpandedView: "layout", _treeViewOpen: true, _forceActive: true, _overflow: "visible",
});
const newFacetField = Doc.LayoutFieldKey(newFacet);
const ranged = Doc.readDocRangeFilter(targetDoc, facetHeader);
@@ -346,16 +346,9 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
* add lock and hide button decorations for the "Dashboards" flyout TreeView
*/
FilterStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps | DocumentViewProps>, property: string) => {
- switch (property.split(":")[0]) {
- case StyleProp.Decorations:
- return !doc || doc.treeViewHideHeaderFields ? (null) :
- <>
- <div className={`styleProvider-treeView-hide${doc.hidden ? "-active" : ""}`} onClick={undoBatch(e =>
- this.removeFilter(StrCast(doc.title))
- )}>
- <FontAwesomeIcon icon={"trash"} size="sm" />
- </div>
- </>;
+ if (property.split(":")[0] === StyleProp.Decorations) {
+ return !doc || doc.treeViewHideHeaderFields ? (null) :
+ DashboardToggleButton(doc, "hidden", "trash", "trash", () => this.removeFilter(StrCast(doc.title)));
}
return this.props.styleProvider?.(doc, props, property);
}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 8a6946b78..e2e08a0e6 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,14 +1,13 @@
-import { action, computed, IReactionDisposer, observable, reaction, runInAction, ObservableMap, untracked } from 'mobx';
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
import { observer } from "mobx-react";
-import { Dictionary } from 'typescript-collections';
import { DataSym, Doc, DocListCast, WidthSym } from '../../../fields/Doc';
import { documentSchema } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
-import { createSchema, listSpec, makeInterface } from '../../../fields/Schema';
+import { createSchema, makeInterface } from '../../../fields/Schema';
import { ComputedField } from '../../../fields/ScriptField';
-import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { Cast, NumCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { TraceMobx } from '../../../fields/util';
import { emptyFunction, OmitKeys, returnOne, Utils } from '../../../Utils';
@@ -30,8 +29,6 @@ import React = require("react");
const path = require('path');
export const pageSchema = createSchema({
- _curPage: "number",
- fitWidth: "boolean",
googlePhotosUrl: "string",
googlePhotosTags: "string"
});
@@ -59,8 +56,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
this._dropDisposer?.();
ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document));
}
+ setViewSpec = (anchor: Doc, preview: boolean) => {
+
+ } // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document
componentDidMount() {
+ this.props.setContentView?.(this); // bcz: do not remove this. without it, stepping into an image in the lightbox causes an infinite loop....
this._disposers.sizer = reaction(() => (
{
forceFull: this.props.renderDepth < 1 || this.layoutDoc._showFullRes,
@@ -102,8 +103,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
const targetDoc = layoutDoc[DataSym];
if (targetDoc[targetField] instanceof ImageField) {
this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField);
- Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(targetDoc));
- Doc.SetNativeWidth(this.dataDoc, Doc.NativeHeight(targetDoc));
+ Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(targetDoc), this.fieldKey);
+ Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(targetDoc), this.fieldKey);
e.stopPropagation();
}
}
@@ -315,6 +316,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
@observable _marqueeing: number[] | undefined;
@observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
@computed get annotationLayer() {
+ TraceMobx();
return <div className="imageBox-annotationLayer" style={{ height: this.props.PanelHeight() }} ref={this._annotationLayer} />;
}
@action
@@ -331,7 +333,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
TraceMobx();
const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding);
const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / (this.props.scaling?.() || 1)}px` : borderRad;
- return (<div className={`imageBox`} onContextMenu={this.specificContextMenu} ref={this._mainCont}
+ return (<div className="imageBox" onContextMenu={this.specificContextMenu} ref={this._mainCont}
style={{
width: this.props.PanelWidth() ? undefined : `100%`,
height: this.props.PanelWidth() ? undefined : `100%`,
@@ -340,32 +342,28 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}} >
<CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
renderDepth={this.props.renderDepth + 1}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}
- CollectionView={undefined}
- PanelHeight={this.props.PanelHeight}
- scaling={returnOne}
- ScreenToLocalTransform={this.screenToLocalTransform}
- PanelWidth={this.props.PanelWidth}
fieldKey={this.annotationKey}
+ CollectionView={undefined}
isAnnotationOverlay={true}
- docFilters={this.props.docFilters}
- docRangeFilters={this.props.docRangeFilters}
- searchFilterDocs={this.props.searchFilterDocs}
- removeDocument={this.removeDocument}
- moveDocument={this.moveDocument}
- addDocument={this.addDocument}
annotationLayerHostsContent={true}
- focus={this.props.focus}
- isSelected={this.props.isSelected}
+ PanelWidth={this.props.PanelWidth}
+ PanelHeight={this.props.PanelHeight}
+ ScreenToLocalTransform={this.screenToLocalTransform}
select={emptyFunction}
isContentActive={this.isContentActive}
- whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}>
+ scaling={returnOne}
+ whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+ removeDocument={this.removeDocument}
+ moveDocument={this.moveDocument}
+ addDocument={this.addDocument}>
{this.contentFunc}
</CollectionFreeFormView>
{this.annotationLayer}
{!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? (null) :
- <MarqueeAnnotator rootDoc={this.rootDoc}
- scrollTop={0} down={this._marqueeing}
+ <MarqueeAnnotator
+ rootDoc={this.rootDoc}
+ scrollTop={0}
+ down={this._marqueeing}
scaling={this.props.scaling}
docView={this.props.docViewPath().lastElement()}
addDocument={this.addDocument}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index d5056d934..feaeb9e21 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -243,6 +243,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
</div>;
}
+ anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
+
@computed get renderPdfView() {
TraceMobx();
return <div className={"pdfBox"} onContextMenu={this.specificContextMenu}
@@ -258,7 +260,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
pdf={this._pdf!}
url={this.pdfUrl!.url.pathname}
isContentActive={this.isContentActive}
- anchorMenuClick={this._sidebarRef.current?.anchorMenuClick}
+ anchorMenuClick={this.anchorMenuClick}
loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined}
setPdfViewer={this.setPdfViewer}
addDocument={this.addDocument}
diff --git a/src/client/views/nodes/ScreenshotBox.scss b/src/client/views/nodes/ScreenshotBox.scss
index ab54cf526..6fb5ea7b3 100644
--- a/src/client/views/nodes/ScreenshotBox.scss
+++ b/src/client/views/nodes/ScreenshotBox.scss
@@ -10,6 +10,13 @@
// }
}
+#CANCAN {
+ canvas {
+ width:100% !important;
+ height: 100% !important;
+ }
+}
+
.screenshotBox-content, .screenshotBox-content-interactive, .screenshotBox-cont-fullScreen {
width: 100%;
z-index: -1; // 0; // logically this should be 0 (or unset) which would give us transparent brush strokes over videos. However, this makes Chrome crawl to a halt
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index c4f8d1143..252c029e4 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -1,7 +1,9 @@
import React = require("react");
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable } from "mobx";
+// import { Canvas } from '@react-three/fiber';
+import { action, computed, observable, reaction } from "mobx";
import { observer } from "mobx-react";
+// import { BufferAttribute, Camera, Vector2, Vector3 } from 'three';
import { DateField } from "../../../fields/DateField";
import { Doc, WidthSym } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
@@ -12,7 +14,7 @@ import { ComputedField } from "../../../fields/ScriptField";
import { Cast, NumCast } from "../../../fields/Types";
import { AudioField, VideoField } from "../../../fields/URLField";
import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, OmitKeys, returnFalse, returnOne, Utils } from "../../../Utils";
+import { emptyFunction, numberRange, OmitKeys, returnFalse, returnOne, Utils } from "../../../Utils";
import { DocUtils } from "../../documents/Documents";
import { DocumentType } from "../../documents/DocumentTypes";
import { Networking } from "../../Network";
@@ -33,18 +35,101 @@ declare class MediaRecorder {
type ScreenshotDocument = makeInterface<[typeof documentSchema]>;
const ScreenshotDocument = makeInterface(documentSchema);
+// interface VideoTileProps {
+// raised: { coord: Vector2, off: Vector3 }[];
+// setRaised: (r: { coord: Vector2, off: Vector3 }[]) => void;
+// x: number;
+// y: number;
+// rootDoc: Doc;
+// color: string;
+// }
+
+// @observer
+// export class VideoTile extends React.Component<VideoTileProps> {
+// @observable _videoRef: HTMLVideoElement | undefined;
+// _mesh: any = undefined;
+
+// render() {
+// const topLeft = [this.props.x, this.props.y];
+// const raised = this.props.raised;
+// const find = (raised: { coord: Vector2, off: Vector3 }[], what: Vector2) => raised.find(r => r.coord.x === what.x && r.coord.y === what.y);
+// const tl1 = find(raised, new Vector2(topLeft[0], topLeft[1] + 1));
+// const tl2 = find(raised, new Vector2(topLeft[0] + 1, topLeft[1] + 1));
+// const tl3 = find(raised, new Vector2(topLeft[0] + 1, topLeft[1]));
+// const tl4 = find(raised, new Vector2(topLeft[0], topLeft[1]));
+// const quad_indices = [0, 2, 1, 0, 3, 2];
+// const quad_uvs = [0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0];
+// const quad_normals = [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,];
+// const quad_vertices =
+// [
+// topLeft[0] - 0.0 + (tl1?.off.x || 0), topLeft[1] + 1.0 + (tl1?.off.y || 0), 0.0 + (tl1?.off.z || 0),
+// topLeft[0] + 1.0 + (tl2?.off.x || 0), topLeft[1] + 1.0 + (tl2?.off.y || 0), 0.0 + (tl2?.off.z || 0),
+// topLeft[0] + 1.0 + (tl3?.off.x || 0), topLeft[1] - 0.0 + (tl3?.off.y || 0), 0.0 + (tl3?.off.z || 0),
+// topLeft[0] - 0.0 + (tl4?.off.x || 0), topLeft[1] - 0.0 + (tl4?.off.y || 0), 0.0 + (tl4?.off.z || 0)
+// ];
+
+// const vertices = new Float32Array(quad_vertices);
+// const normals = new Float32Array(quad_normals);
+// const uvs = new Float32Array(quad_uvs); // Each vertex has one uv coordinate for texture mapping
+// const indices = new Uint32Array(quad_indices); // Use the four vertices to draw the two triangles that make up the square.
+// const popOut = () => NumCast(this.props.rootDoc.popOut);
+// const popOff = () => NumCast(this.props.rootDoc.popOff);
+// return (
+// <mesh key={`mesh${topLeft[0]}${topLeft[1]}`} onClick={action(async e => {
+// this.props.setRaised([
+// { coord: new Vector2(topLeft[0], topLeft[1]), off: new Vector3(-popOff(), -popOff(), popOut()) },
+// { coord: new Vector2(topLeft[0] + 1, topLeft[1]), off: new Vector3(popOff(), -popOff(), popOut()) },
+// { coord: new Vector2(topLeft[0], topLeft[1] + 1), off: new Vector3(-popOff(), popOff(), popOut()) },
+// { coord: new Vector2(topLeft[0] + 1, topLeft[1] + 1), off: new Vector3(popOff(), popOff(), popOut()) }
+// ]);
+// if (!this._videoRef) {
+// (navigator.mediaDevices as any).getDisplayMedia({ video: true }).then(action((stream: any) => {
+// //const videoSettings = stream.getVideoTracks()[0].getSettings();
+// this._videoRef = document.createElement("video");
+// Object.assign(this._videoRef, {
+// srcObject: stream,
+// //height: videoSettings.height,
+// //width: videoSettings.width,
+// autoplay: true
+// });
+// }));
+// }
+// })} ref={(r: any) => this._mesh = r}>
+// <bufferGeometry attach="geometry" ref={(r: any) => {
+// // itemSize = 3 because there are 3 values (components) per vertex
+// r?.setAttribute('position', new BufferAttribute(vertices, 3));
+// r?.setAttribute('normal', new BufferAttribute(normals, 3));
+// r?.setAttribute('uv', new BufferAttribute(uvs, 2));
+// r?.setIndex(new BufferAttribute(indices, 1));
+// }} />
+// {!this._videoRef ? <meshStandardMaterial color={this.props.color} /> :
+// <meshBasicMaterial >
+// <videoTexture attach="map" args={[this._videoRef]} />
+// </meshBasicMaterial>}
+// </mesh>
+// );
+// }
+// }
+
@observer
export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps, ScreenshotDocument>(ScreenshotDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ScreenshotBox, fieldKey); }
- private _videoRef: HTMLVideoElement | null = null;
private _audioRec: any;
private _videoRec: any;
+ @observable private _videoRef: HTMLVideoElement | null = null;
@observable _screenCapture = false;
@computed get recordingStart() { return Cast(this.dataDoc[this.props.fieldKey + "-recordingStart"], DateField)?.date.getTime(); }
constructor(props: any) {
super(props);
- this.setupDictation();
+ if (this.rootDoc.videoWall) {
+ this.rootDoc.nativeWidth = undefined;
+ this.rootDoc.nativeHeight = undefined;
+ this.layoutDoc.popOff = 0;
+ this.layoutDoc.popOut = 1;
+ } else {
+ this.setupDictation();
+ }
}
getAnchor = () => {
const startTime = Cast(this.layoutDoc._currentTimecode, "number", null) || (this._videoRec ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined);
@@ -67,6 +152,16 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
componentDidMount() {
this.dataDoc.nativeWidth = this.dataDoc.nativeHeight = 0;
this.props.setContentView?.(this); // this tells the DocumentView that this ScreenshotBox is the "content" of the document. this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
+ // this.rootDoc.videoWall && reaction(() => ({ width: this.props.PanelWidth(), height: this.props.PanelHeight() }),
+ // ({ width, height }) => {
+ // if (this._camera) {
+ // const angle = -Math.abs(1 - width / height);
+ // const xz = [0, (this._numScreens - 2) / Math.abs(1 + angle)];
+ // this._camera.position.set(this._numScreens / 2 + xz[1] * Math.sin(angle), this._numScreens / 2, xz[1] * Math.cos(angle));
+ // this._camera.lookAt(this._numScreens / 2, this._numScreens / 2, 0);
+ // (this._camera as any).updateProjectionMatrix();
+ // }
+ // });
}
componentWillUnmount() {
const ind = DocUtils.ActiveRecordings.indexOf(this);
@@ -79,26 +174,50 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
}
@computed get content() {
+ if (this.rootDoc.videoWall) return (null);
const interactive = CurrentUserUtils.SelectedTool !== InkTool.None || !this.props.isSelected() ? "" : "-interactive";
return <video className={"videoBox-content" + interactive} key="video"
ref={r => {
this._videoRef = r;
setTimeout(() => {
- if (this.rootDoc.mediaState === "pendingRecording" && this._videoRef) { // TODO glr: use mediaState
+ if (this.rootDoc.mediaState === "pendingRecording" && this._videoRef) {
this.toggleRecording();
}
- }, 1000);
+ }, 100);
}}
- autoPlay={true}
- style={{ width: "100%", height: "100%" }}
+ autoPlay={this._screenCapture}
+ style={{ width: this._screenCapture ? "100%" : undefined, height: this._screenCapture ? "100%" : undefined }}
onCanPlay={this.videoLoad}
controls={true}
onClick={e => e.preventDefault()}>
<source type="video/mp4" />
Not supported.
- </video>;
+ </video>;
}
+ // _numScreens = 5;
+ // _camera: Camera | undefined;
+ // @observable _raised = [] as { coord: Vector2, off: Vector3 }[];
+ // @action setRaised = (r: { coord: Vector2, off: Vector3 }[]) => this._raised = r;
+ @computed get threed() {
+ // if (this.rootDoc.videoWall) {
+ // const screens: any[] = [];
+ // const colors = ["yellow", "red", "orange", "brown", "maroon", "gray"];
+ // let count = 0;
+ // numberRange(this._numScreens).forEach(x => numberRange(this._numScreens).forEach(y => screens.push(
+ // <VideoTile rootDoc={this.rootDoc} color={colors[count++ % colors.length]} x={x} y={y} raised={this._raised} setRaised={this.setRaised} />)));
+ // return <Canvas key="canvas" id="CANCAN" style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }} gl={{ antialias: false }} colorManagement={false} onCreated={props => {
+ // this._camera = props.camera;
+ // props.camera.position.set(this._numScreens / 2, this._numScreens / 2, this._numScreens - 2);
+ // props.camera.lookAt(this._numScreens / 2, this._numScreens / 2, 0);
+ // }}>
+ // {/* <ambientLight />*/}
+ // <pointLight position={[10, 10, 10]} intensity={1} />
+ // {screens}
+ // </ Canvas>;
+ // }
+ return (null);
+ }
toggleRecording = action(async () => {
this._screenCapture = !this._screenCapture;
if (this._screenCapture) {
@@ -155,7 +274,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
dictationTextProto.mediaState = ComputedField.MakeFunction("self.recordingSource.mediaState");
this.dataDoc[this.fieldKey + "-dictation"] = dictationText;
}
- contentFunc = () => [this.content];
+ contentFunc = () => [this.threed, this.content];
videoPanelHeight = () => NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"], 1) / NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"], 1) * this.props.PanelWidth();
formattedPanelHeight = () => Math.max(0, this.props.PanelHeight() - this.videoPanelHeight());
render() {
@@ -183,28 +302,26 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
{this.contentFunc}
</CollectionFreeFormView></div>
<div style={{ position: "relative", height: this.formattedPanelHeight() }}>
- <FormattedTextBox {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
- Document={this.dataDoc[this.fieldKey + "-dictation"]}
- fieldKey={"text"}
- PanelHeight={this.formattedPanelHeight}
- PanelWidth={this.props.PanelWidth}
- focus={this.props.focus}
- isSelected={this.props.isSelected}
- isAnnotationOverlay={true}
- select={emptyFunction}
- isContentActive={returnFalse}
- scaling={returnOne}
- xMargin={25}
- yMargin={10}
- whenChildContentsActiveChanged={emptyFunction}
- removeDocument={returnFalse}
- moveDocument={returnFalse}
- addDocument={returnFalse}
- CollectionView={undefined}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform}
- renderDepth={this.props.renderDepth + 1}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
- </FormattedTextBox></div>
+ {!(this.dataDoc[this.fieldKey + "-dictation"] instanceof Doc) ? (null) :
+ <FormattedTextBox {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
+ Document={this.dataDoc[this.fieldKey + "-dictation"]}
+ fieldKey={"text"}
+ PanelHeight={this.formattedPanelHeight}
+ isAnnotationOverlay={true}
+ select={emptyFunction}
+ isContentActive={returnFalse}
+ scaling={returnOne}
+ xPadding={25}
+ yPadding={10}
+ whenChildContentsActiveChanged={emptyFunction}
+ removeDocument={returnFalse}
+ moveDocument={returnFalse}
+ addDocument={returnFalse}
+ CollectionView={undefined}
+ renderDepth={this.props.renderDepth + 1}
+ ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
+ </FormattedTextBox>}
+ </div>
</div>
{!this.props.isSelected() ? (null) : <div className="screenshotBox-uiButtons">
<div className="screenshotBox-recorder" key="snap" onPointerDown={this.toggleRecording} >
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss
index 30f0c4393..f593f74fb 100644
--- a/src/client/views/nodes/VideoBox.scss
+++ b/src/client/views/nodes/VideoBox.scss
@@ -66,6 +66,7 @@
background-color:rgba(50, 50, 50, 0.2);
transform-origin: left top;
pointer-events:all;
+ cursor: default;
}
.videoBox-timelineButton {
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index fb58ddefc..263fd5a19 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -26,6 +26,8 @@ import { StyleProp } from "../StyleProvider";
import { FieldView, FieldViewProps } from './FieldView';
import { LinkDocPreview } from "./LinkDocPreview";
import "./VideoBox.scss";
+import { DragManager } from "../../util/DragManager";
+import { DocumentManager } from "../../util/DocumentManager";
const path = require('path');
type VideoDocument = makeInterface<[typeof documentSchema]>;
@@ -137,7 +139,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
}
- @action public Snapshot() {
+ @action public Snapshot(downX?: number, downY?: number) {
const width = (this.layoutDoc._width || 0);
const height = (this.layoutDoc._height || 0);
const canvas = document.createElement('canvas');
@@ -176,11 +178,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
const retitled = StrCast(this.rootDoc.title).replace(/[ -\.]/g, "");
const filename = path.basename(encodeURIComponent("snapshot" + retitled + "_" + (this.layoutDoc._currentTimecode || 0).toString().replace(/\./, "_")));
VideoBox.convertDataUri(dataUrl, filename).then((returnedFilename: string) =>
- returnedFilename && this.createRealSummaryLink(returnedFilename));
+ returnedFilename && this.createRealSummaryLink(returnedFilename, downX, downY));
}
}
- private createRealSummaryLink = (relative: string) => {
+ private createRealSummaryLink = (relative: string, downX?: number, downY?: number) => {
const url = this.choosePath(Utils.prepend(relative));
const width = this.layoutDoc._width || 1;
const height = this.layoutDoc._height || 0;
@@ -192,7 +194,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
Doc.SetNativeWidth(Doc.GetProto(imageSummary), Doc.NativeWidth(this.layoutDoc));
Doc.SetNativeHeight(Doc.GetProto(imageSummary), Doc.NativeHeight(this.layoutDoc));
this.props.addDocument?.(imageSummary);
- DocUtils.MakeLink({ doc: imageSummary }, { doc: this.getAnchor() }, "video snapshot");
+ const link = DocUtils.MakeLink({ doc: imageSummary }, { doc: this.getAnchor() }, "video snapshot");
+ link && (Doc.GetProto(link.anchor2 as Doc).timecodeToHide = NumCast((link.anchor2 as Doc).timecodeToShow) + 3);
+ setTimeout(() =>
+ (downX !== undefined && downY !== undefined) && DocumentManager.Instance.getFirstDocumentView(imageSummary)?.startDragging(downX, downY, "move", true));
}
@action
@@ -383,7 +388,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
<span>{"" + formatTime(curTime)}</span>
<span style={{ fontSize: 8 }}>{" " + Math.round((curTime - Math.trunc(curTime)) * 100)}</span>
</div>,
- <div className="videoBox-snapshot" key="snap" onClick={this.onSnapshot} >
+ <div className="videoBox-snapshot" key="snap" onPointerDown={this.onSnapshotDown} >
<FontAwesomeIcon icon="camera" size="lg" />
</div>,
<div className="videoBox-timelineButton" key="timeline" onPointerDown={this.onTimelineHdlDown} style={{ bottom: `${100 - this.heightPercent}%` }}>
@@ -409,10 +414,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
e.preventDefault();
}
- onSnapshot = (e: React.MouseEvent) => {
- this.Snapshot();
- e.stopPropagation();
- e.preventDefault();
+ onSnapshotDown = (e: React.PointerEvent) => {
+ setupMoveUpEvents(this, e, (e) => {
+ this.Snapshot(e.clientX, e.clientY);
+ return true;
+ }, emptyFunction, () => this.Snapshot());
}
onTimelineHdlDown = action((e: React.PointerEvent) => {
@@ -492,7 +498,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
}
playLink = (doc: Doc) => {
- const startTime = Math.max(0, (this._stackedTimeline.current?.anchorStart(doc) || 0) - .25);
+ const startTime = Math.max(0, (this._stackedTimeline.current?.anchorStart(doc) || 0));
const endTime = this._stackedTimeline.current?.anchorEnd(doc);
if (startTime !== undefined) {
if (!this.layoutDoc.dontAutoPlayFollowedLinks) endTime ? this.playFrom(startTime, endTime) : this.playFrom(startTime);
@@ -567,22 +573,22 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
<div className="videoBox-viewer" onPointerDown={this.marqueeDown} >
<div style={{ position: "absolute", transition: this.transition, width: this.panelWidth(), height: this.panelHeight(), top: 0, left: `${(100 - this.heightPercent) / 2}%` }}>
<CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
+ renderDepth={this.props.renderDepth + 1}
fieldKey={this.annotationKey}
+ CollectionView={undefined}
isAnnotationOverlay={true}
annotationLayerHostsContent={true}
- select={emptyFunction}
- isContentActive={this.isContentActive}
- scaling={returnOne}
- docFilters={this.timelineDocFilter}
PanelWidth={this.panelWidth}
PanelHeight={this.panelHeight}
ScreenToLocalTransform={this.screenToLocalTransform}
+ docFilters={this.timelineDocFilter}
+ select={emptyFunction}
+ isContentActive={this.isContentActive}
+ scaling={returnOne}
whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
removeDocument={this.removeDocument}
moveDocument={this.moveDocument}
- addDocument={this.addDocWithTimecode}
- CollectionView={undefined}
- renderDepth={this.props.renderDepth + 1}>
+ addDocument={this.addDocWithTimecode}>
{this.contentFunc}
</CollectionFreeFormView>
</div>
@@ -591,16 +597,17 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
{this.renderTimeline}
{!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? (null) :
<MarqueeAnnotator
- scrollTop={0}
rootDoc={this.rootDoc}
+ scrollTop={0}
down={this._marqueeing}
- docView={this.props.docViewPath().lastElement()}
scaling={this.marqueeFitScaling}
+ docView={this.props.docViewPath().lastElement()}
containerOffset={this.marqueeOffset}
addDocument={this.addDocWithTimecode}
finishMarquee={this.finishMarquee}
savedAnnotations={this._savedAnnotations}
- annotationLayer={this._annotationLayer.current} mainCont={this._mainCont.current}
+ annotationLayer={this._annotationLayer.current}
+ mainCont={this._mainCont.current}
/>}
</div>
</div >);
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index fc6f9ceab..cb7e58559 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -478,6 +478,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1) - this.sidebarWidth(); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.layoutDoc._scrollTop));
+ anchorMenuClick = () => this._sidebarRef.current?.anchorMenuClick;
render() {
const inactiveLayer = this.props.layerProvider?.(this.layoutDoc) === false;
const scale = this.props.scaling?.() || 1;
@@ -531,7 +532,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
<MarqueeAnnotator rootDoc={this.rootDoc}
iframe={this.isFirefox() ? this.iframeClick : undefined}
iframeScaling={this.isFirefox() ? this.iframeScaling : undefined}
- anchorMenuClick={this._sidebarRef.current?.anchorMenuClick}
+ anchorMenuClick={this.anchorMenuClick}
scrollTop={0}
down={this._marqueeing} scaling={returnOne}
addDocument={this.addDocument}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index c2860af76..911ec1560 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { isEqual } from "lodash";
-import { action, computed, IReactionDisposer, reaction, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, reaction, runInAction, observable } from "mobx";
import { observer } from "mobx-react";
import { baseKeymap, selectAll } from "prosemirror-commands";
import { history } from "prosemirror-history";
@@ -68,8 +68,8 @@ const translateGoogleApi = require("translate-google-api");
export interface FormattedTextBoxProps {
makeLink?: () => Opt<Doc>; // bcz: hack: notifies the text document when the container has made a link. allows the text doc to react and setup a hyeprlink for any selected text
hideOnLeave?: boolean; // used by DocumentView for setting caption's hide on leave (bcz: would prefer to have caption-hideOnLeave field set or something similar)
- xMargin?: number; // used to override document's settings for xMargin --- see CollectionCarouselView
- yMargin?: number;
+ xPadding?: number; // used to override document's settings for xMargin --- see CollectionCarouselView
+ yPadding?: number;
noSidebar?: boolean;
dontSelectOnLoad?: boolean; // suppress selecting the text box when loaded
}
@@ -1064,8 +1064,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
});
}
setupEditor(config: any, fieldKey: string) {
- const curText = Cast(this.dataDoc[this.props.fieldKey], RichTextField, null);
- const rtfField = Cast((!curText?.Text && this.layoutDoc[this.props.fieldKey]) || this.dataDoc[fieldKey], RichTextField);
+ const curText = Cast(this.dataDoc[this.props.fieldKey], RichTextField, null) || StrCast(this.dataDoc[this.props.fieldKey]);
+ const rtfField = Cast((!curText && this.layoutDoc[this.props.fieldKey]) || this.dataDoc[fieldKey], RichTextField);
if (this.ProseRef) {
const self = this;
this._editorView?.destroy();
@@ -1075,8 +1075,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const docPos = editorView.coordsAtPos(editorView.state.selection.to);
const viewRect = self._ref.current!.getBoundingClientRect();
const scrollRef = self._scrollRef.current;
- if ((docPos.bottom < viewRect.top || docPos.bottom > viewRect.bottom) && scrollRef) {
- const scrollPos = scrollRef.scrollTop + (docPos.bottom - viewRect.top) * self.props.ScreenToLocalTransform().Scale;
+ const topOff = docPos.top < viewRect.top ? docPos.top - viewRect.top : undefined;
+ const botOff = docPos.bottom > viewRect.bottom ? docPos.bottom - viewRect.bottom : undefined;
+ if ((topOff || botOff) && scrollRef) {
+ const shift = Math.min(topOff ?? Number.MAX_VALUE, botOff ?? Number.MAX_VALUE);
+ const scrollPos = scrollRef.scrollTop + shift * self.props.ScreenToLocalTransform().Scale;
if (this._focusSpeed !== undefined) {
scrollPos && smoothScroll(this._focusSpeed, scrollRef, scrollPos);
} else {
@@ -1118,7 +1121,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const tr = this._editorView.state.tr.setStoredMarks(storedMarks).insertText(FormattedTextBox.SelectOnLoadChar, this._editorView.state.doc.content.size - 1, this._editorView.state.doc.content.size).setStoredMarks(storedMarks);
this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
FormattedTextBox.SelectOnLoadChar = "";
- } else if (curText?.Text && !FormattedTextBox.DontSelectInitialText) {
+ } else if (curText && !FormattedTextBox.DontSelectInitialText) {
selectAll(this._editorView!.state, this._editorView?.dispatch);
this.startUndoTypingBatch();
}
@@ -1132,6 +1135,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
componentWillUnmount() {
+ FormattedTextBox.Focused === this && (FormattedTextBox.Focused = undefined);
Object.values(this._disposers).forEach(disposer => disposer?.());
this.endUndoTypingBatch();
this.unhighlightSearchTerms();
@@ -1236,8 +1240,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
@action
onFocused = (e: React.FocusEvent): void => {
//applyDevTools.applyDevTools(this._editorView);
+ FormattedTextBox.Focused = this;
this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props);
}
+ @observable public static Focused: FormattedTextBox | undefined;
onClick = (e: React.MouseEvent): void => {
if (Math.abs(e.clientX - this._downX) > 4 || Math.abs(e.clientY - this._downY) > 4) {
@@ -1339,7 +1345,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
this._undoTyping = undefined;
return wasUndoing;
}
+ @action
onBlur = (e: any) => {
+ FormattedTextBox.Focused === this && (FormattedTextBox.Focused = undefined);
if (RichTextMenu.Instance?.view === this._editorView && !this.props.isSelected(true)) {
RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined);
}
@@ -1472,8 +1480,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
NativeHeight={returnZero}
PanelHeight={this.props.PanelHeight}
PanelWidth={this.sidebarWidth}
- xMargin={0}
- yMargin={0}
+ xPadding={0}
+ yPadding={0}
scaleField={this.SidebarKey + "-scale"}
isAnnotationOverlay={false}
select={emptyFunction}
@@ -1505,10 +1513,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || this.props.layerProvider?.(this.layoutDoc) !== false);
if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
const minimal = this.props.ignoreAutoHeight;
- const margins = NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0);
+ const margins = NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
const selPad = Math.min(margins, 10);
const padding = Math.max(margins + ((selected && !this.layoutDoc._singleLine) || minimal ? -selPad : 0), 0);
const selPaddingClass = selected && !this.layoutDoc._singleLine && margins >= 10 ? "-selected" : "";
+ const col = this.props.color ? this.props.color : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color);
+ const back = this.props.background ? this.props.background : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor);
return (
<div className="formattedTextBox-cont"
onWheel={e => this.isContentActive() && e.stopPropagation()}
@@ -1524,12 +1534,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
style={{
overflow: this.autoHeight ? "hidden" : undefined,
height: this.props.height || (this.autoHeight && this.props.renderDepth ? "max-content" : undefined),
- background: this.props.background ? this.props.background : StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor)),
- color: this.props.color ? this.props.color : StrCast(this.layoutDoc[this.props.fieldKey + "-color"], this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color)),
- pointerEvents: interactive ? undefined : "none",
- fontSize: this.props.fontSize || Cast(this.layoutDoc._fontSize, "string", null),
+ background: this.props.background ? this.props.background : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
+ color: this.props.color ? this.props.color : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
+ fontSize: this.props.fontSize ? this.props.fontSize : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.FontSize),
fontWeight: Cast(this.layoutDoc._fontWeight, "number", null),
fontFamily: StrCast(this.layoutDoc._fontFamily, "inherit"),
+ pointerEvents: interactive ? undefined : "none",
}}
onContextMenu={this.specificContextMenu}
onKeyDown={this.onKeyDown}
@@ -1551,7 +1561,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
onScroll={this.onScroll} onDrop={this.ondrop} >
<div className={minimal ? "formattedTextBox-minimal" : `formattedTextBox-inner${rounded}${selPaddingClass}`} ref={this.createDropTarget}
style={{
- padding: this.layoutDoc._textBoxPadding ? StrCast(this.layoutDoc._textBoxPadding) : `${padding}px`,
+ padding: StrCast(this.layoutDoc._textBoxPadding, `${padding}px`),
pointerEvents: !active && !SnappingManager.GetIsDragging() ? (this.layoutDoc.isLinkButton ? "none" : undefined) : undefined
}}
/>
@@ -1560,7 +1570,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
{(this.props.noSidebar || this.Document._noSidebar) || this.Document._singleLine ? (null) : this.sidebarHandle}
{!this.layoutDoc._showAudio ? (null) : this.audioHandle}
</div>
- </div>
+ </div >
);
}
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 6821935a0..1fde6e5f0 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -85,7 +85,7 @@ export class FormattedTextBoxComment {
static update(textBox: FormattedTextBox, view: EditorView, lastState?: EditorState, hrefs: string = "") {
FormattedTextBoxComment.textBox = textBox;
if ((hrefs || !lastState?.doc.eq(view.state.doc) || !lastState?.selection.eq(view.state.selection))) {
- FormattedTextBoxComment.setupPreview(view, textBox, hrefs?.trim().split(" "));
+ FormattedTextBoxComment.setupPreview(view, textBox, hrefs?.trim().split(" ").filter(h => h));
}
}
@@ -109,7 +109,7 @@ export class FormattedTextBoxComment {
}
// this checks if the selection is a hyperlink. If so, it displays the target doc's text for internal links, and the url of the target for external links.
- if (state.selection.$from && hrefs) {
+ if (state.selection.$from && hrefs?.length) {
const nbef = findStartOfMark(state.selection.$from, view, findLinkMark);
const naft = findEndOfMark(state.selection.$from, view, findLinkMark) || nbef;
nbef && naft && LinkDocPreview.SetLinkInfo({
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index a2e7b0600..85cf5abd7 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -47,7 +47,7 @@ interface IViewerProps extends FieldViewProps {
setPdfViewer: (view: PDFViewer) => void;
ContentScaling?: () => number;
sidebarWidth: () => number;
- anchorMenuClick?: (anchor: Doc) => void;
+ anchorMenuClick?: () => undefined | ((anchor: Doc) => void);
}
/**
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index aa9e57a96..de4c1e5f9 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -914,8 +914,8 @@ export namespace Doc {
}
export function NativeWidth(doc?: Doc, dataDoc?: Doc, useWidth?: boolean) { return !doc ? 0 : NumCast(doc._nativeWidth, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + "-nativeWidth"], useWidth ? doc[WidthSym]() : 0)); }
export function NativeHeight(doc?: Doc, dataDoc?: Doc, useHeight?: boolean) { return !doc ? 0 : NumCast(doc._nativeHeight, NumCast((dataDoc || doc)[Doc.LayoutFieldKey(doc) + "-nativeHeight"], useHeight ? doc[HeightSym]() : 0)); }
- export function SetNativeWidth(doc: Doc, width: number | undefined) { doc[Doc.LayoutFieldKey(doc) + "-nativeWidth"] = width; }
- export function SetNativeHeight(doc: Doc, height: number | undefined) { doc[Doc.LayoutFieldKey(doc) + "-nativeHeight"] = height; }
+ export function SetNativeWidth(doc: Doc, width: number | undefined, fieldKey?: string) { doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + "-nativeWidth"] = width; }
+ export function SetNativeHeight(doc: Doc, height: number | undefined, fieldKey?: string) { doc[(fieldKey ?? Doc.LayoutFieldKey(doc)) + "-nativeHeight"] = height; }
const manager = new DocData();
diff --git a/src/fields/Schema.ts b/src/fields/Schema.ts
index 78f8a6bfb..7ad376a28 100644
--- a/src/fields/Schema.ts
+++ b/src/fields/Schema.ts
@@ -21,8 +21,6 @@ export interface InterfaceFunc<T extends Interface[]> {
}
export type makeInterface<T extends Interface[]> = AllToInterface<T> & Doc & { proto: Doc | undefined };
-// export function makeInterface<T extends Interface[], U extends Doc>(schemas: T): (doc: U) => All<T, U>;
-// export function makeInterface<T extends Interface, U extends Doc>(schema: T): (doc: U) => makeInterface<T, U>;
export function makeInterface<T extends Interface[]>(...schemas: T): InterfaceFunc<T> {
const schema: Interface = {};
for (const s of schemas) {
@@ -37,18 +35,18 @@ export function makeInterface<T extends Interface[]>(...schemas: T): InterfaceFu
const desc = prop === "proto" ? Doc : (schema as any)[prop]; // bcz: proto doesn't appear in schemas ... maybe it should?
if (typeof desc === "object" && "defaultVal" in desc && "type" in desc) {//defaultSpec
return Cast(field, desc.type, desc.defaultVal);
- } else if (typeof desc === "function" && !ObjectField.isPrototypeOf(desc) && !RefField.isPrototypeOf(desc)) {
+ }
+ if (typeof desc === "function" && !ObjectField.isPrototypeOf(desc) && !RefField.isPrototypeOf(desc)) {
const doc = Cast(field, Doc);
if (doc === undefined) {
return undefined;
- } else if (doc instanceof Doc) {
+ }
+ if (doc instanceof Doc) {
return desc(doc);
- } else {
- return doc.then(doc => doc && desc(doc));
}
- } else {
- return Cast(field, desc);
+ return doc.then(doc => doc && desc(doc));
}
+ return Cast(field, desc);
}
return field;
},
@@ -57,21 +55,9 @@ export function makeInterface<T extends Interface[]>(...schemas: T): InterfaceFu
return true;
}
});
- const fn = (doc: Doc) => {
- doc = doc[SelfProxy];
- // if (!(doc instanceof Doc)) {
- // throw new Error("Currently wrapping a schema in another schema isn't supported");
- // }
- const obj = Object.create(proto, { doc: { value: doc, writable: false } });
- return obj;
- };
- return function (doc?: Doc | Doc[]) {
- if (doc instanceof Doc || doc === undefined) {
- return fn(doc || new Doc);
- } else if (doc instanceof List) {
- return doc.map(fn);
- } else return {};
- };
+ // !(doc instanceof Doc) && (throw new Error("Currently wrapping a schema in another schema isn't supported"));
+ const fn = (doc: Doc) => Object.create(proto, { doc: { value: doc[SelfProxy], writable: false } });
+ return ((doc?: Doc | Doc[]) => (doc instanceof List ? doc : undefined)?.map?.(fn) ?? fn((doc as Doc) ?? new Doc)) as InterfaceFunc<T>;
}
export type makeStrictInterface<T extends Interface> = Partial<ToInterface<T>>;
diff --git a/webpack.config.js b/webpack.config.js
index 30967d618..56bd428e4 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -106,7 +106,9 @@ module.exports = {
}
}]
}
- ]
+ ],
+
+ noParse: [require.resolve('typescript/lib/typescript.js')],
},
plugins,
externals: [