diff --git a/CHANGELOG.md b/CHANGELOG.md index 99bd9f20..64d59bc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [3.9.1] (2025-11-14) + +### Changed +* Migrated to native CSS direction handling (RTL/LTR) for improved compatibility and simpler styling +* Updated dependencies to the latest compatible versions + +### Fixed +* Fixed TinyMCE menu button registration to prevent initialization failure +* Fixed the position of the 'code direction' control in the editor + ## [3.9.0] (2025-11-13) ### Added diff --git a/config/RtlCssPlugin.ts b/config/RtlCssPlugin.ts deleted file mode 100644 index b6fbd940..00000000 --- a/config/RtlCssPlugin.ts +++ /dev/null @@ -1,50 +0,0 @@ -import path from 'path' -import rtlcss from 'rtlcss' -import type { Compiler } from 'webpack' -import type { ConfigureOptions } from 'rtlcss' - -export interface WebpackRTLPluginOptions { - entries: Set - rtlcssConfig: ConfigureOptions - transformFilename: (sourceFilename: string) => string -} - -export class RtlCssPlugin { - private readonly options: WebpackRTLPluginOptions - - private static readonly defaultOptions: WebpackRTLPluginOptions = { - entries: new Set(), - rtlcssConfig: {}, - transformFilename: sourceFilename => - `${path.parse(sourceFilename).name}-rtl.css` - } - - constructor(options: Partial) { - this.options = { ...RtlCssPlugin.defaultOptions, ...options } - } - - apply(compiler: Compiler) { - const { Compilation, sources: { ConcatSource } } = compiler.webpack - const rtlcssProcessor = rtlcss.configure(this.options.rtlcssConfig) - - compiler.hooks.compilation.tap(RtlCssPlugin.name, compilation => { - compilation.hooks.processAssets.tap({ - name: RtlCssPlugin.name, - stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL - }, assets => { - for (const chunk of compilation.chunks) { - if (chunk.name && this.options.entries.has(chunk.name)) { - for (const sourceFilename of chunk.files) { - if ('.css' === path.extname(sourceFilename)) { - const rtlFilename = this.options.transformFilename(sourceFilename) - const ltrCss = assets[sourceFilename].source() - const rtlCss = rtlcssProcessor.process(ltrCss).css - compilation.emitAsset(rtlFilename, new ConcatSource(rtlCss), { sourceFilename }) - } - } - } - } - }) - }) - } -} diff --git a/config/webpack-css.ts b/config/webpack-css.ts index d1710e99..828d7a02 100644 --- a/config/webpack-css.ts +++ b/config/webpack-css.ts @@ -7,7 +7,6 @@ import hslCompat from 'postcss-color-hsl' import MiniCssExtractPlugin from 'mini-css-extract-plugin' import RemoveEmptyScriptsPlugin from 'webpack-remove-empty-scripts' import { glob } from 'glob' -import { RtlCssPlugin } from './RtlCssPlugin' import type { Configuration, EntryObject } from 'webpack' import type { Config as PostCssConfig } from 'postcss-load-config' @@ -103,9 +102,6 @@ export const cssWebpackConfig: Configuration = { .replace(/^codemirror-theme-/, 'editor-themes/') .replace(/-css\.css$/, '.css') : '[name].css' - }), - new RtlCssPlugin({ - entries: new Set(['manage-css', 'edit-css']) }) ] } diff --git a/package-lock.json b/package-lock.json index f9989b99..fc8df56b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "code-snippets", - "version": "3.9.0", + "version": "3.9.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "code-snippets", - "version": "3.9.0", + "version": "3.9.1", "license": "GPL-2.0-or-later", "dependencies": { "@codemirror/fold": "^0.19.4", @@ -38,7 +38,6 @@ "@types/prismjs": "^1.26.5", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.1", - "@types/rtlcss": "^3.5.4", "@types/tinymce": "^4.6.9", "@types/web": "^0.0.202", "@typescript-eslint/eslint-plugin": "^8.24.0", @@ -66,7 +65,6 @@ "postcss-load-config": "^6.0.1", "postcss-loader": "^8.1.1", "react-is": "^19.0.0", - "rtlcss": "^4.3.0", "sass": "^1.84.0", "sass-loader": "^16.0.4", "style-loader": "^4.0.0", @@ -2969,14 +2967,6 @@ "@types/node": "*" } }, - "node_modules/@types/rtlcss": { - "version": "3.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss": "^8.2.x" - } - }, "node_modules/@types/sizzle": { "version": "2.3.6", "dev": true, @@ -10565,23 +10555,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rtlcss": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0", - "postcss": "^8.4.21", - "strip-json-comments": "^3.1.1" - }, - "bin": { - "rtlcss": "bin/rtlcss.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", diff --git a/package.json b/package.json index 590b003c..e4bed401 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "code-snippets", "description": "Manage code snippets running on a WordPress-powered site through a graphical interface.", "homepage": "https://codesnippets.pro", - "version": "3.9.0", + "version": "3.9.1", "main": "src/dist/edit.js", "directories": { "test": "tests" @@ -73,7 +73,6 @@ "@types/prismjs": "^1.26.5", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.1", - "@types/rtlcss": "^3.5.4", "@types/tinymce": "^4.6.9", "@types/web": "^0.0.202", "@typescript-eslint/eslint-plugin": "^8.24.0", @@ -100,7 +99,6 @@ "postcss-load-config": "^6.0.1", "postcss-loader": "^8.1.1", "react-is": "^19.0.0", - "rtlcss": "^4.3.0", "sass": "^1.84.0", "sass-loader": "^16.0.4", "style-loader": "^4.0.0", diff --git a/src/code-snippets.php b/src/code-snippets.php index 5c9cba12..3b04350c 100644 --- a/src/code-snippets.php +++ b/src/code-snippets.php @@ -8,11 +8,11 @@ * License: GPL-2.0-or-later * License URI: license.txt * Text Domain: code-snippets - * Version: 3.9.0 + * Version: 3.9.1 * Requires PHP: 7.4 * Requires at least: 5.0 * - * @version 3.9.0 + * @version 3.9.1 * @package Code_Snippets * @author Shea Bunge * @copyright 2012-2024 Code Snippets Pro @@ -37,7 +37,7 @@ * * @const string */ - define( 'CODE_SNIPPETS_VERSION', '3.9.0' ); + define( 'CODE_SNIPPETS_VERSION', '3.9.1' ); /** * The full path to the main file of this plugin. diff --git a/src/composer.lock b/src/composer.lock index cd9b5b92..56ee40d1 100644 --- a/src/composer.lock +++ b/src/composer.lock @@ -330,29 +330,29 @@ "packages-dev": [ { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.1.2", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1" + "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/845eb62303d2ca9b289ef216356568ccc075ffd1", + "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1", "shasum": "" }, "require": { "composer-plugin-api": "^2.2", "php": ">=5.4", - "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + "squizlabs/php_codesniffer": "^3.1.0 || ^4.0" }, "require-dev": { "composer/composer": "^2.2", "ext-json": "*", "ext-zip": "*", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcompatibility/php-compatibility": "^9.0", + "phpcompatibility/php-compatibility": "^9.0 || ^10.0.0@dev", "yoast/phpunit-polyfills": "^1.0" }, "type": "composer-plugin", @@ -422,7 +422,7 @@ "type": "thanks_dev" } ], - "time": "2025-07-17T20:45:56+00:00" + "time": "2025-11-11T04:32:07+00:00" }, { "name": "phpcompatibility/php-compatibility", @@ -639,27 +639,27 @@ }, { "name": "phpcsstandards/phpcsextra", - "version": "1.4.2", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", - "reference": "8e89a01c7b8fed84a12a2a7f5a23a44cdbe4f62e" + "reference": "b598aa890815b8df16363271b659d73280129101" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/8e89a01c7b8fed84a12a2a7f5a23a44cdbe4f62e", - "reference": "8e89a01c7b8fed84a12a2a7f5a23a44cdbe4f62e", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/b598aa890815b8df16363271b659d73280129101", + "reference": "b598aa890815b8df16363271b659d73280129101", "shasum": "" }, "require": { "php": ">=5.4", - "phpcsstandards/phpcsutils": "^1.1.2", - "squizlabs/php_codesniffer": "^3.13.4 || ^4.0" + "phpcsstandards/phpcsutils": "^1.2.0", + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcsstandards/phpcsdevcs": "^1.1.6", + "phpcsstandards/phpcsdevcs": "^1.2.0", "phpcsstandards/phpcsdevtools": "^1.2.1", "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, @@ -717,32 +717,32 @@ "type": "thanks_dev" } ], - "time": "2025-10-28T17:00:02+00:00" + "time": "2025-11-12T23:06:57+00:00" }, { "name": "phpcsstandards/phpcsutils", - "version": "1.1.3", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", - "reference": "8b8e17615d04f2fc2cd46fc1d2fd888fa21b3cf9" + "reference": "fa82d14ad1c1713224a52c66c78478145fe454ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/8b8e17615d04f2fc2cd46fc1d2fd888fa21b3cf9", - "reference": "8b8e17615d04f2fc2cd46fc1d2fd888fa21b3cf9", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/fa82d14ad1c1713224a52c66c78478145fe454ba", + "reference": "fa82d14ad1c1713224a52c66c78478145fe454ba", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.13.3 || ^4.0" + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" }, "require-dev": { "ext-filter": "*", "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcsstandards/phpcsdevcs": "^1.1.6", + "phpcsstandards/phpcsdevcs": "^1.2.0", "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0 || ^3.0.0" }, "type": "phpcodesniffer-standard", @@ -810,7 +810,7 @@ "type": "thanks_dev" } ], - "time": "2025-10-16T16:39:32+00:00" + "time": "2025-11-11T00:17:56+00:00" }, { "name": "squizlabs/php_codesniffer", diff --git a/src/css/common/_direction.scss b/src/css/common/_direction.scss new file mode 100644 index 00000000..45b6db3b --- /dev/null +++ b/src/css/common/_direction.scss @@ -0,0 +1,8 @@ +:root { + --cs-direction-multiplier: 1; // LTR = 1, RTL = -1 +} + +html[dir="rtl"], +body.rtl { + --cs-direction-multiplier: -1; +} diff --git a/src/css/common/_switch.scss b/src/css/common/_switch.scss index 0123a950..3704c81f 100644 --- a/src/css/common/_switch.scss +++ b/src/css/common/_switch.scss @@ -40,13 +40,13 @@ input[type='checkbox'].switch:checked { &::before { background-color: white; - transform: translateX(100%); + transform: translateX(calc(100% * var(--cs-direction-multiplier))); } } .erroneous-snippet .snippet-activation-switch::before { content: '!'; - transform: translateX(50%); + transform: translateX(calc(50% * var(--cs-direction-multiplier))); text-align: center; font-weight: bold; line-height: 1; diff --git a/src/css/common/_tooltips.scss b/src/css/common/_tooltips.scss index b76547c3..3feec529 100644 --- a/src/css/common/_tooltips.scss +++ b/src/css/common/_tooltips.scss @@ -172,13 +172,13 @@ $bg-color: hsl(0deg 0% 20% / 90%); .tooltip-inline.tooltip-end:hover, .tooltip-inline.tooltip-end:focus { &::before, .tooltip-content { - transform: translateX(10px); + transform: translateX(calc(10px * var(--cs-direction-multiplier))); } } .tooltip-inline.tooltip-start:hover, .tooltip-inline.tooltip-start:focus { &::before, .tooltip-content { - transform: translateX(-10px); + transform: translateX(calc(-10px * var(--cs-direction-multiplier))); } } diff --git a/src/css/edit.scss b/src/css/edit.scss index 37a77f6f..862af07f 100644 --- a/src/css/edit.scss +++ b/src/css/edit.scss @@ -2,6 +2,7 @@ * Styles for the edit snippet admin page. */ +@use 'common/direction'; @use 'common/codemirror'; @use 'common/badges'; @use 'common/switch'; diff --git a/src/css/manage/_cloud.scss b/src/css/manage/_cloud.scss index 572f42a9..14e01376 100644 --- a/src/css/manage/_cloud.scss +++ b/src/css/manage/_cloud.scss @@ -237,7 +237,6 @@ td.column-download { gap: 5px; } - .cloud-table > tbody > tr { block-size: 80px; box-shadow: inset 0 -1px 0 rgb(0 0 0 / 10%); @@ -265,7 +264,6 @@ td.column-download { background-color: #ce0000; border-radius: 50%; - .cloud-connect-active & { background-color: #25a349; } @@ -284,6 +282,10 @@ td.column-download { block-size: 1.25rem; /* 20px */ transform-origin: bottom left; + [dir="rtl"] & { + transform-origin: bottom right; + } + &:hover { stroke: #059669; fill: #6ee7b7; @@ -325,15 +327,15 @@ td.column-download { } 33% { - transform: rotate(7deg) + transform: rotate(calc(7deg * var(--cs-direction-multiplier))); } 66% { - transform: rotate(-15deg) + transform: rotate(calc(-15deg * var(--cs-direction-multiplier))); } 90% { - transform: rotate(5deg) + transform: rotate(calc(5deg * var(--cs-direction-multiplier))); } 100% { diff --git a/src/css/welcome.scss b/src/css/welcome.scss index 81c9872a..5ebfe850 100644 --- a/src/css/welcome.scss +++ b/src/css/welcome.scss @@ -378,6 +378,6 @@ a.csp-card { @keyframes loading-rotate { 100% { - transform: rotate(360deg); + transform: rotate(calc(360deg * var(--cs-direction-multiplier))); } } diff --git a/src/js/components/EditorSidebar/controls/RTLControl.tsx b/src/js/components/EditorSidebar/controls/RTLControl.tsx index 64496508..2dce2b25 100644 --- a/src/js/components/EditorSidebar/controls/RTLControl.tsx +++ b/src/js/components/EditorSidebar/controls/RTLControl.tsx @@ -6,7 +6,7 @@ export const RTLControl: React.FC = () => { const { codeEditorInstance } = useSnippetForm() return ( -
+