aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sokolov <eug-vs@keemail.me>2020-04-18 21:31:11 +0300
committerGitHub <noreply@github.com>2020-04-18 21:31:11 +0300
commitdee39c8ff8e9a417ba2b338beb942f9ad443adf3 (patch)
treea6b1bfa00f5ad925d57d3ded655a8103b911fad4
parent62df0ff96fc9ab832212d223150862c7667d9ffc (diff)
parent0c061c74bfd473be17be755cd19c8952dc115a91 (diff)
downloadreact-benzin-dee39c8ff8e9a417ba2b338beb942f9ad443adf3.tar.gz
Merge pull request #13 from eug-vs/develop
Patch 3.1.1
-rw-r--r--.circleci/config.yml59
-rw-r--r--.eslintrc.json15
-rw-r--r--README.md4
-rw-r--r--package-lock.json422
-rw-r--r--package.json16
-rw-r--r--src/index.tsx137
-rw-r--r--src/lib/Benzin/Benzin.tsx8
-rw-r--r--src/lib/ContentSection/ContentSection.tsx11
-rw-r--r--src/lib/Header/Header.tsx48
-rw-r--r--src/lib/Markdown/CodeBlock.tsx6
-rw-r--r--src/lib/Markdown/Content.tsx51
-rw-r--r--src/lib/Markdown/Markdown.tsx15
-rw-r--r--src/lib/Markdown/Section.tsx22
-rw-r--r--src/lib/Markdown/SyntacticSpan.tsx26
-rw-r--r--src/lib/Markdown/Text.tsx2
-rw-r--r--src/lib/SmartList/SmartList.tsx3
-rw-r--r--src/lib/Window/Window.tsx5
-rw-r--r--src/lib/Window/WindowSurface.tsx6
-rw-r--r--src/react-app-env.d.ts1
19 files changed, 685 insertions, 172 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 84c6a35..85fd519 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -29,7 +29,31 @@ jobs:
name: Test syntax and perform type checking
command: npm test
- deploy:
+ deploy_pages:
+ <<: *defaults
+ steps:
+ - checkout
+ - restore_cache:
+ keys:
+ - v1-dependencies-{{ checksum "package.json" }}
+ # fallback to using the latest cache if no exact match is found
+ - v1-dependencies-
+
+ - add_ssh_keys:
+ fingerprints:
+ - "02:a9:ad:b9:38:7c:39:70:20:ee:92:4c:86:27:43:9d"
+
+ - run:
+ name: Configure github user
+ command: |
+ git config user.email "eug-vs@keemail.me"
+ git config user.name "eug-vs"
+
+ - run:
+ name: Deploy to gh-pages
+ command: npm run deploy-pages
+
+ publish_package:
<<: *defaults
steps:
- checkout
@@ -42,9 +66,10 @@ jobs:
- run:
name: Authenticate with registry
command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/repo/.npmrc
+
- run:
- name: Deploy package
- command: npm run deploy
+ name: Publish package to NPM
+ command: npm run publish-package
workflows:
@@ -52,22 +77,34 @@ workflows:
test:
jobs:
- - checkout_and_test
+ - checkout_and_test:
+ filters:
+ branches:
+ ignore: /^(master|develop)$/
deploy:
jobs:
- checkout_and_test:
filters:
branches:
- ignore: /.*/
- tags:
- only: /^v.*/
- - deploy:
+ only: develop
+ - deploy_pages:
+ filters:
+ branches:
+ only: develop
+ requires:
+ - checkout_and_test
+
+ publish:
+ jobs:
+ - checkout_and_test:
+ filters:
+ branches:
+ only: master
+ - publish_package:
filters:
branches:
- ignore: /.*/
- tags:
- only: /^v.*/
+ only: master
requires:
- checkout_and_test
diff --git a/.eslintrc.json b/.eslintrc.json
index ac05a7f..c86a906 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,12 +1,23 @@
{
"parser": "@typescript-eslint/parser",
"extends": [
- "react-app",
+ "airbnb-typescript",
"plugin:@typescript-eslint/recommended"
],
+ "parserOptions": {
+ "project": "./tsconfig.json"
+ },
"ignorePatterns": "dist/",
"rules": {
"jsx-quotes": ["error", "prefer-double"],
- "quotes": ["error", "single"]
+ "quotes": ["error", "single"],
+ "no-multiple-empty-lines": [2, { "max": 2, "maxEOF": 1 } ],
+ "max-len": ["error", { "code": 120 }],
+ "arrow-parens": [2, "as-needed"],
+ "arrow-body-style": 0,
+ "no-cond-assign": 0,
+ "react/prop-types": 0,
+ "react/no-children-prop": 0,
+ "react/no-danger": 0
}
}
diff --git a/README.md b/README.md
index e528b03..902f6f2 100644
--- a/README.md
+++ b/README.md
@@ -59,4 +59,6 @@ $ npm run build
This command will generate `dist/` folder ready for distribution, which you of course can explore. Note that `tsc` creates type definitions (`.d.ts`) for every corresponding `.js` file. It's very useful because consumers also get access to them.
## Deploying
-Deploying to `npm` is fully automated through **CircleCI**: simply tag a commit as a Release and it will do the job.
+Publishing to `npm` is fully automated through **CircleCI** - package is deployed on every push into `master`. Therefore only release *PR*'s should be merged into `master` branch.
+
+Deploying to `gh-pages` is automatically performed on every commit into `develop` branch.
diff --git a/package-lock.json b/package-lock.json
index c7282df..428aef5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "react-benzin",
- "version": "3.1.0",
+ "version": "3.1.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1082,13 +1082,21 @@
}
},
"@babel/runtime-corejs3": {
- "version": "7.8.4",
- "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.8.4.tgz",
- "integrity": "sha512-+wpLqy5+fbQhvbllvlJEVRIpYj+COUWnnsm+I4jZlA8Lo7/MJmBhGTCHyk1/RWfOqBRJ2MbadddG6QltTKTlrg==",
+ "version": "7.9.2",
+ "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.9.2.tgz",
+ "integrity": "sha512-HHxmgxbIzOfFlZ+tdeRKtaxWOMUoCG5Mu3wKeUmOxjYrwb3AAHgnmtCUbPPK11/raIWLIBK250t8E2BPO0p7jA==",
"dev": true,
"requires": {
"core-js-pure": "^3.0.0",
- "regenerator-runtime": "^0.13.2"
+ "regenerator-runtime": "^0.13.4"
+ },
+ "dependencies": {
+ "regenerator-runtime": {
+ "version": "0.13.5",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
+ "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==",
+ "dev": true
+ }
}
},
"@babel/template": {
@@ -1806,33 +1814,33 @@
"dev": true
},
"@typescript-eslint/eslint-plugin": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.19.0.tgz",
- "integrity": "sha512-u7IcQ9qwsB6U806LupZmINRnQjC+RJyv36sV/ugaFWMHTbFm/hlLTRx3gGYJgHisxcGSTnf+I/fPDieRMhPSQQ==",
+ "version": "2.28.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.28.0.tgz",
+ "integrity": "sha512-w0Ugcq2iatloEabQP56BRWJowliXUP5Wv6f9fKzjJmDW81hOTBxRoJ4LoEOxRpz9gcY51Libytd2ba3yLmSOfg==",
"dev": true,
"requires": {
- "@typescript-eslint/experimental-utils": "2.19.0",
- "eslint-utils": "^1.4.3",
+ "@typescript-eslint/experimental-utils": "2.28.0",
"functional-red-black-tree": "^1.0.1",
"regexpp": "^3.0.0",
"tsutils": "^3.17.1"
},
"dependencies": {
"@typescript-eslint/experimental-utils": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.19.0.tgz",
- "integrity": "sha512-zwpg6zEOPbhB3+GaQfufzlMUOO6GXCNZq6skk+b2ZkZAIoBhVoanWK255BS1g5x9bMwHpLhX0Rpn5Fc3NdCZdg==",
+ "version": "2.28.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.28.0.tgz",
+ "integrity": "sha512-4SL9OWjvFbHumM/Zh/ZeEjUFxrYKtdCi7At4GyKTbQlrj1HcphIDXlje4Uu4cY+qzszR5NdVin4CCm6AXCjd6w==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.3",
- "@typescript-eslint/typescript-estree": "2.19.0",
- "eslint-scope": "^5.0.0"
+ "@typescript-eslint/typescript-estree": "2.28.0",
+ "eslint-scope": "^5.0.0",
+ "eslint-utils": "^2.0.0"
}
},
"@typescript-eslint/typescript-estree": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.19.0.tgz",
- "integrity": "sha512-n6/Xa37k0jQdwpUszffi19AlNbVCR0sdvCs3DmSKMD7wBttKY31lhD2fug5kMD91B2qW4mQldaTEc1PEzvGu8w==",
+ "version": "2.28.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.28.0.tgz",
+ "integrity": "sha512-HDr8MP9wfwkiuqzRVkuM3BeDrOC4cKbO5a6BymZBHUt5y/2pL0BXD6I/C/ceq2IZoHWhcASk+5/zo+dwgu9V8Q==",
"dev": true,
"requires": {
"debug": "^4.1.1",
@@ -1843,6 +1851,15 @@
"semver": "^6.3.0",
"tsutils": "^3.17.1"
}
+ },
+ "eslint-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz",
+ "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ }
}
}
},
@@ -2497,14 +2514,10 @@
}
},
"axobject-query": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.1.1.tgz",
- "integrity": "sha512-lF98xa/yvy6j3fBHAgQXIYl+J4eZadOSqsPojemUqClzNbBV38wWGpUbQbVEyf4eUF5yF7eHmGgGA2JiHyjeqw==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.7.4",
- "@babel/runtime-corejs3": "^7.7.4"
- }
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.1.2.tgz",
+ "integrity": "sha512-ICt34ZmrVt8UQnvPl6TVyDTkmhXmAyAT4Jh5ugfGUX4MOrZ+U/ZY6/sdylRw3qGNr9Ub5AJsaHeDMzNLehRdOQ==",
+ "dev": true
},
"babel-code-frame": {
"version": "6.26.0",
@@ -3882,9 +3895,9 @@
}
},
"core-js-pure": {
- "version": "3.6.4",
- "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.4.tgz",
- "integrity": "sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw==",
+ "version": "3.6.5",
+ "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz",
+ "integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==",
"dev": true
},
"core-util-is": {
@@ -5069,13 +5082,87 @@
}
}
},
- "eslint-config-react-app": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.1.0.tgz",
- "integrity": "sha512-hBaxisHC6HXRVvxX+/t1n8mOdmCVIKgkXsf2WoUkJi7upHJTwYTsdCmx01QPOjKNT34QMQQ9sL0tVBlbiMFjxA==",
+ "eslint-config-airbnb": {
+ "version": "18.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.1.0.tgz",
+ "integrity": "sha512-kZFuQC/MPnH7KJp6v95xsLBf63G/w7YqdPfQ0MUanxQ7zcKUNG8j+sSY860g3NwCBOa62apw16J6pRN+AOgXzw==",
+ "dev": true,
+ "requires": {
+ "eslint-config-airbnb-base": "^14.1.0",
+ "object.assign": "^4.1.0",
+ "object.entries": "^1.1.1"
+ }
+ },
+ "eslint-config-airbnb-base": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.1.0.tgz",
+ "integrity": "sha512-+XCcfGyCnbzOnktDVhwsCAx+9DmrzEmuwxyHUJpw+kqBVT744OUBrB09khgFKlK1lshVww6qXGsYPZpavoNjJw==",
+ "dev": true,
+ "requires": {
+ "confusing-browser-globals": "^1.0.9",
+ "object.assign": "^4.1.0",
+ "object.entries": "^1.1.1"
+ }
+ },
+ "eslint-config-airbnb-typescript": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-7.2.1.tgz",
+ "integrity": "sha512-D3elVKUbdsCfkOVstSyWuiu+KGCVTrYxJPoenPIqZtL6Li/R4xBeVTXjZIui8B8D17bDN3Pz5dSr7jRLY5HqIg==",
"dev": true,
"requires": {
- "confusing-browser-globals": "^1.0.9"
+ "@typescript-eslint/parser": "^2.24.0",
+ "eslint-config-airbnb": "^18.1.0",
+ "eslint-config-airbnb-base": "^14.1.0"
+ },
+ "dependencies": {
+ "@typescript-eslint/experimental-utils": {
+ "version": "2.28.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.28.0.tgz",
+ "integrity": "sha512-4SL9OWjvFbHumM/Zh/ZeEjUFxrYKtdCi7At4GyKTbQlrj1HcphIDXlje4Uu4cY+qzszR5NdVin4CCm6AXCjd6w==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.3",
+ "@typescript-eslint/typescript-estree": "2.28.0",
+ "eslint-scope": "^5.0.0",
+ "eslint-utils": "^2.0.0"
+ }
+ },
+ "@typescript-eslint/parser": {
+ "version": "2.28.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.28.0.tgz",
+ "integrity": "sha512-RqPybRDquui9d+K86lL7iPqH6Dfp9461oyqvlXMNtap+PyqYbkY5dB7LawQjDzot99fqzvS0ZLZdfe+1Bt3Jgw==",
+ "dev": true,
+ "requires": {
+ "@types/eslint-visitor-keys": "^1.0.0",
+ "@typescript-eslint/experimental-utils": "2.28.0",
+ "@typescript-eslint/typescript-estree": "2.28.0",
+ "eslint-visitor-keys": "^1.1.0"
+ }
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "2.28.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.28.0.tgz",
+ "integrity": "sha512-HDr8MP9wfwkiuqzRVkuM3BeDrOC4cKbO5a6BymZBHUt5y/2pL0BXD6I/C/ceq2IZoHWhcASk+5/zo+dwgu9V8Q==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.1.1",
+ "eslint-visitor-keys": "^1.1.0",
+ "glob": "^7.1.6",
+ "is-glob": "^4.0.1",
+ "lodash": "^4.17.15",
+ "semver": "^6.3.0",
+ "tsutils": "^3.17.1"
+ }
+ },
+ "eslint-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz",
+ "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ }
+ }
}
},
"eslint-import-resolver-node": {
@@ -5119,9 +5206,9 @@
}
},
"eslint-module-utils": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz",
- "integrity": "sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==",
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz",
+ "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==",
"dev": true,
"requires": {
"debug": "^2.6.9",
@@ -5207,9 +5294,9 @@
}
},
"eslint-plugin-import": {
- "version": "2.20.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz",
- "integrity": "sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ==",
+ "version": "2.20.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz",
+ "integrity": "sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg==",
"dev": true,
"requires": {
"array-includes": "^3.0.3",
@@ -5379,9 +5466,9 @@
}
},
"eslint-plugin-react": {
- "version": "7.18.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.18.0.tgz",
- "integrity": "sha512-p+PGoGeV4SaZRDsXqdj9OWcOrOpZn8gXoGPcIQTzo2IDMbAKhNDnME9myZWqO3Ic4R3YmwAZ1lDjWl2R2hMUVQ==",
+ "version": "7.19.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz",
+ "integrity": "sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==",
"dev": true,
"requires": {
"array-includes": "^3.1.1",
@@ -5392,7 +5479,10 @@
"object.fromentries": "^2.0.2",
"object.values": "^1.1.1",
"prop-types": "^15.7.2",
- "resolve": "^1.14.2"
+ "resolve": "^1.15.1",
+ "semver": "^6.3.0",
+ "string.prototype.matchall": "^4.0.2",
+ "xregexp": "^4.3.0"
},
"dependencies": {
"doctrine": {
@@ -5403,13 +5493,22 @@
"requires": {
"esutils": "^2.0.2"
}
+ },
+ "resolve": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.1.tgz",
+ "integrity": "sha512-rmAglCSqWWMrrBv/XM6sW0NuRFiKViw/W4d9EbC4pt+49H8JwHy+mcGmALTEg504AUDcLTvb1T2q3E9AnmY+ig==",
+ "dev": true,
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
}
}
},
"eslint-plugin-react-hooks": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz",
- "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==",
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.5.1.tgz",
+ "integrity": "sha512-Y2c4b55R+6ZzwtTppKwSmK/Kar8AdLiC2f9NADCuxbcTgPPg41Gyqa6b9GppgXSvCtkRw43ZE86CT5sejKC6/g==",
"dev": true
},
"eslint-scope": {
@@ -7064,6 +7163,17 @@
"ipaddr.js": "^1.9.0"
}
},
+ "internal-slot": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz",
+ "integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==",
+ "dev": true,
+ "requires": {
+ "es-abstract": "^1.17.0-next.1",
+ "has": "^1.0.3",
+ "side-channel": "^1.0.2"
+ }
+ },
"invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -12064,6 +12174,25 @@
"workbox-webpack-plugin": "4.3.1"
},
"dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "doctrine": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
+ "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2",
+ "isarray": "^1.0.0"
+ }
+ },
"eslint-config-react-app": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.2.0.tgz",
@@ -12072,6 +12201,166 @@
"requires": {
"confusing-browser-globals": "^1.0.9"
}
+ },
+ "eslint-plugin-import": {
+ "version": "2.20.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz",
+ "integrity": "sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ==",
+ "dev": true,
+ "requires": {
+ "array-includes": "^3.0.3",
+ "array.prototype.flat": "^1.2.1",
+ "contains-path": "^0.1.0",
+ "debug": "^2.6.9",
+ "doctrine": "1.5.0",
+ "eslint-import-resolver-node": "^0.3.2",
+ "eslint-module-utils": "^2.4.1",
+ "has": "^1.0.3",
+ "minimatch": "^3.0.4",
+ "object.values": "^1.1.0",
+ "read-pkg-up": "^2.0.0",
+ "resolve": "^1.12.0"
+ }
+ },
+ "eslint-plugin-react": {
+ "version": "7.18.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.18.0.tgz",
+ "integrity": "sha512-p+PGoGeV4SaZRDsXqdj9OWcOrOpZn8gXoGPcIQTzo2IDMbAKhNDnME9myZWqO3Ic4R3YmwAZ1lDjWl2R2hMUVQ==",
+ "dev": true,
+ "requires": {
+ "array-includes": "^3.1.1",
+ "doctrine": "^2.1.0",
+ "has": "^1.0.3",
+ "jsx-ast-utils": "^2.2.3",
+ "object.entries": "^1.1.1",
+ "object.fromentries": "^2.0.2",
+ "object.values": "^1.1.1",
+ "prop-types": "^15.7.2",
+ "resolve": "^1.14.2"
+ },
+ "dependencies": {
+ "doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ }
+ }
+ },
+ "eslint-plugin-react-hooks": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz",
+ "integrity": "sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==",
+ "dev": true
+ },
+ "find-up": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+ "dev": true,
+ "requires": {
+ "locate-path": "^2.0.0"
+ }
+ },
+ "load-json-file": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
+ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "parse-json": "^2.2.0",
+ "pify": "^2.0.0",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+ "dev": true,
+ "requires": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "p-limit": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
+ "dev": true,
+ "requires": {
+ "p-try": "^1.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+ "dev": true,
+ "requires": {
+ "p-limit": "^1.1.0"
+ }
+ },
+ "p-try": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+ "dev": true
+ },
+ "parse-json": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+ "dev": true,
+ "requires": {
+ "error-ex": "^1.2.0"
+ }
+ },
+ "path-type": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
+ "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
+ "dev": true,
+ "requires": {
+ "pify": "^2.0.0"
+ }
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "dev": true
+ },
+ "read-pkg": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
+ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
+ "dev": true,
+ "requires": {
+ "load-json-file": "^2.0.0",
+ "normalize-package-data": "^2.3.2",
+ "path-type": "^2.0.0"
+ }
+ },
+ "read-pkg-up": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
+ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
+ "dev": true,
+ "requires": {
+ "find-up": "^2.0.0",
+ "read-pkg": "^2.0.0"
+ }
}
}
},
@@ -12215,9 +12504,9 @@
}
},
"regexpp": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz",
- "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
+ "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
"dev": true
},
"regexpu-core": {
@@ -12982,6 +13271,16 @@
"integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
"dev": true
},
+ "side-channel": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz",
+ "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==",
+ "dev": true,
+ "requires": {
+ "es-abstract": "^1.17.0-next.1",
+ "object-inspect": "^1.7.0"
+ }
+ },
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
@@ -13547,6 +13846,20 @@
}
}
},
+ "string.prototype.matchall": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz",
+ "integrity": "sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.0",
+ "has-symbols": "^1.0.1",
+ "internal-slot": "^1.0.2",
+ "regexp.prototype.flags": "^1.3.0",
+ "side-channel": "^1.0.2"
+ }
+ },
"string.prototype.trimleft": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
@@ -16603,6 +16916,15 @@
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true
},
+ "xregexp": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz",
+ "integrity": "sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime-corejs3": "^7.8.3"
+ }
+ },
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
diff --git a/package.json b/package.json
index a915372..8493d86 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-benzin",
- "version": "3.1.0",
+ "version": "3.1.1",
"description": "A powerful React Material components library.",
"homepage": "https://eug-vs.github.io/react-benzin",
"main": "dist/index.js",
@@ -12,8 +12,10 @@
"start": "react-scripts start",
"lint": "eslint . --ext ts,tsx --max-warnings 0",
"test": "npm run lint && tsc",
- "build": "rm -rf dist && tsc --project tsconfig.release.json",
- "deploy": "npm run lint && npm run build && npm publish --public"
+ "build-pages": "react-scripts build",
+ "deploy-pages": "npm run build-pages && gh-pages -d build",
+ "compile-dist": "rm -rf dist && tsc --project tsconfig.release.json",
+ "publish-package": "npm run lint && npm run build && npm publish --public"
},
"license": "MIT",
"dependencies": {
@@ -32,10 +34,14 @@
"@types/react-dom": "^16.9.5",
"@types/react-virtualized-auto-sizer": "^1.0.0",
"@types/react-window": "^1.8.1",
- "@typescript-eslint/eslint-plugin": "^2.19.0",
+ "@typescript-eslint/eslint-plugin": "^2.28.0",
"@typescript-eslint/parser": "^2.19.0",
"eslint": "^6.8.0",
- "eslint-config-react-app": "^5.1.0",
+ "eslint-config-airbnb-typescript": "^7.2.1",
+ "eslint-plugin-import": "^2.20.2",
+ "eslint-plugin-jsx-a11y": "^6.2.3",
+ "eslint-plugin-react": "^7.19.0",
+ "eslint-plugin-react-hooks": "^2.5.1",
"gh-pages": "^2.2.0",
"react-scripts": "^3.3.1",
"typescript": "^3.7.5"
diff --git a/src/index.tsx b/src/index.tsx
index b64b207..c5e1989 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,13 +1,14 @@
-import React, { useState } from 'react';
+import React, { useState, useRef } from 'react';
import ReactDOM from 'react-dom';
-import { makeStyles } from '@material-ui/core';
+import { makeStyles, TextField, Button } from '@material-ui/core';
import {
Benzin,
Header,
Window,
Markdown,
+ ContentSection,
} from './lib';
import icon from './assets/icon.svg';
@@ -21,37 +22,114 @@ interface RenderPropTypes {
const useStyles = makeStyles(theme => ({
window: {
padding: theme.spacing(4),
- }
+ },
+ promoButton: {
+ display: 'flex',
+ justifyContent: 'center',
+ marginTop: theme.spacing(4),
+ },
}));
-const Icon = <img src={icon} width="32px" height="37px" alt="logo"/>
+const Icon = <img src={icon} width="32px" height="37px" alt="logo" />;
const headerContents = {
home: null,
- space: null,
- 'spacevim': null,
- 'emoji': null,
+ spacevim: null,
'material-ui': null,
+ custom: null,
+ 'live preview': null,
};
const pageMap: Record<string, string> = {
home: 'https://raw.githubusercontent.com/eug-vs/react-benzin/develop/README.md',
- space: 'https://raw.githubusercontent.com/eug-vs/space/master/docs/environment.md',
- 'spacevim': 'https://raw.githubusercontent.com/spacevim/spacevim/master/README.md',
- emoji: 'https://raw.githubusercontent.com/muan/emoji/gh-pages/README.md',
+ spacevim: 'https://raw.githubusercontent.com/spacevim/spacevim/master/README.md',
'material-ui': 'https://raw.githubusercontent.com/mui-org/material-ui/master/README.md',
};
+const CustomPage: React.FC = () => {
+ const [url, setUrl] = useState<string>('');
+ const inputEl = useRef<HTMLInputElement>(null);
+
+ const handleParseUrl = (): void => {
+ setUrl(inputEl.current?.value || '');
+ };
+
+ return (
+ <>
+ <ContentSection sectionName="Render custom markdown document" level={2}>
+ <p>
+ This should be a link to a valid markdown file. Response should give the file contents.
+ If you copy README file from GitHub, make sure you provide link to raw view.
+ </p>
+ <p>
+ <TextField
+ fullWidth
+ inputRef={inputEl}
+ variant="outlined"
+ color="secondary"
+ label="Markdown url"
+ />
+ </p>
+ <Button variant="contained" color="secondary" onClick={handleParseUrl}>
+ Render!
+ </Button>
+ </ContentSection>
+ <Markdown url={url} />
+ </>
+ );
+};
+
+interface LivePropTypes {
+ setLivePreviewData: (livePreviewData: string) => void;
+}
+
+const LivePreviewPage: React.FC<LivePropTypes> = ({ setLivePreviewData }) => {
+ const inputEl = useRef<HTMLInputElement>(null);
+
+ const handleRender = (): void => {
+ setLivePreviewData(inputEl.current?.value || '');
+ };
+
+ return (
+ <>
+ <ContentSection sectionName="Markdown live preview" level={2}>
+ <p>
+ Start typing and see your text rendered on the left window!
+ We recommend starting with # Header.
+ </p>
+ <p>
+ <TextField
+ fullWidth
+ multiline
+ inputRef={inputEl}
+ variant="outlined"
+ color="primary"
+ label="Markdown"
+ onChange={handleRender}
+ />
+ </p>
+ </ContentSection>
+ </>
+ );
+};
+
+
const App: React.FC = () => {
const classes = useStyles();
- const [page, setPage] = useState('home');
+ const [page, setPage] = useState<string>('home');
+ const [livePreviewData, setLivePreviewData] = useState<string>('');
+
+ const handleGoLivePreview = (): void => {
+ setPage('live preview');
+ };
const url = pageMap[page];
- const fileName = url.slice(url.lastIndexOf('/') + 1);
- const metadata = [
- `## Markdown\n [Markdown file](${url}) *(...${fileName})* that you can see on the left was parsed and processed by **BENZIN**! :rocket:`,
+ const fileName = url?.slice(url.lastIndexOf('/') + 1);
+ const info = [
+ /* eslint-disable max-len */
+ `## Markdown\n [Markdown file](${url}) *(...${fileName})* that you can see on the left was parsed and rendered by **BENZIN**! :rocket:`,
'Switch between tabs on the header to explore other markdown templates. :recycle: ',
'Currently **only core features** of markdown function.',
'Templates on the left are being loaded from the [GitHub](https://github.com), though this pane is generated from plaintext. :pen:',
@@ -61,8 +139,15 @@ const App: React.FC = () => {
'const data = \'# Header\\nHello, *world!*\';',
'ReactDOM.render(<Markdown data={data}/>, document.getElementById(\'root\'));',
'```',
+ /* eslint-enable max-len */
].join('\n');
+ let primaryWindowContent = <Markdown url={url} />;
+ if (page === 'custom') primaryWindowContent = <CustomPage />;
+ else if (page === 'live preview') {
+ primaryWindowContent = <Markdown data={livePreviewData || '# Start typing in the right window!'} />;
+ }
+
return (
<Benzin>
<Header
@@ -75,13 +160,29 @@ const App: React.FC = () => {
setPage={setPage}
/>
<Window type="primary">
- <div className={classes.window}>
- <Markdown url={url} />
- </div>
+ <div className={classes.window}>{primaryWindowContent}</div>
</Window>
<Window type="secondary" name="Feature preview">
<div className={classes.window}>
- <Markdown data={metadata} />
+ {
+ (page === 'live preview')
+ ? <LivePreviewPage setLivePreviewData={setLivePreviewData} />
+ : (
+ <>
+ <Markdown data={info} />
+ <p className={classes.promoButton}>
+ <Button
+ variant="contained"
+ color="primary"
+ size="large"
+ onClick={handleGoLivePreview}
+ >
+ Try it yourself!
+ </Button>
+ </p>
+ </>
+ )
+ }
</div>
</Window>
</Benzin>
diff --git a/src/lib/Benzin/Benzin.tsx b/src/lib/Benzin/Benzin.tsx
index 83ed0b0..bc436f7 100644
--- a/src/lib/Benzin/Benzin.tsx
+++ b/src/lib/Benzin/Benzin.tsx
@@ -8,9 +8,9 @@ import 'typeface-roboto';
declare module '@material-ui/core/styles/createPalette' {
interface TypeBackground {
- elevation1: string;
- elevation2: string;
- elevation3: string;
+ elevation1: string;
+ elevation2: string;
+ elevation3: string;
}
}
@@ -34,7 +34,7 @@ const benzinTheme = createMuiTheme({
text: {
primary: '#f4f4f4',
secondary: 'rgba(255, 255, 255, 0.6)',
- }
+ },
},
});
diff --git a/src/lib/ContentSection/ContentSection.tsx b/src/lib/ContentSection/ContentSection.tsx
index ba8b882..28b1ad5 100644
--- a/src/lib/ContentSection/ContentSection.tsx
+++ b/src/lib/ContentSection/ContentSection.tsx
@@ -3,7 +3,7 @@ import React from 'react';
import {
Typography,
Divider,
- makeStyles
+ makeStyles,
} from '@material-ui/core';
@@ -26,22 +26,21 @@ const useStyles = makeStyles(theme => ({
const ContentSection: React.FC<PropTypes> = ({ sectionName, children, level = 0 }) => {
const classes = useStyles();
- level += 2; // Make everything smaller
- if (level > 6) level = 6;
+ let adjustedLevel = level + 2; // Make everything smaller
+ if (adjustedLevel > 6) adjustedLevel = 6;
type Variant = 'h3' | 'h4' | 'h5' | 'h6';
- const variant: Variant = 'h' + level as Variant;
+ const variant: Variant = `h${adjustedLevel}` as Variant;
return (
<>
<Typography variant={variant}>{sectionName}</Typography>
- <Divider variant="middle"/>
+ <Divider variant="middle" />
<Typography component="div" className={classes.content}>
{children}
</Typography>
</>
);
-
};
diff --git a/src/lib/Header/Header.tsx b/src/lib/Header/Header.tsx
index 233eacb..58be989 100644
--- a/src/lib/Header/Header.tsx
+++ b/src/lib/Header/Header.tsx
@@ -40,13 +40,15 @@ const useStyles = makeStyles(theme => ({
'& svg': {
marginRight: theme.spacing(1),
marginBottom: '0 !important',
- }
- }
- }
+ },
+ },
+ },
}));
-const Header: React.FC<PropTypes> = ({ logo, contents, page, setPage }) => {
+const Header: React.FC<PropTypes> = ({
+ logo, contents, page, setPage,
+}) => {
const classes = useStyles();
const handleChange = (event: React.ChangeEvent<{}>, newPage: string): void => {
@@ -54,25 +56,25 @@ const Header: React.FC<PropTypes> = ({ logo, contents, page, setPage }) => {
};
return (
- <AppBar position="sticky" className={classes.root}>
- <Toolbar>
- {logo.icon}
- <Typography variant="h5" className={classes.logo} color="primary">
- {logo.title}
- </Typography>
- <Tabs onChange={handleChange} value={page}>
- {contents && Object.keys(contents).map((item: string) => (
- <Tab
- label={item}
- icon={contents[item] as JSX.Element}
- value={item}
- className={classes.tab}
- key={item}
- />
- ))}
- </Tabs>
- </Toolbar>
- </AppBar>
+ <AppBar position="sticky" className={classes.root}>
+ <Toolbar>
+ {logo.icon}
+ <Typography variant="h5" className={classes.logo} color="primary">
+ {logo.title}
+ </Typography>
+ <Tabs onChange={handleChange} value={page}>
+ {contents && Object.keys(contents).map((item: string) => (
+ <Tab
+ label={item}
+ icon={contents[item] as JSX.Element}
+ value={item}
+ className={classes.tab}
+ key={item}
+ />
+ ))}
+ </Tabs>
+ </Toolbar>
+ </AppBar>
);
};
diff --git a/src/lib/Markdown/CodeBlock.tsx b/src/lib/Markdown/CodeBlock.tsx
index 5b8edec..394458e 100644
--- a/src/lib/Markdown/CodeBlock.tsx
+++ b/src/lib/Markdown/CodeBlock.tsx
@@ -1,8 +1,8 @@
import React from 'react';
-import { ParserPropTypes } from './types';
import { Paper } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
+import { ParserPropTypes } from './types';
const useStyles = makeStyles(theme => ({
root: {
@@ -10,7 +10,7 @@ const useStyles = makeStyles(theme => ({
padding: theme.spacing(1),
overflowX: 'auto',
fontFamily: 'Monospace',
- scrollbarColor: 'auto'
+ scrollbarColor: 'auto',
},
}));
@@ -21,7 +21,7 @@ const CodeBlock: React.FC<ParserPropTypes> = ({ rawLines }) => {
{rawLines.map(line => <pre>{line}</pre>)}
</Paper>
);
-}
+};
export default CodeBlock;
diff --git a/src/lib/Markdown/Content.tsx b/src/lib/Markdown/Content.tsx
index aaea100..88409fa 100644
--- a/src/lib/Markdown/Content.tsx
+++ b/src/lib/Markdown/Content.tsx
@@ -6,28 +6,32 @@ import { ParserPropTypes } from './types';
const denotesCodeBlock = (line: string): boolean => {
- return line.match(/^```.*$/) !== null;
-}
+ return line.match(/^\s*```.*$/) !== null;
+};
const denotesDottedList = (line: string): boolean => {
- return line.match(/^ ?- .*$/) !== null;
-}
+ return line.match(/^ ?[-*] .*$/) !== null;
+};
-const denotesOpenHtml= (line: string): string => {
+const denotesOpenHtml = (line: string): string => {
const regex = /<([^/\s]*)[^<]*[^/]>/g;
const match = regex.exec(line);
return match ? match[1] : '';
-}
+};
-const denotesClosingHtml= (line: string, tag: string): boolean => {
+const denotesClosingHtml = (line: string, tag: string): boolean => {
const regex = new RegExp(`</${tag}[^<]*>`);
return line.match(regex) !== null;
-}
+};
const denotesSelfClosingHtml = (line: string): string[] | null => {
const regex = /(<[^/\s]*[^<]*\/>)/g;
return line.match(regex);
-}
+};
+
+const declaresNoLineBreak = (line: string): boolean => {
+ return line.match(/\\\|$/) !== null;
+};
const Content: React.FC<ParserPropTypes> = ({ rawLines }) => {
if (!rawLines.length) return null;
@@ -36,33 +40,42 @@ const Content: React.FC<ParserPropTypes> = ({ rawLines }) => {
let buffer;
if (denotesCodeBlock(line)) {
- const closeIndex = rawLines.findIndex(line => denotesCodeBlock(line));
+ const closeIndex = rawLines.findIndex(rawLine => denotesCodeBlock(rawLine));
const codeBlockLines = rawLines.splice(0, closeIndex + 1).slice(0, closeIndex);
- buffer = <CodeBlock rawLines={codeBlockLines} />
+ buffer = <CodeBlock rawLines={codeBlockLines} />;
} else if (denotesDottedList(line)) {
- const closeIndex = rawLines.findIndex(line => !denotesDottedList(line));
+ const closeIndex = rawLines.findIndex(rawLine => !denotesDottedList(rawLine));
const dottedListLines = rawLines.splice(0, closeIndex).slice(0, closeIndex);
dottedListLines.unshift(line);
buffer = <ul>{dottedListLines.map(li => <li><Text line={li.slice(2)} /></li>)}</ul>;
} else if ((buffer = denotesOpenHtml(line))) {
const tag = buffer;
- const closeIndex = rawLines.findIndex(line => denotesClosingHtml(line, tag));
- const htmlLines = rawLines.splice(0, closeIndex + 1).slice(0, closeIndex);
+ const closeIndex = denotesClosingHtml(line, tag) ? -1 : rawLines.findIndex(
+ rawLine => denotesClosingHtml(rawLine, tag),
+ );
+ const htmlLines = rawLines.splice(0, closeIndex + 1);
htmlLines.unshift(line);
- buffer = <div dangerouslySetInnerHTML={{ __html: htmlLines.join('\n') }}></div>;
+ buffer = <div dangerouslySetInnerHTML={{ __html: htmlLines.join('\n') }} />;
} else if ((buffer = denotesSelfClosingHtml(line)) !== null) {
const match = buffer[0];
const [before, after] = line.split(match);
- console.log({ line, match, before, after});
buffer = (
<>
<Text line={before} />
- <div dangerouslySetInnerHTML={{ __html: match }}></div>
+ <div dangerouslySetInnerHTML={{ __html: match }} />
<Text line={after} />
</>
);
+ } else if (declaresNoLineBreak(line)) {
+ const closeIndex = rawLines.findIndex(rawLine => !declaresNoLineBreak(rawLine));
+ const lineBreakLines = rawLines.splice(0, closeIndex).map(rawLine => rawLine.slice(0, -2));
+ lineBreakLines.unshift(line.slice(0, -2));
+ lineBreakLines.push(rawLines.splice(0, 1)[0]);
+ buffer = <p>{lineBreakLines.map(lineBreakLine => <Text line={lineBreakLine} />)}</p>;
+ } else if (denotesClosingHtml(line, '')) {
+ buffer = null;
} else {
- buffer = <p><Text line={line} /></p>
+ buffer = <p><Text line={line} /></p>;
}
return (
@@ -71,7 +84,7 @@ const Content: React.FC<ParserPropTypes> = ({ rawLines }) => {
<Content rawLines={rawLines} />
</>
);
-}
+};
export default Content;
diff --git a/src/lib/Markdown/Markdown.tsx b/src/lib/Markdown/Markdown.tsx
index 09ad54a..cfcf117 100644
--- a/src/lib/Markdown/Markdown.tsx
+++ b/src/lib/Markdown/Markdown.tsx
@@ -8,15 +8,26 @@ interface PropTypes {
url?: string;
}
+const resolveUrls = (line: string, baseUrl: string): string => line.replace(
+ /src="(?!http)(.*)"[\s>]/,
+ (match, url) => `src="${baseUrl}/${url}?sanitize=true"`,
+).replace(
+ /\[(.*\]?.*)\]\((?!http)(.+?)\)/,
+ (match, text, url) => `[${text}](${baseUrl}/${url})`,
+);
+
const Markdown: React.FC<PropTypes> = ({ data, url }) => {
const [markdown, setMarkdown] = useState<string>(data || '');
+ if (url) axios.get(url).then(response => setMarkdown(response.data));
+
useEffect(() => {
if (!url) setMarkdown(data || '');
}, [data, url]);
- if (url) axios.get(url).then(response => setMarkdown(response.data));
- return <Section rawLines={markdown.split('\n')} />
+ const baseUrl = url?.slice(0, url.lastIndexOf('/')) || '';
+ const lines = markdown.split(/\r?\n/).map(line => resolveUrls(line, baseUrl));
+ return <Section rawLines={lines} />;
};
diff --git a/src/lib/Markdown/Section.tsx b/src/lib/Markdown/Section.tsx
index 5ce8954..fc208b1 100644
--- a/src/lib/Markdown/Section.tsx
+++ b/src/lib/Markdown/Section.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import { Typography } from '@material-ui/core';
import ContentSection from '../ContentSection/ContentSection';
import Content from './Content';
import { ParserPropTypes } from './types';
@@ -10,9 +11,9 @@ interface PropTypes extends ParserPropTypes {
const getHeaderLevel = (header: string): number => {
if (!header) return 0;
let level = 0;
- while(header[level] === '#') level++;
+ while (header[level] === '#') level += 1;
return level;
-}
+};
const ChildrenSections: React.FC<PropTypes> = ({ rawLines, level = 0 }) => {
const childrenSectionLines = rawLines.reduce((sections: string[][], line: string) => {
@@ -22,15 +23,22 @@ const ChildrenSections: React.FC<PropTypes> = ({ rawLines, level = 0 }) => {
}
return sections;
}, []);
- const children = childrenSectionLines.map(sectionLines => <Section rawLines={sectionLines} level={level}/>);
- return <> {children} </>;
-}
+ const children = childrenSectionLines.map(sectionLines => <Section rawLines={sectionLines} level={level} />);
+ return <>{children}</>;
+};
const Section: React.FC<PropTypes> = ({ rawLines, level = 0 }) => {
const deeperLevelIndex = rawLines.findIndex(line => line.match(`^#{${level + 1},} .*$`));
const rawContent = rawLines.splice(0, (deeperLevelIndex < 0) ? rawLines.length : deeperLevelIndex);
- if (!level) return <ChildrenSections rawLines={rawLines} level={getHeaderLevel(rawLines[0])}/>;
+ if (!level) {
+ return (
+ <>
+ <Typography><Content rawLines={rawContent} /></Typography>
+ <ChildrenSections rawLines={rawLines} level={getHeaderLevel(rawLines[0])} />
+ </>
+ );
+ }
const sectionName = rawContent.splice(0, 1)[0].slice(level).trim();
const deeperLevel = getHeaderLevel(rawLines[0]);
@@ -40,7 +48,7 @@ const Section: React.FC<PropTypes> = ({ rawLines, level = 0 }) => {
<ChildrenSections rawLines={rawLines} level={deeperLevel} />
</ContentSection>
);
-}
+};
export default Section;
diff --git a/src/lib/Markdown/SyntacticSpan.tsx b/src/lib/Markdown/SyntacticSpan.tsx
index 299bf87..11cc024 100644
--- a/src/lib/Markdown/SyntacticSpan.tsx
+++ b/src/lib/Markdown/SyntacticSpan.tsx
@@ -19,41 +19,41 @@ interface Emoji {
const enclosureRegex = (e: string): RegexPair => ({
local: new RegExp(`${e}([^${e}]+)${e}`),
- global: new RegExp(`(${e}[^${e}]+${e})`)
+ global: new RegExp(`(${e}[^${e}]+${e})`),
});
const regex: Record<string, RegexPair> = {
conceal: {
- global: /(!?\[.+?\]\(.+?\))/g,
- local: /!?\[(.+?)\]\((.+?)\)/
+ global: /(!?\[.+?\]\(.+?\))(?!])/g,
+ local: /!?\[(.*\]?.*)\]\((.+?)\)/,
},
rawLink: {
+ // eslint-disable-next-line max-len
global: /((?:(?:[A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www\.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)(?:(?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[.!/\\\w]*))?)/,
- local: /&^/
+ local: /&^/,
},
emoji: enclosureRegex(':'),
bold: enclosureRegex('\\*\\*'),
italic: enclosureRegex('\\*'),
code: enclosureRegex('`'),
strikeThrough: enclosureRegex('~~'),
-}
+};
const splitter = new RegExp(Object.values(regex).map(pair => pair.global.source).join('|'));
const emojiList: Emoji[] = [];
Object.keys(emojiLib).forEach(name => emojiList.push({ name, char: emojiLib[name].char }));
-console.log({emojiList})
const useStyles = makeStyles(theme => ({
code: {
background: theme.palette.background.default,
- borderRadius: theme.spacing(.5),
- padding: theme.spacing(.5),
+ borderRadius: theme.spacing(0.5),
+ padding: theme.spacing(0.5),
fontFamily: 'Monospace',
},
image: {
maxWidth: '100%',
- maxHeight: '100%'
+ maxHeight: '100%',
},
}));
@@ -64,12 +64,12 @@ const SyntacticSpan: React.FC<PropTypes> = ({ span }) => {
const matchConceal = regex.conceal.local.exec(span);
if (matchConceal) {
if (span[0] === '!') return <img src={matchConceal[2]} alt={matchConceal[1]} className={classes.image} />;
- return <Link href={matchConceal[2]}>{matchConceal[1]}</Link>;
+ return <Link href={matchConceal[2]}><SyntacticSpan span={matchConceal[1]} /></Link>;
}
const matchEmoji = span.match(regex.emoji.local);
if (matchEmoji) {
- const emoji = emojiList.find(emoji => emoji.name === matchEmoji[1]);
+ const emoji = emojiList.find(e => e.name === matchEmoji[1]);
return <span>{emoji ? emoji.char : span}</span>;
}
@@ -83,12 +83,12 @@ const SyntacticSpan: React.FC<PropTypes> = ({ span }) => {
if (matchItalic) return <i>{matchItalic[1]}</i>;
const matchStrikeThrough = span.match(regex.strikeThrough.local);
- if (matchStrikeThrough) return <span style={{textDecoration: 'line-through' }}>{matchStrikeThrough[1]}</span>;
+ if (matchStrikeThrough) return <span style={{ textDecoration: 'line-through' }}>{matchStrikeThrough[1]}</span>;
if (span.match(regex.rawLink.global)) return <Link href={span}>{span}</Link>;
return <>{span}</>;
-}
+};
export { splitter };
diff --git a/src/lib/Markdown/Text.tsx b/src/lib/Markdown/Text.tsx
index e287dee..be715fd 100644
--- a/src/lib/Markdown/Text.tsx
+++ b/src/lib/Markdown/Text.tsx
@@ -7,7 +7,7 @@ interface PropTypes {
const Text: React.FC<PropTypes> = ({ line }) => {
return <>{line.split(splitter).map(span => <SyntacticSpan span={span} />)}</>;
-}
+};
export default Text;
diff --git a/src/lib/SmartList/SmartList.tsx b/src/lib/SmartList/SmartList.tsx
index 22cd3b2..c86c127 100644
--- a/src/lib/SmartList/SmartList.tsx
+++ b/src/lib/SmartList/SmartList.tsx
@@ -21,8 +21,7 @@ interface Size {
const SmartList: React.FC<PropTypes> = ({ itemSize, itemCount, renderItem }) => {
-
- const ResizedList: React.FC<Size> = ({ width, height}) => (
+ const ResizedList: React.FC<Size> = ({ width, height }) => (
<FixedSizeList
height={height}
width={width}
diff --git a/src/lib/Window/Window.tsx b/src/lib/Window/Window.tsx
index 6821593..beaa672 100644
--- a/src/lib/Window/Window.tsx
+++ b/src/lib/Window/Window.tsx
@@ -47,12 +47,13 @@ const Window: React.FC<PropTypes> = ({ type, name, children }) => {
size={size}
position={position}
>
- {name &&
+ {name
+ && (
<div>
<Typography variant="h5" className={classes.header}>{name}</Typography>
<Divider />
</div>
- }
+ )}
{children}
</WindowSurface>
);
diff --git a/src/lib/Window/WindowSurface.tsx b/src/lib/Window/WindowSurface.tsx
index a65e398..1900901 100644
--- a/src/lib/Window/WindowSurface.tsx
+++ b/src/lib/Window/WindowSurface.tsx
@@ -22,7 +22,7 @@ const useStyles = makeStyles(theme => ({
'& a.MuiTypography-root': {
color: theme.palette.primary.light,
},
- }
+ },
}));
@@ -32,12 +32,12 @@ const WindowSurface: React.FC<PropTypes> = ({ size, position, children }) => {
return (
<Paper
variant="outlined"
- style={{...size, ...position}}
+ style={{ ...size, ...position }}
className={classes.surface}
>
{children}
</Paper>
- )
+ );
};
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
index 6431bc5..c7466ce 100644
--- a/src/react-app-env.d.ts
+++ b/src/react-app-env.d.ts
@@ -1 +1,2 @@
+// eslint-disable-next-line
/// <reference types="react-scripts" />