Merge remote-tracking branch 'origin/next' into webgl

This commit is contained in:
Vitaly Turovsky 2024-03-25 03:46:05 +03:00
commit b35bc0882f
25 changed files with 1184 additions and 124 deletions

View file

@ -21,6 +21,10 @@ jobs:
uses: actions/checkout@v2
with:
ref: refs/pull/${{ github.event.issue.number }}/head
- uses: actions/setup-node@v4
with:
node-version: 18
cache: "pnpm"
- name: Install Global Dependencies
run: npm install --global vercel pnpm
- name: Pull Vercel Environment Information
@ -45,3 +49,5 @@ jobs:
with:
message: |
Deployed to Vercel Preview: ${{ steps.deploy.outputs.stdout }}
[Playground](${{ steps.deploy.outputs.stdout }}/playground.html)
[Storybook](${{ steps.deploy.outputs.stdout }}/storybook/)

View file

@ -7,11 +7,12 @@ import './storybook.css'
const preview: Preview = {
decorators: [
(Story) => (
<div id='ui-root'>
(Story, c) => {
const noScaling = c.parameters.noScaling
return <div id={noScaling ? '' : 'ui-root'}>
<Story />
</div>
),
</div>;
},
],
parameters: {
actions: { argTypesRegex: "^on[A-Z].*" },

16
cypress.config.ts Normal file
View file

@ -0,0 +1,16 @@
import { defineConfig } from 'cypress'
export default defineConfig({
video: false,
chromeWebSecurity: false,
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config)
},
baseUrl: 'http://localhost:8080',
specPattern: 'cypress/e2e/**/*.spec.ts',
excludeSpecPattern: ['**/__snapshots__/*', '**/__image_snapshots__/*'],
},
})

View file

@ -1,11 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/cypress-io/cypress/188b9a742ee2ef51102167bfd84b3696a3f72a26/cli/schema/cypress.schema.json",
"baseUrl": "http://localhost:8080",
"testFiles": "**/*.spec.ts",
"video": false,
"chromeWebSecurity": false,
"ignoreTestFiles": [
"**/__snapshots__/*",
"**/__image_snapshots__/*"
]
}

View file

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 225 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

View file

@ -64,10 +64,15 @@
"peerjs": "^1.5.0",
"pretty-bytes": "^6.1.1",
"prismarine-provider-anvil": "github:zardoy/prismarine-provider-anvil#everything",
"prosemirror-example-setup": "^1.2.2",
"prosemirror-markdown": "^1.12.0",
"prosemirror-state": "^1.4.3",
"prosemirror-view": "^1.33.1",
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-transition-group": "^4.4.5",
"remark": "^15.0.1",
"sanitize-filename": "^1.6.3",
"skinview3d": "^3.0.1",
"source-map-js": "^1.0.2",
@ -100,7 +105,7 @@
"constants-browserify": "^1.0.0",
"contro-max": "^0.1.1",
"crypto-browserify": "^3.12.0",
"cypress": "^9.5.4",
"cypress": "^10.11.0",
"cypress-esbuild-preprocessor": "^1.0.2",
"eslint": "^8.50.0",
"eslint-config-zardoy": "^0.2.17",

581
pnpm-lock.yaml generated
View file

@ -68,7 +68,7 @@ importers:
version: 2.8.5
cypress-plugin-snapshots:
specifier: ^1.4.4
version: 1.4.4(cypress@9.5.4)
version: 1.4.4(cypress@10.11.0)
debug:
specifier: ^4.3.4
version: 4.3.4(supports-color@8.1.1)
@ -129,6 +129,18 @@ importers:
prismarine-provider-anvil:
specifier: github:zardoy/prismarine-provider-anvil#everything
version: github.com/zardoy/prismarine-provider-anvil/0ddcd9d48574113308e1fbebef60816aced0846f(minecraft-data@3.62.0)
prosemirror-example-setup:
specifier: ^1.2.2
version: 1.2.2
prosemirror-markdown:
specifier: ^1.12.0
version: 1.12.0
prosemirror-state:
specifier: ^1.4.3
version: 1.4.3
prosemirror-view:
specifier: ^1.33.1
version: 1.33.1
qrcode.react:
specifier: ^3.1.0
version: 3.1.0(react@18.2.0)
@ -141,6 +153,9 @@ importers:
react-transition-group:
specifier: ^4.4.5
version: 4.4.5(react-dom@18.2.0)(react@18.2.0)
remark:
specifier: ^15.0.1
version: 15.0.1
sanitize-filename:
specifier: ^1.6.3
version: 1.6.3
@ -237,8 +252,8 @@ importers:
specifier: ^3.12.0
version: 3.12.0
cypress:
specifier: ^9.5.4
version: 9.5.4
specifier: ^10.11.0
version: 10.11.0
cypress-esbuild-preprocessor:
specifier: ^1.0.2
version: 1.0.2
@ -5008,6 +5023,12 @@ packages:
'@types/node': 20.8.10
dev: true
/@types/debug@4.1.12:
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
dependencies:
'@types/ms': 0.7.34
dev: false
/@types/detect-port@1.3.3:
resolution: {integrity: sha512-bV/jQlAJ/nPY3XqSatkGpu+nGzou+uSwrH1cROhn+jBFg47yaNH+blW4C7p9KhopC7QxCv/6M86s37k8dMk0Yg==}
dev: true
@ -5129,6 +5150,12 @@ packages:
resolution: {integrity: sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg==}
dev: true
/@types/mdast@4.0.3:
resolution: {integrity: sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==}
dependencies:
'@types/unist': 2.0.8
dev: false
/@types/mdx@2.0.8:
resolution: {integrity: sha512-r7/zWe+f9x+zjXqGxf821qz++ld8tp6Z4jUS6qmPZUXH6tfh4riXOhAqb12tWGWAevCFtMt1goLWkQMqIJKpsA==}
dev: true
@ -5153,6 +5180,10 @@ packages:
resolution: {integrity: sha512-ZYFzrvyWUNhaPomn80dsMNgMeXxNWZBdkuG/hWlUvXvbdUH8ZERNBGXnU87McuGcWDsyzX2aChCv/SVN348k3A==}
dev: true
/@types/ms@0.7.34:
resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
dev: false
/@types/node-fetch@2.6.6:
resolution: {integrity: sha512-95X8guJYhfqiuVVhRFxVQcf4hW/2bCuoPwDasMf/531STFoNoWTT7YDnWdXHEZKqAGUigmpG31r2FE70LwnzJw==}
dependencies:
@ -5309,7 +5340,10 @@ packages:
/@types/unist@2.0.8:
resolution: {integrity: sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==}
dev: true
/@types/unist@3.0.2:
resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==}
dev: false
/@types/webxr@0.5.7:
resolution: {integrity: sha512-Rcgs5c2eNFnHp53YOjgtKfl/zWX1Y+uFGUwlSXrWcZWu3yhANRezmph4MninmqybUYT6g9ZE0aQ9QIdPkLR3Kg==}
@ -5339,7 +5373,7 @@ packages:
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
requiresBuild: true
dependencies:
'@types/node': 20.8.10
'@types/node': 20.11.19
optional: true
/@typescript-eslint/eslint-plugin@6.1.0(@typescript-eslint/parser@6.7.3)(eslint@8.50.0)(typescript@5.2.2):
@ -5960,7 +5994,6 @@ packages:
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
/aria-hidden@1.2.3:
resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==}
@ -6242,6 +6275,10 @@ packages:
resolution: {integrity: sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==}
dev: false
/bail@2.0.2:
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
dev: false
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@ -6600,7 +6637,6 @@ packages:
function-bind: 1.1.2
get-intrinsic: 1.2.4
set-function-length: 1.2.1
dev: true
/callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
@ -6731,6 +6767,10 @@ packages:
resolution: {integrity: sha512-CAtbGEDulyjzs05RXy3uKcwqeztz/dMEuAc1Xu9NQBsbrhuGMneL0u9Dj5SoutLKBFYun8txxYIwhjtLNfUmCA==}
dev: false
/character-entities@2.0.2:
resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
dev: false
/check-error@1.0.3:
resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
dependencies:
@ -7119,6 +7159,10 @@ packages:
sha.js: 2.4.11
dev: true
/crelt@1.0.6:
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
dev: false
/cross-spawn@6.0.5:
resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==}
engines: {node: '>=4.8'}
@ -7194,13 +7238,13 @@ packages:
resolution: {integrity: sha512-JsFnm6fBQt/OEzstknJ1KLMTuUERUaG0ZB9fk0KdNUlZqxaVEoQ9/pFvKmqRfzUe2y00cWD++ptccQA4tNAAlQ==}
dev: true
/cypress-plugin-snapshots@1.4.4(cypress@9.5.4):
/cypress-plugin-snapshots@1.4.4(cypress@10.11.0):
resolution: {integrity: sha512-rijq3RTEZNtxQA4KCUwjXinmE1Ww+z6cQW0B14iodFM/HlX5LN16XT/2QS3X1nUXRKt0QdTrAC5MQfMUrjBkSQ==}
engines: {node: '>=8.2.1'}
peerDependencies:
cypress: ^4.5.0
dependencies:
cypress: 9.5.4
cypress: 10.11.0
diff2html: 2.12.2
fs-extra: 7.0.1
image-size: 0.7.5
@ -7222,8 +7266,8 @@ packages:
- utf-8-validate
dev: false
/cypress@9.5.4:
resolution: {integrity: sha512-6AyJAD8phe7IMvOL4oBsI9puRNOWxZjl8z1lgixJMcgJ85JJmyKeP6uqNA0dI1z14lmJ7Qklf2MOgP/xdAqJ/Q==}
/cypress@10.11.0:
resolution: {integrity: sha512-lsaE7dprw5DoXM00skni6W5ElVVLGAdRUUdZjX2dYsGjbY/QnpzWZ95Zom1mkGg0hAaO/QVTZoFVS7Jgr/GUPA==}
engines: {node: '>=12.0.0'}
hasBin: true
requiresBuild: true
@ -7247,7 +7291,7 @@ packages:
dayjs: 1.11.9
debug: 4.3.4(supports-color@8.1.1)
enquirer: 2.4.1
eventemitter2: 6.4.9
eventemitter2: 6.4.7
execa: 4.1.0
executable: 4.1.1
extract-zip: 2.0.1(supports-color@8.1.1)
@ -7265,7 +7309,7 @@ packages:
pretty-bytes: 5.6.0
proxy-from-env: 1.0.0
request-progress: 3.0.0
semver: 7.5.4
semver: 7.6.0
supports-color: 8.1.1
tmp: 0.2.1
untildify: 4.0.0
@ -7358,6 +7402,12 @@ packages:
engines: {node: '>=10'}
dev: true
/decode-named-character-reference@1.0.2:
resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
dependencies:
character-entities: 2.0.2
dev: false
/decompress-response@4.2.1:
resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==}
engines: {node: '>=8'}
@ -7423,7 +7473,6 @@ packages:
es-define-property: 1.0.0
es-errors: 1.3.0
gopd: 1.0.1
dev: true
/define-lazy-prop@2.0.0:
resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
@ -7476,7 +7525,6 @@ packages:
/dequal@2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
dev: true
/des.js@1.1.0:
resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==}
@ -7531,6 +7579,12 @@ packages:
- supports-color
dev: true
/devlop@1.1.0:
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
dependencies:
dequal: 2.0.3
dev: false
/diff-sequences@29.6.3:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@ -7828,7 +7882,6 @@ packages:
/entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
dev: true
/env-paths@2.2.1:
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
@ -7960,12 +8013,10 @@ packages:
engines: {node: '>= 0.4'}
dependencies:
get-intrinsic: 1.2.4
dev: true
/es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
dev: true
/es-iterator-helpers@1.0.17:
resolution: {integrity: sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ==}
@ -8585,8 +8636,8 @@ packages:
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
engines: {node: '>=6'}
/eventemitter2@6.4.9:
resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==}
/eventemitter2@6.4.7:
resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==}
/eventemitter3@4.0.7:
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
@ -9057,7 +9108,6 @@ packages:
/function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
dev: true
/function.prototype.name@1.1.6:
resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
@ -9131,7 +9181,6 @@ packages:
has-proto: 1.0.1
has-symbols: 1.0.3
hasown: 2.0.1
dev: true
/get-nonce@1.0.1:
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
@ -9427,7 +9476,6 @@ packages:
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
dependencies:
es-define-property: 1.0.0
dev: true
/has-proto@1.0.1:
resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
@ -9481,7 +9529,6 @@ packages:
engines: {node: '>= 0.4'}
dependencies:
function-bind: 1.1.2
dev: true
/he@1.2.0:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
@ -10005,6 +10052,11 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/is-plain-obj@4.1.0:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'}
dev: false
/is-plain-object@2.0.4:
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
engines: {node: '>=0.10.0'}
@ -10516,6 +10568,12 @@ packages:
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
/linkify-it@5.0.0:
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
dependencies:
uc.micro: 2.1.0
dev: false
/listr2@3.14.0(enquirer@2.4.1):
resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==}
engines: {node: '>=10.0.0'}
@ -10671,6 +10729,10 @@ packages:
resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==}
dev: false
/longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
dev: false
/looks-same@8.2.3:
resolution: {integrity: sha512-0LK5r4+9t2D56XPVNH3hhG4o0yBYUdeu9FEd8z0ZCs/2fR9zJQj+6ob6ued8iHk3yddrSAdUA+9YGVK2FBMGUw==}
engines: {node: '>= 12.0.0'}
@ -10816,6 +10878,18 @@ packages:
resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==}
dev: true
/markdown-it@14.0.0:
resolution: {integrity: sha512-seFjF0FIcPt4P9U39Bq1JYblX0KZCjDLFFQPHpL5AzHpqPEKtosxmdq/LTVZnjfH7tjt9BxStm+wXcDBNuYmzw==}
hasBin: true
dependencies:
argparse: 2.0.1
entities: 4.5.0
linkify-it: 5.0.0
mdurl: 2.0.0
punycode.js: 2.3.1
uc.micro: 2.1.0
dev: false
/markdown-to-jsx@7.3.2(react@18.2.0):
resolution: {integrity: sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q==}
engines: {node: '>= 10'}
@ -10851,14 +10925,63 @@ packages:
unist-util-visit: 2.0.3
dev: true
/mdast-util-from-markdown@2.0.0:
resolution: {integrity: sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==}
dependencies:
'@types/mdast': 4.0.3
'@types/unist': 3.0.2
decode-named-character-reference: 1.0.2
devlop: 1.1.0
mdast-util-to-string: 4.0.0
micromark: 4.0.0
micromark-util-decode-numeric-character-reference: 2.0.1
micromark-util-decode-string: 2.0.0
micromark-util-normalize-identifier: 2.0.0
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
unist-util-stringify-position: 4.0.0
transitivePeerDependencies:
- supports-color
dev: false
/mdast-util-phrasing@4.1.0:
resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==}
dependencies:
'@types/mdast': 4.0.3
unist-util-is: 6.0.0
dev: false
/mdast-util-to-markdown@2.1.0:
resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==}
dependencies:
'@types/mdast': 4.0.3
'@types/unist': 3.0.2
longest-streak: 3.1.0
mdast-util-phrasing: 4.1.0
mdast-util-to-string: 4.0.0
micromark-util-decode-string: 2.0.0
unist-util-visit: 5.0.0
zwitch: 2.0.4
dev: false
/mdast-util-to-string@1.1.0:
resolution: {integrity: sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==}
dev: true
/mdast-util-to-string@4.0.0:
resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==}
dependencies:
'@types/mdast': 4.0.3
dev: false
/mdn-data@2.0.14:
resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
dev: false
/mdurl@2.0.0:
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
dev: false
/media-typer@0.3.0:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
@ -10914,6 +11037,181 @@ packages:
resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
engines: {node: '>= 0.6'}
/micromark-core-commonmark@2.0.0:
resolution: {integrity: sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==}
dependencies:
decode-named-character-reference: 1.0.2
devlop: 1.1.0
micromark-factory-destination: 2.0.0
micromark-factory-label: 2.0.0
micromark-factory-space: 2.0.0
micromark-factory-title: 2.0.0
micromark-factory-whitespace: 2.0.0
micromark-util-character: 2.1.0
micromark-util-chunked: 2.0.0
micromark-util-classify-character: 2.0.0
micromark-util-html-tag-name: 2.0.0
micromark-util-normalize-identifier: 2.0.0
micromark-util-resolve-all: 2.0.0
micromark-util-subtokenize: 2.0.0
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
dev: false
/micromark-factory-destination@2.0.0:
resolution: {integrity: sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==}
dependencies:
micromark-util-character: 2.1.0
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
dev: false
/micromark-factory-label@2.0.0:
resolution: {integrity: sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==}
dependencies:
devlop: 1.1.0
micromark-util-character: 2.1.0
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
dev: false
/micromark-factory-space@2.0.0:
resolution: {integrity: sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==}
dependencies:
micromark-util-character: 2.1.0
micromark-util-types: 2.0.0
dev: false
/micromark-factory-title@2.0.0:
resolution: {integrity: sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==}
dependencies:
micromark-factory-space: 2.0.0
micromark-util-character: 2.1.0
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
dev: false
/micromark-factory-whitespace@2.0.0:
resolution: {integrity: sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==}
dependencies:
micromark-factory-space: 2.0.0
micromark-util-character: 2.1.0
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
dev: false
/micromark-util-character@2.1.0:
resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==}
dependencies:
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
dev: false
/micromark-util-chunked@2.0.0:
resolution: {integrity: sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==}
dependencies:
micromark-util-symbol: 2.0.0
dev: false
/micromark-util-classify-character@2.0.0:
resolution: {integrity: sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==}
dependencies:
micromark-util-character: 2.1.0
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
dev: false
/micromark-util-combine-extensions@2.0.0:
resolution: {integrity: sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==}
dependencies:
micromark-util-chunked: 2.0.0
micromark-util-types: 2.0.0
dev: false
/micromark-util-decode-numeric-character-reference@2.0.1:
resolution: {integrity: sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==}
dependencies:
micromark-util-symbol: 2.0.0
dev: false
/micromark-util-decode-string@2.0.0:
resolution: {integrity: sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==}
dependencies:
decode-named-character-reference: 1.0.2
micromark-util-character: 2.1.0
micromark-util-decode-numeric-character-reference: 2.0.1
micromark-util-symbol: 2.0.0
dev: false
/micromark-util-encode@2.0.0:
resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==}
dev: false
/micromark-util-html-tag-name@2.0.0:
resolution: {integrity: sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==}
dev: false
/micromark-util-normalize-identifier@2.0.0:
resolution: {integrity: sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==}
dependencies:
micromark-util-symbol: 2.0.0
dev: false
/micromark-util-resolve-all@2.0.0:
resolution: {integrity: sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==}
dependencies:
micromark-util-types: 2.0.0
dev: false
/micromark-util-sanitize-uri@2.0.0:
resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==}
dependencies:
micromark-util-character: 2.1.0
micromark-util-encode: 2.0.0
micromark-util-symbol: 2.0.0
dev: false
/micromark-util-subtokenize@2.0.0:
resolution: {integrity: sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==}
dependencies:
devlop: 1.1.0
micromark-util-chunked: 2.0.0
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
dev: false
/micromark-util-symbol@2.0.0:
resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==}
dev: false
/micromark-util-types@2.0.0:
resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==}
dev: false
/micromark@4.0.0:
resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==}
dependencies:
'@types/debug': 4.1.12
debug: 4.3.4(supports-color@8.1.1)
decode-named-character-reference: 1.0.2
devlop: 1.1.0
micromark-core-commonmark: 2.0.0
micromark-factory-space: 2.0.0
micromark-util-character: 2.1.0
micromark-util-chunked: 2.0.0
micromark-util-combine-extensions: 2.0.0
micromark-util-decode-numeric-character-reference: 2.0.1
micromark-util-encode: 2.0.0
micromark-util-normalize-identifier: 2.0.0
micromark-util-resolve-all: 2.0.0
micromark-util-sanitize-uri: 2.0.0
micromark-util-subtokenize: 2.0.0
micromark-util-symbol: 2.0.0
micromark-util-types: 2.0.0
transitivePeerDependencies:
- supports-color
dev: false
/micromatch@4.0.5:
resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
engines: {node: '>=8.6'}
@ -11508,7 +11806,6 @@ packages:
/object-inspect@1.13.1:
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
dev: true
/object-is@1.1.5:
resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==}
@ -11640,6 +11937,10 @@ packages:
wcwidth: 1.0.1
dev: true
/orderedmap@2.1.1:
resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==}
dev: false
/os-browserify@0.3.0:
resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==}
dev: true
@ -12274,6 +12575,120 @@ packages:
object-assign: 4.1.1
react-is: 16.13.1
/prosemirror-commands@1.5.2:
resolution: {integrity: sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==}
dependencies:
prosemirror-model: 1.19.4
prosemirror-state: 1.4.3
prosemirror-transform: 1.8.0
dev: false
/prosemirror-dropcursor@1.8.1:
resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==}
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.8.0
prosemirror-view: 1.33.1
dev: false
/prosemirror-example-setup@1.2.2:
resolution: {integrity: sha512-pHJc656IgYm249RNp0eQaWNmnyWGk6OrzysWfYI4+NwE14HQ7YNYOlRBLErUS6uCAHIYJLNXf0/XCmf1OCtNbQ==}
dependencies:
prosemirror-commands: 1.5.2
prosemirror-dropcursor: 1.8.1
prosemirror-gapcursor: 1.3.2
prosemirror-history: 1.3.2
prosemirror-inputrules: 1.4.0
prosemirror-keymap: 1.2.2
prosemirror-menu: 1.2.4
prosemirror-schema-list: 1.3.0
prosemirror-state: 1.4.3
dev: false
/prosemirror-gapcursor@1.3.2:
resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==}
dependencies:
prosemirror-keymap: 1.2.2
prosemirror-model: 1.19.4
prosemirror-state: 1.4.3
prosemirror-view: 1.33.1
dev: false
/prosemirror-history@1.3.2:
resolution: {integrity: sha512-/zm0XoU/N/+u7i5zepjmZAEnpvjDtzoPWW6VmKptcAnPadN/SStsBjMImdCEbb3seiNTpveziPTIrXQbHLtU1g==}
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.8.0
prosemirror-view: 1.33.1
rope-sequence: 1.3.4
dev: false
/prosemirror-inputrules@1.4.0:
resolution: {integrity: sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==}
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.8.0
dev: false
/prosemirror-keymap@1.2.2:
resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==}
dependencies:
prosemirror-state: 1.4.3
w3c-keyname: 2.2.8
dev: false
/prosemirror-markdown@1.12.0:
resolution: {integrity: sha512-6F5HS8Z0HDYiS2VQDZzfZP6A0s/I0gbkJy8NCzzDMtcsz3qrfqyroMMeoSjAmOhDITyon11NbXSzztfKi+frSQ==}
dependencies:
markdown-it: 14.0.0
prosemirror-model: 1.19.4
dev: false
/prosemirror-menu@1.2.4:
resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==}
dependencies:
crelt: 1.0.6
prosemirror-commands: 1.5.2
prosemirror-history: 1.3.2
prosemirror-state: 1.4.3
dev: false
/prosemirror-model@1.19.4:
resolution: {integrity: sha512-RPmVXxUfOhyFdayHawjuZCxiROsm9L4FCUA6pWI+l7n2yCBsWy9VpdE1hpDHUS8Vad661YLY9AzqfjLhAKQ4iQ==}
dependencies:
orderedmap: 2.1.1
dev: false
/prosemirror-schema-list@1.3.0:
resolution: {integrity: sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==}
dependencies:
prosemirror-model: 1.19.4
prosemirror-state: 1.4.3
prosemirror-transform: 1.8.0
dev: false
/prosemirror-state@1.4.3:
resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==}
dependencies:
prosemirror-model: 1.19.4
prosemirror-transform: 1.8.0
prosemirror-view: 1.33.1
dev: false
/prosemirror-transform@1.8.0:
resolution: {integrity: sha512-BaSBsIMv52F1BVVMvOmp1yzD3u65uC3HTzCBQV1WDPqJRQ2LuHKcyfn0jwqodo8sR9vVzMzZyI+Dal5W9E6a9A==}
dependencies:
prosemirror-model: 1.19.4
dev: false
/prosemirror-view@1.33.1:
resolution: {integrity: sha512-62qkYgSJIkwIMMCpuGuPzc52DiK1Iod6TWoIMxP4ja6BTD4yO8kCUL64PZ/WhH/dJ9fW0CDO39FhH1EMyhUFEg==}
dependencies:
prosemirror-model: 1.19.4
prosemirror-state: 1.4.3
prosemirror-transform: 1.8.0
dev: false
/protodef-validator@1.3.1:
resolution: {integrity: sha512-lZ5FWKZYR9xOjpMw1+EfZRfCjzNRQWPq+Dk+jki47Sikl2EeWEPnTfnJERwnU/EwFq6us+0zqHHzSsmLeYX+Lg==}
hasBin: true
@ -12337,6 +12752,11 @@ packages:
pump: 2.0.1
dev: true
/punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
dev: false
/punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
@ -12344,7 +12764,6 @@ packages:
/punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
dev: false
/puppeteer-core@2.1.1:
resolution: {integrity: sha512-n13AWriBMPYxnpbb6bnaY5YoY6rGj8vPLrz6CZF3o0qJNEwlcfJVxBzYZ0NJsQ21UbdJoijPCDrM++SUVEz7+w==}
@ -12378,7 +12797,7 @@ packages:
resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==}
engines: {node: '>=0.6'}
dependencies:
side-channel: 1.0.4
side-channel: 1.0.5
/qs@6.11.0:
resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
@ -12942,6 +13361,17 @@ packages:
unist-util-visit: 2.0.3
dev: true
/remark-parse@11.0.0:
resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==}
dependencies:
'@types/mdast': 4.0.3
mdast-util-from-markdown: 2.0.0
micromark-util-types: 2.0.0
unified: 11.0.4
transitivePeerDependencies:
- supports-color
dev: false
/remark-slug@6.1.0:
resolution: {integrity: sha512-oGCxDF9deA8phWvxFuyr3oSJsdyUAxMFbA0mZ7Y1Sas+emILtO+e5WutF9564gDsEN4IXaQXm5pFo6MLH+YmwQ==}
dependencies:
@ -12950,6 +13380,25 @@ packages:
unist-util-visit: 2.0.3
dev: true
/remark-stringify@11.0.0:
resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==}
dependencies:
'@types/mdast': 4.0.3
mdast-util-to-markdown: 2.1.0
unified: 11.0.4
dev: false
/remark@15.0.1:
resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==}
dependencies:
'@types/mdast': 4.0.3
remark-parse: 11.0.0
remark-stringify: 11.0.0
unified: 11.0.4
transitivePeerDependencies:
- supports-color
dev: false
/request-progress@3.0.0:
resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==}
dependencies:
@ -13088,6 +13537,10 @@ packages:
optionalDependencies:
fsevents: 2.3.3
/rope-sequence@1.3.4:
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
dev: false
/rtl-css-js@1.16.1:
resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==}
dependencies:
@ -13264,7 +13717,6 @@ packages:
get-intrinsic: 1.2.4
gopd: 1.0.1
has-property-descriptors: 1.0.2
dev: true
/set-function-name@2.0.1:
resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==}
@ -13356,7 +13808,6 @@ packages:
es-errors: 1.3.0
get-intrinsic: 1.2.4
object-inspect: 1.13.1
dev: true
/siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
@ -14166,7 +14617,7 @@ packages:
engines: {node: '>=6'}
dependencies:
psl: 1.9.0
punycode: 2.3.0
punycode: 2.3.1
universalify: 0.2.0
url-parse: 1.5.10
@ -14184,6 +14635,10 @@ packages:
engines: {node: '>=12'}
dev: true
/trough@2.2.0:
resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
dev: false
/truncate-utf8-bytes@1.0.2:
resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==}
dependencies:
@ -14363,6 +14818,10 @@ packages:
resolution: {integrity: sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==}
dev: false
/uc.micro@2.1.0:
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
dev: false
/ufo@1.3.1:
resolution: {integrity: sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==}
dev: true
@ -14422,6 +14881,18 @@ packages:
diff: 2.2.3
dev: false
/unified@11.0.4:
resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==}
dependencies:
'@types/unist': 3.0.2
bail: 2.0.2
devlop: 1.1.0
extend: 3.0.2
is-plain-obj: 4.1.0
trough: 2.2.0
vfile: 6.0.1
dev: false
/union@0.5.0:
resolution: {integrity: sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==}
engines: {node: '>= 0.8.0'}
@ -14457,6 +14928,18 @@ packages:
resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==}
dev: true
/unist-util-is@6.0.0:
resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
dependencies:
'@types/unist': 3.0.2
dev: false
/unist-util-stringify-position@4.0.0:
resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
dependencies:
'@types/unist': 3.0.2
dev: false
/unist-util-visit-parents@3.1.1:
resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==}
dependencies:
@ -14464,6 +14947,13 @@ packages:
unist-util-is: 4.1.0
dev: true
/unist-util-visit-parents@6.0.1:
resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
dependencies:
'@types/unist': 3.0.2
unist-util-is: 6.0.0
dev: false
/unist-util-visit@2.0.3:
resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==}
dependencies:
@ -14472,6 +14962,14 @@ packages:
unist-util-visit-parents: 3.1.1
dev: true
/unist-util-visit@5.0.0:
resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
dependencies:
'@types/unist': 3.0.2
unist-util-is: 6.0.0
unist-util-visit-parents: 6.0.1
dev: false
/universalify@0.1.2:
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
engines: {node: '>= 4.0.0'}
@ -14706,6 +15204,21 @@ packages:
core-util-is: 1.0.2
extsprintf: 1.3.0
/vfile-message@4.0.2:
resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
dependencies:
'@types/unist': 3.0.2
unist-util-stringify-position: 4.0.0
dev: false
/vfile@6.0.1:
resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==}
dependencies:
'@types/unist': 3.0.2
unist-util-stringify-position: 4.0.0
vfile-message: 4.0.2
dev: false
/vite-node@0.34.6(@types/node@20.8.0):
resolution: {integrity: sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==}
engines: {node: '>=v14.18.0'}
@ -14863,6 +15376,10 @@ packages:
- terser
dev: true
/w3c-keyname@2.2.8:
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
dev: false
/walker@1.0.8:
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
dependencies:
@ -15415,6 +15932,10 @@ packages:
react: 18.2.0
dev: false
/zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
dev: false
github.com/PrismarineJS/mineflayer/195b3cbd70a110080af9b77a4659991c5d9e484a:
resolution: {tarball: https://codeload.github.com/PrismarineJS/mineflayer/tar.gz/195b3cbd70a110080af9b77a4659991c5d9e484a}
name: mineflayer

View file

@ -22,6 +22,10 @@ subscribe(customKeymaps, () => {
localStorage.keymap = JSON.parse(customKeymaps)
})
const controlOptions = {
preventDefault: true
}
export const contro = new ControMax({
commands: {
general: {
@ -58,6 +62,7 @@ export const contro = new ControMax({
}
},
}, {
defaultControlOptions: controlOptions,
target: document,
captureEvents () {
return bot && isGameActive(false)
@ -71,6 +76,10 @@ export const contro = new ControMax({
window.controMax = contro
export type Command = CommandEventArgument<typeof contro['_commandsRaw']>['command']
export const setDoPreventDefault = (state: boolean) => {
controlOptions.preventDefault = state
}
const setSprinting = (state: boolean) => {
bot.setControlState('sprint', state)
gameAdditionalState.isSprinting = state

View file

@ -25,9 +25,9 @@ export const useGoogleLogIn = () => {
const login = useGoogleLogin({
onSuccess (tokenResponse) {
localStorage.hasEverLoggedIn = true
googleProviderData.accessToken = tokenResponse.access_token
googleProviderData.expiresIn = ref(new Date(Date.now() + tokenResponse.expires_in * 1000))
googleProviderData.hasEverLoggedIn = true
googleProviderState.accessToken = tokenResponse.access_token
googleProviderState.expiresIn = ref(new Date(Date.now() + tokenResponse.expires_in * 1000))
googleProviderState.hasEverLoggedIn = true
},
// prompt: hasEverLoggedIn ? 'none' : 'consent',
scope: SCOPES,
@ -35,12 +35,12 @@ export const useGoogleLogIn = () => {
onError (error) {
const accessDenied = error.error === 'access_denied' || error.error === 'invalid_scope' || (error as any).error_subtype === 'access_denied'
if (accessDenied) {
googleProviderData.hasEverLoggedIn = false
googleProviderState.hasEverLoggedIn = false
}
}
})
return () => login({
prompt: googleProviderData.hasEverLoggedIn ? 'none' : 'consent'
prompt: googleProviderState.hasEverLoggedIn ? 'none' : 'consent'
})
}
@ -61,11 +61,11 @@ export const possiblyHandleStateVariable = async () => {
async callback (response) {
if (response.error) {
setLoadingScreenStatus('Error: ' + response.error, true)
googleProviderData.hasEverLoggedIn = false
googleProviderState.hasEverLoggedIn = false
return
}
setLoadingScreenStatus('Opening world in read only mode...')
googleProviderData.accessToken = response.access_token
googleProviderState.accessToken = response.access_token
await mountGoogleDriveFolder(true, parsed.ids[0])
await loadInMemorySave('/google')
}
@ -73,14 +73,14 @@ export const possiblyHandleStateVariable = async () => {
const choice = await showOptionsModal('Select an action...', ['Login'])
if (choice === 'Login') {
tokenClient.requestAccessToken({
prompt: googleProviderData.hasEverLoggedIn ? '' : 'consent',
prompt: googleProviderState.hasEverLoggedIn ? '' : 'consent',
})
} else {
window.close()
}
}
export const googleProviderData = proxy({
export const googleProviderState = proxy({
accessToken: (localStorage.saveAccessToken ? localStorage.accessToken : null) as string | null,
hasEverLoggedIn: !!(localStorage.hasEverLoggedIn),
isReady: false,
@ -92,18 +92,18 @@ export const googleProviderData = proxy({
} | null
})
subscribe(googleProviderData, () => {
localStorage.googleReadonlyMode = googleProviderData.readonlyMode
localStorage.lastSelectedFolder = googleProviderData.lastSelectedFolder ? JSON.stringify(googleProviderData.lastSelectedFolder) : null
if (googleProviderData.hasEverLoggedIn) {
subscribe(googleProviderState, () => {
localStorage.googleReadonlyMode = googleProviderState.readonlyMode
localStorage.lastSelectedFolder = googleProviderState.lastSelectedFolder ? JSON.stringify(googleProviderState.lastSelectedFolder) : null
if (googleProviderState.hasEverLoggedIn) {
localStorage.hasEverLoggedIn = true
} else {
delete localStorage.hasEverLoggedIn
}
if (localStorage.saveAccessToken && googleProviderData) {
if (localStorage.saveAccessToken && googleProviderState) {
// For testing only
localStorage.accessToken = googleProviderData.accessToken || null
localStorage.accessToken = googleProviderState.accessToken || null
} else {
delete localStorage.accessToken
}

View file

@ -0,0 +1,39 @@
import { describe, expect, it } from 'vitest'
import markdownToFormattedText from './markdownToFormattedText'
describe('markdownToFormattedText', () => {
it('should convert markdown to formatted text', () => {
const markdown = '**bold** *italic* [link](https://example.com) k `code`'
const text = markdownToFormattedText(markdown)
const command = '/data merge block ~ ~ ~ {Text1:\'' + JSON.stringify(text[0]) + '\',Text2: \'' + JSON.stringify(text[1]) + '\',Text3:\'' + JSON.stringify(text[2]) + '\',Text4:\'' + JSON.stringify(text[3]) + '\'}' // mojangson
expect(text).toMatchInlineSnapshot(`
[
[
[
{
"bold": true,
"text": "bold",
},
{
"text": " ",
},
{
"italic": true,
"text": "italic",
},
{
"text": " ",
},
{
"text": " k ",
},
"code",
],
],
"",
"",
"",
]
`)
})
})

View file

@ -0,0 +1,58 @@
import { remark } from 'remark'
export default (markdown: string) => {
const arr = markdown.split('\n\n')
const lines = ['', '', '', '']
for (const [i, ast] of arr.map(md => remark().parse(md)).entries()) {
lines[i] = transformToMinecraftJSON(ast as Element)
}
return lines
}
function transformToMinecraftJSON (element: Element): any {
switch (element.type) {
case 'root': {
if (!element.children) return
return element.children.map(child => transformToMinecraftJSON(child)).filter(Boolean)
}
case 'paragraph': {
if (!element.children) return
const transformedChildren = element.children.map(child => transformToMinecraftJSON(child)).filter(Boolean)
return transformedChildren.flat()
}
case 'strong': {
if (!element.children) return
return [{ bold: true, text: element.children[0].value }]
}
case 'text': {
return { text: element.value }
}
case 'emphasis': {
if (!element.children) return
return [{ italic: true, text: element.children[0].value }]
}
default:
// todo leave untouched eg links
return element.value
}
}
interface Position {
start: {
line: number;
column: number;
offset: number;
};
end: {
line: number;
column: number;
offset: number;
};
}
interface Element {
type: string;
children?: Element[];
value?: string;
position: Position;
}

View file

@ -152,6 +152,22 @@ export const guiOptionsScheme: {
},
chatSelect: {
},
},
{
custom () {
return <Category>Sign Editor</Category>
},
autoSignEditor: {
text: 'Enable Sign Editor',
},
wysiwygSignEditor: {
text: 'WYSIWG Editor',
values: [
'auto',
'always',
'never'
],
},
}
],
controls: [

View file

@ -75,6 +75,9 @@ const defaultOptions = {
autoRespawn: false,
mutedSounds: [] as string[],
plugins: [] as Array<{ enabled: boolean, name: string, description: string, script: string }>,
/** Wether to popup sign editor on server action */
autoSignEditor: true,
wysiwygSignEditor: 'auto' as 'auto' | 'always' | 'never',
}
const migrateOptions = (options: Partial<AppOptions & Record<string, any>>) => {

115
src/react/SignEditor.css Normal file
View file

@ -0,0 +1,115 @@
.signs-editor-container {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.4);
display: flex;
justify-content: center;
align-items: center;
}
.signs-editor-inner-container {
position: relative;
width: 700px;
aspect-ratio: 2;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.signs-editor-bg-image {
position: absolute;
z-index: -1;
width: 100%;
height: 100%;
image-rendering: pixelated;
}
.sign-editor {
font: inherit;
font-size: 420%;
width: 90%;
max-height: 90%;
background-color: rgba(255, 255, 255, 0);
border-width: 0px;
overflow: auto;
outline: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
box-sizing: border-box;
resize: none;
text-align: center;
}
/* @media (min-width: 1200px) { */
/* .sign-editor { */
/* font-size: 400%; */
/* } */
/* } */
.ProseMirror p {
font-size: 420%;
text-align: center;
}
@media (max-width: 850px) {
.ProseMirror p {
font-size: 310%;
}
.sign-editor {
font-size: 310%;
}
.signs-editor-inner-container {
width: 500px;
}
}
@media (max-width: 550px) {
.ProseMirror p {
font-size: 180%;
}
.sign-editor {
font-size: 180%;
}
.signs-editor-inner-container {
width: 300px;
}
}
@media (max-width: 350px) {
.ProseMirror p {
font-size: 130%;
}
.sign-editor {
font-size: 130%;
}
.signs-editor-inner-container {
width: 220px;
}
}
.wysiwyg-editor {
color: black;
max-height: 100%;
overflow: hidden;
width: 90%;
margin: 0px;
white-space: pre-wrap;
border: 1px solid #ccc;
}
.sign-editor-button {
position: absolute;
right: 0px;
bottom: 0px;
width: 75px;
}
.ProseMirror-menubar {
background-color: rgba(255, 255, 255, 0.7);
}
.ProseMirror {
}

View file

@ -0,0 +1,25 @@
import type { Meta, StoryObj } from '@storybook/react'
import SignEditor from './SignEditor'
const meta: Meta<typeof SignEditor> = {
component: SignEditor,
render (args) {
return <SignEditor {...args} handleClick={(result) => {
console.log('handleClick', result)
}} />
}
}
export default meta
type Story = StoryObj<typeof SignEditor>;
export const Primary: Story = {
args: {
handleInput () {},
isWysiwyg: false
},
parameters: {
noScaling: true
},
}

83
src/react/SignEditor.tsx Normal file
View file

@ -0,0 +1,83 @@
import { useEffect, useRef } from 'react'
import { focusable } from 'tabbable'
import markdownToFormattedText from '../markdownToFormattedText'
import { ProseMirrorView } from './prosemirror-markdown'
import Button from './Button'
import 'prosemirror-view/style/prosemirror.css'
import 'prosemirror-menu/style/menu.css'
import './SignEditor.css'
const imageSource = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAMCAYAAAB4MH11AAABbElEQVR4AY3BQY6cMBBA0Q+yQZZVi+ndcJVcKGfMgegdvShKVtuokzGSWwwiUd7rfv388Vst0UgMXCobmgsSA5VaQmKgUks0EgNHji8SA9W8GJCQwVNpLhzJ4KFs4B1HEgPVvBiQkMFTaS44tYTEQDXdIkfiHbuyobmguaDPFzIWGrWExEA13SJH4h1uzS/WbPyvroM1v6jWbFRrNv7GfX5EdmXjzTvUEjJ4zjQXjiQGdmXjzTvUEjJ4HF/UEt/kQqW5UEkMzIshY08jg6dRS3yTC5XmgpsXY7pFztQSEgPNJCNv3lGpJVSfTLfImVpCYsB1HdwfxpU1G9eeNF0H94dxZc2G+/yI7MoG3vEv82LI2NNIDLyVDbzjzFE2mnkxZOy5IoNnkpFGc2FXNpp5MWTsOXJ4h1qikrGnkhjYlY1m1icy9lQSA+TCzjvUEpWMPZXEwK5suPvDOFuzcdZ1sOYX1ZqNas3GlTUbzR+jQbEAcs8ZQAAAAABJRU5ErkJggg=='
type Props = {
handleInput: (target: HTMLInputElement) => void,
isWysiwyg: boolean,
handleClick?: (view: ResultType) => void
}
export type ResultType = {
plainText: string[]
} | {
dataText: string[]
}
export default ({ handleInput, isWysiwyg, handleClick }: Props) => {
const prosemirrorContainer = useRef(null)
const editorView = useRef<ProseMirrorView | null>(null)
useEffect(() => {
if (isWysiwyg) {
editorView.current = new ProseMirrorView(prosemirrorContainer.current, '')
}
}, [isWysiwyg])
return <div
className='signs-editor-container'
onKeyDown={(e) => {
// arrow down/up, Enter to navigate between lines
if (isWysiwyg) return // todo
let { code } = e
if ((e.target as HTMLElement).matches('input') && e.key === 'Enter') code = 'ArrowDown'
if (code === 'ArrowDown' || code === 'ArrowUp') {
e.preventDefault()
const dir = code === 'ArrowDown' ? 1 : -1
const elements = focusable(e.currentTarget)
const focusedElemIndex = elements.indexOf(document.activeElement as HTMLElement)
if (focusedElemIndex === -1) return
const nextElem = elements[focusedElemIndex + dir]
nextElem?.focus()
}
}}>
<div className='signs-editor-inner-container'>
<img className='signs-editor-bg-image' src={imageSource} alt='' />
{isWysiwyg ? (
<p ref={prosemirrorContainer} className='wysiwyg-editor'></p>
) : [1, 2, 3, 4].map((value, index) => {
return <input
className='sign-editor'
key={index}
data-key={index}
maxLength={15} // overriden by handleInput
onChange={(e) => {
handleInput(e.currentTarget)
}} />
})
}
<Button onClick={async () => {
if (handleClick) {
if (isWysiwyg) {
const text = markdownToFormattedText(editorView.current!.content)
handleClick({ dataText: text })
} else {
const text = [] as string[]
for (const input of document.getElementsByClassName('sign-editor')) {
text.push((input as HTMLInputElement).value)
}
handleClick({ plainText: text })
}
}
}} className='sign-editor-button' label={'Done'} />
</div>
</div>
}

View file

@ -0,0 +1,84 @@
import { useMemo, useEffect, useState, useRef } from 'react'
import { showModal, hideModal } from '../globalState'
import { setDoPreventDefault } from '../controls'
import { options } from '../optionsStorage'
import { useIsModalActive } from './utils'
import SignEditor, { ResultType } from './SignEditor'
const isWysiwyg = async () => {
const items = await bot.tabComplete('/', true, true)
const commands = new Set<string>(['data'])
for (const item of items) {
if (commands.has(item.match as unknown as string)) {
return true
}
}
return false
}
export default () => {
const [location, setLocation] = useState<{x: number, y: number, z: number} | null>(null)
const [isFrontText, setIsFrontText] = useState(true)
const text = useRef<string[]>(['', '', '', ''])
const [enableWysiwyg, setEnableWysiwyg] = useState(false)
const isModalActive = useIsModalActive('signs-editor-screen')
const handleClick = (result: ResultType) => {
hideModal({ reactType: 'signs-editor-screen' })
if ('plainText' in result) {
bot._client.write('update_sign', {
location,
isFrontText,
text1: result.plainText[0],
text2: result.plainText[1],
text3: result.plainText[2],
text4: result.plainText[3]
})
} else {
if (!location) return
const command = `/data merge block ${location.x} ${location.y} ${location.z} {Text1:'` + JSON.stringify(result.dataText[0]) + '\',Text2: \'' + JSON.stringify(result.dataText[1]) + '\',Text3:\'' + JSON.stringify(result.dataText[2]) + '\',Text4:\'' + JSON.stringify(result.dataText[3]) + '\'}' // mojangson
bot.chat(command)
}
}
const handleInput = (target: HTMLInputElement) => {
const smallSymbols = /[()[\]{} ]/
const largeSymbols = /[;|',.]/
let addLength = 0
for (const letter of target.value) {
if (smallSymbols.test(letter)) {
addLength += 1 - 1 / 1.46
} else if (largeSymbols.test(letter)) {
addLength += 1 - 1 / 3
}
}
text.current[Number(target.dataset.key)] = target.value
target.setAttribute('maxlength', `${15 + Math.ceil(addLength)}`)
}
useEffect(() => {
setDoPreventDefault(!isModalActive) // disable e.preventDefault() since we might be using wysiwyg editor which doesn't use textarea and need default browser behavior to ensure characters are being typed in contenteditable container. Ideally we should do e.preventDefault() only when either ctrl, cmd (meta) or alt key is pressed.
}, [isModalActive])
useMemo(() => {
bot._client.on('open_sign_entity', (packet) => {
if (!options.autoSignEditor) return
setIsFrontText((packet as any).isFrontText ?? true)
setLocation(prev => packet.location)
showModal({ reactType: 'signs-editor-screen' })
if (options.wysiwygSignEditor === 'auto') {
void isWysiwyg().then((value) => {
setEnableWysiwyg(value)
})
} else if (options.wysiwygSignEditor === 'always') {
setEnableWysiwyg(true)
} else {
setEnableWysiwyg(false)
}
})
}, [])
if (!isModalActive) return null
return <SignEditor isWysiwyg={enableWysiwyg} handleInput={handleInput} handleClick={handleClick} />
}

View file

@ -7,7 +7,7 @@ import { googleDriveGetFileIdFromPath, mountExportFolder, mountGoogleDriveFolder
import { hideCurrentModal, showModal } from '../globalState'
import { haveDirectoryPicker, setLoadingScreenStatus } from '../utils'
import { exportWorld } from '../builtinCommands'
import { googleProviderData, useGoogleLogIn, GoogleDriveProvider, isGoogleDriveAvailable, APP_ID } from '../googledrive'
import { googleProviderState, useGoogleLogIn, GoogleDriveProvider, isGoogleDriveAvailable, APP_ID } from '../googledrive'
import Singleplayer, { WorldProps } from './Singleplayer'
import { useIsModalActive } from './utils'
import { showOptionsModal } from './SelectOption'
@ -18,6 +18,7 @@ const worldsProxy = proxy({
value: null as null | WorldProps[],
brokenWorlds: [] as string[],
selectedProvider: 'local' as 'local' | 'google',
selectedGoogleId: '',
error: '',
})
@ -48,7 +49,7 @@ export const readWorlds = (abortController: AbortController) => {
(async () => {
const brokenWorlds = [] as string[]
try {
const loggedIn = !!googleProviderData.accessToken
const loggedIn = !!googleProviderState.accessToken
worldsProxy.value = null
if (worldsProxy.selectedProvider === 'google' && !loggedIn) {
worldsProxy.value = []
@ -135,7 +136,7 @@ export const loadGoogleDriveApi = async () => {
gapi.load('client', () => {
gapi.load('client:picker', () => {
void gapi.client.load('https://www.googleapis.com/discovery/v1/apis/drive/v3/rest').then(() => {
googleProviderData.isReady = true
googleProviderState.isReady = true
resolve()
})
})
@ -145,24 +146,17 @@ export const loadGoogleDriveApi = async () => {
const Inner = () => {
const worlds = useSnapshot(worldsProxy).value as WorldProps[] | null
const { selectedProvider, error, brokenWorlds } = useSnapshot(worldsProxy)
const { selectedProvider, error, brokenWorlds, selectedGoogleId } = useSnapshot(worldsProxy)
const readWorldsAbortController = useRef(new AbortController())
useEffect(() => {
return () => {
worldsProxy.selectedProvider = 'local'
}
}, [])
// 3rd party providers
useEffect(() => {
if (selectedProvider !== 'google') return
void loadGoogleDriveApi()
}, [selectedProvider])
const [selectedGoogleId, setSelectedGoogleId] = useState('')
const loggedIn = !!useSnapshot(googleProviderData).accessToken
const googleDriveReadonly = useSnapshot(googleProviderData).readonlyMode
const loggedIn = !!useSnapshot(googleProviderState).accessToken
const googleDriveReadonly = useSnapshot(googleProviderState).readonlyMode
useEffect(() => {
(async () => {
@ -171,7 +165,7 @@ const Inner = () => {
worldsProxy.value = []
return
}
await mountGoogleDriveFolder(googleProviderData.readonlyMode, selectedGoogleId)
await mountGoogleDriveFolder(googleProviderState.readonlyMode, selectedGoogleId)
const exists = async (path) => {
try {
await fs.promises.stat(path)
@ -199,21 +193,74 @@ const Inner = () => {
const googleLogIn = useGoogleLogIn()
const isGoogleProviderReady = useSnapshot(googleProviderData).isReady
const providerActions = selectedProvider === 'google' ? isGoogleProviderReady ? loggedIn ? {
const googlePicker = useRef/* <google.picker.Picker | null> */(null as any)
useEffect(() => {
return () => {
googlePicker.current?.dispose()
}
})
const selectGoogleFolder = async () => {
if (googleProviderState.lastSelectedFolder) {
// ask to use saved previous fodler
const choice = await showOptionsModal(`Use previously selected folder "${googleProviderState.lastSelectedFolder.name}"?`, ['Yes', 'No'])
if (!choice) return
if (choice === 'Yes') {
worldsProxy.selectedGoogleId = googleProviderState.lastSelectedFolder.id
return
}
}
const { google } = window
const view = new google.picker.DocsView(google.picker.ViewId.FOLDERS)
.setIncludeFolders(true)
.setMimeTypes('application/vnd.google-apps.folder')
.setSelectFolderEnabled(true)
.setParent('root')
googlePicker.current = new google.picker.PickerBuilder()
.enableFeature(google.picker.Feature.NAV_HIDDEN)
.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
.setDeveloperKey('AIzaSyBTiHpEqaLL7mEcrsnSS4M-z8cpRH5UwY0')
.setAppId(APP_ID)
.setOAuthToken(googleProviderState.accessToken)
.addView(view)
.addView(new google.picker.DocsUploadView())
.setTitle('Select a folder with your worlds')
.setCallback((data) => {
if (data.action === google.picker.Action.PICKED) {
googleProviderState.lastSelectedFolder = {
id: data.docs[0].id,
name: data.docs[0].name,
}
worldsProxy.selectedGoogleId = data.docs[0].id
}
})
.build()
googlePicker.current.setVisible(true)
}
const isGoogleProviderReady = useSnapshot(googleProviderState).isReady
const providerActions = loggedIn && selectedProvider === 'google' && isGoogleProviderReady && !selectedGoogleId ? {
'Select Folder': selectGoogleFolder
} : selectedProvider === 'google' ? isGoogleProviderReady ? loggedIn ? {
'Log Out' () {
googleProviderData.hasEverLoggedIn = false
googleProviderData.accessToken = null
googleProviderData.lastSelectedFolder = null
window.google.accounts.oauth2.revoke(googleProviderData.accessToken)
googleProviderState.hasEverLoggedIn = false
googleProviderState.accessToken = null
googleProviderState.lastSelectedFolder = null
window.google.accounts.oauth2.revoke(googleProviderState.accessToken)
},
async [`Read Only: ${googleDriveReadonly ? 'ON' : 'OFF'}`] () {
if (googleProviderData.readonlyMode) {
if (googleProviderState.readonlyMode) {
const choice = await showOptionsModal('[Unstable Feature] Enabling world save might corrupt your worlds, eg remove entities (note: you can always restore previous version of files in Drive)', ['Continue'])
if (choice !== 'Continue') return
}
googleProviderData.readonlyMode = !googleProviderData.readonlyMode
googleProviderState.readonlyMode = !googleProviderState.readonlyMode
},
'Select Folder': selectGoogleFolder,
// 'Worlds Path': <Input rootStyles={{ width: 100 }} placeholder='Worlds path' defaultValue={worldsPath} onBlur={(e) => {
// googleProviderData.worldsPath = e.target.value
// }} />
@ -224,48 +271,9 @@ const Inner = () => {
} : undefined
// end
useEffect(() => {
let picker
if (loggedIn && selectedProvider === 'google' && isGoogleProviderReady) {
const { google } = window
const view = new google.picker.DocsView(google.picker.ViewId.FOLDERS)
.setIncludeFolders(true)
.setMimeTypes('application/vnd.google-apps.folder')
.setSelectFolderEnabled(true)
.setParent('root')
picker = new google.picker.PickerBuilder()
.enableFeature(google.picker.Feature.NAV_HIDDEN)
.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
.setDeveloperKey('AIzaSyBTiHpEqaLL7mEcrsnSS4M-z8cpRH5UwY0')
.setAppId(APP_ID)
.setOAuthToken(googleProviderData.accessToken)
.addView(view)
.addView(new google.picker.DocsUploadView())
.setTitle('Select a folder with your worlds')
.setCallback((data) => {
if (data.action === google.picker.Action.PICKED) {
googleProviderData.lastSelectedFolder = {
id: data.docs[0].id,
name: data.docs[0].name,
}
setSelectedGoogleId(data.docs[0].id)
}
})
.build()
picker.setVisible(true)
}
return () => {
if (picker) picker.dispose()
}
}, [selectedProvider, loggedIn])
return <Singleplayer
error={error}
isReadonly={selectedProvider === 'google' && (googleDriveReadonly || !isGoogleProviderReady)}
isReadonly={selectedProvider === 'google' && (googleDriveReadonly || !isGoogleProviderReady || !selectedGoogleId)}
providers={{
local: 'Local',
google: 'Google Drive',

View file

@ -0,0 +1,77 @@
import { EditorView } from 'prosemirror-view'
import { EditorState } from 'prosemirror-state'
import { schema, defaultMarkdownParser, defaultMarkdownSerializer } from 'prosemirror-markdown'
import { exampleSetup, buildMenuItems } from 'prosemirror-example-setup'
import { MarkSpec } from 'prosemirror-model'
import { toggleMark } from 'prosemirror-commands'
export class ProseMirrorView {
view
constructor (target, content) {
console.log('schema.marks', schema.marks)
//@ts-expect-error
schema.marks.textColor = {
spec: {
attrs: { color: {} },
inline: true,
parseDOM: [
{
style: 'color',
getAttrs: value => ({ color: value })
}
],
toDOM: mark => ['span', { style: `color: ${mark.attrs.color}` }, 0]
},
}
const fullMenu = buildMenuItems(schema).fullMenu as Array<Array<import('prosemirror-menu').MenuItem>>
fullMenu[0] = fullMenu[0].filter(item => item.spec.title !== 'Add or remove link' && item.spec.title !== 'Toggle code font')
fullMenu.splice(3, 1); // remove the insert list, quote & checkbox menu
(fullMenu[1][0] as any).options.label = 'Color' // check-build error: fullMenu[1][0].options.label = 'Color'
// fullMenu[1][0].content[0].spec.label = 'Red'
// fullMenu[1][0].content[0].spec.run = (state, dispatch, view) => {
// console.log('state', state)
// // make <p style="color: red">...</p>
// const { from, to } = state.selection
// const { tr } = state
// console.log(schema.marks)
// tr.addMark(from, to, schema.marks.textColor.create({ color: 'red' }))
// dispatch(tr)
// toggleMark(schema.marks.textColor, { color: 'red' })(state, dispatch, view)
// }
fullMenu[1].splice(1, 1) // remove the type menu
console.log('fullMenu', fullMenu)
this.view = new EditorView(target, {
state: EditorState.create({
doc: defaultMarkdownParser.parse(content) ?? undefined,
plugins: exampleSetup({
schema,
menuContent: fullMenu,
}),
}),
attributes (state) {
return {
autocorrect: 'off',
autocapitalize: 'off',
spellcheck: 'false',
autofocus: 'true',
}
},
})
}
get content () {
const content = defaultMarkdownSerializer.serialize(this.view.state.doc)
console.log('content', content)
return content
}
focus () {
this.view.focus()
}
destroy () {
this.view.destroy()
}
}

View file

@ -15,6 +15,7 @@ import EnterFullscreenButton from './react/EnterFullscreenButton'
import ChatProvider from './react/ChatProvider'
import TitleProvider from './react/TitleProvider'
import ScoreboardProvider from './react/ScoreboardProvider'
import SignEditorProvider from './react/SignEditorProvider'
import SoundMuffler from './react/SoundMuffler'
import TouchControls from './react/TouchControls'
import widgets from './react/widgets'
@ -66,7 +67,10 @@ const InGameUi = () => {
<ScoreboardProvider />
<TouchAreasControlsProvider />
</RobustPortal>
<DisplayQr />
<PerComponentErrorBoundary>
<SignEditorProvider />
<DisplayQr />
</PerComponentErrorBoundary>
<RobustPortal to={document.body}>
{/* becaues of z-index */}
<TouchControls />

View file

@ -5,6 +5,7 @@ export default defineConfig({
test: {
include: [
'../../src/botUtils.test.ts',
'../../src/markdownToFormattedText.test.ts',
'sign-renderer/tests.test.ts'
],
},