From f23e475f8b4db66a09b456ec21396dba1f71763e Mon Sep 17 00:00:00 2001 From: okmttdhr Date: Mon, 25 Mar 2024 16:54:16 +0900 Subject: [PATCH 01/22] Add codemirror to Additional CSS --- package-lock.json | 401 ++++++++++++++++++ package.json | 3 + packages/block-editor/package.json | 2 + .../global-styles/advanced-panel.js | 48 ++- tools/webpack/packages.js | 1 + 5 files changed, 441 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5a23420f5d8884..3f7e6a7b7c2925 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,8 @@ "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { + "@codemirror/lang-css": "6.2.1", + "@codemirror/lang-html": "6.4.8", "@wordpress/a11y": "file:packages/a11y", "@wordpress/annotations": "file:packages/annotations", "@wordpress/api-fetch": "file:packages/api-fetch", @@ -80,6 +82,7 @@ "@wordpress/warning": "file:packages/warning", "@wordpress/widgets": "file:packages/widgets", "@wordpress/wordcount": "file:packages/wordcount", + "codemirror": "6.0.1", "es-module-shims": "^1.8.2", "wicg-inert": "3.1.2" }, @@ -4166,6 +4169,124 @@ "react": "*" } }, + "node_modules/@codemirror/autocomplete": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.15.0.tgz", + "integrity": "sha512-G2Zm0mXznxz97JhaaOdoEG2cVupn4JjPaS4AcNvZzhOsnnG9YVN68VzfoUw6dYTsIxT6a/cmoFEN47KAWhXaOg==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + }, + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.3.3.tgz", + "integrity": "sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/lang-css": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.2.1.tgz", + "integrity": "sha512-/UNWDNV5Viwi/1lpr/dIXJNWiwDxpw13I4pTUAsNxZdg6E0mI2kTQb0P2iHczg1Tu+H4EBgJR+hYhKiHKko7qg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/css": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-html": { + "version": "6.4.8", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.8.tgz", + "integrity": "sha512-tE2YK7wDlb9ZpAH6mpTPiYm6rhfdQKVDa5r9IwIFlwwgvVaKsCfuKKZoJGWsmMZIf3FQAuJ5CHMPLymOtg1hXw==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/css": "^1.1.0", + "@lezer/html": "^1.3.0" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.2.tgz", + "integrity": "sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.1.tgz", + "integrity": "sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.5.0.tgz", + "integrity": "sha512-+5YyicIaaAZKU8K43IQi8TBy6mF6giGeWAH7N96Z5LC30Wm5JMjqxOYIE9mxwMG1NbhT2mA3l9hA4uuKUM3E5g==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.5.6", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.6.tgz", + "integrity": "sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==" + }, + "node_modules/@codemirror/view": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.26.0.tgz", + "integrity": "sha512-nSSmzONpqsNzshPOxiKhK203R6BvABepugAe34QfQDbNDslyjkqBuKgrK5ZBvqNXpfxz5iLrlGTmEfhbQyH46A==", + "dependencies": { + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -6105,6 +6226,57 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/@lezer/common": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz", + "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==" + }, + "node_modules/@lezer/css": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.8.tgz", + "integrity": "sha512-7JhxupKuMBaWQKjQoLtzhGj83DdnZY9MckEOG5+/iLKNK2ZJqKc6hf6uc0HjwCX7Qlok44jBNqZhHKDhEhZYLA==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/highlight": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz", + "integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/html": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.9.tgz", + "integrity": "sha512-MXxeCMPyrcemSLGaTQEZx0dBUH0i+RPl8RN5GwMAzo53nTsd/Unc/t5ZxACeQoyPUM5/GkPLRUs2WliOImzkRA==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.13.tgz", + "integrity": "sha512-5IBr8LIO3xJdJH1e9aj/ZNLE4LSbdsx25wFmGRAZsj2zSmwAYjx26JyU/BYOCpRQlu1jcv1z3vy4NB9+UkfRow==", + "dependencies": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.0.tgz", + "integrity": "sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, "node_modules/@mdx-js/react": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-2.3.0.tgz", @@ -23354,6 +23526,20 @@ "node": ">=0.10.0" } }, + "node_modules/codemirror": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "node_modules/collapse-white-space": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.4.tgz", @@ -24832,6 +25018,11 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==" + }, "node_modules/cross-env": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-3.2.4.tgz", @@ -49655,6 +49846,11 @@ "webpack": "^5.0.0" } }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==" + }, "node_modules/style-search": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", @@ -52239,6 +52435,11 @@ "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" + }, "node_modules/w3c-xmlserializer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", @@ -54837,6 +55038,7 @@ "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", + "@codemirror/lang-css": "6.2.1", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@react-spring/web": "^9.4.5", @@ -54871,6 +55073,7 @@ "@wordpress/wordcount": "file:../wordcount", "change-case": "^4.1.2", "classnames": "^2.3.1", + "codemirror": "6.0.1", "colord": "^2.7.0", "deepmerge": "^4.3.0", "diff": "^4.0.2", @@ -54933,6 +55136,7 @@ "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", + "@codemirror/lang-html": "6.4.8", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/autop": "file:../autop", @@ -54967,6 +55171,7 @@ "@wordpress/wordcount": "file:../wordcount", "change-case": "^4.1.2", "classnames": "^2.3.1", + "codemirror": "6.0.1", "colord": "^2.7.0", "escape-html": "^1.0.3", "fast-average-color": "^9.1.1", @@ -60086,6 +60291,118 @@ "mathjs": "^10.1.1" } }, + "@codemirror/autocomplete": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.15.0.tgz", + "integrity": "sha512-G2Zm0mXznxz97JhaaOdoEG2cVupn4JjPaS4AcNvZzhOsnnG9YVN68VzfoUw6dYTsIxT6a/cmoFEN47KAWhXaOg==", + "requires": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + } + }, + "@codemirror/commands": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.3.3.tgz", + "integrity": "sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==", + "requires": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.1.0" + } + }, + "@codemirror/lang-css": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.2.1.tgz", + "integrity": "sha512-/UNWDNV5Viwi/1lpr/dIXJNWiwDxpw13I4pTUAsNxZdg6E0mI2kTQb0P2iHczg1Tu+H4EBgJR+hYhKiHKko7qg==", + "requires": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.2", + "@lezer/css": "^1.0.0" + } + }, + "@codemirror/lang-html": { + "version": "6.4.8", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.8.tgz", + "integrity": "sha512-tE2YK7wDlb9ZpAH6mpTPiYm6rhfdQKVDa5r9IwIFlwwgvVaKsCfuKKZoJGWsmMZIf3FQAuJ5CHMPLymOtg1hXw==", + "requires": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.4.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/css": "^1.1.0", + "@lezer/html": "^1.3.0" + } + }, + "@codemirror/lang-javascript": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.2.tgz", + "integrity": "sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==", + "requires": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.6.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "@codemirror/language": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.1.tgz", + "integrity": "sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==", + "requires": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "@codemirror/lint": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.5.0.tgz", + "integrity": "sha512-+5YyicIaaAZKU8K43IQi8TBy6mF6giGeWAH7N96Z5LC30Wm5JMjqxOYIE9mxwMG1NbhT2mA3l9hA4uuKUM3E5g==", + "requires": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "@codemirror/search": { + "version": "6.5.6", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.6.tgz", + "integrity": "sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==", + "requires": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "@codemirror/state": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==" + }, + "@codemirror/view": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.26.0.tgz", + "integrity": "sha512-nSSmzONpqsNzshPOxiKhK203R6BvABepugAe34QfQDbNDslyjkqBuKgrK5ZBvqNXpfxz5iLrlGTmEfhbQyH46A==", + "requires": { + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, "@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -61466,6 +61783,57 @@ } } }, + "@lezer/common": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz", + "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==" + }, + "@lezer/css": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.8.tgz", + "integrity": "sha512-7JhxupKuMBaWQKjQoLtzhGj83DdnZY9MckEOG5+/iLKNK2ZJqKc6hf6uc0HjwCX7Qlok44jBNqZhHKDhEhZYLA==", + "requires": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "@lezer/highlight": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.0.tgz", + "integrity": "sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==", + "requires": { + "@lezer/common": "^1.0.0" + } + }, + "@lezer/html": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.9.tgz", + "integrity": "sha512-MXxeCMPyrcemSLGaTQEZx0dBUH0i+RPl8RN5GwMAzo53nTsd/Unc/t5ZxACeQoyPUM5/GkPLRUs2WliOImzkRA==", + "requires": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "@lezer/javascript": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.13.tgz", + "integrity": "sha512-5IBr8LIO3xJdJH1e9aj/ZNLE4LSbdsx25wFmGRAZsj2zSmwAYjx26JyU/BYOCpRQlu1jcv1z3vy4NB9+UkfRow==", + "requires": { + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3", + "@lezer/lr": "^1.3.0" + } + }, + "@lezer/lr": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.0.tgz", + "integrity": "sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==", + "requires": { + "@lezer/common": "^1.0.0" + } + }, "@mdx-js/react": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-2.3.0.tgz", @@ -70862,6 +71230,7 @@ "version": "file:packages/block-editor", "requires": { "@babel/runtime": "^7.16.0", + "@codemirror/lang-css": "6.2.1", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@react-spring/web": "^9.4.5", @@ -70896,6 +71265,7 @@ "@wordpress/wordcount": "file:../wordcount", "change-case": "^4.1.2", "classnames": "^2.3.1", + "codemirror": "6.0.1", "colord": "^2.7.0", "deepmerge": "^4.3.0", "diff": "^4.0.2", @@ -70931,6 +71301,7 @@ "version": "file:packages/block-library", "requires": { "@babel/runtime": "^7.16.0", + "@codemirror/lang-html": "6.4.8", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/autop": "file:../autop", @@ -70965,6 +71336,7 @@ "@wordpress/wordcount": "file:../wordcount", "change-case": "^4.1.2", "classnames": "^2.3.1", + "codemirror": "6.0.1", "colord": "^2.7.0", "escape-html": "^1.0.3", "fast-average-color": "^9.1.1", @@ -75510,6 +75882,20 @@ "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", "dev": true }, + "codemirror": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "requires": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "collapse-white-space": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.4.tgz", @@ -76690,6 +77076,11 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==" + }, "cross-env": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-3.2.4.tgz", @@ -95600,6 +95991,11 @@ "integrity": "sha512-1k9ZosJCRFaRbY6hH49JFlRB0fVSbmnyq1iTPjNxUmGVjBNEmwrrHPenhlp+Lgo51BojHSf6pl2FcqYaN3PfVg==", "dev": true }, + "style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==" + }, "style-search": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", @@ -97543,6 +97939,11 @@ "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true }, + "w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" + }, "w3c-xmlserializer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", diff --git a/package.json b/package.json index 5c63beee49d2a1..99aeaf1863a46c 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "IS_GUTENBERG_PLUGIN": true }, "dependencies": { + "@codemirror/lang-css": "6.2.1", + "@codemirror/lang-html": "6.4.8", "@wordpress/a11y": "file:packages/a11y", "@wordpress/annotations": "file:packages/annotations", "@wordpress/api-fetch": "file:packages/api-fetch", @@ -92,6 +94,7 @@ "@wordpress/warning": "file:packages/warning", "@wordpress/widgets": "file:packages/widgets", "@wordpress/wordcount": "file:packages/wordcount", + "codemirror": "6.0.1", "es-module-shims": "^1.8.2", "wicg-inert": "3.1.2" }, diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index 498eee0c936017..0085c9dfd39d75 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -32,6 +32,7 @@ ], "dependencies": { "@babel/runtime": "^7.16.0", + "@codemirror/lang-css": "6.2.1", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@react-spring/web": "^9.4.5", @@ -66,6 +67,7 @@ "@wordpress/wordcount": "file:../wordcount", "change-case": "^4.1.2", "classnames": "^2.3.1", + "codemirror": "6.0.1", "colord": "^2.7.0", "deepmerge": "^4.3.0", "diff": "^4.0.2", diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index 1ad59451d1468a..4a0dab0f9ca8ac 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -1,12 +1,8 @@ /** * WordPress dependencies */ -import { - TextareaControl, - Notice, - __experimentalVStack as VStack, -} from '@wordpress/components'; -import { useState } from '@wordpress/element'; +import { Notice, __experimentalVStack as VStack } from '@wordpress/components'; +import { useState, useEffect, useRef, useId } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; /** @@ -55,6 +51,33 @@ export default function AdvancedPanel( { ); } + const editorRef = useRef(); + useEffect( () => { + ( async () => { + const { EditorView, basicSetup } = await import( 'codemirror' ); + const { css } = await import( '@codemirror/lang-css' ); + + if ( editorRef.current ) { + new EditorView( { + doc: customCSS, + extensions: [ + basicSetup, + css(), + EditorView.updateListener.of( ( editor ) => { + if ( editor.docChanged ) { + handleOnChange( editor.state.doc.toString() ); + } + } ), + ], + parent: editorRef.current, + } ); + } + } )(); + // We only want to run this once, so we can ignore the dependency array. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [] ); + + const cssEditorId = useId(); return ( { cssError && ( @@ -62,15 +85,12 @@ export default function AdvancedPanel( { { cssError } ) } - handleOnChange( newValue ) } + +
+ id={ cssEditorId } + >
); } diff --git a/tools/webpack/packages.js b/tools/webpack/packages.js index 0a4b8cef574464..9723078a11f4aa 100644 --- a/tools/webpack/packages.js +++ b/tools/webpack/packages.js @@ -160,6 +160,7 @@ module.exports = { } return `webpack://${ info.namespace }/${ info.resourcePath }`; }, + chunkFilename: './build/[name]/[name]-[contenthash].min.js', }, performance: { hints: false, // disable warnings about package sizes From 7b38263aea571c0c804c85b19ced92c6dfe6289b Mon Sep 17 00:00:00 2001 From: okmttdhr Date: Mon, 25 Mar 2024 16:55:39 +0900 Subject: [PATCH 02/22] Add codemirror to Custom HTML block --- packages/block-library/package.json | 2 ++ packages/block-library/src/html/edit.js | 44 ++++++++++++++++++------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/packages/block-library/package.json b/packages/block-library/package.json index 0a024f3a5f422e..957405bb317dc9 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -31,6 +31,7 @@ ], "dependencies": { "@babel/runtime": "^7.16.0", + "@codemirror/lang-html": "6.4.8", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/autop": "file:../autop", @@ -65,6 +66,7 @@ "@wordpress/wordcount": "file:../wordcount", "change-case": "^4.1.2", "classnames": "^2.3.1", + "codemirror": "6.0.1", "colord": "^2.7.0", "escape-html": "^1.0.3", "fast-average-color": "^9.1.1", diff --git a/packages/block-library/src/html/edit.js b/packages/block-library/src/html/edit.js index 3cf2ee08bb68b2..535f5aba543d66 100644 --- a/packages/block-library/src/html/edit.js +++ b/packages/block-library/src/html/edit.js @@ -2,12 +2,8 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { useContext, useState } from '@wordpress/element'; -import { - BlockControls, - PlainText, - useBlockProps, -} from '@wordpress/block-editor'; +import { useContext, useState, useRef, useEffect } from '@wordpress/element'; +import { BlockControls, useBlockProps } from '@wordpress/block-editor'; import { ToolbarButton, Disabled, @@ -27,6 +23,8 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { const instanceId = useInstanceId( HTMLEdit, 'html-edit-desc' ); + const editorRef = useRef(); + function switchToPreview() { setIsPreview( true ); } @@ -40,6 +38,33 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { 'aria-describedby': isPreview ? instanceId : undefined, } ); + useEffect( () => { + ( async () => { + const { EditorView, basicSetup } = await import( 'codemirror' ); + const { html } = await import( '@codemirror/lang-html' ); + + if ( editorRef.current ) { + new EditorView( { + doc: attributes.content, + extensions: [ + basicSetup, + html(), + EditorView.updateListener.of( ( editor ) => { + if ( editor.docChanged ) { + setAttributes( { + content: editor.state.doc.toString(), + } ); + } + } ), + ], + parent: editorRef.current, + } ); + } + } )(); + // Run this only when the UI renders, so we can ignore the dependency array. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ isPreview, isDisabled ] ); + return (
@@ -73,12 +98,7 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { ) : ( - setAttributes( { content } ) } - placeholder={ __( 'Write HTML…' ) } - aria-label={ __( 'HTML' ) } - /> + <div ref={ editorRef } aria-label={ __( 'HTML' ) } /> ) } </div> ); From b2ceddd5fad4dbaa1af1bdc9266f098fb492f0e5 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Tue, 26 Mar 2024 10:06:40 +0900 Subject: [PATCH 03/22] Fix styles --- .../global-styles/advanced-panel.js | 30 +++++++++++++++++-- packages/block-library/src/html/edit.js | 5 ++++ .../src/components/global-styles/style.scss | 24 ++++----------- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index 4a0dab0f9ca8ac..f7cca4db4fcda3 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -52,14 +52,35 @@ export default function AdvancedPanel( { } const editorRef = useRef(); + /** + * Ensure the editor has at least min lines of code, + * as the editor will shrink to fit the content. + * @param {string} content The content to ensure min lines for. + * @return {string} The content with at least min lines. + */ + function ensureMinLines( content ) { + const MIN_LINES = 10; + const lines = content.split( '\n' ); + const lineCount = lines.length; + let result = content; + for ( let i = lineCount; i < MIN_LINES; i++ ) { + result += '\n'; + } + return result; + } useEffect( () => { ( async () => { + /** + * Lazy load CodeMirror by using Webpack's dynamic import. + * This should be replaced with native dynamic import once it's supported. + * @see https://github.com/WordPress/gutenberg/pull/60155 + */ const { EditorView, basicSetup } = await import( 'codemirror' ); const { css } = await import( '@codemirror/lang-css' ); if ( editorRef.current ) { new EditorView( { - doc: customCSS, + doc: ensureMinLines( customCSS ), extensions: [ basicSetup, css(), @@ -85,7 +106,12 @@ export default function AdvancedPanel( { { cssError } </Notice> ) } - <label htmlFor={ cssEditorId }>{ __( 'Additional CSS' ) }</label> + <label + htmlFor={ cssEditorId } + className="block-editor-global-styles-advanced-panel__custom-css-label" + > + { __( 'Additional CSS' ) } + </label> <div ref={ editorRef } onBlur={ handleOnBlur } diff --git a/packages/block-library/src/html/edit.js b/packages/block-library/src/html/edit.js index 535f5aba543d66..cc730814cca5fd 100644 --- a/packages/block-library/src/html/edit.js +++ b/packages/block-library/src/html/edit.js @@ -40,6 +40,11 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { useEffect( () => { ( async () => { + /** + * Lazy load CodeMirror by using Webpack's dynamic import. + * This should be replaced with native dynamic import once it's supported. + * @see https://github.com/WordPress/gutenberg/pull/60155 + */ const { EditorView, basicSetup } = await import( 'codemirror' ); const { html } = await import( '@codemirror/lang-html' ); diff --git a/packages/edit-site/src/components/global-styles/style.scss b/packages/edit-site/src/components/global-styles/style.scss index 5cd5c355fe0dbe..1a1451a6910ceb 100644 --- a/packages/edit-site/src/components/global-styles/style.scss +++ b/packages/edit-site/src/components/global-styles/style.scss @@ -119,25 +119,11 @@ margin: $grid-unit-20; .components-v-stack { - flex: 1 1 auto; - - .block-editor-global-styles-advanced-panel__custom-css-input { - flex: 1 1 auto; - display: flex; - flex-direction: column; - - .components-base-control__field { - flex: 1 1 auto; - display: flex; - flex-direction: column; - - .components-textarea-control__input { - flex: 1 1 auto; - // CSS input is always LTR regardless of language. - /*rtl:ignore*/ - direction: ltr; - } - } + .block-editor-global-styles-advanced-panel__custom-css-label { + font-size: 11px; + font-weight: 500; + line-height: 1.4; + text-transform: uppercase; } } } From 14678ea4fa8d894c4f25c2dbe25572016c9b9993 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Tue, 26 Mar 2024 14:27:29 +0900 Subject: [PATCH 04/22] Add focus change effect --- .../global-styles/advanced-panel.js | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index f7cca4db4fcda3..e1651d70c75cb8 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -33,17 +33,15 @@ export default function AdvancedPanel( { } } } - function handleOnBlur( event ) { - if ( ! event?.target?.value ) { + function handleOnBlur( newValue ) { + if ( ! newValue ) { setCSSError( null ); return; } - const [ transformed ] = transformStyles( - [ { css: event.target.value } ], + [ { css: newValue } ], '.editor-styles-wrapper' ); - setCSSError( transformed === null ? __( 'There is an error with your CSS structure.' ) @@ -89,6 +87,13 @@ export default function AdvancedPanel( { handleOnChange( editor.state.doc.toString() ); } } ), + EditorView.focusChangeEffect.of( + ( editorState, focusing ) => { + if ( ! focusing ) { + handleOnBlur( editorState.doc.toString() ); + } + } + ), ], parent: editorRef.current, } ); @@ -112,11 +117,7 @@ export default function AdvancedPanel( { > { __( 'Additional CSS' ) } </label> - <div - ref={ editorRef } - onBlur={ handleOnBlur } - id={ cssEditorId } - ></div> + <div ref={ editorRef } id={ cssEditorId }></div> </VStack> ); } From 421f2d4ba1256ad97198a2b8004d14af5915e970 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Wed, 27 Mar 2024 09:04:18 +0900 Subject: [PATCH 05/22] Add codemirror as restrictedImport --- .eslintrc.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index 5d7c6b40890510..3ece0e86133a05 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -76,6 +76,21 @@ const restrictedImports = [ message: "edit-widgets is a WordPress top level package that shouldn't be imported into other packages", }, + { + name: 'codemirror', + message: + 'Please use dynamic import (`import()`) instead since it is a large dependency.', + }, + { + name: '@codemirror/lang-css', + message: + 'Please use dynamic import (`import()`) instead since it is a large dependency.', + }, + { + name: '@codemirror/lang-html', + message: + 'Please use dynamic import (`import()`) instead since it is a large dependency.', + }, ]; module.exports = { From 4decdff80fce0b48738b98aca8b44f50ca3c220d Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Wed, 27 Mar 2024 14:57:17 +0900 Subject: [PATCH 06/22] Ensure minimum lines to be full-width --- .../global-styles/advanced-panel.js | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index e1651d70c75cb8..50c6cf837a6b49 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -10,6 +10,9 @@ import { __ } from '@wordpress/i18n'; */ import { default as transformStyles } from '../../utils/transform-styles'; +const EDITOR_ID = + 'block-editor-global-styles-advanced-panel__custom-css-editor'; + export default function AdvancedPanel( { value, onChange, @@ -49,7 +52,6 @@ export default function AdvancedPanel( { ); } - const editorRef = useRef(); /** * Ensure the editor has at least min lines of code, * as the editor will shrink to fit the content. @@ -58,14 +60,39 @@ export default function AdvancedPanel( { */ function ensureMinLines( content ) { const MIN_LINES = 10; + const LINE_HEIGHT = 18.2; // Height of one line in the editor + const MARGIN = 53.4; + let requiredLines = MIN_LINES; + const lines = content.split( '\n' ); - const lineCount = lines.length; + const contentLineCount = lines.length; + + const wrapper = document.querySelector( + '.edit-site-global-styles-screen-css' + ); + if ( wrapper ) { + const wrapperHeight = wrapper.offsetHeight; + const editorHeight = wrapperHeight - MARGIN; + + // Calculate the minimum number of lines that should be displayed + const calcMinLineCount = Math.ceil( editorHeight / LINE_HEIGHT ); + requiredLines = Math.max( MIN_LINES, calcMinLineCount ); + + // Set the max height of the editor allowing scrolling by `overflow-y: scroll` + const editor = document.getElementById( EDITOR_ID ); + if ( editor ) { + editor.style.height = `${ editorHeight }px`; + } + } + let result = content; - for ( let i = lineCount; i < MIN_LINES; i++ ) { + for ( let i = contentLineCount; i < requiredLines; i++ ) { result += '\n'; } + return result; } + const editorRef = useRef(); useEffect( () => { ( async () => { /** From a3e89a9f6101681a40e49a5a3f4a2758128e50ee Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Wed, 27 Mar 2024 15:02:58 +0900 Subject: [PATCH 07/22] Add indenting with tab --- .eslintrc.js | 10 ++++++++++ package-lock.json | 10 ++++++++++ package.json | 2 ++ packages/block-editor/package.json | 2 ++ .../src/components/global-styles/advanced-panel.js | 8 +++++--- packages/block-library/package.json | 2 ++ packages/block-library/src/html/edit.js | 3 +++ 7 files changed, 34 insertions(+), 3 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 3ece0e86133a05..f4928df58f8f93 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -81,6 +81,11 @@ const restrictedImports = [ message: 'Please use dynamic import (`import()`) instead since it is a large dependency.', }, + { + name: '@codemirror/commands', + message: + 'Please use dynamic import (`import()`) instead since it is a large dependency.', + }, { name: '@codemirror/lang-css', message: @@ -91,6 +96,11 @@ const restrictedImports = [ message: 'Please use dynamic import (`import()`) instead since it is a large dependency.', }, + { + name: '@codemirror/view', + message: + 'Please use dynamic import (`import()`) instead since it is a large dependency.', + }, ]; module.exports = { diff --git a/package-lock.json b/package-lock.json index 3f7e6a7b7c2925..9b6b5831a29414 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,10 @@ "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { + "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", "@codemirror/lang-html": "6.4.8", + "@codemirror/view": "6.26.0", "@wordpress/a11y": "file:packages/a11y", "@wordpress/annotations": "file:packages/annotations", "@wordpress/api-fetch": "file:packages/api-fetch", @@ -55038,7 +55040,9 @@ "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", + "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", + "@codemirror/view": "6.26.0", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@react-spring/web": "^9.4.5", @@ -55136,7 +55140,9 @@ "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", + "@codemirror/commands": "6.3.3", "@codemirror/lang-html": "6.4.8", + "@codemirror/view": "6.26.0", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/autop": "file:../autop", @@ -71230,7 +71236,9 @@ "version": "file:packages/block-editor", "requires": { "@babel/runtime": "^7.16.0", + "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", + "@codemirror/view": "6.26.0", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@react-spring/web": "^9.4.5", @@ -71301,7 +71309,9 @@ "version": "file:packages/block-library", "requires": { "@babel/runtime": "^7.16.0", + "@codemirror/commands": "6.3.3", "@codemirror/lang-html": "6.4.8", + "@codemirror/view": "6.26.0", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/autop": "file:../autop", diff --git a/package.json b/package.json index 99aeaf1863a46c..41f6801036cb4a 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,10 @@ "IS_GUTENBERG_PLUGIN": true }, "dependencies": { + "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", "@codemirror/lang-html": "6.4.8", + "@codemirror/view": "6.26.0", "@wordpress/a11y": "file:packages/a11y", "@wordpress/annotations": "file:packages/annotations", "@wordpress/api-fetch": "file:packages/api-fetch", diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index 0085c9dfd39d75..359e1f1c486581 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -32,7 +32,9 @@ ], "dependencies": { "@babel/runtime": "^7.16.0", + "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", + "@codemirror/view": "6.26.0", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@react-spring/web": "^9.4.5", diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index 50c6cf837a6b49..e2d622f5ea711b 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { Notice, __experimentalVStack as VStack } from '@wordpress/components'; -import { useState, useEffect, useRef, useId } from '@wordpress/element'; +import { useState, useEffect, useRef } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; /** @@ -101,6 +101,8 @@ export default function AdvancedPanel( { * @see https://github.com/WordPress/gutenberg/pull/60155 */ const { EditorView, basicSetup } = await import( 'codemirror' ); + const {indentWithTab} = await import('@codemirror/commands'); + const {keymap} = await import('@codemirror/view'); const { css } = await import( '@codemirror/lang-css' ); if ( editorRef.current ) { @@ -109,6 +111,7 @@ export default function AdvancedPanel( { extensions: [ basicSetup, css(), + keymap.of([indentWithTab]), EditorView.updateListener.of( ( editor ) => { if ( editor.docChanged ) { handleOnChange( editor.state.doc.toString() ); @@ -130,7 +133,6 @@ export default function AdvancedPanel( { // eslint-disable-next-line react-hooks/exhaustive-deps }, [] ); - const cssEditorId = useId(); return ( <VStack spacing={ 3 }> { cssError && ( @@ -139,7 +141,7 @@ export default function AdvancedPanel( { </Notice> ) } <label - htmlFor={ cssEditorId } + htmlFor={ EDITOR_ID } className="block-editor-global-styles-advanced-panel__custom-css-label" > { __( 'Additional CSS' ) } diff --git a/packages/block-library/package.json b/packages/block-library/package.json index 957405bb317dc9..100e7063f5258c 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -31,7 +31,9 @@ ], "dependencies": { "@babel/runtime": "^7.16.0", + "@codemirror/commands": "6.3.3", "@codemirror/lang-html": "6.4.8", + "@codemirror/view": "6.26.0", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/autop": "file:../autop", diff --git a/packages/block-library/src/html/edit.js b/packages/block-library/src/html/edit.js index cc730814cca5fd..583a57294c44d8 100644 --- a/packages/block-library/src/html/edit.js +++ b/packages/block-library/src/html/edit.js @@ -46,6 +46,8 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { * @see https://github.com/WordPress/gutenberg/pull/60155 */ const { EditorView, basicSetup } = await import( 'codemirror' ); + const {indentWithTab} = await import('@codemirror/commands'); + const {keymap} = await import('@codemirror/view'); const { html } = await import( '@codemirror/lang-html' ); if ( editorRef.current ) { @@ -54,6 +56,7 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { extensions: [ basicSetup, html(), + keymap.of([indentWithTab]), EditorView.updateListener.of( ( editor ) => { if ( editor.docChanged ) { setAttributes( { From 9394fc9b305ae18aa730a6229fe5e54e19585672 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Wed, 27 Mar 2024 15:03:46 +0900 Subject: [PATCH 08/22] Add instructions to focus out of the editor --- .../global-styles/advanced-panel.js | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index e2d622f5ea711b..563a68ca4fdfd1 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -13,6 +13,8 @@ import { default as transformStyles } from '../../utils/transform-styles'; const EDITOR_ID = 'block-editor-global-styles-advanced-panel__custom-css-editor'; +const EDITOR_INSTRUCTIONS_ID = `${ EDITOR_ID }-instructions`; + export default function AdvancedPanel( { value, onChange, @@ -101,8 +103,8 @@ export default function AdvancedPanel( { * @see https://github.com/WordPress/gutenberg/pull/60155 */ const { EditorView, basicSetup } = await import( 'codemirror' ); - const {indentWithTab} = await import('@codemirror/commands'); - const {keymap} = await import('@codemirror/view'); + const { indentWithTab } = await import( '@codemirror/commands' ); + const { keymap } = await import( '@codemirror/view' ); const { css } = await import( '@codemirror/lang-css' ); if ( editorRef.current ) { @@ -111,7 +113,7 @@ export default function AdvancedPanel( { extensions: [ basicSetup, css(), - keymap.of([indentWithTab]), + keymap.of( [ indentWithTab ] ), EditorView.updateListener.of( ( editor ) => { if ( editor.docChanged ) { handleOnChange( editor.state.doc.toString() ); @@ -146,7 +148,20 @@ export default function AdvancedPanel( { > { __( 'Additional CSS' ) } </label> - <div ref={ editorRef } id={ cssEditorId }></div> + <div + id={ EDITOR_INSTRUCTIONS_ID } + className={ EDITOR_INSTRUCTIONS_ID } + > + { __( + `This editor allows you to input Additional CSS and customize the site's appearance with your own styles. Press Escape then Tab to move focus out of the editor.` + ) } + </div> + <div + ref={ editorRef } + id={ EDITOR_ID } + className={ EDITOR_ID } + aria-describedby={ EDITOR_INSTRUCTIONS_ID } + ></div> </VStack> ); } From 15e2486dd0926b2f62454aaf1b90ca94c999d379 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Wed, 27 Mar 2024 15:12:27 +0900 Subject: [PATCH 09/22] Align styles with the existing ones --- .../src/components/global-styles/style.scss | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/edit-site/src/components/global-styles/style.scss b/packages/edit-site/src/components/global-styles/style.scss index 1a1451a6910ceb..a433ea3032a639 100644 --- a/packages/edit-site/src/components/global-styles/style.scss +++ b/packages/edit-site/src/components/global-styles/style.scss @@ -125,6 +125,29 @@ line-height: 1.4; text-transform: uppercase; } + .block-editor-global-styles-advanced-panel__custom-css-editor { + overflow-y: scroll; + border: 1px solid var($gray-600); + border-radius: $radius-block-ui; + &:focus-within { + box-shadow: 0 0 0 calc(1.5px - 1px) var(--wp-admin-theme-color); + border-color: var(--wp-admin-theme-color); + outline: transparent solid 2px; + } + } + .block-editor-global-styles-advanced-panel__custom-css-editor-instructions { + display: none; + } + .cm-editor { + // Override the default CodeMirror font-family. + .cm-line { + font-family: $editor-html-font; + } + // Hide the line numbers, as the space is limited. + .cm-gutters { + display: none; + } + } } } From 59a81b5666a1ee6bb69dbe115c177c1c3bc0d0b9 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Wed, 27 Mar 2024 16:18:53 +0900 Subject: [PATCH 10/22] Fix lint --- packages/block-library/src/html/edit.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/html/edit.js b/packages/block-library/src/html/edit.js index 583a57294c44d8..b6e1eb13ff6b0c 100644 --- a/packages/block-library/src/html/edit.js +++ b/packages/block-library/src/html/edit.js @@ -46,8 +46,8 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { * @see https://github.com/WordPress/gutenberg/pull/60155 */ const { EditorView, basicSetup } = await import( 'codemirror' ); - const {indentWithTab} = await import('@codemirror/commands'); - const {keymap} = await import('@codemirror/view'); + const { indentWithTab } = await import( '@codemirror/commands' ); + const { keymap } = await import( '@codemirror/view' ); const { html } = await import( '@codemirror/lang-html' ); if ( editorRef.current ) { @@ -56,7 +56,7 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { extensions: [ basicSetup, html(), - keymap.of([indentWithTab]), + keymap.of( [ indentWithTab ] ), EditorView.updateListener.of( ( editor ) => { if ( editor.docChanged ) { setAttributes( { From 4c6262cbf9de63e7bf6b3687a983c162b221f0fd Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Thu, 28 Mar 2024 14:45:07 +0900 Subject: [PATCH 11/22] Extract EditorView component --- .../global-styles/advanced-panel.js | 109 ++-------------- .../components/global-styles/editor-view.js | 117 ++++++++++++++++++ 2 files changed, 129 insertions(+), 97 deletions(-) create mode 100644 packages/block-editor/src/components/global-styles/editor-view.js diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index 563a68ca4fdfd1..e5c0ac0cfe0954 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { Notice, __experimentalVStack as VStack } from '@wordpress/components'; -import { useState, useEffect, useRef } from '@wordpress/element'; +import { useState, Suspense, lazy } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; /** @@ -10,9 +10,10 @@ import { __ } from '@wordpress/i18n'; */ import { default as transformStyles } from '../../utils/transform-styles'; +const EditorView = lazy( () => import( './editor-view' ) ); + const EDITOR_ID = 'block-editor-global-styles-advanced-panel__custom-css-editor'; - const EDITOR_INSTRUCTIONS_ID = `${ EDITOR_ID }-instructions`; export default function AdvancedPanel( { @@ -54,87 +55,6 @@ export default function AdvancedPanel( { ); } - /** - * Ensure the editor has at least min lines of code, - * as the editor will shrink to fit the content. - * @param {string} content The content to ensure min lines for. - * @return {string} The content with at least min lines. - */ - function ensureMinLines( content ) { - const MIN_LINES = 10; - const LINE_HEIGHT = 18.2; // Height of one line in the editor - const MARGIN = 53.4; - let requiredLines = MIN_LINES; - - const lines = content.split( '\n' ); - const contentLineCount = lines.length; - - const wrapper = document.querySelector( - '.edit-site-global-styles-screen-css' - ); - if ( wrapper ) { - const wrapperHeight = wrapper.offsetHeight; - const editorHeight = wrapperHeight - MARGIN; - - // Calculate the minimum number of lines that should be displayed - const calcMinLineCount = Math.ceil( editorHeight / LINE_HEIGHT ); - requiredLines = Math.max( MIN_LINES, calcMinLineCount ); - - // Set the max height of the editor allowing scrolling by `overflow-y: scroll` - const editor = document.getElementById( EDITOR_ID ); - if ( editor ) { - editor.style.height = `${ editorHeight }px`; - } - } - - let result = content; - for ( let i = contentLineCount; i < requiredLines; i++ ) { - result += '\n'; - } - - return result; - } - const editorRef = useRef(); - useEffect( () => { - ( async () => { - /** - * Lazy load CodeMirror by using Webpack's dynamic import. - * This should be replaced with native dynamic import once it's supported. - * @see https://github.com/WordPress/gutenberg/pull/60155 - */ - const { EditorView, basicSetup } = await import( 'codemirror' ); - const { indentWithTab } = await import( '@codemirror/commands' ); - const { keymap } = await import( '@codemirror/view' ); - const { css } = await import( '@codemirror/lang-css' ); - - if ( editorRef.current ) { - new EditorView( { - doc: ensureMinLines( customCSS ), - extensions: [ - basicSetup, - css(), - keymap.of( [ indentWithTab ] ), - EditorView.updateListener.of( ( editor ) => { - if ( editor.docChanged ) { - handleOnChange( editor.state.doc.toString() ); - } - } ), - EditorView.focusChangeEffect.of( - ( editorState, focusing ) => { - if ( ! focusing ) { - handleOnBlur( editorState.doc.toString() ); - } - } - ), - ], - parent: editorRef.current, - } ); - } - } )(); - // We only want to run this once, so we can ignore the dependency array. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [] ); - return ( <VStack spacing={ 3 }> { cssError && ( @@ -148,20 +68,15 @@ export default function AdvancedPanel( { > { __( 'Additional CSS' ) } </label> - <div - id={ EDITOR_INSTRUCTIONS_ID } - className={ EDITOR_INSTRUCTIONS_ID } - > - { __( - `This editor allows you to input Additional CSS and customize the site's appearance with your own styles. Press Escape then Tab to move focus out of the editor.` - ) } - </div> - <div - ref={ editorRef } - id={ EDITOR_ID } - className={ EDITOR_ID } - aria-describedby={ EDITOR_INSTRUCTIONS_ID } - ></div> + <Suspense fallback={ null }> + <EditorView + editorId={EDITOR_ID} + editorInstructionsId={EDITOR_INSTRUCTIONS_ID} + customCSS={ customCSS } + onChange={ handleOnChange } + onBlur={ handleOnBlur } + /> + </Suspense> </VStack> ); } diff --git a/packages/block-editor/src/components/global-styles/editor-view.js b/packages/block-editor/src/components/global-styles/editor-view.js new file mode 100644 index 00000000000000..99ecbd4a007ede --- /dev/null +++ b/packages/block-editor/src/components/global-styles/editor-view.js @@ -0,0 +1,117 @@ +/** + * External dependencies + */ +import { EditorView as CmEditorView, basicSetup } from 'codemirror'; +import { indentWithTab } from '@codemirror/commands'; +import { keymap } from '@codemirror/view'; +import { css } from '@codemirror/lang-css'; + +/** + * WordPress dependencies + */ +import { useEffect, useRef } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; + +const EditorView = ({editorId, editorInstructionsId, customCSS, onChange, onBlur}) => { + /** + * Ensure the editor has at least min lines of code, + * as the editor will shrink to fit the content. + * @param {string} content The content to ensure min lines for. + * @return {string} The content with at least min lines. + */ + function ensureMinLines( content ) { + const MIN_LINES = 10; + const LINE_HEIGHT = 18.2; // Height of one line in the editor + const MARGIN = 53.4; + let requiredLines = MIN_LINES; + + const lines = content.split( '\n' ); + const contentLineCount = lines.length; + + const wrapper = document.querySelector( + '.edit-site-global-styles-screen-css' + ); + if ( wrapper ) { + const wrapperHeight = wrapper.offsetHeight; + const editorHeight = wrapperHeight - MARGIN; + + // Calculate the minimum number of lines that should be displayed + const calcMinLineCount = Math.ceil( editorHeight / LINE_HEIGHT ); + requiredLines = Math.max( MIN_LINES, calcMinLineCount ); + + // Set the max height of the editor allowing scrolling by `overflow-y: scroll` + const editor = document.getElementById( editorId ); + if ( editor ) { + editor.style.height = `${ editorHeight }px`; + } + } + + let result = content; + for ( let i = contentLineCount; i < requiredLines; i++ ) { + result += '\n'; + } + + return result; + } + const editorRef = useRef(null); + useEffect( () => { + ( async () => { + /** + * Lazy load CodeMirror by using Webpack's dynamic import. + * This should be replaced with native dynamic import once it's supported. + * @see https://github.com/WordPress/gutenberg/pull/60155 + */ + // const { EditorView: CmEditorView, basicSetup } = await import( 'codemirror' ); + // const { indentWithTab } = await import( '@codemirror/commands' ); + // const { keymap } = await import( '@codemirror/view' ); + // const { css } = await import( '@codemirror/lang-css' ); + + if ( editorRef.current ) { + new CmEditorView( { + doc: ensureMinLines( customCSS ), + extensions: [ + basicSetup, + css(), + keymap.of( [ indentWithTab ] ), + CmEditorView.updateListener.of( ( editor ) => { + if ( editor.docChanged ) { + onChange( editor.state.doc.toString() ); + } + } ), + CmEditorView.focusChangeEffect.of( + ( editorState, focusing ) => { + if ( ! focusing ) { + onBlur( editorState.doc.toString() ); + } + return null; + } + ), + ], + parent: editorRef.current, + } ); + } + } )(); + // We only want to run this once, so we can ignore the dependency array. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [] ); + return ( + <> + <div + id={ editorInstructionsId } + className={ editorInstructionsId } + > + { __( + `This editor allows you to input Additional CSS and customize the site's appearance with your own styles. Press Escape then Tab to move focus out of the editor.` + ) } + </div> + <div + ref={ editorRef } + id={ editorId } + className={ editorId } + aria-describedby={ editorInstructionsId } + ></div> + </> + ); +}; + +export default EditorView; \ No newline at end of file From ee88fcd2e9d60d44727aee4de15635db5a61af35 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Thu, 28 Mar 2024 14:45:41 +0900 Subject: [PATCH 12/22] Fix incorrect use of var() --- packages/edit-site/src/components/global-styles/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/global-styles/style.scss b/packages/edit-site/src/components/global-styles/style.scss index a433ea3032a639..07ab720d5cb204 100644 --- a/packages/edit-site/src/components/global-styles/style.scss +++ b/packages/edit-site/src/components/global-styles/style.scss @@ -127,7 +127,7 @@ } .block-editor-global-styles-advanced-panel__custom-css-editor { overflow-y: scroll; - border: 1px solid var($gray-600); + border: 1px solid $gray-600; border-radius: $radius-block-ui; &:focus-within { box-shadow: 0 0 0 calc(1.5px - 1px) var(--wp-admin-theme-color); From a6519f27ca1945ac41b81b2123a171af0d082857 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Thu, 28 Mar 2024 18:05:55 +0900 Subject: [PATCH 13/22] Reuse EditorView component --- packages/block-editor/package.json | 1 + .../global-styles/advanced-panel.js | 86 +++++++++++-- .../components/global-styles/editor-view.js | 121 ++++++++---------- packages/block-editor/src/components/index.js | 5 + packages/block-library/package.json | 4 - packages/block-library/src/html/edit.js | 54 +++----- 6 files changed, 149 insertions(+), 122 deletions(-) diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index 359e1f1c486581..5879841593bc8f 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -34,6 +34,7 @@ "@babel/runtime": "^7.16.0", "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", + "@codemirror/lang-html": "6.2.1", "@codemirror/view": "6.26.0", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index e5c0ac0cfe0954..59c96bf216ef33 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -2,20 +2,72 @@ * WordPress dependencies */ import { Notice, __experimentalVStack as VStack } from '@wordpress/components'; -import { useState, Suspense, lazy } from '@wordpress/element'; +import { useState, useEffect } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ import { default as transformStyles } from '../../utils/transform-styles'; - -const EditorView = lazy( () => import( './editor-view' ) ); +import EditorView from './editor-view'; const EDITOR_ID = 'block-editor-global-styles-advanced-panel__custom-css-editor'; const EDITOR_INSTRUCTIONS_ID = `${ EDITOR_ID }-instructions`; +/** + * Returns the value that should be set for the code editor height + */ +function getEditorHeight() { + const MARGIN = 53.4; + const wrapper = document.querySelector( + '.edit-site-global-styles-screen-css' + ); + if ( wrapper ) { + const wrapperHeight = wrapper.offsetHeight; + const editorHeight = wrapperHeight - MARGIN; + return editorHeight; + } + return 0; +} + +/** + * Ensure the editor has at least min lines of code, as the editor will shrink to fit the content. + * + * @param {string} content - The content to ensure min lines for. + * @param {string} editorId - The ID of the editor. + * @returns {string} The content with at least min lines. + */ +function ensureMinLines( content, editorId ) { + const MIN_LINES = 10; + const LINE_HEIGHT = 18.2; // Height of one line in the editor + // const MARGIN = 53.4; + let requiredLines = MIN_LINES; + + const lines = content.split( '\n' ); + const contentLineCount = lines.length; + + const editorHeight = getEditorHeight(); + if ( editorHeight !== 0 ) { + // Calculate the minimum number of lines that should be displayed + const calcMinLineCount = Math.ceil( editorHeight / LINE_HEIGHT ); + requiredLines = Math.max( MIN_LINES, calcMinLineCount ); + + // Set the max height of the editor allowing scrolling by `overflow-y: scroll` + const editor = document.getElementById( editorId ); + if ( editor ) { + editor.style.height = `${ editorHeight }px`; + } + } + + let result = content; + for ( let i = contentLineCount; i < requiredLines; i++ ) { + result += '\n'; + } + + return result; +} + export default function AdvancedPanel( { value, onChange, @@ -23,7 +75,6 @@ export default function AdvancedPanel( { } ) { // Custom CSS const [ cssError, setCSSError ] = useState( null ); - const customCSS = inheritedValue?.css; function handleOnChange( newValue ) { onChange( { ...value, @@ -55,6 +106,18 @@ export default function AdvancedPanel( { ); } + const [ customCSS, setCustomeCSS ] = useState( '' ); + useEffect( () => { + if ( ! inheritedValue?.css ) { + return; + } + if ( customCSS !== '' ) { + return; + } + setCustomeCSS( ensureMinLines( inheritedValue?.css, EDITOR_ID ) ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [inheritedValue?.css]) + return ( <VStack spacing={ 3 }> { cssError && ( @@ -68,15 +131,20 @@ export default function AdvancedPanel( { > { __( 'Additional CSS' ) } </label> - <Suspense fallback={ null }> + { + customCSS !== '' && <EditorView + content={ customCSS } editorId={EDITOR_ID} editorInstructionsId={EDITOR_INSTRUCTIONS_ID} - customCSS={ customCSS } - onChange={ handleOnChange } + editorInstructionsText={__( + `This editor allows you to input Additional CSS and customize the site's appearance with your own styles.` + )} + mode="css" onBlur={ handleOnBlur } - /> - </Suspense> + onChange={ handleOnChange } + /> + } </VStack> ); } diff --git a/packages/block-editor/src/components/global-styles/editor-view.js b/packages/block-editor/src/components/global-styles/editor-view.js index 99ecbd4a007ede..8b6845c291f267 100644 --- a/packages/block-editor/src/components/global-styles/editor-view.js +++ b/packages/block-editor/src/components/global-styles/editor-view.js @@ -1,58 +1,33 @@ -/** - * External dependencies - */ -import { EditorView as CmEditorView, basicSetup } from 'codemirror'; -import { indentWithTab } from '@codemirror/commands'; -import { keymap } from '@codemirror/view'; -import { css } from '@codemirror/lang-css'; - /** * WordPress dependencies */ import { useEffect, useRef } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -const EditorView = ({editorId, editorInstructionsId, customCSS, onChange, onBlur}) => { - /** - * Ensure the editor has at least min lines of code, - * as the editor will shrink to fit the content. - * @param {string} content The content to ensure min lines for. - * @return {string} The content with at least min lines. - */ - function ensureMinLines( content ) { - const MIN_LINES = 10; - const LINE_HEIGHT = 18.2; // Height of one line in the editor - const MARGIN = 53.4; - let requiredLines = MIN_LINES; - - const lines = content.split( '\n' ); - const contentLineCount = lines.length; - - const wrapper = document.querySelector( - '.edit-site-global-styles-screen-css' - ); - if ( wrapper ) { - const wrapperHeight = wrapper.offsetHeight; - const editorHeight = wrapperHeight - MARGIN; - - // Calculate the minimum number of lines that should be displayed - const calcMinLineCount = Math.ceil( editorHeight / LINE_HEIGHT ); - requiredLines = Math.max( MIN_LINES, calcMinLineCount ); - - // Set the max height of the editor allowing scrolling by `overflow-y: scroll` - const editor = document.getElementById( editorId ); - if ( editor ) { - editor.style.height = `${ editorHeight }px`; - } - } - - let result = content; - for ( let i = contentLineCount; i < requiredLines; i++ ) { - result += '\n'; - } - - return result; +function importLanguageSupport( mode ) { + switch ( mode ) { + case 'css': + return import( '@codemirror/lang-css' ); + case 'html': + return import( '@codemirror/lang-html' ); + default: + return import( '@codemirror/lang-css' ); } +} + +/** + * EditorView provided by CodeMirror + * + * @param {Object} props + * @param {string} props.content - Text content of the editor. + * @param {string} props.editorId + * @param {string} props.editorInstructionsId + * @param {string} props.editorInstructionsText - Instructions text for accessibility. + * @param {Function} props.onChange - Callback for when the content changes. + * @param {Function} [props.onBlur] - Callback for when the editor loses focus. + * @param {string} props.mode - Language mode for the editor. Currently supports 'css' and 'html'. + */ +const EditorView = ({content, editorId, editorInstructionsId, editorInstructionsText, onChange, onBlur, mode}) => { const editorRef = useRef(null); useEffect( () => { ( async () => { @@ -61,31 +36,35 @@ const EditorView = ({editorId, editorInstructionsId, customCSS, onChange, onBlur * This should be replaced with native dynamic import once it's supported. * @see https://github.com/WordPress/gutenberg/pull/60155 */ - // const { EditorView: CmEditorView, basicSetup } = await import( 'codemirror' ); - // const { indentWithTab } = await import( '@codemirror/commands' ); - // const { keymap } = await import( '@codemirror/view' ); - // const { css } = await import( '@codemirror/lang-css' ); + const [{ EditorView: CmEditorView, basicSetup }, { indentWithTab }, { keymap }, languageSupport] = + await Promise.all([ + import( 'codemirror' ), + import( '@codemirror/commands' ), + import( '@codemirror/view' ), + importLanguageSupport( mode ) + ]) if ( editorRef.current ) { new CmEditorView( { - doc: ensureMinLines( customCSS ), + doc: content, extensions: [ basicSetup, - css(), + languageSupport[mode](), keymap.of( [ indentWithTab ] ), CmEditorView.updateListener.of( ( editor ) => { if ( editor.docChanged ) { onChange( editor.state.doc.toString() ); } } ), - CmEditorView.focusChangeEffect.of( + ...(onBlur ? + [CmEditorView.focusChangeEffect.of( ( editorState, focusing ) => { if ( ! focusing ) { onBlur( editorState.doc.toString() ); } return null; } - ), + )] : []), ], parent: editorRef.current, } ); @@ -96,20 +75,22 @@ const EditorView = ({editorId, editorInstructionsId, customCSS, onChange, onBlur }, [] ); return ( <> - <div - id={ editorInstructionsId } - className={ editorInstructionsId } - > - { __( - `This editor allows you to input Additional CSS and customize the site's appearance with your own styles. Press Escape then Tab to move focus out of the editor.` - ) } - </div> - <div - ref={ editorRef } - id={ editorId } - className={ editorId } - aria-describedby={ editorInstructionsId } - ></div> + <div + id={ editorInstructionsId } + className={ editorInstructionsId } + style={ { display: 'none' } } + > + { editorInstructionsText } + { __( + `Press Escape then Tab to move focus out of the editor.` + ) } + </div> + <div + ref={ editorRef } + id={ editorId } + className={ editorId } + aria-describedby={ editorInstructionsId } + ></div> </> ); }; diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 5263ca3332b250..6c12410722d7f3 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -174,3 +174,8 @@ export { useBlockCommands } from './use-block-commands'; * The following rename hint component can be removed in 6.4. */ export { default as ReusableBlocksRenameHint } from './inserter/reusable-block-rename-hint'; + +/** + * Code editor using CodeMirror. + */ +export { default as EditorView } from './global-styles/editor-view'; \ No newline at end of file diff --git a/packages/block-library/package.json b/packages/block-library/package.json index 100e7063f5258c..0a024f3a5f422e 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -31,9 +31,6 @@ ], "dependencies": { "@babel/runtime": "^7.16.0", - "@codemirror/commands": "6.3.3", - "@codemirror/lang-html": "6.4.8", - "@codemirror/view": "6.26.0", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/autop": "file:../autop", @@ -68,7 +65,6 @@ "@wordpress/wordcount": "file:../wordcount", "change-case": "^4.1.2", "classnames": "^2.3.1", - "codemirror": "6.0.1", "colord": "^2.7.0", "escape-html": "^1.0.3", "fast-average-color": "^9.1.1", diff --git a/packages/block-library/src/html/edit.js b/packages/block-library/src/html/edit.js index b6e1eb13ff6b0c..2894d1a34a5fdf 100644 --- a/packages/block-library/src/html/edit.js +++ b/packages/block-library/src/html/edit.js @@ -2,8 +2,8 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { useContext, useState, useRef, useEffect } from '@wordpress/element'; -import { BlockControls, useBlockProps } from '@wordpress/block-editor'; +import { useContext, useState } from '@wordpress/element'; +import { BlockControls, useBlockProps, EditorView } from '@wordpress/block-editor'; import { ToolbarButton, Disabled, @@ -23,8 +23,6 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { const instanceId = useInstanceId( HTMLEdit, 'html-edit-desc' ); - const editorRef = useRef(); - function switchToPreview() { setIsPreview( true ); } @@ -38,40 +36,9 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { 'aria-describedby': isPreview ? instanceId : undefined, } ); - useEffect( () => { - ( async () => { - /** - * Lazy load CodeMirror by using Webpack's dynamic import. - * This should be replaced with native dynamic import once it's supported. - * @see https://github.com/WordPress/gutenberg/pull/60155 - */ - const { EditorView, basicSetup } = await import( 'codemirror' ); - const { indentWithTab } = await import( '@codemirror/commands' ); - const { keymap } = await import( '@codemirror/view' ); - const { html } = await import( '@codemirror/lang-html' ); - - if ( editorRef.current ) { - new EditorView( { - doc: attributes.content, - extensions: [ - basicSetup, - html(), - keymap.of( [ indentWithTab ] ), - EditorView.updateListener.of( ( editor ) => { - if ( editor.docChanged ) { - setAttributes( { - content: editor.state.doc.toString(), - } ); - } - } ), - ], - parent: editorRef.current, - } ); - } - } )(); - // Run this only when the UI renders, so we can ignore the dependency array. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ isPreview, isDisabled ] ); + function onChange( newContent ) { + setAttributes( { content: newContent } ); + } return ( <div { ...blockProps }> @@ -106,7 +73,16 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { </VisuallyHidden> </> ) : ( - <div ref={ editorRef } aria-label={ __( 'HTML' ) } /> + <EditorView + content={ attributes.content } + editorId={'block-library-html__editor'} + editorInstructionsId={'block-library-html__editor-instructions'} + editorInstructionsText={__( + `This editor allows you to input your custom HTML.` + )} + mode="html" + onChange={ onChange } + /> ) } </div> ); From 57f47703cee6e8f4fc907cdda32bc4b29b437b76 Mon Sep 17 00:00:00 2001 From: "okmttdhr, tada" <okmttdhr@users.noreply.github.com> Date: Fri, 29 Mar 2024 10:12:36 +0900 Subject: [PATCH 14/22] Fix wrong package version Co-authored-by: Lena Morita <lena@jaguchi.com> --- packages/block-editor/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index 5879841593bc8f..d8f4f077638957 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -34,7 +34,7 @@ "@babel/runtime": "^7.16.0", "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", - "@codemirror/lang-html": "6.2.1", + "@codemirror/lang-html": "6.4.8", "@codemirror/view": "6.26.0", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", From dff73f6dcee47b6f59ca45f32898948dc061a034 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Fri, 29 Mar 2024 10:14:34 +0900 Subject: [PATCH 15/22] Fix typo in variable name --- .../src/components/global-styles/advanced-panel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index 59c96bf216ef33..7b4817454a9e46 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -106,7 +106,7 @@ export default function AdvancedPanel( { ); } - const [ customCSS, setCustomeCSS ] = useState( '' ); + const [ customCSS, setCustomCSS ] = useState( '' ); useEffect( () => { if ( ! inheritedValue?.css ) { return; @@ -114,7 +114,7 @@ export default function AdvancedPanel( { if ( customCSS !== '' ) { return; } - setCustomeCSS( ensureMinLines( inheritedValue?.css, EDITOR_ID ) ); + setCustomCSS( ensureMinLines( inheritedValue?.css, EDITOR_ID ) ); // eslint-disable-next-line react-hooks/exhaustive-deps }, [inheritedValue?.css]) From e7aa264060d507cec971744e4aab7480d7299ce0 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Mon, 1 Apr 2024 10:44:44 +0900 Subject: [PATCH 16/22] Remove unnecessary condition in useEffect --- .../src/components/global-styles/advanced-panel.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index 7b4817454a9e46..bb4ab1cd58643e 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -108,9 +108,6 @@ export default function AdvancedPanel( { const [ customCSS, setCustomCSS ] = useState( '' ); useEffect( () => { - if ( ! inheritedValue?.css ) { - return; - } if ( customCSS !== '' ) { return; } From fb5ba29f0cc7557496104d7eaa072764d91e698a Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Mon, 1 Apr 2024 10:45:22 +0900 Subject: [PATCH 17/22] Use @\mixins --- .../edit-site/src/components/global-styles/style.scss | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/style.scss b/packages/edit-site/src/components/global-styles/style.scss index 07ab720d5cb204..829ab855443bb9 100644 --- a/packages/edit-site/src/components/global-styles/style.scss +++ b/packages/edit-site/src/components/global-styles/style.scss @@ -127,17 +127,11 @@ } .block-editor-global-styles-advanced-panel__custom-css-editor { overflow-y: scroll; - border: 1px solid $gray-600; - border-radius: $radius-block-ui; + @include input-style__neutral(); &:focus-within { - box-shadow: 0 0 0 calc(1.5px - 1px) var(--wp-admin-theme-color); - border-color: var(--wp-admin-theme-color); - outline: transparent solid 2px; + @include input-style__focus(); } } - .block-editor-global-styles-advanced-panel__custom-css-editor-instructions { - display: none; - } .cm-editor { // Override the default CodeMirror font-family. .cm-line { From a10641694690116bebc433aab4edab320109b284 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Mon, 1 Apr 2024 10:45:40 +0900 Subject: [PATCH 18/22] Add VisuallyHidden component to hide editor instructions --- .../src/components/global-styles/editor-view.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/editor-view.js b/packages/block-editor/src/components/global-styles/editor-view.js index 8b6845c291f267..46834360f0ef92 100644 --- a/packages/block-editor/src/components/global-styles/editor-view.js +++ b/packages/block-editor/src/components/global-styles/editor-view.js @@ -1,6 +1,7 @@ /** * WordPress dependencies */ +import { VisuallyHidden } from '@wordpress/components'; import { useEffect, useRef } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; @@ -75,16 +76,14 @@ const EditorView = ({content, editorId, editorInstructionsId, editorInstructions }, [] ); return ( <> - <div + <VisuallyHidden id={ editorInstructionsId } - className={ editorInstructionsId } - style={ { display: 'none' } } > { editorInstructionsText } { __( `Press Escape then Tab to move focus out of the editor.` ) } - </div> + </VisuallyHidden> <div ref={ editorRef } id={ editorId } From 30ae96e736308b01d965b39cbe38c6f4bc23d793 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Mon, 1 Apr 2024 15:21:54 +0900 Subject: [PATCH 19/22] Fix editor height isn't calculated properly --- .../global-styles/advanced-panel.js | 67 +++++++++---------- .../components/global-styles/editor-view.js | 30 +++++++-- 2 files changed, 57 insertions(+), 40 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index bb4ab1cd58643e..171657cc606bd1 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { Notice, __experimentalVStack as VStack } from '@wordpress/components'; -import { useState, useEffect } from '@wordpress/element'; +import { useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; /** @@ -19,26 +19,22 @@ const EDITOR_INSTRUCTIONS_ID = `${ EDITOR_ID }-instructions`; * Returns the value that should be set for the code editor height */ function getEditorHeight() { - const MARGIN = 53.4; - const wrapper = document.querySelector( - '.edit-site-global-styles-screen-css' - ); - if ( wrapper ) { - const wrapperHeight = wrapper.offsetHeight; - const editorHeight = wrapperHeight - MARGIN; - return editorHeight; - } - return 0; + /** + * (height of all the elements in the sidebar except the editor) + (height of the header) + (height of the footer) + * Currently, it's desktop-optimized. + */ + const MARGIN = 234 + 60 + 25; + const editorHeight = window.innerHeight - MARGIN; + return editorHeight; } /** * Ensure the editor has at least min lines of code, as the editor will shrink to fit the content. * * @param {string} content - The content to ensure min lines for. - * @param {string} editorId - The ID of the editor. - * @returns {string} The content with at least min lines. + * @return {string} The content with at least min lines. */ -function ensureMinLines( content, editorId ) { +function ensureMinLines( content ) { const MIN_LINES = 10; const LINE_HEIGHT = 18.2; // Height of one line in the editor // const MARGIN = 53.4; @@ -52,12 +48,6 @@ function ensureMinLines( content, editorId ) { // Calculate the minimum number of lines that should be displayed const calcMinLineCount = Math.ceil( editorHeight / LINE_HEIGHT ); requiredLines = Math.max( MIN_LINES, calcMinLineCount ); - - // Set the max height of the editor allowing scrolling by `overflow-y: scroll` - const editor = document.getElementById( editorId ); - if ( editor ) { - editor.style.height = `${ editorHeight }px`; - } } let result = content; @@ -68,6 +58,20 @@ function ensureMinLines( content, editorId ) { return result; } +/** + * Ensure the editor has at most max height to allow scrolling by `overflow-y: scroll`. + * It needs to run after the editor DOM is mounted. + */ +function ensureMaxHeight() { + const editorHeight = getEditorHeight(); + if ( editorHeight !== 0 ) { + const editor = document.getElementById( EDITOR_ID ); + if ( editor ) { + editor.style.height = `${ editorHeight }px`; + } + } +} + export default function AdvancedPanel( { value, onChange, @@ -106,15 +110,6 @@ export default function AdvancedPanel( { ); } - const [ customCSS, setCustomCSS ] = useState( '' ); - useEffect( () => { - if ( customCSS !== '' ) { - return; - } - setCustomCSS( ensureMinLines( inheritedValue?.css, EDITOR_ID ) ); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [inheritedValue?.css]) - return ( <VStack spacing={ 3 }> { cssError && ( @@ -129,17 +124,21 @@ export default function AdvancedPanel( { { __( 'Additional CSS' ) } </label> { - customCSS !== '' && <EditorView - content={ customCSS } editorId={EDITOR_ID} editorInstructionsId={EDITOR_INSTRUCTIONS_ID} editorInstructionsText={__( `This editor allows you to input Additional CSS and customize the site's appearance with your own styles.` )} - mode="css" - onBlur={ handleOnBlur } - onChange={ handleOnChange } + initialConfig={ + { + callback: ensureMaxHeight, + content: ensureMinLines( inheritedValue?.css ), + onBlur: handleOnBlur, + onChange: handleOnChange, + mode: "css", + } + } /> } </VStack> diff --git a/packages/block-editor/src/components/global-styles/editor-view.js b/packages/block-editor/src/components/global-styles/editor-view.js index 46834360f0ef92..0a0a367168fb4c 100644 --- a/packages/block-editor/src/components/global-styles/editor-view.js +++ b/packages/block-editor/src/components/global-styles/editor-view.js @@ -16,19 +16,36 @@ function importLanguageSupport( mode ) { } } +/** + * @typedef {Object} Config + * @property {Function} callback - Callback after the editor is initialized. + * @property {string} content - Text content of the editor. + * @property {Function} onChange - Callback for when the content changes. + * @property {Function} [onBlur] - Callback for when the editor loses focus. + * @property {string} mode - Language mode for the editor. Currently supports 'css' and 'html'. + */ + /** * EditorView provided by CodeMirror - * + * * @param {Object} props - * @param {string} props.content - Text content of the editor. * @param {string} props.editorId * @param {string} props.editorInstructionsId * @param {string} props.editorInstructionsText - Instructions text for accessibility. - * @param {Function} props.onChange - Callback for when the content changes. - * @param {Function} [props.onBlur] - Callback for when the editor loses focus. - * @param {string} props.mode - Language mode for the editor. Currently supports 'css' and 'html'. + * @param {Config} props.initialConfig - Initial configuration for the editor. This can only be used for the initial setup of the editor. */ -const EditorView = ({content, editorId, editorInstructionsId, editorInstructionsText, onChange, onBlur, mode}) => { +const EditorView = ({ + editorId, + editorInstructionsId, + editorInstructionsText, + initialConfig: { + callback, + content, + onChange, + onBlur, + mode, + }, +}) => { const editorRef = useRef(null); useEffect( () => { ( async () => { @@ -69,6 +86,7 @@ const EditorView = ({content, editorId, editorInstructionsId, editorInstructions ], parent: editorRef.current, } ); + callback(); } } )(); // We only want to run this once, so we can ignore the dependency array. From af8af11c5183bad36e879fad4d1e7b2c11230026 Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Mon, 1 Apr 2024 16:14:35 +0900 Subject: [PATCH 20/22] Use BaseControl for Additional CSS --- .../global-styles/advanced-panel.js | 26 +++++++++---------- .../components/global-styles/editor-view.js | 23 ++++++++++------ packages/block-library/src/html/edit.js | 8 +++--- .../src/components/global-styles/style.scss | 6 ----- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index 171657cc606bd1..eb478d8ad25c21 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { Notice, __experimentalVStack as VStack } from '@wordpress/components'; +import { Notice, __experimentalVStack as VStack, BaseControl } from '@wordpress/components'; import { useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; @@ -13,7 +13,6 @@ import EditorView from './editor-view'; const EDITOR_ID = 'block-editor-global-styles-advanced-panel__custom-css-editor'; -const EDITOR_INSTRUCTIONS_ID = `${ EDITOR_ID }-instructions`; /** * Returns the value that should be set for the code editor height @@ -117,19 +116,18 @@ export default function AdvancedPanel( { { cssError } </Notice> ) } - <label - htmlFor={ EDITOR_ID } - className="block-editor-global-styles-advanced-panel__custom-css-label" + <BaseControl + id={ EDITOR_ID } + help={`${__( + `This editor allows you to input Additional CSS and customize the site's appearance with your own styles.` + )} ${__( + `Press Escape then Tab to move focus out of the editor.` + )}` + } + label={__( 'Additional CSS' )} > - { __( 'Additional CSS' ) } - </label> - { <EditorView editorId={EDITOR_ID} - editorInstructionsId={EDITOR_INSTRUCTIONS_ID} - editorInstructionsText={__( - `This editor allows you to input Additional CSS and customize the site's appearance with your own styles.` - )} initialConfig={ { callback: ensureMaxHeight, @@ -139,8 +137,8 @@ export default function AdvancedPanel( { mode: "css", } } - /> - } + /> + </BaseControl> </VStack> ); } diff --git a/packages/block-editor/src/components/global-styles/editor-view.js b/packages/block-editor/src/components/global-styles/editor-view.js index 0a0a367168fb4c..6fc13d7e305391 100644 --- a/packages/block-editor/src/components/global-styles/editor-view.js +++ b/packages/block-editor/src/components/global-styles/editor-view.js @@ -5,6 +5,11 @@ import { VisuallyHidden } from '@wordpress/components'; import { useEffect, useRef } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; +/** + * Dynamically import the language support for the editor. + * + * @param {string} mode - Language mode for the editor. Currently supports 'css' and 'html'. + */ function importLanguageSupport( mode ) { switch ( mode ) { case 'css': @@ -18,7 +23,7 @@ function importLanguageSupport( mode ) { /** * @typedef {Object} Config - * @property {Function} callback - Callback after the editor is initialized. + * @property {Function} [callback] - Callback after the editor is initialized. * @property {string} content - Text content of the editor. * @property {Function} onChange - Callback for when the content changes. * @property {Function} [onBlur] - Callback for when the editor loses focus. @@ -30,8 +35,8 @@ function importLanguageSupport( mode ) { * * @param {Object} props * @param {string} props.editorId - * @param {string} props.editorInstructionsId - * @param {string} props.editorInstructionsText - Instructions text for accessibility. + * @param {string} [props.editorInstructionsId] + * @param {string} [props.editorInstructionsText] - Instructions text for accessibility. * @param {Config} props.initialConfig - Initial configuration for the editor. This can only be used for the initial setup of the editor. */ const EditorView = ({ @@ -39,7 +44,7 @@ const EditorView = ({ editorInstructionsId, editorInstructionsText, initialConfig: { - callback, + callback, content, onChange, onBlur, @@ -86,22 +91,24 @@ const EditorView = ({ ], parent: editorRef.current, } ); - callback(); + if (typeof callback === 'function') { + callback(); + } } } )(); - // We only want to run this once, so we can ignore the dependency array. + // We only want to run this once when the editor is initialized, so we can ignore the dependency array. // eslint-disable-next-line react-hooks/exhaustive-deps }, [] ); return ( <> - <VisuallyHidden + {editorInstructionsId && (<VisuallyHidden id={ editorInstructionsId } > { editorInstructionsText } { __( `Press Escape then Tab to move focus out of the editor.` ) } - </VisuallyHidden> + </VisuallyHidden>)} <div ref={ editorRef } id={ editorId } diff --git a/packages/block-library/src/html/edit.js b/packages/block-library/src/html/edit.js index 2894d1a34a5fdf..49ca2c3715e2fd 100644 --- a/packages/block-library/src/html/edit.js +++ b/packages/block-library/src/html/edit.js @@ -74,14 +74,16 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { </> ) : ( <EditorView - content={ attributes.content } editorId={'block-library-html__editor'} editorInstructionsId={'block-library-html__editor-instructions'} editorInstructionsText={__( `This editor allows you to input your custom HTML.` )} - mode="html" - onChange={ onChange } + initialConfig={{ + content: attributes.content, + onChange, + mode: 'html', + }} /> ) } </div> diff --git a/packages/edit-site/src/components/global-styles/style.scss b/packages/edit-site/src/components/global-styles/style.scss index 829ab855443bb9..22be157b309ff1 100644 --- a/packages/edit-site/src/components/global-styles/style.scss +++ b/packages/edit-site/src/components/global-styles/style.scss @@ -119,12 +119,6 @@ margin: $grid-unit-20; .components-v-stack { - .block-editor-global-styles-advanced-panel__custom-css-label { - font-size: 11px; - font-weight: 500; - line-height: 1.4; - text-transform: uppercase; - } .block-editor-global-styles-advanced-panel__custom-css-editor { overflow-y: scroll; @include input-style__neutral(); From b0054fc7c7c1caff6e2f6538baa4b13d7456510a Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Tue, 2 Apr 2024 14:38:36 +0900 Subject: [PATCH 21/22] Utilize useInstanceId --- .../global-styles/advanced-panel.js | 18 +++++++++-------- .../components/global-styles/editor-view.js | 20 +++++++++---------- packages/block-library/src/html/edit.js | 1 - 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.js b/packages/block-editor/src/components/global-styles/advanced-panel.js index eb478d8ad25c21..952c97fc5883c7 100644 --- a/packages/block-editor/src/components/global-styles/advanced-panel.js +++ b/packages/block-editor/src/components/global-styles/advanced-panel.js @@ -4,6 +4,7 @@ import { Notice, __experimentalVStack as VStack, BaseControl } from '@wordpress/components'; import { useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; +import { useInstanceId } from '@wordpress/compose'; /** * Internal dependencies @@ -11,9 +12,6 @@ import { __ } from '@wordpress/i18n'; import { default as transformStyles } from '../../utils/transform-styles'; import EditorView from './editor-view'; -const EDITOR_ID = - 'block-editor-global-styles-advanced-panel__custom-css-editor'; - /** * Returns the value that should be set for the code editor height */ @@ -60,11 +58,13 @@ function ensureMinLines( content ) { /** * Ensure the editor has at most max height to allow scrolling by `overflow-y: scroll`. * It needs to run after the editor DOM is mounted. + * + * @param {string} editorId - The id of the editor. */ -function ensureMaxHeight() { +function ensureMaxHeight(editorId) { const editorHeight = getEditorHeight(); if ( editorHeight !== 0 ) { - const editor = document.getElementById( EDITOR_ID ); + const editor = document.getElementById( editorId ); if ( editor ) { editor.style.height = `${ editorHeight }px`; } @@ -78,6 +78,8 @@ export default function AdvancedPanel( { } ) { // Custom CSS const [ cssError, setCSSError ] = useState( null ); + const instanceId = useInstanceId( AdvancedPanel ); + function handleOnChange( newValue ) { onChange( { ...value, @@ -117,7 +119,7 @@ export default function AdvancedPanel( { </Notice> ) } <BaseControl - id={ EDITOR_ID } + id={ instanceId } help={`${__( `This editor allows you to input Additional CSS and customize the site's appearance with your own styles.` )} ${__( @@ -127,10 +129,10 @@ export default function AdvancedPanel( { label={__( 'Additional CSS' )} > <EditorView - editorId={EDITOR_ID} + editorId={instanceId} initialConfig={ { - callback: ensureMaxHeight, + callback: () => ensureMaxHeight(instanceId), content: ensureMinLines( inheritedValue?.css ), onBlur: handleOnBlur, onChange: handleOnChange, diff --git a/packages/block-editor/src/components/global-styles/editor-view.js b/packages/block-editor/src/components/global-styles/editor-view.js index 6fc13d7e305391..5d478c93c76517 100644 --- a/packages/block-editor/src/components/global-styles/editor-view.js +++ b/packages/block-editor/src/components/global-styles/editor-view.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { VisuallyHidden } from '@wordpress/components'; +import { useInstanceId } from '@wordpress/compose'; import { useEffect, useRef } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; @@ -24,10 +25,10 @@ function importLanguageSupport( mode ) { /** * @typedef {Object} Config * @property {Function} [callback] - Callback after the editor is initialized. - * @property {string} content - Text content of the editor. - * @property {Function} onChange - Callback for when the content changes. - * @property {Function} [onBlur] - Callback for when the editor loses focus. - * @property {string} mode - Language mode for the editor. Currently supports 'css' and 'html'. + * @property {string} content - Text content of the editor. + * @property {Function} onChange - Callback for when the content changes. + * @property {Function} [onBlur] - Callback for when the editor loses focus. + * @property {string} mode - Language mode for the editor. Currently supports 'css' and 'html'. */ /** @@ -35,13 +36,11 @@ function importLanguageSupport( mode ) { * * @param {Object} props * @param {string} props.editorId - * @param {string} [props.editorInstructionsId] * @param {string} [props.editorInstructionsText] - Instructions text for accessibility. - * @param {Config} props.initialConfig - Initial configuration for the editor. This can only be used for the initial setup of the editor. + * @param {Config} props.initialConfig - Initial configuration for the editor. This can only be used for the initial setup of the editor. */ const EditorView = ({ editorId, - editorInstructionsId, editorInstructionsText, initialConfig: { callback, @@ -52,6 +51,7 @@ const EditorView = ({ }, }) => { const editorRef = useRef(null); + const instanceId = useInstanceId( EditorView ); useEffect( () => { ( async () => { /** @@ -101,8 +101,8 @@ const EditorView = ({ }, [] ); return ( <> - {editorInstructionsId && (<VisuallyHidden - id={ editorInstructionsId } + {editorInstructionsText && (<VisuallyHidden + id={ instanceId } > { editorInstructionsText } { __( @@ -113,7 +113,7 @@ const EditorView = ({ ref={ editorRef } id={ editorId } className={ editorId } - aria-describedby={ editorInstructionsId } + aria-describedby={ instanceId } ></div> </> ); diff --git a/packages/block-library/src/html/edit.js b/packages/block-library/src/html/edit.js index 49ca2c3715e2fd..ba068849632e5d 100644 --- a/packages/block-library/src/html/edit.js +++ b/packages/block-library/src/html/edit.js @@ -75,7 +75,6 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) { ) : ( <EditorView editorId={'block-library-html__editor'} - editorInstructionsId={'block-library-html__editor-instructions'} editorInstructionsText={__( `This editor allows you to input your custom HTML.` )} From ab798850a26fb3d4e1f6c63830631aa1cfe1634e Mon Sep 17 00:00:00 2001 From: okmttdhr <okmttdhr@users.noreply.github.com> Date: Wed, 3 Apr 2024 12:22:18 +0900 Subject: [PATCH 22/22] Switch the editor's light/dark mode --- package-lock.json | 13 ++++------ package.json | 1 + packages/block-editor/package.json | 1 + .../components/global-styles/editor-view.js | 26 +++++++++++++++++-- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9b6b5831a29414..6e7c0ab3200169 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", "@codemirror/lang-html": "6.4.8", + "@codemirror/state": "6.4.1", "@codemirror/view": "6.26.0", "@wordpress/a11y": "file:packages/a11y", "@wordpress/annotations": "file:packages/annotations", @@ -55042,6 +55043,8 @@ "@babel/runtime": "^7.16.0", "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", + "@codemirror/lang-html": "6.4.8", + "@codemirror/state": "6.4.1", "@codemirror/view": "6.26.0", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", @@ -55140,9 +55143,6 @@ "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", - "@codemirror/commands": "6.3.3", - "@codemirror/lang-html": "6.4.8", - "@codemirror/view": "6.26.0", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/autop": "file:../autop", @@ -55177,7 +55177,6 @@ "@wordpress/wordcount": "file:../wordcount", "change-case": "^4.1.2", "classnames": "^2.3.1", - "codemirror": "6.0.1", "colord": "^2.7.0", "escape-html": "^1.0.3", "fast-average-color": "^9.1.1", @@ -71238,6 +71237,8 @@ "@babel/runtime": "^7.16.0", "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", + "@codemirror/lang-html": "6.4.8", + "@codemirror/state": "6.4.1", "@codemirror/view": "6.26.0", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", @@ -71309,9 +71310,6 @@ "version": "file:packages/block-library", "requires": { "@babel/runtime": "^7.16.0", - "@codemirror/commands": "6.3.3", - "@codemirror/lang-html": "6.4.8", - "@codemirror/view": "6.26.0", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/autop": "file:../autop", @@ -71346,7 +71344,6 @@ "@wordpress/wordcount": "file:../wordcount", "change-case": "^4.1.2", "classnames": "^2.3.1", - "codemirror": "6.0.1", "colord": "^2.7.0", "escape-html": "^1.0.3", "fast-average-color": "^9.1.1", diff --git a/package.json b/package.json index 41f6801036cb4a..c1fd43fb05a8da 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", "@codemirror/lang-html": "6.4.8", + "@codemirror/state": "6.4.1", "@codemirror/view": "6.26.0", "@wordpress/a11y": "file:packages/a11y", "@wordpress/annotations": "file:packages/annotations", diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index d8f4f077638957..35a8cf4f82a195 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -35,6 +35,7 @@ "@codemirror/commands": "6.3.3", "@codemirror/lang-css": "6.2.1", "@codemirror/lang-html": "6.4.8", + "@codemirror/state": "6.4.1", "@codemirror/view": "6.26.0", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", diff --git a/packages/block-editor/src/components/global-styles/editor-view.js b/packages/block-editor/src/components/global-styles/editor-view.js index 5d478c93c76517..8d0775761c9185 100644 --- a/packages/block-editor/src/components/global-styles/editor-view.js +++ b/packages/block-editor/src/components/global-styles/editor-view.js @@ -59,16 +59,19 @@ const EditorView = ({ * This should be replaced with native dynamic import once it's supported. * @see https://github.com/WordPress/gutenberg/pull/60155 */ - const [{ EditorView: CmEditorView, basicSetup }, { indentWithTab }, { keymap }, languageSupport] = + const [{ EditorView: CmEditorView, basicSetup }, { indentWithTab }, { Compartment }, { keymap }, languageSupport] = await Promise.all([ import( 'codemirror' ), import( '@codemirror/commands' ), + import( '@codemirror/state' ), import( '@codemirror/view' ), importLanguageSupport( mode ) ]) if ( editorRef.current ) { - new CmEditorView( { + const isDarkTheme = editorRef.current.closest( '.is-dark-theme' ); + const theme = new Compartment(); + const view = new CmEditorView( { doc: content, extensions: [ basicSetup, @@ -88,9 +91,28 @@ const EditorView = ({ return null; } )] : []), + theme.of(CmEditorView.theme({}, { dark: isDarkTheme })), ], parent: editorRef.current, } ); + + /** + * Observe `body` to detect dark theme changes. + */ + const observer = new window.MutationObserver( ( mutations ) => { + mutations.forEach( ( mutation ) => { + if ( mutation.attributeName === 'class' ) { + view.dispatch({ + effects: theme.reconfigure(CmEditorView.theme({}, { dark: editorRef.current.closest( '.is-dark-theme' ) })), + }); + } + }); + }); + observer.observe( + editorRef.current.closest( 'body' ), + { attributes: true } + ); + if (typeof callback === 'function') { callback(); }