diff --git a/package-lock.json b/package-lock.json index 35bbde5..4ef4918 100644 --- a/package-lock.json +++ b/package-lock.json @@ -92,7 +92,6 @@ "node_modules/@babel/core": { "version": "7.27.4", "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -638,7 +637,6 @@ "node_modules/@babel/plugin-syntax-flow": { "version": "7.27.1", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1390,7 +1388,6 @@ "node_modules/@babel/plugin-transform-react-jsx": { "version": "7.27.1", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", @@ -1773,7 +1770,6 @@ "node_modules/@babel/runtime": { "version": "7.27.6", "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -3116,6 +3112,7 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -3136,6 +3133,7 @@ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "dequal": "^2.0.3" } @@ -3145,7 +3143,8 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@testing-library/jest-dom": { "version": "6.9.1", @@ -3214,7 +3213,8 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -3497,7 +3497,6 @@ "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.62.0", "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", "@typescript-eslint/scope-manager": "5.62.0", @@ -3547,7 +3546,6 @@ "node_modules/@typescript-eslint/parser": { "version": "5.62.0", "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -3900,7 +3898,6 @@ "node_modules/acorn": { "version": "8.15.0", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3971,7 +3968,6 @@ "node_modules/ajv": { "version": "6.12.6", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -4769,7 +4765,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001726", "electron-to-chromium": "^1.5.173", @@ -5119,8 +5114,7 @@ "version": "5.65.19", "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.19.tgz", "integrity": "sha512-+aFkvqhaAVr1gferNMuN8vkTSrWIFvzlMV9I2KBLCWS2WpZ2+UAkZjlMZmEuT+gcXTi6RrGQCkWq1/bDtGqhIA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/collect-v8-coverage": { "version": "1.0.2", @@ -5369,7 +5363,6 @@ "version": "3.43.0", "hasInstallScript": true, "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" @@ -5766,8 +5759,7 @@ }, "node_modules/csstype": { "version": "3.1.3", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -5963,6 +5955,7 @@ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -6621,7 +6614,6 @@ "node_modules/eslint": { "version": "8.57.1", "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -9146,7 +9138,6 @@ "node_modules/jest": { "version": "27.5.1", "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "^27.5.1", "import-local": "^3.0.2", @@ -10510,6 +10501,7 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -11467,7 +11459,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -12513,7 +12504,6 @@ "node_modules/postcss-selector-parser": { "version": "6.1.2", "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -12673,7 +12663,6 @@ "node_modules/prop-types": { "version": "15.8.1", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -12829,7 +12818,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -12966,7 +12954,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -13010,7 +12997,6 @@ "node_modules/react-refresh": { "version": "0.11.0", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -13432,7 +13418,6 @@ "node_modules/rollup": { "version": "2.79.2", "license": "MIT", - "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -13667,7 +13652,6 @@ "node_modules/schema-utils/node_modules/ajv": { "version": "8.17.1", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -15283,7 +15267,6 @@ "node_modules/type-fest": { "version": "0.21.3", "license": "(MIT OR CC0-1.0)", - "peer": true, "engines": { "node": ">=10" }, @@ -15659,7 +15642,6 @@ "node_modules/webpack": { "version": "5.99.9", "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", @@ -15726,7 +15708,6 @@ "node_modules/webpack-dev-server": { "version": "4.15.2", "license": "MIT", - "peer": true, "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -16119,7 +16100,6 @@ "node_modules/workbox-build/node_modules/ajv": { "version": "8.17.1", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -16537,7 +16517,6 @@ "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.30.tgz", "integrity": "sha512-vv/9h42eCMC81ZHDFswuu/MKzkl/vyq1BhaNGfHyOonwlG4CJbQF4oiBBJPvfdeCt/PlVDWh7Nov9D34YY09uQ==", "license": "MIT", - "peer": true, "dependencies": { "lib0": "^0.2.99" }, @@ -16566,7 +16545,6 @@ "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/components/Editor.js b/src/components/Editor.js index 24c6116..9b2a463 100644 --- a/src/components/Editor.js +++ b/src/components/Editor.js @@ -48,6 +48,7 @@ const Editor = ({ socketRef, roomId, fileId, fileName, onCodeChange, userName, c const bookmarksRef = useRef(new Map()); const timeoutsRef = useRef(new Map()); const [peers, setPeers] = useState([]); + const [charCount, setCharCount] = useState(0); // Enforce readOnly dynamically useEffect(() => { @@ -104,9 +105,10 @@ const Editor = ({ socketRef, roomId, fileId, fileName, onCodeChange, userName, c }, }); editorRef.current = editor; - editor.on('change', (instance) => { - if (onCodeChange) onCodeChange(fileId, instance.getValue()); + const value = instance.getValue(); + setCharCount(value.length); + if (onCodeChange) onCodeChange(fileId, value); }); if (onEditorReady) onEditorReady(fileId, editor); @@ -127,11 +129,17 @@ const Editor = ({ socketRef, roomId, fileId, fileName, onCodeChange, userName, c // Inject initialContent once provider syncs, but only if the doc is still empty const handleSync = (isSynced) => { - if (isSynced && initialContent && ytext.length === 0) { - ydoc.transact(() => { - ytext.insert(0, initialContent); - }); - } + if (isSynced) { + setCharCount(ytext.length); + + if (initialContent && ytext.length === 0) { + ydoc.transact(() => { + ytext.insert(0, initialContent); + }); + + setCharCount(initialContent.length); + } + } }; provider.on('sync', handleSync); @@ -238,7 +246,20 @@ const Editor = ({ socketRef, roomId, fileId, fileName, onCodeChange, userName, c ) : ( + <> +
+ Characters: {charCount} +
+ )} );