flow: massive refactor
This commit is contained in:
parent
684a3cce21
commit
3b0c27a530
|
@ -1,5 +1,3 @@
|
||||||
require('dotenv/config');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
options: {
|
options: {
|
||||||
root: __dirname,
|
root: __dirname,
|
||||||
|
|
33
latus.yml
33
latus.yml
|
@ -1,15 +1,31 @@
|
||||||
'@avocado/behavior': {}
|
'@avocado/behavior': {}
|
||||||
|
'@avocado/behavior/persea': {}
|
||||||
'@avocado/entity': {}
|
'@avocado/entity': {}
|
||||||
|
'@avocado/entity/persea': {}
|
||||||
'@avocado/graphics': {}
|
'@avocado/graphics': {}
|
||||||
|
'@avocado/graphics/persea': {}
|
||||||
'@avocado/input': {}
|
'@avocado/input': {}
|
||||||
'@avocado/math': {}
|
'@avocado/math': {}
|
||||||
|
'@avocado/math/persea': {}
|
||||||
|
'@avocado/persea': {}
|
||||||
'@avocado/physics': {}
|
'@avocado/physics': {}
|
||||||
'@avocado/resource': {}
|
'@avocado/resource': {
|
||||||
|
'persea.controllers': [
|
||||||
|
'@avocado/graphics/persea',
|
||||||
|
'@avocado/entity/persea',
|
||||||
|
'@avocado/sound/persea',
|
||||||
|
'@avocado/timing/persea',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
'@avocado/resource/persea': {}
|
||||||
'@avocado/s13n': {}
|
'@avocado/s13n': {}
|
||||||
'@avocado/sound': {}
|
'@avocado/sound': {}
|
||||||
|
'@avocado/sound/persea': {}
|
||||||
'@avocado/timing': {}
|
'@avocado/timing': {}
|
||||||
|
'@avocado/timing/persea': {}
|
||||||
'@avocado/topdown': {}
|
'@avocado/topdown': {}
|
||||||
'@avocado/traits': {}
|
'@avocado/traits': {}
|
||||||
|
'@avocado/traits/persea': {}
|
||||||
'@humus/combat': {}
|
'@humus/combat': {}
|
||||||
'@humus/combat/persea': {}
|
'@humus/combat/persea': {}
|
||||||
'@humus/core': {}
|
'@humus/core': {}
|
||||||
|
@ -68,7 +84,7 @@
|
||||||
'@latus/socket': {
|
'@latus/socket': {
|
||||||
packets.decorate: [
|
packets.decorate: [
|
||||||
'@latus/governor/server',
|
'@latus/governor/server',
|
||||||
'@persea/json/server',
|
'@persea/core/server',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
'@latus/socket/client': {}
|
'@latus/socket/client': {}
|
||||||
|
@ -86,15 +102,4 @@
|
||||||
'@latus/user/session': {}
|
'@latus/user/session': {}
|
||||||
'@persea/app': {}
|
'@persea/app': {}
|
||||||
'@persea/bootstrap': {}
|
'@persea/bootstrap': {}
|
||||||
'@persea/core': {
|
'@persea/core': {}
|
||||||
'resource-controllers': [
|
|
||||||
'@persea/entity',
|
|
||||||
'@persea/sound',
|
|
||||||
'@persea/timing',
|
|
||||||
'@persea/json',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
'@persea/entity': {}
|
|
||||||
'@persea/json': {}
|
|
||||||
'@persea/sound': {}
|
|
||||||
'@persea/timing': {}
|
|
||||||
|
|
|
@ -24,10 +24,6 @@
|
||||||
"@persea/app": "^3.0.0",
|
"@persea/app": "^3.0.0",
|
||||||
"@persea/bootstrap": "^3.0.0",
|
"@persea/bootstrap": "^3.0.0",
|
||||||
"@persea/core": "^3.0.0",
|
"@persea/core": "^3.0.0",
|
||||||
"@persea/entity": "^3.0.0",
|
|
||||||
"@persea/json": "^3.0.0",
|
|
||||||
"@persea/sound": "^3.0.0",
|
|
||||||
"@persea/timing": "^3.0.0",
|
|
||||||
"dotenv": "^8.2.0"
|
"dotenv": "^8.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
"@avocado/graphics": "^2.0.0",
|
"@avocado/graphics": "^2.0.0",
|
||||||
"@avocado/input": "^2.0.0",
|
"@avocado/input": "^2.0.0",
|
||||||
"@avocado/math": "^2.0.0",
|
"@avocado/math": "^2.0.0",
|
||||||
|
"@avocado/persea": "^1.0.0",
|
||||||
"@avocado/physics": "^1.0.0",
|
"@avocado/physics": "^1.0.0",
|
||||||
"@avocado/resource": "^2.0.0",
|
"@avocado/resource": "^2.0.0",
|
||||||
"@avocado/s13n": "^2.0.0",
|
"@avocado/s13n": "^2.0.0",
|
||||||
|
|
|
@ -2,12 +2,9 @@ import './index.scss';
|
||||||
|
|
||||||
import {join} from 'path';
|
import {join} from 'path';
|
||||||
|
|
||||||
|
import {ProjectContext} from '@avocado/persea';
|
||||||
import {PropTypes, React} from '@latus/react';
|
import {PropTypes, React} from '@latus/react';
|
||||||
import {ProjectContext} from '@persea/core';
|
import {Link, Route} from 'react-router-dom';
|
||||||
import {
|
|
||||||
Link,
|
|
||||||
Route,
|
|
||||||
} from 'react-router-dom';
|
|
||||||
import Tree from 'react-ui-tree';
|
import Tree from 'react-ui-tree';
|
||||||
|
|
||||||
import ResourceRoute from '../resource/route';
|
import ResourceRoute from '../resource/route';
|
||||||
|
@ -51,8 +48,6 @@ const Project = ({structure: {label, resourcePaths}, uuid}) => (
|
||||||
<Tree
|
<Tree
|
||||||
paddingLeft={20}
|
paddingLeft={20}
|
||||||
tree={treeFromResourcePaths(label, uuid, resourcePaths)}
|
tree={treeFromResourcePaths(label, uuid, resourcePaths)}
|
||||||
// onChange={this.handleChange}
|
|
||||||
// isNodeCollapsed={this.isNodeCollapsed}
|
|
||||||
renderNode={renderNode}
|
renderNode={renderNode}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
|
import {UriContext} from '@avocado/persea';
|
||||||
|
import {Resource} from '@avocado/resource/persea';
|
||||||
import {PropTypes, React} from '@latus/react';
|
import {PropTypes, React} from '@latus/react';
|
||||||
|
import {useSelector} from '@latus/redux';
|
||||||
|
import {resourceSelector} from '@persea/core';
|
||||||
|
|
||||||
import Resource from '../index';
|
const ResourceRoute = ({match: {params: {uri, uuid}}}) => {
|
||||||
|
const resource = useSelector((state) => resourceSelector(state, `${uuid}${uri}`));
|
||||||
const ResourceRoute = ({match: {params: {uri, uuid}}}) => (
|
return (
|
||||||
<Resource uri={uri} uuid={uuid} />
|
<UriContext.Provider value={uri}>
|
||||||
);
|
<Resource resource={resource} />
|
||||||
|
</UriContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
ResourceRoute.displayName = 'ResourceRoute';
|
ResourceRoute.displayName = 'ResourceRoute';
|
||||||
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import {React} from '@latus/react';
|
|
||||||
import {connectRouter, routerMiddleware} from 'connected-react-router';
|
|
||||||
import {createBrowserHistory} from 'history';
|
|
||||||
|
|
||||||
import Persea from 'components/persea';
|
|
||||||
|
|
||||||
const history = createBrowserHistory();
|
|
||||||
|
|
||||||
const Index = () => (
|
|
||||||
<Persea history={history} />
|
|
||||||
);
|
|
||||||
|
|
||||||
export default {
|
|
||||||
hooks: {
|
|
||||||
'@latus/react/components': () => Index,
|
|
||||||
'@latus/redux/slices': () => ({
|
|
||||||
router: connectRouter(history),
|
|
||||||
}),
|
|
||||||
'@latus/redux/store': (options) => {
|
|
||||||
options.middleware.push(routerMiddleware(history));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -89,6 +89,13 @@
|
||||||
d3-quadtree "^2.0.0"
|
d3-quadtree "^2.0.0"
|
||||||
debug "4.3.1"
|
debug "4.3.1"
|
||||||
|
|
||||||
|
"@avocado/persea@^1.0.0":
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "http://npm.cha0sdev/@avocado%2fpersea/-/persea-1.0.0.tgz#922d6c8fdfeae00cbd8130652f00b08a8d3285f9"
|
||||||
|
integrity sha512-NgWoASjjyFHjbwyg0MDoGa79BgqRSkpeO9CVtud777KPwgKzH2Q5xt6QyY0diIWWUhdokChWyljV76iY/o609A==
|
||||||
|
dependencies:
|
||||||
|
"@latus/react" "^2.0.0"
|
||||||
|
|
||||||
"@avocado/physics@^1.0.0":
|
"@avocado/physics@^1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "http://npm.cha0sdev/@avocado%2fphysics/-/physics-1.0.0.tgz#f1611f510da2aa3906ff298ec0335b0f650ad5a5"
|
resolved "http://npm.cha0sdev/@avocado%2fphysics/-/physics-1.0.0.tgz#f1611f510da2aa3906ff298ec0335b0f650ad5a5"
|
||||||
|
@ -235,6 +242,13 @@
|
||||||
eslint-visitor-keys "^1.3.0"
|
eslint-visitor-keys "^1.3.0"
|
||||||
semver "^6.3.0"
|
semver "^6.3.0"
|
||||||
|
|
||||||
|
"@babel/eslint-plugin@^7.13.10":
|
||||||
|
version "7.13.10"
|
||||||
|
resolved "http://npm.cha0sdev/@babel%2feslint-plugin/-/eslint-plugin-7.13.10.tgz#6720c32d52a4fef817796c7bb55a87b80320bbe7"
|
||||||
|
integrity sha512-xsNxo099fKnJ2rArkuuMOTPxxTLZSXwbFXdH4GjqQRKTOr6S1odQlE+R3Leid56VFQ3KVAR295vVNG9fqNQVvQ==
|
||||||
|
dependencies:
|
||||||
|
eslint-rule-composer "^0.3.0"
|
||||||
|
|
||||||
"@babel/generator@^7.13.0", "@babel/generator@^7.13.9":
|
"@babel/generator@^7.13.0", "@babel/generator@^7.13.9":
|
||||||
version "7.13.9"
|
version "7.13.9"
|
||||||
resolved "http://npm.cha0sdev/@babel%2fgenerator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
|
resolved "http://npm.cha0sdev/@babel%2fgenerator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
|
||||||
|
@ -451,7 +465,7 @@
|
||||||
chalk "^2.0.0"
|
chalk "^2.0.0"
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
|
|
||||||
"@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.7.0":
|
"@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.13.12", "@babel/parser@^7.7.0":
|
||||||
version "7.13.12"
|
version "7.13.12"
|
||||||
resolved "http://npm.cha0sdev/@babel%2fparser/-/parser-7.13.12.tgz#ba320059420774394d3b0c0233ba40e4250b81d1"
|
resolved "http://npm.cha0sdev/@babel%2fparser/-/parser-7.13.12.tgz#ba320059420774394d3b0c0233ba40e4250b81d1"
|
||||||
integrity sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw==
|
integrity sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw==
|
||||||
|
@ -1201,15 +1215,18 @@
|
||||||
|
|
||||||
"@latus/build@1.x":
|
"@latus/build@1.x":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "http://npm.cha0sdev/@latus%2fbuild/-/build-1.0.0.tgz#69cdd493e23c90adeb04238d2d52fbfb9cb84c0c"
|
resolved "http://npm.cha0sdev/@latus%2fbuild/-/build-1.0.0.tgz#2e374dac9323f44944896f651f4512ae8860a2d0"
|
||||||
integrity sha512-CTRQj9ghX1l64ffR3SnYSeVHNWUuAWjni8ykuXeuC6hNd6tuY9vpQKyZbBaJGvH7o+rwsdYb65ncKTGrXLByMQ==
|
integrity sha512-o+/smEvv2b8CQIKMgQlrxceMJb1AfVq4RyNlnIbNJZIlY+ifuyXb0ERvfHYo0pZ+El/n9KV5MM5K62/FpluPXA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/eslint-parser" "^7.13.10"
|
"@babel/eslint-parser" "^7.13.10"
|
||||||
|
"@babel/eslint-plugin" "^7.13.10"
|
||||||
|
"@babel/parser" "^7.13.12"
|
||||||
"@babel/plugin-proposal-class-properties" "^7.12.13"
|
"@babel/plugin-proposal-class-properties" "^7.12.13"
|
||||||
"@babel/plugin-proposal-optional-chaining" "^7.12.16"
|
"@babel/plugin-proposal-optional-chaining" "^7.12.16"
|
||||||
"@babel/plugin-proposal-private-methods" "^7.12.13"
|
"@babel/plugin-proposal-private-methods" "^7.12.13"
|
||||||
"@babel/plugin-syntax-jsx" "^7.12.13"
|
"@babel/plugin-syntax-jsx" "^7.12.13"
|
||||||
"@babel/preset-react" "^7.12.13"
|
"@babel/preset-react" "^7.12.13"
|
||||||
|
"@babel/types" "^7.13.12"
|
||||||
"@neutrinojs/airbnb" "^9.4.0"
|
"@neutrinojs/airbnb" "^9.4.0"
|
||||||
"@neutrinojs/banner" "^9.4.0"
|
"@neutrinojs/banner" "^9.4.0"
|
||||||
"@neutrinojs/copy" "^9.4.0"
|
"@neutrinojs/copy" "^9.4.0"
|
||||||
|
@ -1227,17 +1244,21 @@
|
||||||
|
|
||||||
"@latus/core@2.0.0", "@latus/core@^2.0.0":
|
"@latus/core@2.0.0", "@latus/core@^2.0.0":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "http://npm.cha0sdev/@latus%2fcore/-/core-2.0.0.tgz#12a0f3c11c9832a60e6726ea74ce0ae9b45e9faf"
|
resolved "http://npm.cha0sdev/@latus%2fcore/-/core-2.0.0.tgz#55bf7e61e287a6fe65289d36cdff20ca217e7eb0"
|
||||||
integrity sha512-JMxgl8Qsvby2OKtzXEs7cjamvsgVxEbJXbjebsmDl+J9Cq5513/4Xpq37EYYvT6FEZpoHFoIkQsaG+89JQzTwg==
|
integrity sha512-pXM3C0drjfCGfvOycl7KLxh/hTa1ShEdGjJrrTnAtoMZo8Q4yjkT4+TrEiytrZzj59uUVj5IWXaip1olWodY2Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
autoprefixer "^9.8.6"
|
"@neutrinojs/banner" "^9.5.0"
|
||||||
|
"@neutrinojs/node" "^9.1.0"
|
||||||
debug "4.3.1"
|
debug "4.3.1"
|
||||||
|
deepmerge "^4.2.2"
|
||||||
js-yaml "3.14.0"
|
js-yaml "3.14.0"
|
||||||
lodash.flatten "^4.4.0"
|
lodash.flatten "^4.4.0"
|
||||||
lodash.get "^4.4.2"
|
lodash.get "^4.4.2"
|
||||||
lodash.set "^4.3.2"
|
lodash.set "^4.3.2"
|
||||||
|
lodash.without "^4.4.0"
|
||||||
mkdirp "^1.0.4"
|
mkdirp "^1.0.4"
|
||||||
webpack-virtual-modules "^0.4.1"
|
raw-loader "^4.0.2"
|
||||||
|
webpack-node-externals "2.5.2"
|
||||||
|
|
||||||
"@latus/db@^2.0.0":
|
"@latus/db@^2.0.0":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
|
@ -1385,7 +1406,7 @@
|
||||||
eslint-plugin-react "^7.21.5"
|
eslint-plugin-react "^7.21.5"
|
||||||
eslint-plugin-react-hooks "^4.2.0"
|
eslint-plugin-react-hooks "^4.2.0"
|
||||||
|
|
||||||
"@neutrinojs/banner@^9.4.0":
|
"@neutrinojs/banner@9.5.0", "@neutrinojs/banner@^9.4.0", "@neutrinojs/banner@^9.5.0":
|
||||||
version "9.5.0"
|
version "9.5.0"
|
||||||
resolved "http://npm.cha0sdev/@neutrinojs%2fbanner/-/banner-9.5.0.tgz#ee8df39db5d76033211a1811428e444a06d7222f"
|
resolved "http://npm.cha0sdev/@neutrinojs%2fbanner/-/banner-9.5.0.tgz#ee8df39db5d76033211a1811428e444a06d7222f"
|
||||||
integrity sha512-SL4nT0V1Wykf+LcRlCp/L8Frt4dk7MZITToC+OeDz2w6V7gg8YfEwDfdEg+aampjyUoxaq+A02ZyZP1TyRDtLA==
|
integrity sha512-SL4nT0V1Wykf+LcRlCp/L8Frt4dk7MZITToC+OeDz2w6V7gg8YfEwDfdEg+aampjyUoxaq+A02ZyZP1TyRDtLA==
|
||||||
|
@ -1467,6 +1488,23 @@
|
||||||
deepmerge "^1.5.2"
|
deepmerge "^1.5.2"
|
||||||
lodash.omit "^4.5.0"
|
lodash.omit "^4.5.0"
|
||||||
|
|
||||||
|
"@neutrinojs/node@^9.1.0":
|
||||||
|
version "9.5.0"
|
||||||
|
resolved "http://npm.cha0sdev/@neutrinojs%2fnode/-/node-9.5.0.tgz#41da54a6af461ca329b194063640a2aa0e84f32e"
|
||||||
|
integrity sha512-kJjdEKCdBnKWD51Qnm6REAUdaLrJc3qjA3wFcJ11v1wddu7Ihaa2S4qNjcrCDYrxSPD1vVoUlE+nyucsX+dO4w==
|
||||||
|
dependencies:
|
||||||
|
"@babel/core" "^7.12.10"
|
||||||
|
"@babel/plugin-syntax-dynamic-import" "^7.8.3"
|
||||||
|
"@babel/preset-env" "^7.12.11"
|
||||||
|
"@neutrinojs/banner" "9.5.0"
|
||||||
|
"@neutrinojs/clean" "9.5.0"
|
||||||
|
"@neutrinojs/compile-loader" "9.5.0"
|
||||||
|
"@neutrinojs/start-server" "9.5.0"
|
||||||
|
babel-merge "^3.0.0"
|
||||||
|
deepmerge "^1.5.2"
|
||||||
|
lodash.omit "^4.5.0"
|
||||||
|
webpack-node-externals "^1.7.2"
|
||||||
|
|
||||||
"@neutrinojs/react@^9.4.0":
|
"@neutrinojs/react@^9.4.0":
|
||||||
version "9.5.0"
|
version "9.5.0"
|
||||||
resolved "http://npm.cha0sdev/@neutrinojs%2freact/-/react-9.5.0.tgz#3ea0c94aaef7045c74fc53b581d7e989a83e67dd"
|
resolved "http://npm.cha0sdev/@neutrinojs%2freact/-/react-9.5.0.tgz#3ea0c94aaef7045c74fc53b581d7e989a83e67dd"
|
||||||
|
@ -1481,6 +1519,13 @@
|
||||||
eslint-plugin-react "^7.21.5"
|
eslint-plugin-react "^7.21.5"
|
||||||
eslint-plugin-react-hooks "^4.2.0"
|
eslint-plugin-react-hooks "^4.2.0"
|
||||||
|
|
||||||
|
"@neutrinojs/start-server@9.5.0":
|
||||||
|
version "9.5.0"
|
||||||
|
resolved "http://npm.cha0sdev/@neutrinojs%2fstart-server/-/start-server-9.5.0.tgz#f0d21a7f2c9c57897769e56ee042bd1d242275a4"
|
||||||
|
integrity sha512-gNRISZAbJpAZRIUfIxCWFEzEhfM/4ibmbGzz9jFJloH+fQw6JpOWF6bhhBZNDFFTj/6GKFi40CJrte4V3ywNBA==
|
||||||
|
dependencies:
|
||||||
|
start-server-webpack-plugin "^2.2.5"
|
||||||
|
|
||||||
"@neutrinojs/style-loader@9.5.0":
|
"@neutrinojs/style-loader@9.5.0":
|
||||||
version "9.5.0"
|
version "9.5.0"
|
||||||
resolved "http://npm.cha0sdev/@neutrinojs%2fstyle-loader/-/style-loader-9.5.0.tgz#5f1f151d76f5f1168e557612d5e3407ffb99049e"
|
resolved "http://npm.cha0sdev/@neutrinojs%2fstyle-loader/-/style-loader-9.5.0.tgz#5f1f151d76f5f1168e557612d5e3407ffb99049e"
|
||||||
|
@ -7934,6 +7979,14 @@ raw-body@2.4.0:
|
||||||
iconv-lite "0.4.24"
|
iconv-lite "0.4.24"
|
||||||
unpipe "1.0.0"
|
unpipe "1.0.0"
|
||||||
|
|
||||||
|
raw-loader@^4.0.2:
|
||||||
|
version "4.0.2"
|
||||||
|
resolved "http://npm.cha0sdev/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6"
|
||||||
|
integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==
|
||||||
|
dependencies:
|
||||||
|
loader-utils "^2.0.0"
|
||||||
|
schema-utils "^3.0.0"
|
||||||
|
|
||||||
rc@^1.2.7:
|
rc@^1.2.7:
|
||||||
version "1.2.8"
|
version "1.2.8"
|
||||||
resolved "http://npm.cha0sdev/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
|
resolved "http://npm.cha0sdev/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
|
||||||
|
@ -9104,6 +9157,11 @@ ssri@^6.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
figgy-pudding "^3.5.1"
|
figgy-pudding "^3.5.1"
|
||||||
|
|
||||||
|
start-server-webpack-plugin@^2.2.5:
|
||||||
|
version "2.2.5"
|
||||||
|
resolved "http://npm.cha0sdev/start-server-webpack-plugin/-/start-server-webpack-plugin-2.2.5.tgz#4a2838759b0f36acd11b0b2f5f196f289ae29d31"
|
||||||
|
integrity sha512-DRCkciwCJoCFZ+wt3wWMkR1M2mpVhJbUKFXqhK3FWyIUKYb42NnocH5sMwqgo+nPNHupqNwK/v8lgfBbr2NKdg==
|
||||||
|
|
||||||
static-extend@^0.1.1:
|
static-extend@^0.1.1:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "http://npm.cha0sdev/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
|
resolved "http://npm.cha0sdev/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
|
||||||
|
@ -9999,6 +10057,11 @@ webpack-node-externals@2.5.2:
|
||||||
resolved "http://npm.cha0sdev/webpack-node-externals/-/webpack-node-externals-2.5.2.tgz#178e017a24fec6015bc9e672c77958a6afac861d"
|
resolved "http://npm.cha0sdev/webpack-node-externals/-/webpack-node-externals-2.5.2.tgz#178e017a24fec6015bc9e672c77958a6afac861d"
|
||||||
integrity sha512-aHdl/y2N7PW2Sx7K+r3AxpJO+aDMcYzMQd60Qxefq3+EwhewSbTBqNumOsCE1JsCUNoyfGj5465N0sSf6hc/5w==
|
integrity sha512-aHdl/y2N7PW2Sx7K+r3AxpJO+aDMcYzMQd60Qxefq3+EwhewSbTBqNumOsCE1JsCUNoyfGj5465N0sSf6hc/5w==
|
||||||
|
|
||||||
|
webpack-node-externals@^1.7.2:
|
||||||
|
version "1.7.2"
|
||||||
|
resolved "http://npm.cha0sdev/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz#6e1ee79ac67c070402ba700ef033a9b8d52ac4e3"
|
||||||
|
integrity sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg==
|
||||||
|
|
||||||
webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1:
|
webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1:
|
||||||
version "1.4.3"
|
version "1.4.3"
|
||||||
resolved "http://npm.cha0sdev/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
|
resolved "http://npm.cha0sdev/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
"test": "latus-build test"
|
"test": "latus-build test"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"client.js",
|
|
||||||
"client.js.map",
|
|
||||||
"index.js",
|
"index.js",
|
||||||
"index.js.map",
|
"index.js.map",
|
||||||
"server.js",
|
"server.js",
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
export default {
|
|
||||||
hooks: {
|
|
||||||
'@latus/core/starting': (latus) => {
|
|
||||||
window.latus = latus;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -45,6 +45,13 @@
|
||||||
eslint-visitor-keys "^1.3.0"
|
eslint-visitor-keys "^1.3.0"
|
||||||
semver "^6.3.0"
|
semver "^6.3.0"
|
||||||
|
|
||||||
|
"@babel/eslint-plugin@^7.13.10":
|
||||||
|
version "7.13.10"
|
||||||
|
resolved "http://npm.cha0sdev/@babel%2feslint-plugin/-/eslint-plugin-7.13.10.tgz#6720c32d52a4fef817796c7bb55a87b80320bbe7"
|
||||||
|
integrity sha512-xsNxo099fKnJ2rArkuuMOTPxxTLZSXwbFXdH4GjqQRKTOr6S1odQlE+R3Leid56VFQ3KVAR295vVNG9fqNQVvQ==
|
||||||
|
dependencies:
|
||||||
|
eslint-rule-composer "^0.3.0"
|
||||||
|
|
||||||
"@babel/generator@^7.13.0", "@babel/generator@^7.13.9":
|
"@babel/generator@^7.13.0", "@babel/generator@^7.13.9":
|
||||||
version "7.13.9"
|
version "7.13.9"
|
||||||
resolved "http://npm.cha0sdev/@babel%2fgenerator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
|
resolved "http://npm.cha0sdev/@babel%2fgenerator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
|
||||||
|
@ -197,7 +204,7 @@
|
||||||
chalk "^2.0.0"
|
chalk "^2.0.0"
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
|
|
||||||
"@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.7.0":
|
"@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.13.12", "@babel/parser@^7.7.0":
|
||||||
version "7.13.12"
|
version "7.13.12"
|
||||||
resolved "http://npm.cha0sdev/@babel%2fparser/-/parser-7.13.12.tgz#ba320059420774394d3b0c0233ba40e4250b81d1"
|
resolved "http://npm.cha0sdev/@babel%2fparser/-/parser-7.13.12.tgz#ba320059420774394d3b0c0233ba40e4250b81d1"
|
||||||
integrity sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw==
|
integrity sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw==
|
||||||
|
@ -356,15 +363,18 @@
|
||||||
|
|
||||||
"@latus/build@1.x":
|
"@latus/build@1.x":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "http://npm.cha0sdev/@latus%2fbuild/-/build-1.0.0.tgz#69cdd493e23c90adeb04238d2d52fbfb9cb84c0c"
|
resolved "http://npm.cha0sdev/@latus%2fbuild/-/build-1.0.0.tgz#2e374dac9323f44944896f651f4512ae8860a2d0"
|
||||||
integrity sha512-CTRQj9ghX1l64ffR3SnYSeVHNWUuAWjni8ykuXeuC6hNd6tuY9vpQKyZbBaJGvH7o+rwsdYb65ncKTGrXLByMQ==
|
integrity sha512-o+/smEvv2b8CQIKMgQlrxceMJb1AfVq4RyNlnIbNJZIlY+ifuyXb0ERvfHYo0pZ+El/n9KV5MM5K62/FpluPXA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/eslint-parser" "^7.13.10"
|
"@babel/eslint-parser" "^7.13.10"
|
||||||
|
"@babel/eslint-plugin" "^7.13.10"
|
||||||
|
"@babel/parser" "^7.13.12"
|
||||||
"@babel/plugin-proposal-class-properties" "^7.12.13"
|
"@babel/plugin-proposal-class-properties" "^7.12.13"
|
||||||
"@babel/plugin-proposal-optional-chaining" "^7.12.16"
|
"@babel/plugin-proposal-optional-chaining" "^7.12.16"
|
||||||
"@babel/plugin-proposal-private-methods" "^7.12.13"
|
"@babel/plugin-proposal-private-methods" "^7.12.13"
|
||||||
"@babel/plugin-syntax-jsx" "^7.12.13"
|
"@babel/plugin-syntax-jsx" "^7.12.13"
|
||||||
"@babel/preset-react" "^7.12.13"
|
"@babel/preset-react" "^7.12.13"
|
||||||
|
"@babel/types" "^7.13.12"
|
||||||
"@neutrinojs/airbnb" "^9.4.0"
|
"@neutrinojs/airbnb" "^9.4.0"
|
||||||
"@neutrinojs/banner" "^9.4.0"
|
"@neutrinojs/banner" "^9.4.0"
|
||||||
"@neutrinojs/copy" "^9.4.0"
|
"@neutrinojs/copy" "^9.4.0"
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
"test": "latus-build test"
|
"test": "latus-build test"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"client.js",
|
|
||||||
"client.js.map",
|
|
||||||
"index.js",
|
"index.js",
|
||||||
"index.js.map",
|
"index.js.map",
|
||||||
"server.js",
|
"server.js",
|
||||||
|
@ -23,12 +21,14 @@
|
||||||
"@avocado/graphics": "^2.0.0",
|
"@avocado/graphics": "^2.0.0",
|
||||||
"@avocado/math": "^2.0.0",
|
"@avocado/math": "^2.0.0",
|
||||||
"@avocado/react": "^1.0.0",
|
"@avocado/react": "^1.0.0",
|
||||||
|
"@avocado/resource": "^2.0.0",
|
||||||
"@latus/core": "^2.0.0",
|
"@latus/core": "^2.0.0",
|
||||||
"@latus/db": "^2.0.0",
|
"@latus/db": "^2.0.0",
|
||||||
"@latus/react": "^2.0.0",
|
"@latus/react": "^2.0.0",
|
||||||
"@latus/redux": "^2.0.0",
|
"@latus/redux": "^2.0.0",
|
||||||
"deepmerge": "^4.2.2",
|
"deepmerge": "^4.2.2",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
|
"fast-json-patch": "^3.0.0-1",
|
||||||
"glob": "^7.1.6",
|
"glob": "^7.1.6",
|
||||||
"lodash.flatten": "^4.4.0",
|
"lodash.flatten": "^4.4.0",
|
||||||
"natsort": "^2.0.2",
|
"natsort": "^2.0.2",
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
import {PropTypes, React} from '@latus/react';
|
|
||||||
import merge from 'deepmerge';
|
|
||||||
import ReactModal from 'react-modal';
|
|
||||||
|
|
||||||
const Modal = ({
|
|
||||||
children,
|
|
||||||
isOpen,
|
|
||||||
onRequestClose,
|
|
||||||
style,
|
|
||||||
}) => (
|
|
||||||
<ReactModal
|
|
||||||
ariaHideApp={false}
|
|
||||||
style={merge(
|
|
||||||
{
|
|
||||||
overlay: {
|
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
background: 'rgb(64, 64, 64)',
|
|
||||||
border: 'rgba(255, 255, 255, 0.2)',
|
|
||||||
padding: '1em',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
style,
|
|
||||||
)}
|
|
||||||
isOpen={isOpen}
|
|
||||||
onRequestClose={onRequestClose}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</ReactModal>
|
|
||||||
);
|
|
||||||
|
|
||||||
Modal.defaultProps = {
|
|
||||||
style: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
Modal.displayName = 'Modal';
|
|
||||||
|
|
||||||
Modal.propTypes = {
|
|
||||||
children: PropTypes.node.isRequired,
|
|
||||||
isOpen: PropTypes.bool.isRequired,
|
|
||||||
onRequestClose: PropTypes.func.isRequired,
|
|
||||||
style: PropTypes.shape({}),
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Modal;
|
|
|
@ -1,109 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useEffect,
|
|
||||||
useRef,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
const Number = ({
|
|
||||||
integer,
|
|
||||||
max,
|
|
||||||
min,
|
|
||||||
onChange,
|
|
||||||
step,
|
|
||||||
value,
|
|
||||||
}) => {
|
|
||||||
const inputRef = useRef(null);
|
|
||||||
const parser = integer ? (v) => parseInt(v, 10) : parseFloat;
|
|
||||||
const changeClamped = (event, change) => {
|
|
||||||
const clamped = Math.min(max, Math.max(min, change));
|
|
||||||
if (value !== clamped) {
|
|
||||||
onChange(event, clamped);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const increment = (event, factor) => {
|
|
||||||
const value = parser(inputRef.current.value);
|
|
||||||
const incrementBy = event.shiftKey ? (step / 10) : step;
|
|
||||||
changeClamped(event, parser(parser(value + (factor * incrementBy)).toPrecision(12)));
|
|
||||||
};
|
|
||||||
const onWheel = (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
if (event.deltaY > 0) {
|
|
||||||
increment(event, -1);
|
|
||||||
}
|
|
||||||
else if (event.deltaY < 0) {
|
|
||||||
increment(event, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Workaround for https://github.com/facebook/react/issues/8968
|
|
||||||
useEffect(() => {
|
|
||||||
if (!inputRef.current) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const input = inputRef.current;
|
|
||||||
input.addEventListener('wheel', onWheel);
|
|
||||||
return () => {
|
|
||||||
input.removeEventListener('wheel', onWheel);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
step = parser(step);
|
|
||||||
return (
|
|
||||||
<div className="number">
|
|
||||||
<>
|
|
||||||
<input
|
|
||||||
className="number__input"
|
|
||||||
onChange={(event) => {
|
|
||||||
changeClamped(event, parser(event.target.value));
|
|
||||||
}}
|
|
||||||
// onWheel={onWheel}
|
|
||||||
ref={inputRef}
|
|
||||||
step={step}
|
|
||||||
type="number"
|
|
||||||
value={'undefined' === typeof value ? '' : value}
|
|
||||||
/>
|
|
||||||
<div className="number__controls">
|
|
||||||
<button
|
|
||||||
onClick={(event) => {
|
|
||||||
increment(event, 1);
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<span className="number__button-label">+</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={(event) => {
|
|
||||||
increment(event, -1);
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<span className="number__button-label">-</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Number.defaultProps = {
|
|
||||||
integer: false,
|
|
||||||
max: Infinity,
|
|
||||||
min: -Infinity,
|
|
||||||
onChange: null,
|
|
||||||
step: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
Number.displayName = 'Number';
|
|
||||||
|
|
||||||
Number.propTypes = {
|
|
||||||
integer: PropTypes.bool,
|
|
||||||
max: PropTypes.number,
|
|
||||||
min: PropTypes.number,
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
step: PropTypes.number,
|
|
||||||
value: PropTypes.number.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Number;
|
|
|
@ -1,37 +0,0 @@
|
||||||
.number {
|
|
||||||
display: flex;
|
|
||||||
max-height: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.number__input {
|
|
||||||
&::-webkit-outer-spin-button,
|
|
||||||
&::-webkit-inner-spin-button {
|
|
||||||
appearance: none;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
&[type=number] {
|
|
||||||
appearance: textfield;
|
|
||||||
}
|
|
||||||
max-width: 5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.number__controls {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
button {
|
|
||||||
border-left: none;
|
|
||||||
font-size: 0.5em;
|
|
||||||
flex-grow: 1;
|
|
||||||
height: 1em;
|
|
||||||
margin: 0;
|
|
||||||
&:first-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.number__button-label {
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 2em;
|
|
||||||
line-height: 0.5em;
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
import NumberComponent from '../number';
|
|
||||||
|
|
||||||
const Range = ({
|
|
||||||
integer,
|
|
||||||
onChange,
|
|
||||||
range,
|
|
||||||
}) => {
|
|
||||||
const [isSingle, setIsSingle] = useState('undefined' === typeof range.min);
|
|
||||||
return (
|
|
||||||
<div className="range">
|
|
||||||
<NumberComponent
|
|
||||||
integer={integer}
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
isSingle
|
|
||||||
? value
|
|
||||||
: {
|
|
||||||
min: value,
|
|
||||||
max: range.max,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={isSingle ? range : range.min}
|
|
||||||
/>
|
|
||||||
<label className="range__to-label">
|
|
||||||
∆
|
|
||||||
{isSingle && '?'}
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={!isSingle}
|
|
||||||
onChange={(event) => {
|
|
||||||
setIsSingle(!event.target.checked);
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
!event.target.checked
|
|
||||||
? range.min
|
|
||||||
: {
|
|
||||||
min: range,
|
|
||||||
max: range,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
{!isSingle && (
|
|
||||||
<NumberComponent
|
|
||||||
integer={integer}
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
{
|
|
||||||
min: range.min,
|
|
||||||
max: value,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={range.max}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const createRangePropType = (isRequired) => (props, propName, componentName) => {
|
|
||||||
const fail = (why) => new Error(
|
|
||||||
`Invalid prop ${propName} suppied to ${componentName}. ${why}.`,
|
|
||||||
);
|
|
||||||
const range = props[propName];
|
|
||||||
if (!range && isRequired) {
|
|
||||||
return fail('Is required but missing');
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
(
|
|
||||||
'undefined' === typeof range.min
|
|
||||||
|| 'undefined' === typeof range.max
|
|
||||||
)
|
|
||||||
&& Number.isNaN(range)
|
|
||||||
) {
|
|
||||||
return fail('Expected {min, max} or a Number');
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
export const rangePropType = createRangePropType(false);
|
|
||||||
rangePropType.isRequired = createRangePropType(true);
|
|
||||||
|
|
||||||
Range.defaultProps = {
|
|
||||||
integer: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
Range.displayName = 'Range';
|
|
||||||
|
|
||||||
Range.propTypes = {
|
|
||||||
integer: PropTypes.bool,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
range: rangePropType.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Range;
|
|
|
@ -1,15 +0,0 @@
|
||||||
.range {
|
|
||||||
display: flex;
|
|
||||||
height: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.range__to-label {
|
|
||||||
align-self: center;
|
|
||||||
&:last-child {
|
|
||||||
margin-right: -0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.range input[type="number"] {
|
|
||||||
margin-left: 1em;
|
|
||||||
}
|
|
|
@ -1,125 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
import Number from '../number';
|
|
||||||
|
|
||||||
const Rectangle = ({
|
|
||||||
integer,
|
|
||||||
labels,
|
|
||||||
onChange,
|
|
||||||
value,
|
|
||||||
}) => (
|
|
||||||
<div className="rectangle">
|
|
||||||
<label>
|
|
||||||
<div className="rectangle__label-text">{labels[0]}</div>
|
|
||||||
<Number
|
|
||||||
integer={integer}
|
|
||||||
onChange={(event, number) => {
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
[
|
|
||||||
number,
|
|
||||||
value[1],
|
|
||||||
value[2],
|
|
||||||
value[3],
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={value[0] || 0}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<div className="rectangle__label-text">{labels[1]}</div>
|
|
||||||
<Number
|
|
||||||
integer={integer}
|
|
||||||
onChange={(event, number) => {
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
[
|
|
||||||
value[0],
|
|
||||||
number,
|
|
||||||
value[2],
|
|
||||||
value[3],
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={value[1] || 0}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<div className="rectangle__label-text">{labels[2]}</div>
|
|
||||||
<Number
|
|
||||||
integer={integer}
|
|
||||||
onChange={(event, number) => {
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
[
|
|
||||||
value[0],
|
|
||||||
value[1],
|
|
||||||
number,
|
|
||||||
value[3],
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={value[2] || 0}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<div className="rectangle__label-text">{labels[3]}</div>
|
|
||||||
<Number
|
|
||||||
integer={integer}
|
|
||||||
onChange={(event, number) => {
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
[
|
|
||||||
value[0],
|
|
||||||
value[1],
|
|
||||||
value[2],
|
|
||||||
number,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={value[3] || 0}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const createRectanglePropType = (isRequired) => (props, propName, componentName) => {
|
|
||||||
const fail = (why) => new Error(
|
|
||||||
`Invalid prop ${propName} suppied to ${componentName}. ${why}.`,
|
|
||||||
);
|
|
||||||
const rectangle = props[propName];
|
|
||||||
if (!rectangle && isRequired) {
|
|
||||||
return fail('Is required but missing');
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
!Array.isArray(rectangle)
|
|
||||||
|| 4 !== rectangle.length
|
|
||||||
) {
|
|
||||||
return fail('Expected 4-length array rectangle');
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
export const rectanglePropType = createRectanglePropType(false);
|
|
||||||
rectanglePropType.isRequired = createRectanglePropType(true);
|
|
||||||
|
|
||||||
Rectangle.defaultProps = {
|
|
||||||
integer: false,
|
|
||||||
labels: ['X', 'Y', 'Width', 'Height'],
|
|
||||||
};
|
|
||||||
|
|
||||||
Rectangle.displayName = 'Rectangle';
|
|
||||||
|
|
||||||
Rectangle.propTypes = {
|
|
||||||
integer: PropTypes.bool,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
labels: PropTypes.arrayOf(PropTypes.string),
|
|
||||||
value: rectanglePropType.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Rectangle;
|
|
|
@ -1,8 +0,0 @@
|
||||||
.rectangle {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rectangle__label-text {
|
|
||||||
font-size: 0.7em;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
|
@ -1,110 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
import Vector from '../vector';
|
|
||||||
|
|
||||||
const VectorRange = ({
|
|
||||||
integer,
|
|
||||||
onChange,
|
|
||||||
range,
|
|
||||||
}) => {
|
|
||||||
const [isSingle, setIsSingle] = useState(Array.isArray(range));
|
|
||||||
return (
|
|
||||||
<div className="vector-range">
|
|
||||||
<Vector
|
|
||||||
integer={integer}
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
isSingle
|
|
||||||
? value
|
|
||||||
: {
|
|
||||||
min: value,
|
|
||||||
max: range.max,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={isSingle ? range : range.min}
|
|
||||||
/>
|
|
||||||
<label className="vector-range__to-label">
|
|
||||||
∆
|
|
||||||
{isSingle && '?'}
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={!isSingle}
|
|
||||||
onChange={(event) => {
|
|
||||||
setIsSingle(!event.target.checked);
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
!event.target.checked
|
|
||||||
? range.min
|
|
||||||
: {
|
|
||||||
min: range,
|
|
||||||
max: range,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
{!isSingle && (
|
|
||||||
<Vector
|
|
||||||
integer={integer}
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
{
|
|
||||||
min: range.min,
|
|
||||||
max: value,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={range.max}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const createVectorRangePropType = (isRequired) => (props, propName, componentName) => {
|
|
||||||
const fail = (why) => new Error(
|
|
||||||
`Invalid prop ${propName} suppied to ${componentName}. ${why}.`,
|
|
||||||
);
|
|
||||||
const range = props[propName];
|
|
||||||
if (!range && isRequired) {
|
|
||||||
return fail('Is required but missing');
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
(
|
|
||||||
'undefined' === typeof range.min
|
|
||||||
|| 'undefined' === typeof range.max
|
|
||||||
)
|
|
||||||
&& (
|
|
||||||
!Array.isArray(range)
|
|
||||||
|| 2 !== range.length
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return fail('Expected {min, max} or a Vector');
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
export const vectorRangePropType = createVectorRangePropType(false);
|
|
||||||
vectorRangePropType.isRequired = createVectorRangePropType(true);
|
|
||||||
|
|
||||||
VectorRange.defaultProps = {
|
|
||||||
integer: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
VectorRange.displayName = 'VectorRange';
|
|
||||||
|
|
||||||
VectorRange.propTypes = {
|
|
||||||
integer: PropTypes.bool,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
range: vectorRangePropType.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default VectorRange;
|
|
|
@ -1,11 +0,0 @@
|
||||||
.vector-range {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vector-range__to-label {
|
|
||||||
align-self: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vector-range input[type="number"] {
|
|
||||||
margin-left: 1em;
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
import Number from '../number';
|
|
||||||
|
|
||||||
const Vector = ({
|
|
||||||
integer,
|
|
||||||
labels,
|
|
||||||
onChange,
|
|
||||||
value,
|
|
||||||
}) => (
|
|
||||||
<div className="vector">
|
|
||||||
<label>
|
|
||||||
<div className="vector__label-text">{labels[0]}</div>
|
|
||||||
<Number
|
|
||||||
integer={integer}
|
|
||||||
onChange={(event, number) => {
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
[
|
|
||||||
number,
|
|
||||||
value[1],
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={value[0] || 0}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<div className="vector__label-text">{labels[1]}</div>
|
|
||||||
<Number
|
|
||||||
integer={integer}
|
|
||||||
onChange={(event, number) => {
|
|
||||||
onChange(
|
|
||||||
event,
|
|
||||||
[
|
|
||||||
value[0],
|
|
||||||
number,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={value[1] || 0}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const createVectorPropType = (isRequired) => (props, propName, componentName) => {
|
|
||||||
const fail = (why) => new Error(
|
|
||||||
`Invalid prop ${propName} suppied to ${componentName}. ${why}.`,
|
|
||||||
);
|
|
||||||
const vector = props[propName];
|
|
||||||
if (!vector && isRequired) {
|
|
||||||
return fail('Is required but missing');
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
!Array.isArray(vector)
|
|
||||||
|| 2 !== vector.length
|
|
||||||
) {
|
|
||||||
return fail('Expected 2-length array vector');
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
export const vectorPropType = createVectorPropType(false);
|
|
||||||
vectorPropType.isRequired = createVectorPropType(true);
|
|
||||||
|
|
||||||
Vector.defaultProps = {
|
|
||||||
integer: false,
|
|
||||||
labels: ['X', 'Y'],
|
|
||||||
};
|
|
||||||
|
|
||||||
Vector.displayName = 'Vector';
|
|
||||||
|
|
||||||
Vector.propTypes = {
|
|
||||||
integer: PropTypes.bool,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
labels: PropTypes.arrayOf(PropTypes.string),
|
|
||||||
value: vectorPropType.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Vector;
|
|
|
@ -1,8 +0,0 @@
|
||||||
.vector {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vector__label-text {
|
|
||||||
font-size: 0.7em;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
import {createContext} from '@latus/react';
|
|
||||||
|
|
||||||
export default createContext(undefined);
|
|
|
@ -1,3 +0,0 @@
|
||||||
import {createContext} from '@latus/react';
|
|
||||||
|
|
||||||
export default createContext(undefined);
|
|
|
@ -1,5 +0,0 @@
|
||||||
import {useContext} from '@latus/react';
|
|
||||||
|
|
||||||
import ProjectContext from '../context/project';
|
|
||||||
|
|
||||||
export default () => useContext(ProjectContext);
|
|
|
@ -1,5 +0,0 @@
|
||||||
import {useContext} from '@latus/react';
|
|
||||||
|
|
||||||
import UriContext from '../context/uri';
|
|
||||||
|
|
||||||
export default () => useContext(UriContext);
|
|
|
@ -1,42 +1,18 @@
|
||||||
import flatten from 'lodash.flatten';
|
import {patchJsonResource} from '@avocado/resource/persea';
|
||||||
|
|
||||||
import BinaryResourceController from './resource-controllers/binary';
|
|
||||||
import ImageResourceController from './resource-controllers/image';
|
|
||||||
import TextResourceController from './resource-controllers/text';
|
|
||||||
import {projects, user} from './state';
|
import {projects, user} from './state';
|
||||||
|
|
||||||
export {default as Modal} from './components/modal';
|
|
||||||
export {default as Number} from './components/number';
|
|
||||||
export {default as Range, rangePropType} from './components/range';
|
|
||||||
export {default as Rectangle, rectanglePropType} from './components/rectangle';
|
|
||||||
export {default as Vector, vectorPropType} from './components/vector';
|
|
||||||
export {default as VectorRange, vectorRangePropType} from './components/vector-range';
|
|
||||||
export {default as ProjectContext} from './context/project';
|
|
||||||
export {default as UriContext} from './context/uri';
|
|
||||||
export {default as useProject} from './hooks/use-project';
|
|
||||||
export {default as useUri} from './hooks/use-uri';
|
|
||||||
export * from './state';
|
export * from './state';
|
||||||
|
|
||||||
export {
|
|
||||||
BinaryResourceController,
|
|
||||||
ImageResourceController,
|
|
||||||
TextResourceController,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
hooks: {
|
hooks: {
|
||||||
'@latus/core/config': () => ({
|
'@latus/redux/effects': (latus) => {
|
||||||
'resource-controllers': [],
|
const withSocket = (fn) => (...args) => fn(...args.concat(latus.get('%socket')));
|
||||||
}),
|
return {
|
||||||
'@latus/core/starting': async (latus) => {
|
[patchJsonResource]: withSocket((store, action, socket) => {
|
||||||
const Controllers = flatten(await latus.invokeOrdered('@persea/core/resource-controllers'));
|
socket.send(['Action', action]);
|
||||||
Controllers.push(
|
}),
|
||||||
ImageResourceController,
|
};
|
||||||
TextResourceController,
|
|
||||||
BinaryResourceController,
|
|
||||||
);
|
|
||||||
const Controller = (uri) => Controllers.find(({matcher}) => uri.match(matcher));
|
|
||||||
latus.set('%resource-controllers', Controller);
|
|
||||||
},
|
},
|
||||||
'@latus/redux/slices': () => ({
|
'@latus/redux/slices': () => ({
|
||||||
projects,
|
projects,
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
} from '@latus/react';
|
|
||||||
import HexEditor from 'react-hex-editor';
|
|
||||||
import oneDarkPro from 'react-hex-editor/themes/oneDarkPro';
|
|
||||||
|
|
||||||
const BinaryComponent = ({resource}) => {
|
|
||||||
// eslint-disable-next-line no-use-before-define
|
|
||||||
const buffer = BinaryController.decode(resource);
|
|
||||||
return (
|
|
||||||
<HexEditor
|
|
||||||
className="binary-renderer"
|
|
||||||
columns={0x10}
|
|
||||||
data={new Uint8Array(buffer.buffer)}
|
|
||||||
showAscii
|
|
||||||
showColumnLabels
|
|
||||||
showRowLabels
|
|
||||||
theme={{hexEditor: oneDarkPro}}
|
|
||||||
rows={Math.min(30, Math.ceil(buffer.length / 0x10))}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
BinaryComponent.displayName = 'BinaryComponent';
|
|
||||||
|
|
||||||
BinaryComponent.propTypes = {
|
|
||||||
resource: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class BinaryController {
|
|
||||||
|
|
||||||
static Component({resource}) {
|
|
||||||
return (
|
|
||||||
<BinaryComponent resource={resource} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static decode(encoded) {
|
|
||||||
return Buffer.from(encoded, 'base64');
|
|
||||||
}
|
|
||||||
|
|
||||||
static encode(buffer) {
|
|
||||||
return buffer.toString('base64');
|
|
||||||
}
|
|
||||||
|
|
||||||
static get matcher() {
|
|
||||||
return /.*/;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
import BinaryController from '../binary';
|
|
||||||
|
|
||||||
const ImageComponent = ({resource}) => {
|
|
||||||
// eslint-disable-next-line no-use-before-define
|
|
||||||
const buffer = ImageController.decode(resource);
|
|
||||||
return (
|
|
||||||
<div className="image-renderer">
|
|
||||||
<div
|
|
||||||
className="holder"
|
|
||||||
style={{backgroundImage: `url(data:;base64,${buffer.toString('base64')})`}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
ImageComponent.displayName = 'ImageComponent';
|
|
||||||
|
|
||||||
ImageComponent.propTypes = {
|
|
||||||
resource: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class ImageController extends BinaryController {
|
|
||||||
|
|
||||||
static Component({resource}) {
|
|
||||||
return (
|
|
||||||
<ImageComponent resource={resource} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static get matcher() {
|
|
||||||
return /\.(?:bmp|gif|jpe?g|png)$/;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
.image-renderer {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
.holder {
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: contain;
|
|
||||||
background-position: center;
|
|
||||||
height: 100%;
|
|
||||||
image-rendering: pixelated;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
const TextComponent = ({resource}) => (
|
|
||||||
<div className="text-renderer">{resource}</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
TextComponent.displayName = 'TextComponent';
|
|
||||||
|
|
||||||
TextComponent.propTypes = {
|
|
||||||
resource: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class TextController {
|
|
||||||
|
|
||||||
static Component({resource}) {
|
|
||||||
return (
|
|
||||||
<TextComponent resource={resource} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static decode(encoded) {
|
|
||||||
return Buffer.from(encoded, 'utf8');
|
|
||||||
}
|
|
||||||
|
|
||||||
static encode(buffer) {
|
|
||||||
return buffer.toString('utf8');
|
|
||||||
}
|
|
||||||
|
|
||||||
static get matcher() {
|
|
||||||
return /\.txt$/;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
.text-renderer {
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
|
@ -1,14 +1,57 @@
|
||||||
|
import fs from 'fs';
|
||||||
import {join} from 'path';
|
import {join} from 'path';
|
||||||
|
import {promisify} from 'util';
|
||||||
|
|
||||||
import {decorateWithLatus, gatherWithLatus} from '@latus/core';
|
import {decorateWithLatus, gatherWithLatus} from '@latus/core';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
|
import {applyPatch} from 'fast-json-patch';
|
||||||
|
|
||||||
import projectsState from './state/projects';
|
import projectsState from './state/projects';
|
||||||
|
|
||||||
|
const readFile = promisify(fs.readFile);
|
||||||
|
const writeFile = promisify(fs.writeFile);
|
||||||
|
|
||||||
const resources = express.static(join(process.cwd(), 'projects'));
|
const resources = express.static(join(process.cwd(), 'projects'));
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
hooks: {
|
hooks: {
|
||||||
|
'@latus/core/starting': (latus) => {
|
||||||
|
latus.set('%patches', []);
|
||||||
|
const flushPatches = async () => {
|
||||||
|
const patches = latus.get('%patches');
|
||||||
|
if (patches.length > 0) {
|
||||||
|
const patching = {};
|
||||||
|
while (patches.length > 0) {
|
||||||
|
const {patch, project, uri} = patches.shift();
|
||||||
|
const path = join(process.cwd(), 'projects', project, uri);
|
||||||
|
if (!patching[path]) {
|
||||||
|
const {toBuffer, fromBuffer} = latus.get('%resource-controllers')
|
||||||
|
.find(({matcher}) => uri.match(matcher));
|
||||||
|
patching[path] = new Promise((resolve) => {
|
||||||
|
readFile(path).then((buffer) => {
|
||||||
|
resolve({
|
||||||
|
toBuffer,
|
||||||
|
json: fromBuffer(buffer, latus),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const {json} = await patching[path];
|
||||||
|
applyPatch(json, patch);
|
||||||
|
}
|
||||||
|
const entries = Object.entries(patching);
|
||||||
|
for (let i = 0; i < entries.length; i++) {
|
||||||
|
const [path, promise] = entries[i];
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const {toBuffer, json} = await promise;
|
||||||
|
writeFile(path, toBuffer(json, latus));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(flushPatches, 0);
|
||||||
|
};
|
||||||
|
setTimeout(flushPatches, 0);
|
||||||
|
},
|
||||||
'@latus/db/server/models': gatherWithLatus(
|
'@latus/db/server/models': gatherWithLatus(
|
||||||
require.context('./models', false, /\.js$/),
|
require.context('./models', false, /\.js$/),
|
||||||
),
|
),
|
||||||
|
@ -38,5 +81,8 @@ export default {
|
||||||
: 0,
|
: 0,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
'@latus/socket/packets.decorate': decorateWithLatus(
|
||||||
|
require.context('./packets/decorators', false, /\.js$/),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {patchJsonResource} from '../../../state/json';
|
import {patchJsonResource} from '@avocado/resource/persea';
|
||||||
|
|
||||||
export default (Action, latus) => class ProjectAction extends Action {
|
export default (Action, latus) => class ProjectAction extends Action {
|
||||||
|
|
|
@ -25,9 +25,10 @@ const projectResources = async (uuid, resourcePaths, latus) => {
|
||||||
.map(([, path]) => path);
|
.map(([, path]) => path);
|
||||||
return filePaths
|
return filePaths
|
||||||
.reduce(async (r, path) => {
|
.reduce(async (r, path) => {
|
||||||
const {encode} = latus.get('%resource-controllers')(path);
|
const {fromBuffer} = latus.get('%resource-controllers')
|
||||||
|
.find(({matcher}) => path.match(matcher));
|
||||||
try {
|
try {
|
||||||
const encoded = await encode(
|
const encoded = await fromBuffer(
|
||||||
await readFile(join(process.cwd(), 'projects', uuid, path)),
|
await readFile(join(process.cwd(), 'projects', uuid, path)),
|
||||||
latus,
|
latus,
|
||||||
);
|
);
|
||||||
|
|
|
@ -142,6 +142,13 @@
|
||||||
eslint-visitor-keys "^1.3.0"
|
eslint-visitor-keys "^1.3.0"
|
||||||
semver "^6.3.0"
|
semver "^6.3.0"
|
||||||
|
|
||||||
|
"@babel/eslint-plugin@^7.13.10":
|
||||||
|
version "7.13.10"
|
||||||
|
resolved "http://npm.cha0sdev/@babel%2feslint-plugin/-/eslint-plugin-7.13.10.tgz#6720c32d52a4fef817796c7bb55a87b80320bbe7"
|
||||||
|
integrity sha512-xsNxo099fKnJ2rArkuuMOTPxxTLZSXwbFXdH4GjqQRKTOr6S1odQlE+R3Leid56VFQ3KVAR295vVNG9fqNQVvQ==
|
||||||
|
dependencies:
|
||||||
|
eslint-rule-composer "^0.3.0"
|
||||||
|
|
||||||
"@babel/generator@^7.13.0", "@babel/generator@^7.13.9":
|
"@babel/generator@^7.13.0", "@babel/generator@^7.13.9":
|
||||||
version "7.13.9"
|
version "7.13.9"
|
||||||
resolved "http://npm.cha0sdev/@babel%2fgenerator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
|
resolved "http://npm.cha0sdev/@babel%2fgenerator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
|
||||||
|
@ -358,7 +365,7 @@
|
||||||
chalk "^2.0.0"
|
chalk "^2.0.0"
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
|
|
||||||
"@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.7.0":
|
"@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.13.12", "@babel/parser@^7.7.0":
|
||||||
version "7.13.12"
|
version "7.13.12"
|
||||||
resolved "http://npm.cha0sdev/@babel%2fparser/-/parser-7.13.12.tgz#ba320059420774394d3b0c0233ba40e4250b81d1"
|
resolved "http://npm.cha0sdev/@babel%2fparser/-/parser-7.13.12.tgz#ba320059420774394d3b0c0233ba40e4250b81d1"
|
||||||
integrity sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw==
|
integrity sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw==
|
||||||
|
@ -1020,15 +1027,18 @@
|
||||||
|
|
||||||
"@latus/build@1.x":
|
"@latus/build@1.x":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "http://npm.cha0sdev/@latus%2fbuild/-/build-1.0.0.tgz#69cdd493e23c90adeb04238d2d52fbfb9cb84c0c"
|
resolved "http://npm.cha0sdev/@latus%2fbuild/-/build-1.0.0.tgz#2e374dac9323f44944896f651f4512ae8860a2d0"
|
||||||
integrity sha512-CTRQj9ghX1l64ffR3SnYSeVHNWUuAWjni8ykuXeuC6hNd6tuY9vpQKyZbBaJGvH7o+rwsdYb65ncKTGrXLByMQ==
|
integrity sha512-o+/smEvv2b8CQIKMgQlrxceMJb1AfVq4RyNlnIbNJZIlY+ifuyXb0ERvfHYo0pZ+El/n9KV5MM5K62/FpluPXA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/eslint-parser" "^7.13.10"
|
"@babel/eslint-parser" "^7.13.10"
|
||||||
|
"@babel/eslint-plugin" "^7.13.10"
|
||||||
|
"@babel/parser" "^7.13.12"
|
||||||
"@babel/plugin-proposal-class-properties" "^7.12.13"
|
"@babel/plugin-proposal-class-properties" "^7.12.13"
|
||||||
"@babel/plugin-proposal-optional-chaining" "^7.12.16"
|
"@babel/plugin-proposal-optional-chaining" "^7.12.16"
|
||||||
"@babel/plugin-proposal-private-methods" "^7.12.13"
|
"@babel/plugin-proposal-private-methods" "^7.12.13"
|
||||||
"@babel/plugin-syntax-jsx" "^7.12.13"
|
"@babel/plugin-syntax-jsx" "^7.12.13"
|
||||||
"@babel/preset-react" "^7.12.13"
|
"@babel/preset-react" "^7.12.13"
|
||||||
|
"@babel/types" "^7.13.12"
|
||||||
"@neutrinojs/airbnb" "^9.4.0"
|
"@neutrinojs/airbnb" "^9.4.0"
|
||||||
"@neutrinojs/banner" "^9.4.0"
|
"@neutrinojs/banner" "^9.4.0"
|
||||||
"@neutrinojs/copy" "^9.4.0"
|
"@neutrinojs/copy" "^9.4.0"
|
||||||
|
@ -1046,17 +1056,21 @@
|
||||||
|
|
||||||
"@latus/core@2.0.0", "@latus/core@^2.0.0":
|
"@latus/core@2.0.0", "@latus/core@^2.0.0":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "http://npm.cha0sdev/@latus%2fcore/-/core-2.0.0.tgz#12a0f3c11c9832a60e6726ea74ce0ae9b45e9faf"
|
resolved "http://npm.cha0sdev/@latus%2fcore/-/core-2.0.0.tgz#55bf7e61e287a6fe65289d36cdff20ca217e7eb0"
|
||||||
integrity sha512-JMxgl8Qsvby2OKtzXEs7cjamvsgVxEbJXbjebsmDl+J9Cq5513/4Xpq37EYYvT6FEZpoHFoIkQsaG+89JQzTwg==
|
integrity sha512-pXM3C0drjfCGfvOycl7KLxh/hTa1ShEdGjJrrTnAtoMZo8Q4yjkT4+TrEiytrZzj59uUVj5IWXaip1olWodY2Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
autoprefixer "^9.8.6"
|
"@neutrinojs/banner" "^9.5.0"
|
||||||
|
"@neutrinojs/node" "^9.1.0"
|
||||||
debug "4.3.1"
|
debug "4.3.1"
|
||||||
|
deepmerge "^4.2.2"
|
||||||
js-yaml "3.14.0"
|
js-yaml "3.14.0"
|
||||||
lodash.flatten "^4.4.0"
|
lodash.flatten "^4.4.0"
|
||||||
lodash.get "^4.4.2"
|
lodash.get "^4.4.2"
|
||||||
lodash.set "^4.3.2"
|
lodash.set "^4.3.2"
|
||||||
|
lodash.without "^4.4.0"
|
||||||
mkdirp "^1.0.4"
|
mkdirp "^1.0.4"
|
||||||
webpack-virtual-modules "^0.4.1"
|
raw-loader "^4.0.2"
|
||||||
|
webpack-node-externals "2.5.2"
|
||||||
|
|
||||||
"@latus/db@^2.0.0":
|
"@latus/db@^2.0.0":
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
|
@ -1159,7 +1173,7 @@
|
||||||
eslint-plugin-react "^7.21.5"
|
eslint-plugin-react "^7.21.5"
|
||||||
eslint-plugin-react-hooks "^4.2.0"
|
eslint-plugin-react-hooks "^4.2.0"
|
||||||
|
|
||||||
"@neutrinojs/banner@^9.4.0":
|
"@neutrinojs/banner@9.5.0", "@neutrinojs/banner@^9.4.0", "@neutrinojs/banner@^9.5.0":
|
||||||
version "9.5.0"
|
version "9.5.0"
|
||||||
resolved "http://npm.cha0sdev/@neutrinojs%2fbanner/-/banner-9.5.0.tgz#ee8df39db5d76033211a1811428e444a06d7222f"
|
resolved "http://npm.cha0sdev/@neutrinojs%2fbanner/-/banner-9.5.0.tgz#ee8df39db5d76033211a1811428e444a06d7222f"
|
||||||
integrity sha512-SL4nT0V1Wykf+LcRlCp/L8Frt4dk7MZITToC+OeDz2w6V7gg8YfEwDfdEg+aampjyUoxaq+A02ZyZP1TyRDtLA==
|
integrity sha512-SL4nT0V1Wykf+LcRlCp/L8Frt4dk7MZITToC+OeDz2w6V7gg8YfEwDfdEg+aampjyUoxaq+A02ZyZP1TyRDtLA==
|
||||||
|
@ -1241,6 +1255,23 @@
|
||||||
deepmerge "^1.5.2"
|
deepmerge "^1.5.2"
|
||||||
lodash.omit "^4.5.0"
|
lodash.omit "^4.5.0"
|
||||||
|
|
||||||
|
"@neutrinojs/node@^9.1.0":
|
||||||
|
version "9.5.0"
|
||||||
|
resolved "http://npm.cha0sdev/@neutrinojs%2fnode/-/node-9.5.0.tgz#41da54a6af461ca329b194063640a2aa0e84f32e"
|
||||||
|
integrity sha512-kJjdEKCdBnKWD51Qnm6REAUdaLrJc3qjA3wFcJ11v1wddu7Ihaa2S4qNjcrCDYrxSPD1vVoUlE+nyucsX+dO4w==
|
||||||
|
dependencies:
|
||||||
|
"@babel/core" "^7.12.10"
|
||||||
|
"@babel/plugin-syntax-dynamic-import" "^7.8.3"
|
||||||
|
"@babel/preset-env" "^7.12.11"
|
||||||
|
"@neutrinojs/banner" "9.5.0"
|
||||||
|
"@neutrinojs/clean" "9.5.0"
|
||||||
|
"@neutrinojs/compile-loader" "9.5.0"
|
||||||
|
"@neutrinojs/start-server" "9.5.0"
|
||||||
|
babel-merge "^3.0.0"
|
||||||
|
deepmerge "^1.5.2"
|
||||||
|
lodash.omit "^4.5.0"
|
||||||
|
webpack-node-externals "^1.7.2"
|
||||||
|
|
||||||
"@neutrinojs/react@^9.4.0":
|
"@neutrinojs/react@^9.4.0":
|
||||||
version "9.5.0"
|
version "9.5.0"
|
||||||
resolved "http://npm.cha0sdev/@neutrinojs%2freact/-/react-9.5.0.tgz#3ea0c94aaef7045c74fc53b581d7e989a83e67dd"
|
resolved "http://npm.cha0sdev/@neutrinojs%2freact/-/react-9.5.0.tgz#3ea0c94aaef7045c74fc53b581d7e989a83e67dd"
|
||||||
|
@ -1255,6 +1286,13 @@
|
||||||
eslint-plugin-react "^7.21.5"
|
eslint-plugin-react "^7.21.5"
|
||||||
eslint-plugin-react-hooks "^4.2.0"
|
eslint-plugin-react-hooks "^4.2.0"
|
||||||
|
|
||||||
|
"@neutrinojs/start-server@9.5.0":
|
||||||
|
version "9.5.0"
|
||||||
|
resolved "http://npm.cha0sdev/@neutrinojs%2fstart-server/-/start-server-9.5.0.tgz#f0d21a7f2c9c57897769e56ee042bd1d242275a4"
|
||||||
|
integrity sha512-gNRISZAbJpAZRIUfIxCWFEzEhfM/4ibmbGzz9jFJloH+fQw6JpOWF6bhhBZNDFFTj/6GKFi40CJrte4V3ywNBA==
|
||||||
|
dependencies:
|
||||||
|
start-server-webpack-plugin "^2.2.5"
|
||||||
|
|
||||||
"@neutrinojs/style-loader@9.5.0":
|
"@neutrinojs/style-loader@9.5.0":
|
||||||
version "9.5.0"
|
version "9.5.0"
|
||||||
resolved "http://npm.cha0sdev/@neutrinojs%2fstyle-loader/-/style-loader-9.5.0.tgz#5f1f151d76f5f1168e557612d5e3407ffb99049e"
|
resolved "http://npm.cha0sdev/@neutrinojs%2fstyle-loader/-/style-loader-9.5.0.tgz#5f1f151d76f5f1168e557612d5e3407ffb99049e"
|
||||||
|
@ -3901,6 +3939,11 @@ fast-deep-equal@^3.1.1:
|
||||||
resolved "http://npm.cha0sdev/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
resolved "http://npm.cha0sdev/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||||
|
|
||||||
|
fast-json-patch@^3.0.0-1:
|
||||||
|
version "3.0.0-1"
|
||||||
|
resolved "http://npm.cha0sdev/fast-json-patch/-/fast-json-patch-3.0.0-1.tgz#4c68f2e7acfbab6d29d1719c44be51899c93dabb"
|
||||||
|
integrity sha512-6pdFb07cknxvPzCeLsFHStEy+MysPJPgZQ9LbQ/2O67unQF93SNqfdSqnPPl71YMHX+AD8gbl7iuoGFzHEdDuw==
|
||||||
|
|
||||||
fast-json-stable-stringify@^2.0.0:
|
fast-json-stable-stringify@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "http://npm.cha0sdev/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
resolved "http://npm.cha0sdev/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
||||||
|
@ -5445,6 +5488,11 @@ lodash.uniq@^4.5.0:
|
||||||
resolved "http://npm.cha0sdev/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
resolved "http://npm.cha0sdev/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||||
|
|
||||||
|
lodash.without@^4.4.0:
|
||||||
|
version "4.4.0"
|
||||||
|
resolved "http://npm.cha0sdev/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
|
||||||
|
integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=
|
||||||
|
|
||||||
lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4, lodash@~4.17.10:
|
lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4, lodash@~4.17.10:
|
||||||
version "4.17.21"
|
version "4.17.21"
|
||||||
resolved "http://npm.cha0sdev/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
resolved "http://npm.cha0sdev/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||||
|
@ -6907,6 +6955,14 @@ raw-body@2.4.0:
|
||||||
iconv-lite "0.4.24"
|
iconv-lite "0.4.24"
|
||||||
unpipe "1.0.0"
|
unpipe "1.0.0"
|
||||||
|
|
||||||
|
raw-loader@^4.0.2:
|
||||||
|
version "4.0.2"
|
||||||
|
resolved "http://npm.cha0sdev/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6"
|
||||||
|
integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==
|
||||||
|
dependencies:
|
||||||
|
loader-utils "^2.0.0"
|
||||||
|
schema-utils "^3.0.0"
|
||||||
|
|
||||||
rc-align@^4.0.0:
|
rc-align@^4.0.0:
|
||||||
version "4.0.9"
|
version "4.0.9"
|
||||||
resolved "http://npm.cha0sdev/rc-align/-/rc-align-4.0.9.tgz#46d8801c4a139ff6a65ad1674e8efceac98f85f2"
|
resolved "http://npm.cha0sdev/rc-align/-/rc-align-4.0.9.tgz#46d8801c4a139ff6a65ad1674e8efceac98f85f2"
|
||||||
|
@ -7952,6 +8008,11 @@ ssri@^6.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
figgy-pudding "^3.5.1"
|
figgy-pudding "^3.5.1"
|
||||||
|
|
||||||
|
start-server-webpack-plugin@^2.2.5:
|
||||||
|
version "2.2.5"
|
||||||
|
resolved "http://npm.cha0sdev/start-server-webpack-plugin/-/start-server-webpack-plugin-2.2.5.tgz#4a2838759b0f36acd11b0b2f5f196f289ae29d31"
|
||||||
|
integrity sha512-DRCkciwCJoCFZ+wt3wWMkR1M2mpVhJbUKFXqhK3FWyIUKYb42NnocH5sMwqgo+nPNHupqNwK/v8lgfBbr2NKdg==
|
||||||
|
|
||||||
static-extend@^0.1.1:
|
static-extend@^0.1.1:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "http://npm.cha0sdev/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
|
resolved "http://npm.cha0sdev/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
|
||||||
|
@ -8759,6 +8820,11 @@ webpack-node-externals@2.5.2:
|
||||||
resolved "http://npm.cha0sdev/webpack-node-externals/-/webpack-node-externals-2.5.2.tgz#178e017a24fec6015bc9e672c77958a6afac861d"
|
resolved "http://npm.cha0sdev/webpack-node-externals/-/webpack-node-externals-2.5.2.tgz#178e017a24fec6015bc9e672c77958a6afac861d"
|
||||||
integrity sha512-aHdl/y2N7PW2Sx7K+r3AxpJO+aDMcYzMQd60Qxefq3+EwhewSbTBqNumOsCE1JsCUNoyfGj5465N0sSf6hc/5w==
|
integrity sha512-aHdl/y2N7PW2Sx7K+r3AxpJO+aDMcYzMQd60Qxefq3+EwhewSbTBqNumOsCE1JsCUNoyfGj5465N0sSf6hc/5w==
|
||||||
|
|
||||||
|
webpack-node-externals@^1.7.2:
|
||||||
|
version "1.7.2"
|
||||||
|
resolved "http://npm.cha0sdev/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz#6e1ee79ac67c070402ba700ef033a9b8d52ac4e3"
|
||||||
|
integrity sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg==
|
||||||
|
|
||||||
webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1:
|
webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1:
|
||||||
version "1.4.3"
|
version "1.4.3"
|
||||||
resolved "http://npm.cha0sdev/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
|
resolved "http://npm.cha0sdev/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
|
||||||
|
|
7
packages/entity/.gitignore
vendored
7
packages/entity/.gitignore
vendored
|
@ -1,7 +0,0 @@
|
||||||
**/*.js
|
|
||||||
**/*.map
|
|
||||||
!/.*
|
|
||||||
!/postcss.config.js
|
|
||||||
!/webpack.config.js
|
|
||||||
!src/**/*.js
|
|
||||||
!/test/**/*.js
|
|
|
@ -1,41 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@persea/entity",
|
|
||||||
"version": "3.0.0",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"build": "latus-build",
|
|
||||||
"clean": "latus-build clean",
|
|
||||||
"fp": "latus-build forcepublish",
|
|
||||||
"lint": "latus-build lint",
|
|
||||||
"test": "latus-build test"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"client.js",
|
|
||||||
"client.js.map",
|
|
||||||
"index.js",
|
|
||||||
"index.js.map",
|
|
||||||
"test.js",
|
|
||||||
"test.js.map"
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"@avocado/behavior": "^2.0.0",
|
|
||||||
"@avocado/entity": "^2.0.0",
|
|
||||||
"@avocado/graphics": "^2.0.0",
|
|
||||||
"@avocado/math": "^2.0.0",
|
|
||||||
"@avocado/react": "^1.0.0",
|
|
||||||
"@avocado/traits": "^2.0.0",
|
|
||||||
"@latus/core": "^2.0.0",
|
|
||||||
"@latus/react": "^2.0.0",
|
|
||||||
"@latus/redux": "^2.0.0",
|
|
||||||
"@persea/core": "^1.0.0",
|
|
||||||
"@persea/json": "^1.0.0",
|
|
||||||
"classnames": "^2.2.6",
|
|
||||||
"lodash.difference": "^4.5.0",
|
|
||||||
"natsort": "^2.0.2",
|
|
||||||
"react-autosuggest": "^10.1.0",
|
|
||||||
"react-tabs": "^3.1.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@latus/build": "1.x"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
import './condition.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {PropTypes, React} from '@latus/react';
|
|
||||||
import {useJsonPatcher} from '@persea/json';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
|
|
||||||
import Variant from './help/variant';
|
|
||||||
|
|
||||||
const Condition = ({context, path, value}) => {
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const operands = value.operands.map((operand, i) => {
|
|
||||||
const operandKey = join(path, 'operands', i.toString());
|
|
||||||
return (
|
|
||||||
<Variant
|
|
||||||
context={context}
|
|
||||||
key={operandKey}
|
|
||||||
onChange={(event, value, localPath) => {
|
|
||||||
patch({
|
|
||||||
path: localPath,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
path={operandKey}
|
|
||||||
type="any"
|
|
||||||
value={operand}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
const operator = (
|
|
||||||
<select
|
|
||||||
key={join(path, 'operator')}
|
|
||||||
onChange={(event) => {
|
|
||||||
patch({
|
|
||||||
path: join(path, 'operator'),
|
|
||||||
value: event.target.value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
value={value.operator}
|
|
||||||
>
|
|
||||||
<option value="is">is</option>
|
|
||||||
<option value="isnt">isnt</option>
|
|
||||||
<option value=">">></option>
|
|
||||||
<option value=">=">>=</option>
|
|
||||||
<option value="<"><</option>
|
|
||||||
<option value="<="><=</option>
|
|
||||||
<option value="or">or</option>
|
|
||||||
<option value="and">and</option>
|
|
||||||
<option value="contains">contains</option>
|
|
||||||
</select>
|
|
||||||
);
|
|
||||||
const renderables = [];
|
|
||||||
switch (value.operator) {
|
|
||||||
case 'or':
|
|
||||||
case 'and':
|
|
||||||
renderables.push(operator);
|
|
||||||
renderables.push(...operands.map((operand, i) => (
|
|
||||||
<div className="operand__wrapper">
|
|
||||||
{operand}
|
|
||||||
<button
|
|
||||||
className="condition__remove-operand"
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: join(path, 'operands', i.toString()),
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
x
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)));
|
|
||||||
renderables.push(
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'add',
|
|
||||||
path: join(path, 'operands/-'),
|
|
||||||
value: {
|
|
||||||
type: 'literal',
|
|
||||||
value: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Add operand
|
|
||||||
</button>,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
renderables.push(operands.shift());
|
|
||||||
renderables.push(operator);
|
|
||||||
renderables.push(...operands);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classnames(
|
|
||||||
'condition',
|
|
||||||
{'condition--vertical': -1 !== ['and', 'or'].indexOf(value.operator)},
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{renderables}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Condition.defaultProps = {};
|
|
||||||
|
|
||||||
Condition.displayName = 'Condition';
|
|
||||||
|
|
||||||
Condition.propTypes = {
|
|
||||||
context: PropTypes.shape({
|
|
||||||
describeChildren: PropTypes.func,
|
|
||||||
get: PropTypes.func,
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.shape({
|
|
||||||
operator: PropTypes.string,
|
|
||||||
operands: PropTypes.arrayOf(
|
|
||||||
PropTypes.any,
|
|
||||||
),
|
|
||||||
}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Condition;
|
|
|
@ -1,49 +0,0 @@
|
||||||
.condition {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
&.condition--vertical {
|
|
||||||
align-items: flex-start;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition--vertical {
|
|
||||||
|
|
||||||
> select {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
> .expression,
|
|
||||||
> .key,
|
|
||||||
> .literal {
|
|
||||||
margin-left: 1em;
|
|
||||||
}
|
|
||||||
> .expression {
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition .condition--vertical {
|
|
||||||
padding-top: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.operand__wrapper {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
padding-left: 0.5em;
|
|
||||||
width: 100%;
|
|
||||||
&:nth-of-type(2n+1) {
|
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
|
||||||
}
|
|
||||||
> button {
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
padding: 1em;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,366 +0,0 @@
|
||||||
import './expression.scss';
|
|
||||||
|
|
||||||
import {join, relative} from 'path';
|
|
||||||
|
|
||||||
import {compile, isInvocation, isKey} from '@avocado/behavior';
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useLatus,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {useJsonPatcher} from '@persea/json';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
|
|
||||||
import Invocation from './expression/invocation';
|
|
||||||
import Key from './expression/key';
|
|
||||||
import Variant from './help/variant';
|
|
||||||
|
|
||||||
const Expression = ({
|
|
||||||
context,
|
|
||||||
path,
|
|
||||||
type,
|
|
||||||
value,
|
|
||||||
vararg,
|
|
||||||
}) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const types = latus.get('%behavior-types');
|
|
||||||
let i = 0;
|
|
||||||
const {ops, value: expressionValue} = value;
|
|
||||||
const Renderables = [];
|
|
||||||
let opsCount = 0;
|
|
||||||
// eslint-disable-next-line react/destructuring-assignment
|
|
||||||
let description = context.describeChildren();
|
|
||||||
const onChange = (event, value, localPath) => {
|
|
||||||
const patches = [];
|
|
||||||
const j = parseInt(relative(path, localPath).split('/')[1], 10);
|
|
||||||
if (j < ops.length - 1) {
|
|
||||||
for (let k = j + 1; k < ops.length; ++k) {
|
|
||||||
patches.unshift({
|
|
||||||
op: 'remove',
|
|
||||||
path: join(path, 'ops', k.toString()),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (event && j === ops.length) {
|
|
||||||
patches.push({
|
|
||||||
op: 'add',
|
|
||||||
path: join(path, 'ops', j.toString()),
|
|
||||||
value: {
|
|
||||||
type: 'key',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
patches.push({
|
|
||||||
path: localPath,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
patch(patches);
|
|
||||||
};
|
|
||||||
do {
|
|
||||||
const op = ops[i];
|
|
||||||
const opPath = join(path, 'ops', opsCount.toString());
|
|
||||||
const nextOp = i === ops.length - 1 ? undefined : ops[i + 1];
|
|
||||||
if (isKey(op)) {
|
|
||||||
const isFirst = 0 === i;
|
|
||||||
const isLast = i === ops.length - 1 ? true : isInvocation(ops[i + 1]);
|
|
||||||
Renderables.push(
|
|
||||||
<Key
|
|
||||||
childrenDescription={{
|
|
||||||
...(
|
|
||||||
isFirst && 'void' !== type
|
|
||||||
? {
|
|
||||||
'[literal]': {label: '', type},
|
|
||||||
}
|
|
||||||
: {}
|
|
||||||
),
|
|
||||||
...(
|
|
||||||
vararg && isFirst
|
|
||||||
? {'...': {label: '', type: description.type}}
|
|
||||||
: {}
|
|
||||||
),
|
|
||||||
...(
|
|
||||||
isLast && !isFirst
|
|
||||||
? {'.': {label: '', type: description.type}}
|
|
||||||
: {}
|
|
||||||
),
|
|
||||||
...description.children,
|
|
||||||
...(
|
|
||||||
isFirst
|
|
||||||
? {
|
|
||||||
'[key]': {label: '', type: 'undefined'},
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
'[key]': {label: '', type: 'undefined'},
|
|
||||||
'[invoke]': {label: '', type: 'undefined'},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
key={opPath}
|
|
||||||
onChange={((i) => (event, value, localPath) => {
|
|
||||||
if ('.' === value || '...' === value) {
|
|
||||||
const parts = localPath.split('/');
|
|
||||||
parts.pop();
|
|
||||||
parts.pop();
|
|
||||||
if ('...' === value) {
|
|
||||||
parts.pop();
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: parts.join('/'),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const patches = [];
|
|
||||||
for (let j = i; j < ops.length; ++j) {
|
|
||||||
patches.unshift(
|
|
||||||
{
|
|
||||||
op: 'remove',
|
|
||||||
path: join(parts.join('/'), j.toString()),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
patch(patches);
|
|
||||||
}
|
|
||||||
else if ('[literal]' === value) {
|
|
||||||
patch({
|
|
||||||
op: 'replace',
|
|
||||||
path,
|
|
||||||
value: {
|
|
||||||
type: 'literal',
|
|
||||||
value: null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
onChange(event, value, localPath);
|
|
||||||
}
|
|
||||||
})(i)}
|
|
||||||
path={opPath}
|
|
||||||
value={op.key}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
opsCount += 1;
|
|
||||||
}
|
|
||||||
if (isInvocation(op)) {
|
|
||||||
const R = Renderables.pop();
|
|
||||||
Renderables.push(
|
|
||||||
<div
|
|
||||||
className="expression__invocation-toggle-wrapper"
|
|
||||||
key={`${opPath}-toggle-from`}
|
|
||||||
>
|
|
||||||
{R}
|
|
||||||
<button
|
|
||||||
className="expression__invocation-toggle from"
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: opPath,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
→
|
|
||||||
</button>
|
|
||||||
</div>,
|
|
||||||
);
|
|
||||||
Renderables.push(
|
|
||||||
<Invocation
|
|
||||||
context={context}
|
|
||||||
description={description}
|
|
||||||
Expression={Expression}
|
|
||||||
key={opPath}
|
|
||||||
onChange={onChange}
|
|
||||||
op={op}
|
|
||||||
path={opPath}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
opsCount += 1;
|
|
||||||
}
|
|
||||||
if (isKey(op)) {
|
|
||||||
const current = compile({type: 'expression', ops: ops.slice(0, i + 1)}, latus)(context);
|
|
||||||
description = description.children?.[op.key] || {type: 'undefined'};
|
|
||||||
const {args, type} = description;
|
|
||||||
if ('void' !== type) {
|
|
||||||
description = {
|
|
||||||
...context.constructor.descriptionFor(
|
|
||||||
type,
|
|
||||||
current,
|
|
||||||
latus,
|
|
||||||
),
|
|
||||||
...(args ? {args} : {}),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (description.args && (!nextOp || !isInvocation(nextOp))) {
|
|
||||||
const R = Renderables.pop();
|
|
||||||
Renderables.push(
|
|
||||||
<div
|
|
||||||
className="expression__invocation-toggle-wrapper"
|
|
||||||
key={`${opPath}-toggle-to`}
|
|
||||||
>
|
|
||||||
{R}
|
|
||||||
<button
|
|
||||||
className="expression__invocation-toggle to"
|
|
||||||
onClick={((description, opPath) => () => {
|
|
||||||
const parts = opPath.split('/');
|
|
||||||
parts.push(parseInt(parts.pop(), 10) + 1);
|
|
||||||
patch({
|
|
||||||
op: 'add',
|
|
||||||
path: parts.join('/'),
|
|
||||||
value: {
|
|
||||||
type: 'invoke',
|
|
||||||
args: description.vararg
|
|
||||||
? []
|
|
||||||
: description.args.map(
|
|
||||||
(arg) => ({
|
|
||||||
...(false === arg.compile ? {compile: false} : {}),
|
|
||||||
...(
|
|
||||||
(types[arg.type] || types.undefined).create(
|
|
||||||
(arg.options?.length || 0) > 0
|
|
||||||
? arg.options[0].value
|
|
||||||
: undefined,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})(description, opPath)}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
→
|
|
||||||
</button>
|
|
||||||
</div>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isInvocation(op)) {
|
|
||||||
if ('void' !== description.type) {
|
|
||||||
description = context.constructor.descriptionFor(
|
|
||||||
description.type,
|
|
||||||
undefined,
|
|
||||||
latus,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (i++ < ops.length - 1);
|
|
||||||
if (
|
|
||||||
description.children
|
|
||||||
|| 'undefined' === description.type
|
|
||||||
) {
|
|
||||||
const opPath = join(path, 'ops', opsCount.toString());
|
|
||||||
Renderables.push(
|
|
||||||
<Key
|
|
||||||
childrenDescription={{
|
|
||||||
'.': {label: '', type: description.type},
|
|
||||||
...(description.children || {}),
|
|
||||||
'[key]': {label: '', type: 'undefined'},
|
|
||||||
'[invoke]': {label: '', type: 'undefined'},
|
|
||||||
}}
|
|
||||||
key={opPath}
|
|
||||||
onChange={onChange}
|
|
||||||
path={opPath}
|
|
||||||
value="."
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
opsCount += 1;
|
|
||||||
}
|
|
||||||
const [lastOp] = ops.slice(-1);
|
|
||||||
if (
|
|
||||||
'void' === type
|
|
||||||
&& isKey(lastOp)
|
|
||||||
) {
|
|
||||||
const opPath = join(path, 'value');
|
|
||||||
Renderables.push(
|
|
||||||
<Key
|
|
||||||
childrenDescription={{
|
|
||||||
'≡': {label: '', type: description.type},
|
|
||||||
'≔': {label: '', type: 'void'},
|
|
||||||
}}
|
|
||||||
key={opPath}
|
|
||||||
onChange={(event, value) => {
|
|
||||||
if ('≡' === value) {
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: opPath,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
patch({
|
|
||||||
path: opPath,
|
|
||||||
value: (types[description.type] || types.undefined).create(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
path={opPath}
|
|
||||||
value={expressionValue ? '≔' : '≡'}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
if (expressionValue) {
|
|
||||||
const expressionType = isKey(lastOp) && description.args
|
|
||||||
? 'function'
|
|
||||||
: description.type;
|
|
||||||
Renderables.push(
|
|
||||||
<Variant
|
|
||||||
context={context}
|
|
||||||
onChange={(event, value, localPath) => {
|
|
||||||
patch({
|
|
||||||
path: localPath,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
key={join(opPath, 'expression')}
|
|
||||||
path={opPath}
|
|
||||||
type={expressionType}
|
|
||||||
value={expressionValue}
|
|
||||||
vararg={vararg}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let realType = description.type;
|
|
||||||
if (isKey(lastOp) && description.args) {
|
|
||||||
realType = 'function';
|
|
||||||
}
|
|
||||||
if (expressionValue) {
|
|
||||||
realType = 'undefined' === description.type ? 'undefined' : 'void';
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classnames(
|
|
||||||
'expression',
|
|
||||||
{'wrong-type': 'any' !== type && 'undefined' !== type && realType !== type},
|
|
||||||
{'undefined-type': 'undefined' === realType},
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{Renderables}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Expression.defaultProps = {
|
|
||||||
vararg: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
Expression.displayName = 'Expression';
|
|
||||||
|
|
||||||
Expression.propTypes = {
|
|
||||||
context: PropTypes.shape({
|
|
||||||
constructor: PropTypes.func,
|
|
||||||
describeChildren: PropTypes.func,
|
|
||||||
get: PropTypes.func,
|
|
||||||
}).isRequired,
|
|
||||||
value: PropTypes.shape({
|
|
||||||
ops: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
key: PropTypes.string,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
// eslint-disable-next-line react/forbid-prop-types
|
|
||||||
value: PropTypes.any,
|
|
||||||
}).isRequired,
|
|
||||||
vararg: PropTypes.bool,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
type: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Expression;
|
|
|
@ -1,37 +0,0 @@
|
||||||
.expression {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
button, .button {
|
|
||||||
color: #00bdd6;
|
|
||||||
}
|
|
||||||
&.wrong-type {
|
|
||||||
background-color: rgb(180, 0, 0);
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
&.undefined-type {
|
|
||||||
background-color: rgb(180, 180, 0);
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
> .expression {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.expression__invocation-toggle-wrapper {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expression__invocation-toggle {
|
|
||||||
background: #222222;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0.25em;
|
|
||||||
pointer-events: auto;
|
|
||||||
&:hover {
|
|
||||||
background: #333333;
|
|
||||||
}
|
|
||||||
&.to {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,137 +0,0 @@
|
||||||
import './invocation.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {useJsonPatcher} from '@persea/json';
|
|
||||||
|
|
||||||
import Variant from '../help/variant';
|
|
||||||
import Key from './key';
|
|
||||||
|
|
||||||
const Invocation = ({
|
|
||||||
context,
|
|
||||||
description,
|
|
||||||
onChange,
|
|
||||||
op,
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const argComponent = (arg, i) => {
|
|
||||||
const argPath = join(path, 'args', i.toString());
|
|
||||||
if ('undefined' === arg.type) {
|
|
||||||
return (
|
|
||||||
<Key
|
|
||||||
childrenDescription={{
|
|
||||||
'...': {label: '', type: 'undefined'},
|
|
||||||
'[literal]': {label: '', type: 'undefined'},
|
|
||||||
...context.describeChildren().children,
|
|
||||||
'[key]': {label: '', type: 'undefined'},
|
|
||||||
}}
|
|
||||||
key={path}
|
|
||||||
onChange={(event, value) => {
|
|
||||||
if ('[literal]' === value) {
|
|
||||||
patch({
|
|
||||||
type: 'add',
|
|
||||||
path: argPath,
|
|
||||||
value: {
|
|
||||||
type: 'literal',
|
|
||||||
value: null,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
patch({
|
|
||||||
type: 'add',
|
|
||||||
path: argPath,
|
|
||||||
value: {
|
|
||||||
type: 'expression',
|
|
||||||
ops: [
|
|
||||||
{
|
|
||||||
type: 'key',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
onChange(false, value, join(argPath, 'ops/0/key'));
|
|
||||||
}}
|
|
||||||
path={argPath}
|
|
||||||
value="..."
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let darg;
|
|
||||||
if ('function' === typeof description?.args) {
|
|
||||||
darg = description?.args(i);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const j = description.vararg ? i % description?.args?.length : i;
|
|
||||||
darg = description?.args?.[j];
|
|
||||||
}
|
|
||||||
const type = darg?.type || 'undefined';
|
|
||||||
return (
|
|
||||||
<Variant
|
|
||||||
context={context}
|
|
||||||
onChange={onChange}
|
|
||||||
options={darg?.options}
|
|
||||||
path={argPath}
|
|
||||||
type={type}
|
|
||||||
value={arg}
|
|
||||||
vararg={
|
|
||||||
'undefined' === type
|
|
||||||
|| description.vararg
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const isVarArg = 'undefined' === description.type || description.vararg;
|
|
||||||
const args = op.args.concat();
|
|
||||||
if (isVarArg) {
|
|
||||||
args.push({type: 'undefined'});
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="invocation">
|
|
||||||
{args.length > 0 && (
|
|
||||||
<div className="invocation__args-wrapper">
|
|
||||||
{
|
|
||||||
args.map((arg, i) => (
|
|
||||||
<div
|
|
||||||
key={join(path, 'args', i.toString())}
|
|
||||||
className="invocation__arg"
|
|
||||||
>
|
|
||||||
{argComponent(arg, i)}
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Invocation.displayName = 'Invocation';
|
|
||||||
|
|
||||||
Invocation.propTypes = {
|
|
||||||
context: PropTypes.shape({
|
|
||||||
describeChildren: PropTypes.func,
|
|
||||||
}).isRequired,
|
|
||||||
description: PropTypes.shape({
|
|
||||||
args: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({
|
|
||||||
options: PropTypes.arrayOf(PropTypes.any),
|
|
||||||
type: PropTypes.string,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
type: PropTypes.string,
|
|
||||||
vararg: PropTypes.bool,
|
|
||||||
}).isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
op: PropTypes.shape({
|
|
||||||
args: PropTypes.arrayOf(PropTypes.any),
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Invocation;
|
|
|
@ -1,53 +0,0 @@
|
||||||
.invocation {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
margin-left: 0.25em;
|
|
||||||
> .expression {
|
|
||||||
margin: 0 0.5em;
|
|
||||||
}
|
|
||||||
&:after {
|
|
||||||
color: #00bdd6;
|
|
||||||
content: ')';
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
&:before {
|
|
||||||
color: #00bdd6;
|
|
||||||
content: '(';
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.invocation__args-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin: 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.invocation__arg {
|
|
||||||
align-items: center;
|
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
|
||||||
display: flex;
|
|
||||||
padding: 0.5em;
|
|
||||||
position: relative;
|
|
||||||
&:nth-of-type(2n+1) {
|
|
||||||
background-color: rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
&:after {
|
|
||||||
color: #00bdd6;
|
|
||||||
content: ',';
|
|
||||||
font-size: 1.5em;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
&:last-of-type {
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.invocation__arg-sep {
|
|
||||||
align-self: flex-end;
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
import './key.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useEffect,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {useJsonPatcher} from '@persea/json';
|
|
||||||
import natsort from 'natsort';
|
|
||||||
|
|
||||||
const sorter = natsort({insensitive: true});
|
|
||||||
|
|
||||||
const Key = ({
|
|
||||||
childrenDescription,
|
|
||||||
onChange,
|
|
||||||
path,
|
|
||||||
value,
|
|
||||||
}) => {
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const customizeRef = useRef();
|
|
||||||
const [customization, setCustomization] = useState(false);
|
|
||||||
const [customizationPath, setCustomizationPath] = useState('/');
|
|
||||||
useEffect(() => {
|
|
||||||
customizeRef.current?.focus();
|
|
||||||
});
|
|
||||||
const optionKeys = Object.entries(childrenDescription).map(([key]) => key);
|
|
||||||
if (-1 === optionKeys.indexOf(value)) {
|
|
||||||
optionKeys.unshift(value);
|
|
||||||
}
|
|
||||||
const options = optionKeys
|
|
||||||
.sort(sorter)
|
|
||||||
.map((key) => (
|
|
||||||
<option key={key} value={key}>{key}</option>
|
|
||||||
));
|
|
||||||
const confirmCustomization = () => {
|
|
||||||
const parts = customizationPath.split('/');
|
|
||||||
parts.pop();
|
|
||||||
setCustomization(false);
|
|
||||||
setCustomizationPath('/');
|
|
||||||
if ('value' === parts[parts.length - 1]) {
|
|
||||||
patch({
|
|
||||||
type: 'add',
|
|
||||||
path: parts.join('/'),
|
|
||||||
value: {
|
|
||||||
type: 'expression',
|
|
||||||
ops: [
|
|
||||||
{
|
|
||||||
type: 'key',
|
|
||||||
key: customization,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
patch({
|
|
||||||
type: 'add',
|
|
||||||
path: parts.join('/'),
|
|
||||||
value: {
|
|
||||||
type: 'key',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
onChange(false, customization, join(parts.join('/'), 'key'));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="key"
|
|
||||||
>
|
|
||||||
{
|
|
||||||
false === customization
|
|
||||||
? (
|
|
||||||
<select
|
|
||||||
className="key__selector"
|
|
||||||
onChange={(event) => {
|
|
||||||
const localPath = join(path, 'key');
|
|
||||||
const {target: {value}} = event;
|
|
||||||
switch (value) {
|
|
||||||
case '[key]': {
|
|
||||||
setCustomization('');
|
|
||||||
setCustomizationPath(localPath);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case '[invoke]': {
|
|
||||||
const parts = localPath.split('/');
|
|
||||||
parts.pop();
|
|
||||||
patch({
|
|
||||||
type: 'add',
|
|
||||||
path: parts.join('/'),
|
|
||||||
value: {
|
|
||||||
type: 'invoke',
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
onChange(event, value, localPath);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
value={value}
|
|
||||||
>
|
|
||||||
{options}
|
|
||||||
</select>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
onBlur={confirmCustomization}
|
|
||||||
onChange={({target: {value}}) => {
|
|
||||||
setCustomization(value);
|
|
||||||
}}
|
|
||||||
onKeyPress={(event) => {
|
|
||||||
if ('Enter' === event.key) {
|
|
||||||
confirmCustomization(event);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
ref={customizeRef}
|
|
||||||
value={customization}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Key.displayName = 'Key';
|
|
||||||
|
|
||||||
Key.propTypes = {
|
|
||||||
childrenDescription: PropTypes.shape({}).isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Key;
|
|
|
@ -1,3 +0,0 @@
|
||||||
.key__selector {
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
|
@ -1,149 +0,0 @@
|
||||||
import './expressions.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {compile} from '@avocado/behavior';
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useLatus,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {useJsonPatcher} from '@persea/json';
|
|
||||||
|
|
||||||
import Expression from './expression';
|
|
||||||
|
|
||||||
const Expressions = ({
|
|
||||||
context,
|
|
||||||
value: {expressions},
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const createExpressionSwapper = (l, r) => () => {
|
|
||||||
const le = expressions[l];
|
|
||||||
const re = expressions[r];
|
|
||||||
patch([
|
|
||||||
{
|
|
||||||
path: join(path, 'expressions', l.toString()),
|
|
||||||
value: re,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: join(path, 'expressions', r.toString()),
|
|
||||||
value: le,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
let currentContext = context;
|
|
||||||
return (
|
|
||||||
<div className="expressions">
|
|
||||||
{
|
|
||||||
expressions.map((expression, i) => {
|
|
||||||
currentContext = currentContext.clone();
|
|
||||||
const {ops} = expression;
|
|
||||||
if (3 === ops.length && 'context' === ops[0].key && 'add' === ops[1].key) {
|
|
||||||
const [key, value] = ops[2].args;
|
|
||||||
if ('undefined' !== key.type && 'undefined' !== value.type) {
|
|
||||||
currentContext.add(
|
|
||||||
compile(key, latus)(currentContext),
|
|
||||||
compile(value, latus)(currentContext),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const expressionPath = join(path, 'expressions', i.toString());
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="expressions__expression-wrapper"
|
|
||||||
key={expressionPath}
|
|
||||||
>
|
|
||||||
<div className="expressions__move-expression">
|
|
||||||
{i > 0 && (
|
|
||||||
<button
|
|
||||||
className="expressions__move-expression-up"
|
|
||||||
onClick={createExpressionSwapper(i, i - 1)}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
🠹
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<div className="expressions__move-expression-spacer" />
|
|
||||||
{i < expressions.length - 1 && (
|
|
||||||
<button
|
|
||||||
className="expressions__move-expression-down"
|
|
||||||
onClick={createExpressionSwapper(i, i + 1)}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
🠻
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<Expression
|
|
||||||
context={currentContext}
|
|
||||||
value={expression}
|
|
||||||
path={expressionPath}
|
|
||||||
type="void"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
className="expressions__remove-expression"
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: expressionPath,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
x
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
<div className="expressions__expression-wrapper">
|
|
||||||
<button
|
|
||||||
className="expressions__add-expression"
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'add',
|
|
||||||
path: join(path, 'expressions/-'),
|
|
||||||
value: {
|
|
||||||
type: 'expression',
|
|
||||||
ops: [
|
|
||||||
{
|
|
||||||
type: 'key',
|
|
||||||
key: 'Flow',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'key',
|
|
||||||
key: 'nop',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'invoke',
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
Add expression
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Expressions.displayName = 'Expressions';
|
|
||||||
|
|
||||||
Expressions.propTypes = {
|
|
||||||
context: PropTypes.shape({}).isRequired,
|
|
||||||
value: PropTypes.shape({
|
|
||||||
type: PropTypes.string,
|
|
||||||
expressions: PropTypes.arrayOf(
|
|
||||||
PropTypes.shape({}),
|
|
||||||
),
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Expressions;
|
|
|
@ -1,54 +0,0 @@
|
||||||
.expressions__expression-wrapper {
|
|
||||||
align-items: center;
|
|
||||||
background-color: rgba(0, 0, 0, 0.05);
|
|
||||||
display: flex;
|
|
||||||
&:nth-of-type(2n+1) {
|
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
|
||||||
}
|
|
||||||
button, .button {
|
|
||||||
color: #00bdd6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__move-expression {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__move-expression-up,
|
|
||||||
.expressions__move-expression-down {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 0.5em;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__move-expression-up
|
|
||||||
+ .expressions__move-expression-spacer
|
|
||||||
+ .expressions__move-expression-down {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__expression-wrapper > .expression {
|
|
||||||
margin-right: 0.5em;
|
|
||||||
padding: 0.5em;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__remove-expression {
|
|
||||||
background-color: transparent;
|
|
||||||
border: none;
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
padding: 1em;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expressions__add-expression {
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin-left: 0.5em;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useLatus,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
const Variant = (props) => {
|
|
||||||
const {value} = props;
|
|
||||||
const {type} = value;
|
|
||||||
const latus = useLatus();
|
|
||||||
const BehaviorControllers = latus.get('%behavior-controllers');
|
|
||||||
const Controller = BehaviorControllers[type];
|
|
||||||
return (
|
|
||||||
<Controller
|
|
||||||
value={value}
|
|
||||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Variant.displayName = 'Variant';
|
|
||||||
|
|
||||||
Variant.propTypes = {
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.shape({
|
|
||||||
type: PropTypes.string,
|
|
||||||
}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Variant;
|
|
|
@ -1,263 +0,0 @@
|
||||||
import './literal.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {Context} from '@avocado/behavior';
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useLatus,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {
|
|
||||||
Number,
|
|
||||||
Rectangle,
|
|
||||||
Vector,
|
|
||||||
} from '@persea/core';
|
|
||||||
import {
|
|
||||||
JsonComponent,
|
|
||||||
useJsonPatcher,
|
|
||||||
} from '@persea/json';
|
|
||||||
|
|
||||||
import Key from './expression/key';
|
|
||||||
|
|
||||||
const Literal = ({
|
|
||||||
context,
|
|
||||||
onChange,
|
|
||||||
path,
|
|
||||||
type,
|
|
||||||
options,
|
|
||||||
value,
|
|
||||||
vararg,
|
|
||||||
}) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const [selectingType, setSelectingType] = useState(false);
|
|
||||||
const types = latus.get('%behavior-types');
|
|
||||||
const setLiteralType = (type) => {
|
|
||||||
const value = (types[type] || types.undefined).create();
|
|
||||||
if (null !== value) {
|
|
||||||
patch({
|
|
||||||
op: 'replace',
|
|
||||||
path,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setSelectingType(false);
|
|
||||||
};
|
|
||||||
// eslint-disable-next-line react/destructuring-assignment
|
|
||||||
const contextDescription = context.describeChildren();
|
|
||||||
const valueComponent = (path, type, {value}) => {
|
|
||||||
switch (type) {
|
|
||||||
case 'bool': {
|
|
||||||
return (
|
|
||||||
<select
|
|
||||||
onChange={(event) => {
|
|
||||||
onChange(event, !!event.target.value, path);
|
|
||||||
}}
|
|
||||||
value={null === value ? false : value}
|
|
||||||
>
|
|
||||||
<option value={false}>false</option>
|
|
||||||
<option value>true</option>
|
|
||||||
</select>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case 'number':
|
|
||||||
return (
|
|
||||||
<Number
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(event, value, path);
|
|
||||||
}}
|
|
||||||
value={null === value ? 0 : value}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'string':
|
|
||||||
return (
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
onChange={(event) => {
|
|
||||||
onChange(event, event.target.value, path);
|
|
||||||
}}
|
|
||||||
value={null === value ? '' : value}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'object':
|
|
||||||
return (
|
|
||||||
<JsonComponent
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(event, value, path);
|
|
||||||
}}
|
|
||||||
json={null === value ? {} : value}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'vector':
|
|
||||||
return (
|
|
||||||
<Vector
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(event, value, path);
|
|
||||||
}}
|
|
||||||
value={null === value ? [0, 0] : value}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'rectangle':
|
|
||||||
return (
|
|
||||||
<Rectangle
|
|
||||||
onChange={(event, value) => {
|
|
||||||
onChange(event, value, path);
|
|
||||||
}}
|
|
||||||
value={null === value ? [0, 0, 0, 0] : value}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case 'function':
|
|
||||||
case 'null':
|
|
||||||
case 'array':
|
|
||||||
return null;
|
|
||||||
default: {
|
|
||||||
const elements = [];
|
|
||||||
if ('undefined' === type || 'any' === type) {
|
|
||||||
elements.push(
|
|
||||||
<select
|
|
||||||
key={join(path, 'equality')}
|
|
||||||
onChange={({target: {value}}) => {
|
|
||||||
setSelectingType('≟' === value);
|
|
||||||
}}
|
|
||||||
value={selectingType ? '≟' : '='}
|
|
||||||
>
|
|
||||||
<option>=</option>
|
|
||||||
<option>≟</option>
|
|
||||||
</select>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if ('undefined' !== typeof value) {
|
|
||||||
elements.push(
|
|
||||||
<div className="component" key={join(path, 'component')}>
|
|
||||||
{
|
|
||||||
valueComponent(
|
|
||||||
path,
|
|
||||||
Context.descriptionFor(undefined, value, latus).type,
|
|
||||||
{value},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <>{elements}</>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const {type: inferred} = Context.descriptionFor(undefined, value.value, latus);
|
|
||||||
const typeKey = `[literal ${inferred}]`;
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{
|
|
||||||
selectingType
|
|
||||||
? (
|
|
||||||
<select
|
|
||||||
onChange={({target: {value}}) => {
|
|
||||||
setLiteralType(value);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option>- Select type -</option>
|
|
||||||
{
|
|
||||||
Object.entries(types)
|
|
||||||
.filter(([type, value]) => value.create && type)
|
|
||||||
.map(([type]) => type)
|
|
||||||
.map((type) => <option key={type} value={type}>{type}</option>)
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
)
|
|
||||||
: (
|
|
||||||
<Key
|
|
||||||
childrenDescription={{
|
|
||||||
...(
|
|
||||||
'undefined' === type
|
|
||||||
? {'.': {label: '', type: 'undefined'}}
|
|
||||||
: {}
|
|
||||||
),
|
|
||||||
...(
|
|
||||||
vararg
|
|
||||||
? {'...': {label: '', type: 'undefined'}}
|
|
||||||
: {}
|
|
||||||
),
|
|
||||||
[typeKey]: {label: '', type: value.type},
|
|
||||||
...contextDescription.children,
|
|
||||||
'[key]': {label: '', type: value.type},
|
|
||||||
}}
|
|
||||||
onChange={(event, value) => {
|
|
||||||
if ('.' === value || '...' === value) {
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
patch({
|
|
||||||
op: 'replace',
|
|
||||||
path,
|
|
||||||
value: {
|
|
||||||
type: 'expression',
|
|
||||||
ops: [
|
|
||||||
{
|
|
||||||
type: 'key',
|
|
||||||
key: value,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
path={path}
|
|
||||||
value={typeKey}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
<div className="literal">
|
|
||||||
{
|
|
||||||
options.length > 0
|
|
||||||
? (
|
|
||||||
<select
|
|
||||||
onChange={(event) => {
|
|
||||||
onChange(event, options[event.target.value].value, join(path, 'value'));
|
|
||||||
}}
|
|
||||||
value={options.findIndex(({value: optionValue}) => value.value === optionValue)}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
Object.entries(options)
|
|
||||||
.map(([key, {label}]) => (
|
|
||||||
<option
|
|
||||||
key={label}
|
|
||||||
value={key}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</option>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
)
|
|
||||||
: valueComponent(join(path, 'value'), type, value)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Literal.defaultProps = {
|
|
||||||
options: [],
|
|
||||||
vararg: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
Literal.displayName = 'Literal';
|
|
||||||
|
|
||||||
Literal.propTypes = {
|
|
||||||
context: PropTypes.shape({
|
|
||||||
describeChildren: PropTypes.func,
|
|
||||||
}).isRequired,
|
|
||||||
type: PropTypes.string.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
options: PropTypes.arrayOf(PropTypes.any),
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
// eslint-disable-next-line react/forbid-prop-types
|
|
||||||
value: PropTypes.any.isRequired,
|
|
||||||
vararg: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Literal;
|
|
|
@ -1,5 +0,0 @@
|
||||||
.literal {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
export default async (latus) => {
|
|
||||||
const {Entity} = latus.get('%resources');
|
|
||||||
const Traits = latus.get('%traits');
|
|
||||||
const AllTraits = Object.fromEntries(
|
|
||||||
Object.entries(Traits)
|
|
||||||
.filter(([key]) => !Number.isInteger(parseInt(key, 10))),
|
|
||||||
);
|
|
||||||
return Entity.load({
|
|
||||||
traits: Object.entries(AllTraits).reduce((r, [type]) => ({...r, [type]: {}}), {}),
|
|
||||||
});
|
|
||||||
};
|
|
|
@ -1,23 +0,0 @@
|
||||||
import {
|
|
||||||
useEffect,
|
|
||||||
useState,
|
|
||||||
useLatus,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
export default (json) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const {Entity} = latus.get('%resources');
|
|
||||||
const [entity, setEntity] = useState();
|
|
||||||
useEffect(() => {
|
|
||||||
if (entity) {
|
|
||||||
entity.destroy();
|
|
||||||
}
|
|
||||||
setEntity();
|
|
||||||
const loadEntity = async () => {
|
|
||||||
setEntity(await Entity.load(json));
|
|
||||||
};
|
|
||||||
loadEntity();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [Entity, json]);
|
|
||||||
return entity;
|
|
||||||
};
|
|
|
@ -1,42 +0,0 @@
|
||||||
import {basename, extname} from 'path';
|
|
||||||
|
|
||||||
import {camelCase} from '@latus/core';
|
|
||||||
|
|
||||||
import Condition from './behavior-components/condition';
|
|
||||||
import Expression from './behavior-components/expression';
|
|
||||||
import Expressions from './behavior-components/expressions';
|
|
||||||
import Literal from './behavior-components/literal';
|
|
||||||
import EntityResourceController from './resource-controllers/entity';
|
|
||||||
|
|
||||||
export {default as fullEntity} from './full-entity';
|
|
||||||
|
|
||||||
export {
|
|
||||||
EntityResourceController,
|
|
||||||
Expression,
|
|
||||||
Expressions,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
hooks: {
|
|
||||||
'@latus/core/starting': async (latus) => {
|
|
||||||
const TraitRenderers = latus.invokeReduce('@persea/entity/trait-components');
|
|
||||||
latus.set('%trait-components', TraitRenderers);
|
|
||||||
latus.set('%behavior-controllers', {
|
|
||||||
condition: Condition,
|
|
||||||
expression: Expression,
|
|
||||||
expressions: Expressions,
|
|
||||||
literal: Literal,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'@persea/core/resource-controllers': () => [
|
|
||||||
EntityResourceController,
|
|
||||||
],
|
|
||||||
'@persea/entity/trait-components': () => {
|
|
||||||
const context = require.context('./trait-components', false, /\.jsx$/);
|
|
||||||
return context.keys().reduce((r, key) => ({
|
|
||||||
...r,
|
|
||||||
[camelCase(basename(key, extname(key)))]: context(key).default,
|
|
||||||
}), {});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,142 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useEffect,
|
|
||||||
useLatus,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {
|
|
||||||
useUri,
|
|
||||||
} from '@persea/core';
|
|
||||||
import {
|
|
||||||
JsonResourceController,
|
|
||||||
} from '@persea/json';
|
|
||||||
import {
|
|
||||||
Tab,
|
|
||||||
Tabs,
|
|
||||||
TabList,
|
|
||||||
TabPanel,
|
|
||||||
} from 'react-tabs';
|
|
||||||
|
|
||||||
import Traits from './traits';
|
|
||||||
import View from './view';
|
|
||||||
|
|
||||||
const EntityComponent = ({
|
|
||||||
resource,
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const uri = useUri();
|
|
||||||
const {Entity, EntityList} = latus.get('%resources');
|
|
||||||
const [entity, setEntity] = useState();
|
|
||||||
useEffect(() => {
|
|
||||||
setEntity();
|
|
||||||
const loadEntity = async () => {
|
|
||||||
const entity = await Entity.load(resource);
|
|
||||||
entity.list = new EntityList();
|
|
||||||
setEntity(entity);
|
|
||||||
};
|
|
||||||
loadEntity();
|
|
||||||
return () => {
|
|
||||||
if (entity) {
|
|
||||||
entity.destroy();
|
|
||||||
}
|
|
||||||
setEntity();
|
|
||||||
};
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [Entity, join(uri, path)]);
|
|
||||||
useEffect(() => {
|
|
||||||
const load = async () => {
|
|
||||||
await entity?.load(resource);
|
|
||||||
};
|
|
||||||
load();
|
|
||||||
}, [Entity, entity, resource]);
|
|
||||||
if (!entity) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="entity-renderer">
|
|
||||||
<Tabs>
|
|
||||||
<div className="entity-renderer__workspacePanes">
|
|
||||||
<TabPanel>
|
|
||||||
<Traits
|
|
||||||
entity={entity}
|
|
||||||
json={resource.traits}
|
|
||||||
path={join(path, '/traits')}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
<TabPanel>
|
|
||||||
<View entity={entity} />
|
|
||||||
</TabPanel>
|
|
||||||
</div>
|
|
||||||
<div className="entity-renderer__workspaceTabs">
|
|
||||||
<TabList>
|
|
||||||
<Tab>Traits</Tab>
|
|
||||||
<Tab>View</Tab>
|
|
||||||
</TabList>
|
|
||||||
</div>
|
|
||||||
</Tabs>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
EntityComponent.defaultProps = {
|
|
||||||
path: '/',
|
|
||||||
};
|
|
||||||
|
|
||||||
EntityComponent.displayName = 'EntityComponent';
|
|
||||||
|
|
||||||
EntityComponent.propTypes = {
|
|
||||||
resource: PropTypes.shape({
|
|
||||||
traits: PropTypes.shape({}),
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class EntityController extends JsonResourceController {
|
|
||||||
|
|
||||||
static Component({
|
|
||||||
resource,
|
|
||||||
path,
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<EntityComponent
|
|
||||||
resource={resource}
|
|
||||||
path={path}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static decode(encoded, latus) {
|
|
||||||
const {Entity} = latus.get('%resources');
|
|
||||||
const json = Entity.withoutDefaults(encoded);
|
|
||||||
return super.decode({
|
|
||||||
...json,
|
|
||||||
traits: Object.fromEntries(
|
|
||||||
Object.entries(json.traits)
|
|
||||||
.sort(([l], [r]) => (l < r ? -1 : 1)),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static encode(buffer, latus) {
|
|
||||||
const {Entity} = latus.get('%resources');
|
|
||||||
const json = Entity.withDefaults(super.encode(buffer));
|
|
||||||
return {
|
|
||||||
...json,
|
|
||||||
traits: Object.fromEntries(
|
|
||||||
Object.entries(json.traits)
|
|
||||||
.sort(([l], [r]) => (l < r ? -1 : 1)),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static get matcher() {
|
|
||||||
return /\.entity\.json$/;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
@import '~react-tabs/style/react-tabs.scss';
|
|
||||||
|
|
||||||
.entity-renderer {
|
|
||||||
height: 100%;
|
|
||||||
> .react-tabs {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.entity-renderer__workspacePanes {
|
|
||||||
flex-grow: 1;
|
|
||||||
min-height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
> .react-tabs__tab-panel {
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.entity-renderer__workspaceTabs {
|
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
|
||||||
text-orientation: mixed;
|
|
||||||
writing-mode: vertical-rl;
|
|
||||||
.react-tabs__tab {
|
|
||||||
border-left: none;
|
|
||||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
.react-tabs__tab-panel {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {Rectangle, Vector} from '@avocado/math';
|
|
||||||
import {Stage} from '@avocado/react';
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useEffect,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
const EntityStage = ({entity}) => {
|
|
||||||
const [size, setSize] = useState([0, 0]);
|
|
||||||
useEffect(() => {
|
|
||||||
if (!entity) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
entity.tick(0);
|
|
||||||
const size = Vector.add([64, 64], Vector.scale(Rectangle.size(entity.visibleAabb), 8));
|
|
||||||
setSize(size);
|
|
||||||
entity.setPosition(Vector.scale(size, 0.5));
|
|
||||||
}, [entity]);
|
|
||||||
return (
|
|
||||||
<div className="entity-stage">
|
|
||||||
<Stage
|
|
||||||
renderable={entity.container}
|
|
||||||
size={size}
|
|
||||||
ticker={(elapsed) => {
|
|
||||||
entity.tick(elapsed);
|
|
||||||
entity.renderTick();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
EntityStage.displayName = 'EntityStage';
|
|
||||||
|
|
||||||
EntityStage.propTypes = {
|
|
||||||
entity: PropTypes.shape({
|
|
||||||
container: PropTypes.shape({}),
|
|
||||||
renderTick: PropTypes.func,
|
|
||||||
setPosition: PropTypes.func,
|
|
||||||
tick: PropTypes.func,
|
|
||||||
visibleAabb: PropTypes.arrayOf(PropTypes.number),
|
|
||||||
}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EntityStage;
|
|
|
@ -1,151 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useLatus,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {Modal} from '@persea/core';
|
|
||||||
import {JsonResourceController, useJsonPatcher} from '@persea/json';
|
|
||||||
import difference from 'lodash.difference';
|
|
||||||
import {
|
|
||||||
Tab,
|
|
||||||
Tabs,
|
|
||||||
TabList,
|
|
||||||
TabPanel,
|
|
||||||
} from 'react-tabs';
|
|
||||||
|
|
||||||
import Suggest from './suggest';
|
|
||||||
|
|
||||||
const NoTraitRenderer = ({path, json}) => (
|
|
||||||
<JsonResourceController.Component path={path} resource={json} />
|
|
||||||
);
|
|
||||||
|
|
||||||
NoTraitRenderer.displayName = 'NoTraitRenderer';
|
|
||||||
|
|
||||||
NoTraitRenderer.propTypes = {
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
json: PropTypes.shape({}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
const Traits = ({
|
|
||||||
entity,
|
|
||||||
json,
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const buttonRef = useRef();
|
|
||||||
const latus = useLatus();
|
|
||||||
const [isSelecting, setIsSelecting] = useState(false);
|
|
||||||
const types = Object.keys(json).sort((l, r) => (l < r ? -1 : 1));
|
|
||||||
const tabs = types.map((type) => (
|
|
||||||
<Tab key={type}>
|
|
||||||
{type}
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="traits__tab-close"
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: join(path, type),
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
✕
|
|
||||||
</button>
|
|
||||||
</Tab>
|
|
||||||
));
|
|
||||||
const Traits = latus.get('%traits');
|
|
||||||
const suggestible = difference(
|
|
||||||
Object.entries(Traits)
|
|
||||||
.filter(([key]) => !Number.isInteger(parseInt(key, 10)))
|
|
||||||
.map(([, {type}]) => type),
|
|
||||||
types,
|
|
||||||
);
|
|
||||||
const TraitRenderers = latus.get('%trait-components');
|
|
||||||
const tabPanels = types.map((type) => {
|
|
||||||
const TraitRenderer = TraitRenderers[type]
|
|
||||||
? TraitRenderers[type]
|
|
||||||
: NoTraitRenderer;
|
|
||||||
return (
|
|
||||||
<TabPanel key={type}>
|
|
||||||
<TraitRenderer
|
|
||||||
entity={entity}
|
|
||||||
json={json[type]}
|
|
||||||
path={join(path, type)}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<div className="traits">
|
|
||||||
<Tabs>
|
|
||||||
<div className="traits__tab-bar">
|
|
||||||
<button
|
|
||||||
className="traits__add-trait"
|
|
||||||
onClick={() => {
|
|
||||||
if (suggestible.length > 0) {
|
|
||||||
setIsSelecting(true);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
ref={buttonRef}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
+
|
|
||||||
</button>
|
|
||||||
<Modal
|
|
||||||
style={{
|
|
||||||
content: {
|
|
||||||
top: buttonRef.current
|
|
||||||
? `${buttonRef.current.getBoundingClientRect().top}px`
|
|
||||||
: 0,
|
|
||||||
left: buttonRef.current
|
|
||||||
? `${buttonRef.current.getBoundingClientRect().left}px`
|
|
||||||
: 0,
|
|
||||||
bottom: 'auto',
|
|
||||||
padding: '0.5em',
|
|
||||||
right: 'auto',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
isOpen={isSelecting}
|
|
||||||
onRequestClose={() => {
|
|
||||||
setIsSelecting(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Suggest
|
|
||||||
onChange={(event, type) => {
|
|
||||||
setIsSelecting(false);
|
|
||||||
patch({
|
|
||||||
path: join(path, type),
|
|
||||||
value: Traits[type].withDefaults({}),
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
types={suggestible}
|
|
||||||
/>
|
|
||||||
</Modal>
|
|
||||||
<TabList>
|
|
||||||
{tabs}
|
|
||||||
</TabList>
|
|
||||||
</div>
|
|
||||||
<div className="traits__tab-panes">
|
|
||||||
{tabPanels}
|
|
||||||
</div>
|
|
||||||
</Tabs>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Traits.displayName = 'Traits';
|
|
||||||
|
|
||||||
Traits.propTypes = {
|
|
||||||
entity: PropTypes.shape({}).isRequired,
|
|
||||||
json: PropTypes.shape({}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Traits;
|
|
|
@ -1,37 +0,0 @@
|
||||||
.traits {
|
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 1em;
|
|
||||||
> .react-tabs {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.react-tabs__tab-list {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.traits__tab-bar {
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.traits__tab-panes {
|
|
||||||
flex-shrink: 999;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.traits__add-trait {
|
|
||||||
background-color: #171717;
|
|
||||||
border: none;
|
|
||||||
margin: 0;
|
|
||||||
margin-right: 1em;
|
|
||||||
min-width: 2.5em;
|
|
||||||
height: 2.5em;
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useEffect,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
import Autosuggest from 'react-autosuggest';
|
|
||||||
|
|
||||||
const Suggest = ({
|
|
||||||
onChange,
|
|
||||||
types,
|
|
||||||
}) => {
|
|
||||||
const ref = useRef();
|
|
||||||
useEffect(() => {
|
|
||||||
if (ref.current) {
|
|
||||||
ref.current.focus();
|
|
||||||
}
|
|
||||||
}, [ref]);
|
|
||||||
const [suggestions, setSuggestions] = useState([]);
|
|
||||||
const [typed, setTyped] = useState('');
|
|
||||||
const calculateSuggestions = (value) => {
|
|
||||||
const inputValue = value.trim().toLowerCase();
|
|
||||||
return '' === inputValue
|
|
||||||
? types
|
|
||||||
: types
|
|
||||||
.filter((type) => type.toLowerCase().includes(inputValue))
|
|
||||||
.map((type) => ({type}));
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className="traits-suggestor">
|
|
||||||
<Autosuggest
|
|
||||||
suggestions={suggestions}
|
|
||||||
onSuggestionsFetchRequested={({value}) => {
|
|
||||||
setSuggestions(calculateSuggestions(value));
|
|
||||||
}}
|
|
||||||
onSuggestionsClearRequested={() => {
|
|
||||||
setSuggestions([]);
|
|
||||||
}}
|
|
||||||
getSuggestionValue={({type}) => type}
|
|
||||||
renderSuggestion={({type}) => (
|
|
||||||
<div>{type}</div>
|
|
||||||
)}
|
|
||||||
inputProps={{
|
|
||||||
onChange: (event, {newValue}) => {
|
|
||||||
const {target: {value}} = event;
|
|
||||||
if (!value) {
|
|
||||||
onChange(event, newValue);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setTyped(event.target.value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ref,
|
|
||||||
value: typed,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Suggest.displayName = 'Suggest';
|
|
||||||
|
|
||||||
Suggest.propTypes = {
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
types: PropTypes.arrayOf(PropTypes.string).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Suggest;
|
|
|
@ -1,37 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
import EntityStage from '../stage';
|
|
||||||
|
|
||||||
const View = ({entity}) => {
|
|
||||||
let output;
|
|
||||||
if (!entity.is('Visible')) {
|
|
||||||
output = (
|
|
||||||
<p className="entity-view__not-visible">
|
|
||||||
This entity isn't graphically visible.
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
output = <EntityStage entity={entity} />;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="entity-view">
|
|
||||||
{output}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
View.displayName = 'View';
|
|
||||||
|
|
||||||
View.propTypes = {
|
|
||||||
entity: PropTypes.shape({
|
|
||||||
is: PropTypes.func,
|
|
||||||
}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default View;
|
|
|
@ -1,17 +0,0 @@
|
||||||
.entity-view {
|
|
||||||
height: 100%;
|
|
||||||
padding: 1em;
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
.entity-stage {
|
|
||||||
display: inline-block;
|
|
||||||
left: 50%;
|
|
||||||
line-height: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
canvas {
|
|
||||||
image-rendering: pixelated;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
import './alive.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {Context} from '@avocado/behavior';
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useEffect,
|
|
||||||
useLatus,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {Number} from '@persea/core';
|
|
||||||
import {useJsonPatcher} from '@persea/json';
|
|
||||||
|
|
||||||
import Condition from '../behavior-components/condition';
|
|
||||||
import Expressions from '../behavior-components/expressions';
|
|
||||||
|
|
||||||
const Alive = ({
|
|
||||||
entity,
|
|
||||||
json,
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const createContextWithEntity = () => (
|
|
||||||
new Context(
|
|
||||||
{
|
|
||||||
entity,
|
|
||||||
},
|
|
||||||
latus,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const [context, setContext] = useState(createContextWithEntity(entity));
|
|
||||||
useEffect(() => {
|
|
||||||
setContext(createContextWithEntity(entity));
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [entity]);
|
|
||||||
return (
|
|
||||||
<div className="alive">
|
|
||||||
<div className="label">
|
|
||||||
<div className="vertical">Death actions</div>
|
|
||||||
<Expressions
|
|
||||||
context={context}
|
|
||||||
value={json.params.deathActions}
|
|
||||||
path={join(path, 'params/deathActions')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="label">
|
|
||||||
<div>Death condition</div>
|
|
||||||
<Condition
|
|
||||||
context={context}
|
|
||||||
value={json.params.deathCondition}
|
|
||||||
path={join(path, 'params/deathCondition')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<label>
|
|
||||||
Life
|
|
||||||
<div className="alive__life">
|
|
||||||
<Number
|
|
||||||
onChange={patch.onChange(join(path, 'state/life'))}
|
|
||||||
value={json.state.life}
|
|
||||||
/>
|
|
||||||
<div className="alive__life-separator">/</div>
|
|
||||||
<Number
|
|
||||||
onChange={patch.onChange(join(path, 'state/maxLife'))}
|
|
||||||
value={json.state.maxLife}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Alive.displayName = 'Alive';
|
|
||||||
|
|
||||||
Alive.propTypes = {
|
|
||||||
entity: PropTypes.shape({
|
|
||||||
context: PropTypes.shape({}),
|
|
||||||
}).isRequired,
|
|
||||||
json: PropTypes.shape({
|
|
||||||
params: PropTypes.shape({
|
|
||||||
deathActions: PropTypes.shape({
|
|
||||||
expressions: PropTypes.arrayOf(PropTypes.shape({})),
|
|
||||||
}),
|
|
||||||
deathCondition: PropTypes.shape({}),
|
|
||||||
}),
|
|
||||||
state: PropTypes.shape({
|
|
||||||
life: PropTypes.number,
|
|
||||||
maxLife: PropTypes.number,
|
|
||||||
}),
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Alive;
|
|
|
@ -1,8 +0,0 @@
|
||||||
.alive__life {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alive__life-separator {
|
|
||||||
padding: 0 0.5em;
|
|
||||||
}
|
|
|
@ -1,168 +0,0 @@
|
||||||
import './behaved.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {
|
|
||||||
Number,
|
|
||||||
} from '@persea/core';
|
|
||||||
import {
|
|
||||||
JsonTabs,
|
|
||||||
useJsonPatcher,
|
|
||||||
} from '@persea/json';
|
|
||||||
import {
|
|
||||||
Tab,
|
|
||||||
Tabs,
|
|
||||||
TabList,
|
|
||||||
TabPanel,
|
|
||||||
} from 'react-tabs';
|
|
||||||
|
|
||||||
import Expression from '../behavior-components/expression';
|
|
||||||
import Expressions from '../behavior-components/expressions';
|
|
||||||
|
|
||||||
const Behaved = ({
|
|
||||||
entity,
|
|
||||||
json,
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
return (
|
|
||||||
<div className="behaved">
|
|
||||||
<Tabs>
|
|
||||||
<TabList>
|
|
||||||
<Tab>Daemons</Tab>
|
|
||||||
<Tab>Routines</Tab>
|
|
||||||
<Tab>Collectives</Tab>
|
|
||||||
</TabList>
|
|
||||||
<div className="behaved__tab-panels">
|
|
||||||
<TabPanel>
|
|
||||||
<JsonTabs
|
|
||||||
createPanel={(expressions, key) => (
|
|
||||||
<Expressions
|
|
||||||
context={entity.context}
|
|
||||||
value={expressions}
|
|
||||||
path={join(path, 'params/daemons', key)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
defaultValue={{
|
|
||||||
type: 'expressions',
|
|
||||||
expressions: [],
|
|
||||||
}}
|
|
||||||
path={join(path, 'params/daemons')}
|
|
||||||
map={json.params.daemons}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
<TabPanel>
|
|
||||||
<JsonTabs
|
|
||||||
createPanel={(expressions, key) => (
|
|
||||||
<Expressions
|
|
||||||
context={entity.context}
|
|
||||||
value={expressions}
|
|
||||||
path={join(path, 'params/routines', key)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
defaultValue={{
|
|
||||||
type: 'expressions',
|
|
||||||
expressions: [],
|
|
||||||
}}
|
|
||||||
path={join(path, 'params/routines')}
|
|
||||||
map={json.params.routines}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
<TabPanel>
|
|
||||||
<JsonTabs
|
|
||||||
createPanel={(
|
|
||||||
{
|
|
||||||
find,
|
|
||||||
max,
|
|
||||||
reset,
|
|
||||||
threshold,
|
|
||||||
},
|
|
||||||
key,
|
|
||||||
) => (
|
|
||||||
<>
|
|
||||||
<div className="label">
|
|
||||||
<div className="vertical">Find</div>
|
|
||||||
<Expression
|
|
||||||
context={entity.context}
|
|
||||||
value={find}
|
|
||||||
path={join(path, 'params/collectives', key, 'find')}
|
|
||||||
type="array"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="label">
|
|
||||||
<div className="vertical">Reset</div>
|
|
||||||
<Expressions
|
|
||||||
context={entity.context}
|
|
||||||
value={reset}
|
|
||||||
path={join(path, 'params/collectives', key, 'reset')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="label">
|
|
||||||
<div>Threshold</div>
|
|
||||||
<Number
|
|
||||||
onChange={patch.onChange(join(path, 'params/collectives', key, 'threshold'))}
|
|
||||||
value={threshold}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="label">
|
|
||||||
<div>Max</div>
|
|
||||||
<Number
|
|
||||||
onChange={patch.onChange(join(path, 'params/collectives', key, 'max'))}
|
|
||||||
value={max}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
defaultValue={{
|
|
||||||
find: {
|
|
||||||
type: 'expression',
|
|
||||||
ops: [
|
|
||||||
{
|
|
||||||
type: 'key',
|
|
||||||
key: 'entity',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'key',
|
|
||||||
key: 'list',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
max: 128,
|
|
||||||
reset: {
|
|
||||||
type: 'expressions',
|
|
||||||
expressions: [],
|
|
||||||
},
|
|
||||||
threshold: 1,
|
|
||||||
}}
|
|
||||||
path={join(path, 'params/collectives')}
|
|
||||||
map={json.params.collectives}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
</div>
|
|
||||||
</Tabs>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Behaved.displayName = 'Behaved';
|
|
||||||
|
|
||||||
Behaved.propTypes = {
|
|
||||||
entity: PropTypes.shape({
|
|
||||||
context: PropTypes.shape({}),
|
|
||||||
}).isRequired,
|
|
||||||
json: PropTypes.shape({
|
|
||||||
params: PropTypes.shape({
|
|
||||||
collectives: PropTypes.shape({}),
|
|
||||||
daemons: PropTypes.shape({}),
|
|
||||||
routines: PropTypes.shape({}),
|
|
||||||
}),
|
|
||||||
state: PropTypes.shape({}),
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Behaved;
|
|
|
@ -1,9 +0,0 @@
|
||||||
.behaved__routines-tab-bar {
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.behaved__tab-panels > .react-tabs__tab-panel{
|
|
||||||
padding-top: 1em;
|
|
||||||
}
|
|
|
@ -1,148 +0,0 @@
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Context,
|
|
||||||
} from '@avocado/behavior';
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useEffect,
|
|
||||||
useLatus,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {
|
|
||||||
JsonComponent,
|
|
||||||
useJsonPatcher,
|
|
||||||
} from '@persea/json';
|
|
||||||
|
|
||||||
import Expressions from '../behavior-components/expressions';
|
|
||||||
import fullEntity from '../full-entity';
|
|
||||||
|
|
||||||
const Collider = ({
|
|
||||||
entity,
|
|
||||||
json,
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const [context, setContext] = useState();
|
|
||||||
useEffect(() => {
|
|
||||||
const createContext = async () => {
|
|
||||||
const context = new Context(
|
|
||||||
{
|
|
||||||
entity,
|
|
||||||
incident: [0, 0],
|
|
||||||
other: await fullEntity(latus),
|
|
||||||
},
|
|
||||||
latus,
|
|
||||||
);
|
|
||||||
setContext(context);
|
|
||||||
};
|
|
||||||
createContext();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [entity]);
|
|
||||||
return (
|
|
||||||
<div className="collider">
|
|
||||||
<div className="label">
|
|
||||||
Collides with groups
|
|
||||||
<JsonComponent
|
|
||||||
onChange={patch.onChange(join(path, 'params/collidesWithGroups'))}
|
|
||||||
json={json.params.collidesWithGroups}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="label">
|
|
||||||
<div className="vertical">Collision start</div>
|
|
||||||
{context && (
|
|
||||||
<Expressions
|
|
||||||
context={context}
|
|
||||||
value={json.params.collisionStartActions}
|
|
||||||
path={join(path, 'params/collisionStartActions')}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="label">
|
|
||||||
<div className="vertical">Collision end</div>
|
|
||||||
{context && (
|
|
||||||
<Expressions
|
|
||||||
context={context}
|
|
||||||
value={json.params.collisionEndActions}
|
|
||||||
path={join(path, 'params/collisionEndActions')}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="label">
|
|
||||||
Active collision
|
|
||||||
{json.params.activeCollision ? '' : '?'}
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={json.params.activeCollision}
|
|
||||||
onChange={patch.onChange(join(path, 'params/activeCollision'), 'checked')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="label">
|
|
||||||
Collision group
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
onChange={patch.onChange(join(path, 'params/collisionGroup'))}
|
|
||||||
value={json.params.collisionGroup}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="label">
|
|
||||||
Is sensor
|
|
||||||
{json.params.isSensor ? '' : '?'}
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={json.params.isSensor}
|
|
||||||
onChange={patch.onChange(join(path, 'params/isSensor'), 'checked')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="label">
|
|
||||||
Is checking collisions
|
|
||||||
{json.state.isCheckingCollisions ? '' : '?'}
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={json.state.isCheckingCollisions}
|
|
||||||
onChange={patch.onChange(join(path, 'state/isCheckingCollisions'), 'checked')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="label">
|
|
||||||
Is colliding
|
|
||||||
{json.state.isColliding ? '' : '?'}
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={json.state.isColliding}
|
|
||||||
onChange={patch.onChange(join(path, 'state/isColliding'), 'checked')}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Collider.defaultProps = {};
|
|
||||||
|
|
||||||
Collider.displayName = 'Collider';
|
|
||||||
|
|
||||||
Collider.propTypes = {
|
|
||||||
entity: PropTypes.shape({
|
|
||||||
context: PropTypes.shape({}),
|
|
||||||
}).isRequired,
|
|
||||||
json: PropTypes.shape({
|
|
||||||
params: PropTypes.shape({
|
|
||||||
activeCollision: PropTypes.bool,
|
|
||||||
collidesWithGroups: PropTypes.arrayOf(
|
|
||||||
PropTypes.string,
|
|
||||||
),
|
|
||||||
collisionEndActions: PropTypes.shape({}),
|
|
||||||
collisionStartActions: PropTypes.shape({}),
|
|
||||||
collisionGroup: PropTypes.string,
|
|
||||||
isSensor: PropTypes.bool,
|
|
||||||
}),
|
|
||||||
state: PropTypes.shape({
|
|
||||||
isCheckingCollisions: PropTypes.bool,
|
|
||||||
isColliding: PropTypes.bool,
|
|
||||||
}),
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Collider;
|
|
|
@ -1,71 +0,0 @@
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {PropTypes, React} from '@latus/react';
|
|
||||||
import {
|
|
||||||
Number,
|
|
||||||
} from '@persea/core';
|
|
||||||
import {useJsonPatcher} from '@persea/json';
|
|
||||||
|
|
||||||
const Directional = ({json, path}) => {
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
return (
|
|
||||||
<div className="directional">
|
|
||||||
<label>
|
|
||||||
Direction count
|
|
||||||
<select
|
|
||||||
onChange={(event) => {
|
|
||||||
const value = parseInt(event.target.value, 10);
|
|
||||||
patch.onChange(join(path, 'params/directionCount'))(event, value);
|
|
||||||
}}
|
|
||||||
value={json.params.directionCount}
|
|
||||||
>
|
|
||||||
<option value={1}>Unidirectional</option>
|
|
||||||
<option value={4}>4-direction</option>
|
|
||||||
<option value={8}>8-direction</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Track movement
|
|
||||||
{json.params.trackMovement ? '' : '?'}
|
|
||||||
<input
|
|
||||||
onChange={patch.onChange(join(path, 'params/trackMovement'), 'checked')}
|
|
||||||
checked={json.params.trackMovement}
|
|
||||||
type="checkbox"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Direction
|
|
||||||
<Number
|
|
||||||
integer
|
|
||||||
min={0}
|
|
||||||
max={json.params.directionCount - 1}
|
|
||||||
onChange={patch.onChange(join(path, 'state/direction'))}
|
|
||||||
value={json.state.direction}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Directional.defaultProps = {};
|
|
||||||
|
|
||||||
Directional.displayName = 'Directional';
|
|
||||||
|
|
||||||
Directional.propTypes = {
|
|
||||||
entity: PropTypes.shape({
|
|
||||||
context: PropTypes.shape({}),
|
|
||||||
}).isRequired,
|
|
||||||
json: PropTypes.shape({
|
|
||||||
params: PropTypes.shape({
|
|
||||||
directionCount: PropTypes.number,
|
|
||||||
trackMovement: PropTypes.bool,
|
|
||||||
}),
|
|
||||||
state: PropTypes.shape({
|
|
||||||
direction: PropTypes.number,
|
|
||||||
}),
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
Directional.propTypes = {};
|
|
||||||
|
|
||||||
export default Directional;
|
|
|
@ -1,182 +0,0 @@
|
||||||
import './emitted.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {
|
|
||||||
memo,
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {
|
|
||||||
Number,
|
|
||||||
Range,
|
|
||||||
rangePropType,
|
|
||||||
VectorRange,
|
|
||||||
vectorRangePropType,
|
|
||||||
} from '@persea/core';
|
|
||||||
import {useJsonPatcher} from '@persea/json';
|
|
||||||
|
|
||||||
const Emitted = memo(({json, path}) => {
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const [hasSelfPosition, setHasSelfPosition] = useState(null !== json.params.position);
|
|
||||||
return (
|
|
||||||
<div className="emitted">
|
|
||||||
<label>
|
|
||||||
<span className="grow">Alpha</span>
|
|
||||||
<label>
|
|
||||||
Start
|
|
||||||
<Range
|
|
||||||
onChange={patch.onChange(join(path, 'params/alpha/start'))}
|
|
||||||
range={json.params.alpha.start}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
End
|
|
||||||
<Range
|
|
||||||
onChange={patch.onChange(join(path, 'params/alpha/end'))}
|
|
||||||
range={json.params.alpha.end}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Force
|
|
||||||
<VectorRange
|
|
||||||
onChange={patch.onChange(join(path, 'params/force'))}
|
|
||||||
range={json.params.force}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Mass
|
|
||||||
<Number
|
|
||||||
onChange={patch.onChange(join(path, 'params/mass'))}
|
|
||||||
value={json.params.mass}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<span className="grow">Position</span>
|
|
||||||
<label>
|
|
||||||
Use emitter's position
|
|
||||||
{hasSelfPosition ? '?' : ''}
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={!hasSelfPosition}
|
|
||||||
onChange={(event) => {
|
|
||||||
const hasSelfPosition = !event.target.checked;
|
|
||||||
patch({
|
|
||||||
path: join(path, 'params/position'),
|
|
||||||
value: hasSelfPosition ? [0, 0] : null,
|
|
||||||
});
|
|
||||||
setHasSelfPosition(hasSelfPosition);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
{hasSelfPosition && (
|
|
||||||
<VectorRange
|
|
||||||
onChange={patch.onChange(join(path, 'params/position'))}
|
|
||||||
range={json.params.position}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Starting rotation
|
|
||||||
<Range
|
|
||||||
onChange={patch.onChange(join(path, 'params/rotation/start'))}
|
|
||||||
range={json.params.rotation.start}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Rotation to add
|
|
||||||
<Range
|
|
||||||
onChange={patch.onChange(join(path, 'params/rotation/add'))}
|
|
||||||
range={json.params.rotation.add}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<span className="grow">Scale</span>
|
|
||||||
<label>
|
|
||||||
Start
|
|
||||||
<Range
|
|
||||||
onChange={patch.onChange(join(path, 'params/scale/start'))}
|
|
||||||
range={json.params.scale.start}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
End
|
|
||||||
<Range
|
|
||||||
onChange={patch.onChange(join(path, 'params/scale/end'))}
|
|
||||||
range={json.params.scale.end}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Transient
|
|
||||||
{json.params.transient ? '' : '?'}
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={json.params.transient}
|
|
||||||
onChange={patch.onChange(join(path, 'params/transient'), 'checked')}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Time-to-live
|
|
||||||
<Range
|
|
||||||
onChange={patch.onChange(join(path, 'params/ttl'))}
|
|
||||||
range={json.params.ttl}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<span className="grow">Velocity</span>
|
|
||||||
<label>
|
|
||||||
Angle
|
|
||||||
<Range
|
|
||||||
onChange={patch.onChange(join(path, 'params/velocity/angle'))}
|
|
||||||
range={json.params.velocity.angle}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Magnitude
|
|
||||||
<Range
|
|
||||||
onChange={patch.onChange(join(path, 'params/velocity/magnitude'))}
|
|
||||||
range={json.params.velocity.magnitude}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Emitted.displayName = 'Emitted';
|
|
||||||
|
|
||||||
Emitted.propTypes = {
|
|
||||||
json: PropTypes.shape({
|
|
||||||
params: PropTypes.shape({
|
|
||||||
alpha: PropTypes.shape({
|
|
||||||
start: rangePropType,
|
|
||||||
end: rangePropType,
|
|
||||||
}),
|
|
||||||
force: vectorRangePropType,
|
|
||||||
listed: PropTypes.bool,
|
|
||||||
mass: PropTypes.number,
|
|
||||||
// eslint-disable-next-line react/forbid-prop-types
|
|
||||||
position: PropTypes.any,
|
|
||||||
rotation: PropTypes.shape({
|
|
||||||
start: rangePropType,
|
|
||||||
add: rangePropType,
|
|
||||||
}),
|
|
||||||
scale: PropTypes.shape({
|
|
||||||
start: rangePropType,
|
|
||||||
end: rangePropType,
|
|
||||||
}),
|
|
||||||
transient: PropTypes.bool,
|
|
||||||
ttl: PropTypes.number,
|
|
||||||
velocity: PropTypes.shape({
|
|
||||||
angle: rangePropType,
|
|
||||||
magnitude: rangePropType,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Emitted;
|
|
|
@ -1,3 +0,0 @@
|
||||||
.emitted .grow {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {
|
|
||||||
memo,
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useLatus,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {
|
|
||||||
JsonTabs,
|
|
||||||
} from '@persea/json';
|
|
||||||
|
|
||||||
import Particle from './emitter/particle';
|
|
||||||
|
|
||||||
const Emitter = memo(({
|
|
||||||
entity,
|
|
||||||
json,
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const {Emitted} = latus.get('%traits');
|
|
||||||
return (
|
|
||||||
<div className="emitter">
|
|
||||||
<JsonTabs
|
|
||||||
createPanel={(particle, key) => (
|
|
||||||
<Particle
|
|
||||||
entity={entity}
|
|
||||||
key={key}
|
|
||||||
particle={particle}
|
|
||||||
path={join(path, 'params/particles', key)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
defaultValue={{
|
|
||||||
rate: 0,
|
|
||||||
count: 1,
|
|
||||||
traits: {
|
|
||||||
Emitted: Emitted.withDefaults({}),
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
path={join(path, 'params/particles')}
|
|
||||||
map={json.params.particles}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Emitter.displayName = 'Emitter';
|
|
||||||
|
|
||||||
Emitter.propTypes = {
|
|
||||||
entity: PropTypes.shape({}).isRequired,
|
|
||||||
json: PropTypes.shape({
|
|
||||||
params: PropTypes.shape({
|
|
||||||
particles: PropTypes.shape({}),
|
|
||||||
}),
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Emitter;
|
|
|
@ -1,89 +0,0 @@
|
||||||
import './particle.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {EntityListView} from '@avocado/entity';
|
|
||||||
import {Stage} from '@avocado/react';
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useLatus,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {Number} from '@persea/core';
|
|
||||||
import {useJsonPatcher} from '@persea/json';
|
|
||||||
|
|
||||||
import Entity from '../../resource-controllers/entity';
|
|
||||||
|
|
||||||
const Particle = ({
|
|
||||||
entity,
|
|
||||||
particle,
|
|
||||||
path,
|
|
||||||
}) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const {EntityList} = latus.get('%resources');
|
|
||||||
const entityList = new EntityList();
|
|
||||||
const entityListView = new EntityListView(entityList);
|
|
||||||
entityList.addEntity(entity);
|
|
||||||
return (
|
|
||||||
<div className="emitter__particle">
|
|
||||||
<div className="emitter__particle-controls">
|
|
||||||
<Stage
|
|
||||||
fps={60}
|
|
||||||
renderable={entityListView}
|
|
||||||
size={[200, 200]}
|
|
||||||
ticker={(elapsed) => {
|
|
||||||
entityList.tick(elapsed);
|
|
||||||
entityListView.renderTick(elapsed);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div className="emitter__particle-inputs">
|
|
||||||
<label>
|
|
||||||
Rate
|
|
||||||
<Number
|
|
||||||
value={particle.rate || 0}
|
|
||||||
onChange={patch.onChange(join(path, 'rate'))}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
Count
|
|
||||||
<Number
|
|
||||||
integer
|
|
||||||
min={1}
|
|
||||||
value={particle.count || 1}
|
|
||||||
onChange={patch.onChange(join(path, 'count'))}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
className="emitter__particle-emit"
|
|
||||||
type="button"
|
|
||||||
onClick={() => {
|
|
||||||
entity.emitParticleJson(particle);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Emit particles
|
|
||||||
</button>
|
|
||||||
<Entity.Component
|
|
||||||
resource={particle}
|
|
||||||
path={path}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Particle.displayName = 'Particle';
|
|
||||||
|
|
||||||
Particle.propTypes = {
|
|
||||||
entity: PropTypes.shape({
|
|
||||||
emitParticleJson: PropTypes.func,
|
|
||||||
}).isRequired,
|
|
||||||
particle: PropTypes.shape({
|
|
||||||
count: PropTypes.number,
|
|
||||||
rate: PropTypes.number,
|
|
||||||
}).isRequired,
|
|
||||||
path: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Particle;
|
|
|
@ -1,15 +0,0 @@
|
||||||
.emitter__particle-label {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emitter__particle-controls {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emitter__particle-inputs {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emitter__particle-emit {
|
|
||||||
margin: 0.5em;
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
import {expect} from 'chai';
|
|
||||||
|
|
||||||
it('exists', () => {
|
|
||||||
expect(true).to.be.true;
|
|
||||||
});
|
|
File diff suppressed because it is too large
Load Diff
7
packages/json/.gitignore
vendored
7
packages/json/.gitignore
vendored
|
@ -1,7 +0,0 @@
|
||||||
**/*.js
|
|
||||||
**/*.map
|
|
||||||
!/.*
|
|
||||||
!/postcss.config.js
|
|
||||||
!/webpack.config.js
|
|
||||||
!src/**/*.js
|
|
||||||
!/test/**/*.js
|
|
|
@ -1,35 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@persea/json",
|
|
||||||
"version": "3.0.0",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"build": "latus-build",
|
|
||||||
"clean": "latus-build clean",
|
|
||||||
"fp": "latus-build forcepublish",
|
|
||||||
"lint": "latus-build lint",
|
|
||||||
"test": "latus-build test"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"index.js",
|
|
||||||
"index.js.map",
|
|
||||||
"server.js",
|
|
||||||
"server.js.map",
|
|
||||||
"test.js",
|
|
||||||
"test.js.map"
|
|
||||||
],
|
|
||||||
"dependencies": {
|
|
||||||
"@avocado/resource": "^2.0.0",
|
|
||||||
"@latus/core": "^2.0.0",
|
|
||||||
"@latus/react": "^2.0.0",
|
|
||||||
"@latus/redux": "^2.0.0",
|
|
||||||
"@persea/core": "^1.0.0",
|
|
||||||
"autoprefixer": "^9.8.6",
|
|
||||||
"debug": "4.3.1",
|
|
||||||
"fast-json-patch": "^3.0.0-1",
|
|
||||||
"react-json-editor-ajrm": "^2.5.13",
|
|
||||||
"react-tabs": "^3.1.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@latus/build": "1.x"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,167 +0,0 @@
|
||||||
import './index.scss';
|
|
||||||
|
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useEffect,
|
|
||||||
usePrevious,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
import {
|
|
||||||
Tab,
|
|
||||||
Tabs,
|
|
||||||
TabList,
|
|
||||||
TabPanel,
|
|
||||||
} from 'react-tabs';
|
|
||||||
|
|
||||||
import useJsonPatcher from '../../hooks/use-json-patcher';
|
|
||||||
|
|
||||||
const JsonTabs = ({
|
|
||||||
createPanel,
|
|
||||||
defaultValue,
|
|
||||||
immutable,
|
|
||||||
path,
|
|
||||||
map,
|
|
||||||
}) => {
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
const editingRef = useRef();
|
|
||||||
useEffect(() => {
|
|
||||||
editingRef.current?.focus();
|
|
||||||
});
|
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
|
||||||
const previousEditing = usePrevious(isEditing);
|
|
||||||
const [previousKey, setPreviousKey] = useState(false);
|
|
||||||
useEffect(() => {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (false === previousEditing) {
|
|
||||||
editingRef.current?.select();
|
|
||||||
}
|
|
||||||
}, 10);
|
|
||||||
}, [editingRef, isEditing, previousEditing]);
|
|
||||||
const tabs = [];
|
|
||||||
const tabPanels = [];
|
|
||||||
Object.entries(map).forEach(([key, value]) => {
|
|
||||||
const confirmEdit = () => {
|
|
||||||
if (isEditing && previousKey !== isEditing) {
|
|
||||||
patch({
|
|
||||||
op: 'move',
|
|
||||||
from: join(path, previousKey),
|
|
||||||
path: join(path, isEditing),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setIsEditing(false);
|
|
||||||
setPreviousKey(false);
|
|
||||||
};
|
|
||||||
tabs.push(
|
|
||||||
<Tab
|
|
||||||
key={key}
|
|
||||||
onDoubleClick={() => {
|
|
||||||
setPreviousKey(key);
|
|
||||||
setIsEditing(key);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
key === previousKey
|
|
||||||
? (
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={isEditing}
|
|
||||||
onBlur={confirmEdit}
|
|
||||||
onChange={({target: {value}}) => {
|
|
||||||
setPreviousKey(key);
|
|
||||||
setIsEditing(value);
|
|
||||||
}}
|
|
||||||
onKeyPress={({key}) => {
|
|
||||||
if ('Enter' === key) {
|
|
||||||
confirmEdit();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
ref={editingRef}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
: key
|
|
||||||
}
|
|
||||||
{!immutable && (
|
|
||||||
<>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="json-tabs__remove"
|
|
||||||
onClick={() => {
|
|
||||||
patch({
|
|
||||||
op: 'remove',
|
|
||||||
path: join(path, key),
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
✕
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Tab>,
|
|
||||||
);
|
|
||||||
tabPanels.push(
|
|
||||||
<TabPanel key={key}>
|
|
||||||
{createPanel(value, key)}
|
|
||||||
</TabPanel>,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<div className="json-tabs">
|
|
||||||
<Tabs>
|
|
||||||
<div className="json-tabs__bar">
|
|
||||||
{(!immutable && 'undefined' !== typeof defaultValue) && (
|
|
||||||
<button
|
|
||||||
className="json-tabs__add"
|
|
||||||
onClick={() => {
|
|
||||||
let i = 1;
|
|
||||||
let key = 'untitled';
|
|
||||||
while (map[key]) {
|
|
||||||
key = `untitled (${i++})`;
|
|
||||||
}
|
|
||||||
patch({
|
|
||||||
op: 'add',
|
|
||||||
path: join(path, key),
|
|
||||||
value: defaultValue,
|
|
||||||
});
|
|
||||||
setIsEditing(key);
|
|
||||||
setPreviousKey(key);
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
+
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<TabList>
|
|
||||||
{tabs}
|
|
||||||
</TabList>
|
|
||||||
</div>
|
|
||||||
<div className="json-tabs__panes">
|
|
||||||
{tabPanels}
|
|
||||||
</div>
|
|
||||||
</Tabs>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
JsonTabs.defaultProps = {
|
|
||||||
defaultValue: undefined,
|
|
||||||
immutable: false,
|
|
||||||
path: '/',
|
|
||||||
};
|
|
||||||
|
|
||||||
JsonTabs.displayName = 'JsonTabs';
|
|
||||||
|
|
||||||
JsonTabs.propTypes = {
|
|
||||||
createPanel: PropTypes.func.isRequired,
|
|
||||||
// eslint-disable-next-line react/forbid-prop-types
|
|
||||||
defaultValue: PropTypes.any,
|
|
||||||
immutable: PropTypes.bool,
|
|
||||||
map: PropTypes.objectOf(PropTypes.any).isRequired,
|
|
||||||
path: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default JsonTabs;
|
|
|
@ -1,14 +0,0 @@
|
||||||
.json-tabs__bar {
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.json-tabs__add {
|
|
||||||
background-color: #171717;
|
|
||||||
border: none;
|
|
||||||
margin: 0;
|
|
||||||
margin-right: 1em;
|
|
||||||
min-width: 2.5em;
|
|
||||||
height: 2.5em;
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
import './json.scss';
|
|
||||||
|
|
||||||
import {
|
|
||||||
PropTypes,
|
|
||||||
React,
|
|
||||||
useEffect,
|
|
||||||
useRef,
|
|
||||||
} from '@latus/react';
|
|
||||||
import JSONInput from 'react-json-editor-ajrm';
|
|
||||||
import locale from 'react-json-editor-ajrm/locale/en';
|
|
||||||
|
|
||||||
const JsonComponent = ({
|
|
||||||
onChange,
|
|
||||||
json,
|
|
||||||
}) => {
|
|
||||||
const ref = useRef();
|
|
||||||
useEffect(() => {
|
|
||||||
const {current} = ref;
|
|
||||||
if (!current) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const onClick = (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
};
|
|
||||||
current.addEventListener('click', onClick);
|
|
||||||
return () => {
|
|
||||||
current.removeEventListener('click', onClick);
|
|
||||||
};
|
|
||||||
}, [ref]);
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="json-editor"
|
|
||||||
ref={ref}
|
|
||||||
>
|
|
||||||
<JSONInput
|
|
||||||
locale={locale}
|
|
||||||
placeholder={json}
|
|
||||||
onChange={({jsObject}) => {
|
|
||||||
if (jsObject) {
|
|
||||||
onChange(null, jsObject);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
JsonComponent.displayName = 'JsonComponent';
|
|
||||||
|
|
||||||
JsonComponent.propTypes = {
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
json: PropTypes.shape({}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default JsonComponent;
|
|
|
@ -1,20 +0,0 @@
|
||||||
.json-editor {
|
|
||||||
height: 100%;
|
|
||||||
[name="outer-box"], [name="container"] {
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
[name="container"] [name="body"] {
|
|
||||||
font-size: 1em !important;
|
|
||||||
}
|
|
||||||
[name="warning-box"] p {
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
svg {
|
|
||||||
height: 15px;
|
|
||||||
position: absolute;
|
|
||||||
right: -5px;
|
|
||||||
top: -5px;
|
|
||||||
width: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
import {JsonResource} from '@avocado/resource';
|
|
||||||
import {
|
|
||||||
useEffect,
|
|
||||||
useLatus,
|
|
||||||
useState,
|
|
||||||
} from '@latus/react';
|
|
||||||
|
|
||||||
export default (json) => {
|
|
||||||
const latus = useLatus();
|
|
||||||
const [fullJson, setFullJson] = useState();
|
|
||||||
useEffect(() => {
|
|
||||||
const loadJson = async () => {
|
|
||||||
setFullJson(await JsonResource.extendJson(json));
|
|
||||||
};
|
|
||||||
loadJson();
|
|
||||||
}, [latus, json]);
|
|
||||||
return fullJson;
|
|
||||||
};
|
|
|
@ -1,32 +0,0 @@
|
||||||
import {useDispatch} from '@latus/redux';
|
|
||||||
import {useProject, useUri} from '@persea/core';
|
|
||||||
import {patchJsonResource} from '../state/json';
|
|
||||||
|
|
||||||
export default () => {
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const project = useProject();
|
|
||||||
const uri = useUri();
|
|
||||||
const patch = (opOrOps) => {
|
|
||||||
const patch = (
|
|
||||||
Array.isArray(opOrOps)
|
|
||||||
? opOrOps
|
|
||||||
: [opOrOps]
|
|
||||||
)
|
|
||||||
.map((op) => ({
|
|
||||||
op: 'replace',
|
|
||||||
...op,
|
|
||||||
}));
|
|
||||||
dispatch(patchJsonResource({
|
|
||||||
patch,
|
|
||||||
project,
|
|
||||||
uri,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
patch.onChange = (path, key = 'value') => (event, value) => {
|
|
||||||
patch({
|
|
||||||
path,
|
|
||||||
value: 'undefined' === typeof value ? event.target[key] : value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
return patch;
|
|
||||||
};
|
|
|
@ -1,28 +0,0 @@
|
||||||
import JsonResourceController from './resource-controllers/json';
|
|
||||||
import {patchJsonResource} from './state/json';
|
|
||||||
import reducer from './state/reducer';
|
|
||||||
|
|
||||||
export {default as JsonTabs} from './components/json-tabs';
|
|
||||||
export {default as JsonComponent} from './components/json';
|
|
||||||
export {default as useFullJson} from './hooks/use-full-json';
|
|
||||||
export {default as useJsonPatcher} from './hooks/use-json-patcher';
|
|
||||||
export * from './state';
|
|
||||||
|
|
||||||
export {JsonResourceController};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
hooks: {
|
|
||||||
'@latus/redux/effects': (latus) => {
|
|
||||||
const withSocket = (fn) => (...args) => fn(...args.concat(latus.get('%socket')));
|
|
||||||
return {
|
|
||||||
[patchJsonResource]: withSocket((store, action, socket) => {
|
|
||||||
socket.send(['Action', action]);
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
'@latus/redux/reducers': () => reducer,
|
|
||||||
'@persea/core/resource-controllers': () => [
|
|
||||||
JsonResourceController,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,45 +0,0 @@
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {React} from '@latus/react';
|
|
||||||
import {compare} from 'fast-json-patch';
|
|
||||||
|
|
||||||
import JsonComponent from '../components/json';
|
|
||||||
import useJsonPatcher from '../hooks/use-json-patcher';
|
|
||||||
|
|
||||||
export default class JsonController {
|
|
||||||
|
|
||||||
static Component({path, resource}) {
|
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
||||||
const patch = useJsonPatcher();
|
|
||||||
return (
|
|
||||||
<JsonComponent
|
|
||||||
onChange={(event, value) => {
|
|
||||||
if (value) {
|
|
||||||
const diff = compare(resource, value)
|
|
||||||
.map((op) => ({
|
|
||||||
...op,
|
|
||||||
path: join(path, op.path),
|
|
||||||
}));
|
|
||||||
if (diff.length > 0) {
|
|
||||||
patch(diff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
json={resource}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static decode(encoded) {
|
|
||||||
return Buffer.from(JSON.stringify(encoded, null, 2), 'utf8');
|
|
||||||
}
|
|
||||||
|
|
||||||
static encode(buffer) {
|
|
||||||
return JSON.parse(buffer.toString('utf8'));
|
|
||||||
}
|
|
||||||
|
|
||||||
static get matcher() {
|
|
||||||
return /\.json$/;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
import fs from 'fs';
|
|
||||||
import {join} from 'path';
|
|
||||||
import {promisify} from 'util';
|
|
||||||
|
|
||||||
import {decorateWithLatus} from '@latus/core';
|
|
||||||
import {applyPatch} from 'fast-json-patch';
|
|
||||||
|
|
||||||
const readFile = promisify(fs.readFile);
|
|
||||||
const writeFile = promisify(fs.writeFile);
|
|
||||||
|
|
||||||
export default {
|
|
||||||
hooks: {
|
|
||||||
'@latus/core/starting': (latus) => {
|
|
||||||
latus.set('%patches', []);
|
|
||||||
const flushPatches = async () => {
|
|
||||||
const patches = latus.get('%patches');
|
|
||||||
if (patches.length > 0) {
|
|
||||||
const patching = {};
|
|
||||||
while (patches.length > 0) {
|
|
||||||
const {patch, project, uri} = patches.shift();
|
|
||||||
const {decode, encode} = latus.get('%resource-controllers')(uri);
|
|
||||||
const path = join(process.cwd(), 'projects', project, uri);
|
|
||||||
if (!patching[path]) {
|
|
||||||
patching[path] = new Promise((resolve) => {
|
|
||||||
readFile(path).then((buffer) => {
|
|
||||||
resolve({
|
|
||||||
decode,
|
|
||||||
json: encode(buffer, latus),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
const {json} = await patching[path];
|
|
||||||
applyPatch(json, patch);
|
|
||||||
}
|
|
||||||
const entries = Object.entries(patching);
|
|
||||||
for (let i = 0; i < entries.length; i++) {
|
|
||||||
const [path, promise] = entries[i];
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
const {decode, json} = await promise;
|
|
||||||
writeFile(path, decode(json, latus));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setTimeout(flushPatches, 0);
|
|
||||||
};
|
|
||||||
setTimeout(flushPatches, 0);
|
|
||||||
},
|
|
||||||
'@latus/socket/packets.decorate': decorateWithLatus(
|
|
||||||
require.context('./packets/decorators', false, /\.js$/),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './json';
|
|
|
@ -1,5 +0,0 @@
|
||||||
import {createAction} from '@latus/redux';
|
|
||||||
|
|
||||||
export const patchJsonResource = createAction('@persea/json/patchResource');
|
|
||||||
|
|
||||||
export default () => {};
|
|
|
@ -1,14 +0,0 @@
|
||||||
import {createNextState} from '@latus/redux';
|
|
||||||
import {applyPatch} from 'fast-json-patch';
|
|
||||||
|
|
||||||
import {patchJsonResource} from './json';
|
|
||||||
|
|
||||||
export default (state, {payload, type}) => {
|
|
||||||
if (type !== patchJsonResource.toString()) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
const {patch, project, uri} = payload;
|
|
||||||
return createNextState(state, (draft) => {
|
|
||||||
applyPatch(draft.projects.resources[`${project}${uri}`], patch);
|
|
||||||
});
|
|
||||||
};
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user