From c01d480ced1efb30c0c796f13f8f43a89879e5a1 Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Mon, 16 Mar 2026 14:40:47 +0100
Subject: [PATCH 04/17] unnecesary log
---
.../Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx b/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx
index 0d39afe80..aae5eb45b 100644
--- a/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx
+++ b/src/components/Editor/Runners/PythonRunner/PyodideRunner/PyodideRunner.jsx
@@ -366,8 +366,7 @@ const PyodideRunner = ({ active, outputPanels = ["text", "visual"] }) => {
};
if (!pyodideWorker && active) {
- console.warn("PyodideWorker is not initialized");
- return;
+ return null;
}
return (
From 2bb82328c382fffaf900fe6cafef00e77f83ac02 Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Mon, 16 Mar 2026 14:43:12 +0100
Subject: [PATCH 05/17] avoid web-component loading icon
---
src/web-component.html | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/web-component.html b/src/web-component.html
index f65c1414b..4ccd277d4 100644
--- a/src/web-component.html
+++ b/src/web-component.html
@@ -50,6 +50,7 @@
+
Editor Web component
From 6614735d1d38b71d7de373e3871c6d2c57e84252 Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Mon, 16 Mar 2026 15:26:08 +0100
Subject: [PATCH 06/17] toast warning removal
---
src/containers/WebComponentLoader.jsx | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/containers/WebComponentLoader.jsx b/src/containers/WebComponentLoader.jsx
index f468a97bd..5f6e2d30a 100644
--- a/src/containers/WebComponentLoader.jsx
+++ b/src/containers/WebComponentLoader.jsx
@@ -32,6 +32,15 @@ import {
projectOwnerLoadedEvent,
} from "../events/WebComponentCustomEvents";
+const TOAST_CONTAINER_DEFAULTS = {
+ ...(ToastContainer.defaultProps || {}),
+};
+
+// react-toastify v8 uses defaultProps on a function component, which React
+// warns about in development. We pass the same defaults explicitly instead.
+// We should upgrade to version 10 in a different commit, this removes the warning
+ToastContainer.defaultProps = undefined;
+
const WebComponentLoader = (props) => {
const {
assetsIdentifier,
@@ -222,6 +231,7 @@ const WebComponentLoader = (props) => {
{internalStyles.toString()}
Date: Mon, 16 Mar 2026 15:39:41 +0100
Subject: [PATCH 07/17] show warning only once
- avoid noise when this "DEPRECATED: icons as React elements will not be
supported in future releases" is emitted several times
---
src/web-component.js | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/web-component.js b/src/web-component.js
index 2ac855093..054b28e70 100644
--- a/src/web-component.js
+++ b/src/web-component.js
@@ -11,6 +11,21 @@ import { stopCodeRun, stopDraw, triggerCodeRun } from "./redux/EditorSlice";
import { BrowserRouter } from "react-router-dom";
import { resetStore } from "./redux/RootSlice";
+const originalWarn = console.warn.bind(console);
+let hasShownDesignSystemIconWarning = false;
+const warningText = "DEPRECATED: icons as React elements will not be supported in future releases";
+// This should be addressed by applying the fix, in @raspberrypifoundation/design-system-react
+// This shows the warning once instead of N times
+console.warn = (...args) => {
+ if (args[0] === warningText) {
+ if (hasShownDesignSystemIconWarning) {
+ return;
+ }
+ hasShownDesignSystemIconWarning = true;
+ }
+ originalWarn(...args);
+};
+
Sentry.init({
dsn: process.env.REACT_APP_SENTRY_DSN,
integrations: [new BrowserTracing()],
From 2ba7350196418117ff0eb846411d091bded0b210 Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Mon, 16 Mar 2026 16:06:03 +0100
Subject: [PATCH 08/17] reduce warnings by early destruct
---
.../ScratchEditor/ScratchIntegrationHOC.jsx | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/components/ScratchEditor/ScratchIntegrationHOC.jsx b/src/components/ScratchEditor/ScratchIntegrationHOC.jsx
index 87bea0424..927560748 100644
--- a/src/components/ScratchEditor/ScratchIntegrationHOC.jsx
+++ b/src/components/ScratchEditor/ScratchIntegrationHOC.jsx
@@ -43,6 +43,10 @@ const ScratchIntegrationHOC = function (WrappedComponent) {
return;
}
+ if (event.data?.type === "webpackOk") {
+ return;
+ }
+
switch (event.data.type) {
case "scratch-gui-download":
this.handleDownload(event);
@@ -80,7 +84,16 @@ const ScratchIntegrationHOC = function (WrappedComponent) {
this.props.onClickSave();
}
render() {
- const { ...componentProps } = this.props;
+ const {
+ loadProject,
+ localesOnly,
+ onClickRemix,
+ onClickSave,
+ saveProjectSb3,
+ setStageSize,
+ ...componentProps
+ } = this.props;
+
return ;
}
}
From f7b96a6f8a8f97e9a5947e073af3508463c22b92 Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Mon, 16 Mar 2026 18:25:43 +0100
Subject: [PATCH 09/17] capture and de-dupe scratch warnings to avoid console
flooding
---
src/scratch.jsx | 3 +
src/utils/dedupeScratchWarnings.js | 96 ++++++++++++++++++++++++++++++
2 files changed, 99 insertions(+)
create mode 100644 src/utils/dedupeScratchWarnings.js
diff --git a/src/scratch.jsx b/src/scratch.jsx
index ca1d4a150..444a266df 100644
--- a/src/scratch.jsx
+++ b/src/scratch.jsx
@@ -5,9 +5,12 @@ import { compose } from "redux";
import GUI, { AppStateHOC } from "@scratch/scratch-gui";
import ScratchIntegrationHOC from "./components/ScratchEditor/ScratchIntegrationHOC.jsx";
+import dedupeScratchWarnings from "./utils/dedupeScratchWarnings.js";
import ScratchStyles from "./assets/stylesheets/Scratch.scss";
+dedupeScratchWarnings();
+
const appTarget = document.getElementById("app");
document.getElementById("scratch-loading")?.remove();
GUI.setAppElement(appTarget);
diff --git a/src/utils/dedupeScratchWarnings.js b/src/utils/dedupeScratchWarnings.js
new file mode 100644
index 000000000..49e4802d2
--- /dev/null
+++ b/src/utils/dedupeScratchWarnings.js
@@ -0,0 +1,96 @@
+const scratchConsoleBrokerKey = "__scratchConsoleBrokerInstalled";
+
+const scratchWarningMatchers = [
+ {
+ method: "error",
+ needle: "Support for defaultProps will be removed",
+ id: "react-default-props",
+ summary:
+ "React 18 compatibility warnings about function-component defaultProps",
+ },
+ {
+ method: "error",
+ needle: "React does not recognize the `%s` prop on a DOM element",
+ id: "react-dom-props",
+ summary: "React warnings about scratch-editor props leaking onto DOM nodes",
+ },
+ {
+ method: "error",
+ needle: "Unknown event handler property `%s`",
+ id: "react-event-props",
+ summary: "React warnings about unsupported event handler props",
+ },
+ {
+ method: "warn",
+ needle: "componentWillMount has been renamed",
+ id: "react-component-will-mount",
+ summary: "React warnings about legacy componentWillMount usage",
+ },
+ {
+ method: "warn",
+ needle: "componentWillReceiveProps has been renamed",
+ id: "react-component-will-receive-props",
+ summary: "React warnings about legacy componentWillReceiveProps usage",
+ },
+ {
+ method: "error",
+ needle: "findDOMNode is deprecated",
+ id: "react-find-dom-node",
+ summary: "React warnings about deprecated findDOMNode usage",
+ },
+];
+
+const getScratchConsoleCategory = (method, args) => {
+ const message = typeof args[0] === "string" ? args[0] : "";
+ const matcher = scratchWarningMatchers.find(
+ (candidate) =>
+ candidate.method === method && message.includes(candidate.needle),
+ );
+
+ return matcher || null;
+};
+
+const dedupeScratchWarnings = () => {
+ if (process.env.NODE_ENV === "production" || typeof window !== "object") {
+ return;
+ }
+
+ if (window[scratchConsoleBrokerKey]) {
+ return;
+ }
+
+ window[scratchConsoleBrokerKey] = true;
+
+ const seenCategories = new Set();
+ const originalError = console.error.bind(console);
+ const originalWarn = console.warn.bind(console);
+
+ const emitCategorySummary = (category) => {
+ if (seenCategories.has(category.id)) {
+ return;
+ }
+
+ seenCategories.add(category.id);
+ originalWarn(
+ `[scratch-editor] emitted ${category.summary}. Further duplicates suppressed.`,
+ );
+ };
+
+ const wrapConsoleMethod = (method, originalMethod) => {
+ return (...args) => {
+ const category = getScratchConsoleCategory(method, args);
+
+ if (category) {
+ emitCategorySummary(category);
+ return;
+ }
+
+ originalMethod(...args);
+ };
+ };
+
+ console.error = wrapConsoleMethod("error", originalError);
+ console.warn = wrapConsoleMethod("warn", originalWarn);
+};
+
+export default dedupeScratchWarnings;
From bf24876c37c70bd2471bb53362f08766f8f4285d Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Mon, 16 Mar 2026 18:30:37 +0100
Subject: [PATCH 10/17] create a utility following pattern for design system
warnings
---
src/utils/dedupeDesignSystemWarnings.js | 32 +++++++++++++++++++++++++
src/web-component.js | 16 ++-----------
2 files changed, 34 insertions(+), 14 deletions(-)
create mode 100644 src/utils/dedupeDesignSystemWarnings.js
diff --git a/src/utils/dedupeDesignSystemWarnings.js b/src/utils/dedupeDesignSystemWarnings.js
new file mode 100644
index 000000000..e275eef45
--- /dev/null
+++ b/src/utils/dedupeDesignSystemWarnings.js
@@ -0,0 +1,32 @@
+const designSystemWarningsKey = "__designSystemWarningsDeduped";
+const designSystemIconWarning =
+ "DEPRECATED: icons as React elements will not be supported in future releases";
+
+const dedupeDesignSystemWarnings = () => {
+ if (process.env.NODE_ENV === "production" || typeof window !== "object") {
+ return;
+ }
+
+ if (window[designSystemWarningsKey]) {
+ return;
+ }
+
+ window[designSystemWarningsKey] = true;
+
+ const originalWarn = console.warn.bind(console);
+ let hasShownDesignSystemIconWarning = false;
+
+ console.warn = (...args) => {
+ if (args[0] === designSystemIconWarning) {
+ if (hasShownDesignSystemIconWarning) {
+ return;
+ }
+
+ hasShownDesignSystemIconWarning = true;
+ }
+
+ originalWarn(...args);
+ };
+};
+
+export default dedupeDesignSystemWarnings;
diff --git a/src/web-component.js b/src/web-component.js
index 054b28e70..244cae1f9 100644
--- a/src/web-component.js
+++ b/src/web-component.js
@@ -10,21 +10,9 @@ import camelCase from "camelcase";
import { stopCodeRun, stopDraw, triggerCodeRun } from "./redux/EditorSlice";
import { BrowserRouter } from "react-router-dom";
import { resetStore } from "./redux/RootSlice";
+import dedupeDesignSystemWarnings from "./utils/dedupeDesignSystemWarnings";
-const originalWarn = console.warn.bind(console);
-let hasShownDesignSystemIconWarning = false;
-const warningText = "DEPRECATED: icons as React elements will not be supported in future releases";
-// This should be addressed by applying the fix, in @raspberrypifoundation/design-system-react
-// This shows the warning once instead of N times
-console.warn = (...args) => {
- if (args[0] === warningText) {
- if (hasShownDesignSystemIconWarning) {
- return;
- }
- hasShownDesignSystemIconWarning = true;
- }
- originalWarn(...args);
-};
+dedupeDesignSystemWarnings();
Sentry.init({
dsn: process.env.REACT_APP_SENTRY_DSN,
From 54483aa66f4a8f3bf5cdae34a583afd3c554effc Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Mon, 16 Mar 2026 18:32:20 +0100
Subject: [PATCH 11/17] lint after changes
---
.../Editor/Runners/PythonRunner/OutputViewToggle.jsx | 4 ++--
src/components/Menus/Sidebar/Sidebar.jsx | 4 ++--
src/hooks/useProject.js | 4 ++--
src/utils/ResizableWithHandle.js | 4 ++--
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/components/Editor/Runners/PythonRunner/OutputViewToggle.jsx b/src/components/Editor/Runners/PythonRunner/OutputViewToggle.jsx
index ef640237b..fe76de2da 100644
--- a/src/components/Editor/Runners/PythonRunner/OutputViewToggle.jsx
+++ b/src/components/Editor/Runners/PythonRunner/OutputViewToggle.jsx
@@ -38,8 +38,8 @@ const OutputViewToggle = () => {
isMobile
? null
: isSplitView
- ? t("outputViewToggle.buttonTabLabel")
- : t("outputViewToggle.buttonSplitLabel")
+ ? t("outputViewToggle.buttonTabLabel")
+ : t("outputViewToggle.buttonSplitLabel")
}
disabled={codeRunTriggered || drawTriggered}
label={
diff --git a/src/components/Menus/Sidebar/Sidebar.jsx b/src/components/Menus/Sidebar/Sidebar.jsx
index 994b5ed87..86037eef1 100644
--- a/src/components/Menus/Sidebar/Sidebar.jsx
+++ b/src/components/Menus/Sidebar/Sidebar.jsx
@@ -139,8 +139,8 @@ const Sidebar = ({ options = [], plugins = [], allowMobileView = true }) => {
autoOpenPlugin
? autoOpenPlugin.name
: instructionsEditable || instructionsSteps
- ? "instructions"
- : "file",
+ ? "instructions"
+ : "file",
);
const hasInstructions = instructionsSteps && instructionsSteps.length > 0;
diff --git a/src/hooks/useProject.js b/src/hooks/useProject.js
index 98c110621..d67b279a9 100644
--- a/src/hooks/useProject.js
+++ b/src/hooks/useProject.js
@@ -30,7 +30,7 @@ export const useProject = ({
const [cachedProject, setCachedProject] = useState(
getCachedProject(projectIdentifier),
);
- const { i18n } = useTranslation();
+ const { i18n, t } = useTranslation();
const dispatch = useDispatch();
const effectiveLocale = locale ?? i18n.language;
@@ -107,7 +107,7 @@ export const useProject = ({
const data = {
...defaultPythonProject,
- name: i18n.t("project.untitled", {
+ name: t("project.untitled", {
lng: effectiveLocale,
defaultValue: defaultPythonProject.name,
}),
diff --git a/src/utils/ResizableWithHandle.js b/src/utils/ResizableWithHandle.js
index fd66d9a76..796f5f7e5 100644
--- a/src/utils/ResizableWithHandle.js
+++ b/src/utils/ResizableWithHandle.js
@@ -56,8 +56,8 @@ const ResizableWithHandle = (props) => {
let handleComponent = ["right", "left"].includes(handleDirection)
? { [handleDirection]: }
: ["top", "bottom"].includes(handleDirection)
- ? { [handleDirection]: }
- : {};
+ ? { [handleDirection]: }
+ : {};
let handleWrapperClass = `resizable-with-handle__handle resizable-with-handle__handle--${handleDirection}`;
From d61e1c923682a1dc56f7a617e719c2aa68ae376d Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Mon, 16 Mar 2026 19:10:42 +0100
Subject: [PATCH 12/17] update the way is pulled locales to maintain
translation
- In order to have locales we need to make defaultProjects async,
added helpers to de-ref async loading and wait for locales to be loaded
before shown
---
src/hooks/useProject.js | 33 ++++++++++++++++++++-----------
src/hooks/useProject.test.js | 12 +++++++-----
src/utils/defaultProjects.js | 38 ++++++++++++++++++++++++++++++++++++
3 files changed, 67 insertions(+), 16 deletions(-)
diff --git a/src/hooks/useProject.js b/src/hooks/useProject.js
index d67b279a9..793b30ad5 100644
--- a/src/hooks/useProject.js
+++ b/src/hooks/useProject.js
@@ -2,7 +2,7 @@
import { useRef, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { syncProject, setProject } from "../redux/EditorSlice";
-import { defaultPythonProject } from "../utils/defaultProjects";
+import { createDefaultPythonProject } from "../utils/defaultProjects";
import { useTranslation } from "react-i18next";
export const useProject = ({
@@ -30,7 +30,7 @@ export const useProject = ({
const [cachedProject, setCachedProject] = useState(
getCachedProject(projectIdentifier),
);
- const { i18n, t } = useTranslation();
+ const { i18n } = useTranslation();
const dispatch = useDispatch();
const effectiveLocale = locale ?? i18n.language;
@@ -43,7 +43,13 @@ export const useProject = ({
}, [projectIdentifier]);
useEffect(() => {
- if (!loadRemix) {
+ let didUnmount = false;
+
+ const loadProjectData = async () => {
+ if (loadRemix) {
+ return;
+ }
+
const is_cached_saved_project =
projectIdentifier &&
cachedProject &&
@@ -105,15 +111,20 @@ export const useProject = ({
return;
}
- const data = {
- ...defaultPythonProject,
- name: t("project.untitled", {
- lng: effectiveLocale,
- defaultValue: defaultPythonProject.name,
- }),
- };
+ const data = await createDefaultPythonProject(effectiveLocale);
+
+ if (didUnmount) {
+ return;
+ }
+
dispatch(setProject(data));
- }
+ };
+
+ void loadProjectData();
+
+ return () => {
+ didUnmount = true;
+ };
}, [
code,
projectIdentifier,
diff --git a/src/hooks/useProject.test.js b/src/hooks/useProject.test.js
index 7198e4aaf..b60a4bb13 100644
--- a/src/hooks/useProject.test.js
+++ b/src/hooks/useProject.test.js
@@ -57,11 +57,13 @@ describe("When not embedded", () => {
test("If no identifier uses default python project", () => {
renderHook(() => useProject({}), { wrapper });
- expect(setProject).toHaveBeenCalledWith(
- expect.objectContaining({
- ...defaultPythonProject,
- name: "project.untitled",
- }),
+ return waitFor(() =>
+ expect(setProject).toHaveBeenCalledWith(
+ expect.objectContaining({
+ ...defaultPythonProject,
+ name: "project.untitled",
+ }),
+ ),
);
});
diff --git a/src/utils/defaultProjects.js b/src/utils/defaultProjects.js
index dcc9d9e01..ec703496d 100644
--- a/src/utils/defaultProjects.js
+++ b/src/utils/defaultProjects.js
@@ -1,3 +1,5 @@
+import i18n from "./i18n";
+
const UNTITLED_PROJECT_NAME = "Untitled project";
export const defaultPythonProject = {
@@ -25,3 +27,39 @@ export const DEFAULT_PROJECTS = {
python: defaultPythonProject,
html: defaultHtmlProject,
};
+
+export const createDefaultPythonProject = async (locale = i18n.language) => {
+ try {
+ if (locale && i18n.resolvedLanguage !== locale) {
+ await i18n.changeLanguage?.(locale);
+ }
+ } catch {
+ // Fall back to the default untitled name if locale files fail.
+ }
+
+ return {
+ ...defaultPythonProject,
+ name: i18n.t("project.untitled", {
+ lng: locale,
+ defaultValue: UNTITLED_PROJECT_NAME,
+ }),
+ };
+};
+
+export const createDefaultHtmlProject = async (locale = i18n.language) => {
+ try {
+ if (locale && i18n.resolvedLanguage !== locale) {
+ await i18n.changeLanguage?.(locale);
+ }
+ } catch {
+ // Fall back to the default untitled name if locale files fail.
+ }
+
+ return {
+ ...defaultHtmlProject,
+ name: i18n.t("project.untitled", {
+ lng: locale,
+ defaultValue: UNTITLED_PROJECT_NAME,
+ }),
+ };
+};
From aa9fcb81b0824393968e942c39cb7083919551d8 Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Mon, 16 Mar 2026 19:25:44 +0100
Subject: [PATCH 13/17] simplify dedupe files
---
src/utils/dedupeDesignSystemWarnings.js | 16 +--
src/utils/dedupeScratchWarnings.js | 129 ++++++++++--------------
2 files changed, 64 insertions(+), 81 deletions(-)
diff --git a/src/utils/dedupeDesignSystemWarnings.js b/src/utils/dedupeDesignSystemWarnings.js
index e275eef45..6cdc23985 100644
--- a/src/utils/dedupeDesignSystemWarnings.js
+++ b/src/utils/dedupeDesignSystemWarnings.js
@@ -3,26 +3,26 @@ const designSystemIconWarning =
"DEPRECATED: icons as React elements will not be supported in future releases";
const dedupeDesignSystemWarnings = () => {
- if (process.env.NODE_ENV === "production" || typeof window !== "object") {
- return;
- }
-
- if (window[designSystemWarningsKey]) {
+ if (
+ process.env.NODE_ENV === "production" ||
+ typeof window !== "object" ||
+ window[designSystemWarningsKey]
+ ) {
return;
}
window[designSystemWarningsKey] = true;
const originalWarn = console.warn.bind(console);
- let hasShownDesignSystemIconWarning = false;
+ let didWarnIcon = false;
console.warn = (...args) => {
if (args[0] === designSystemIconWarning) {
- if (hasShownDesignSystemIconWarning) {
+ if (didWarnIcon) {
return;
}
- hasShownDesignSystemIconWarning = true;
+ didWarnIcon = true;
}
originalWarn(...args);
diff --git a/src/utils/dedupeScratchWarnings.js b/src/utils/dedupeScratchWarnings.js
index 49e4802d2..168361b08 100644
--- a/src/utils/dedupeScratchWarnings.js
+++ b/src/utils/dedupeScratchWarnings.js
@@ -1,96 +1,79 @@
-const scratchConsoleBrokerKey = "__scratchConsoleBrokerInstalled";
+const scratchWarningsKey = "__scratchWarningsDeduped";
-const scratchWarningMatchers = [
- {
- method: "error",
- needle: "Support for defaultProps will be removed",
- id: "react-default-props",
- summary:
+const scratchWarningMatchers = {
+ error: [
+ [
+ "Support for defaultProps will be removed",
"React 18 compatibility warnings about function-component defaultProps",
- },
- {
- method: "error",
- needle: "React does not recognize the `%s` prop on a DOM element",
- id: "react-dom-props",
- summary: "React warnings about scratch-editor props leaking onto DOM nodes",
- },
- {
- method: "error",
- needle: "Unknown event handler property `%s`",
- id: "react-event-props",
- summary: "React warnings about unsupported event handler props",
- },
- {
- method: "warn",
- needle: "componentWillMount has been renamed",
- id: "react-component-will-mount",
- summary: "React warnings about legacy componentWillMount usage",
- },
- {
- method: "warn",
- needle: "componentWillReceiveProps has been renamed",
- id: "react-component-will-receive-props",
- summary: "React warnings about legacy componentWillReceiveProps usage",
- },
- {
- method: "error",
- needle: "findDOMNode is deprecated",
- id: "react-find-dom-node",
- summary: "React warnings about deprecated findDOMNode usage",
- },
-];
-
-const getScratchConsoleCategory = (method, args) => {
- const message = typeof args[0] === "string" ? args[0] : "";
- const matcher = scratchWarningMatchers.find(
- (candidate) =>
- candidate.method === method && message.includes(candidate.needle),
- );
-
- return matcher || null;
+ ],
+ [
+ "React does not recognize the `%s` prop on a DOM element",
+ "React warnings about scratch-editor props leaking onto DOM nodes",
+ ],
+ [
+ "Unknown event handler property `%s`",
+ "React warnings about unsupported event handler props",
+ ],
+ [
+ "findDOMNode is deprecated",
+ "React warnings about deprecated findDOMNode usage",
+ ],
+ ],
+ warn: [
+ [
+ "componentWillMount has been renamed",
+ "React warnings about legacy componentWillMount usage",
+ ],
+ [
+ "componentWillReceiveProps has been renamed",
+ "React warnings about legacy componentWillReceiveProps usage",
+ ],
+ ],
};
const dedupeScratchWarnings = () => {
- if (process.env.NODE_ENV === "production" || typeof window !== "object") {
- return;
- }
-
- if (window[scratchConsoleBrokerKey]) {
+ if (
+ process.env.NODE_ENV === "production" ||
+ typeof window !== "object" ||
+ window[scratchWarningsKey]
+ ) {
return;
}
- window[scratchConsoleBrokerKey] = true;
+ window[scratchWarningsKey] = true;
- const seenCategories = new Set();
- const originalError = console.error.bind(console);
+ const seenSummaries = new Set();
const originalWarn = console.warn.bind(console);
- const emitCategorySummary = (category) => {
- if (seenCategories.has(category.id)) {
- return;
- }
+ const wrapConsoleMethod = (method) => {
+ const originalMethod = console[method].bind(console);
- seenCategories.add(category.id);
- originalWarn(
- `[scratch-editor] emitted ${category.summary}. Further duplicates suppressed.`,
- );
- };
-
- const wrapConsoleMethod = (method, originalMethod) => {
return (...args) => {
- const category = getScratchConsoleCategory(method, args);
+ const message = typeof args[0] === "string" ? args[0] : "";
+ const summary = scratchWarningMatchers[method]?.find(([needle]) =>
+ message.includes(needle),
+ );
+
+ if (!summary) {
+ originalMethod(...args);
+ return;
+ }
+
+ const [, text] = summary;
- if (category) {
- emitCategorySummary(category);
+ if (seenSummaries.has(text)) {
return;
}
- originalMethod(...args);
+ seenSummaries.add(text);
+ originalWarn(
+ `[scratch-editor] emitted ${text}. Further duplicates suppressed.`,
+ );
};
};
- console.error = wrapConsoleMethod("error", originalError);
- console.warn = wrapConsoleMethod("warn", originalWarn);
+ console.error = wrapConsoleMethod("error");
+ console.warn = wrapConsoleMethod("warn");
};
export default dedupeScratchWarnings;
From 0e7f5bf9c2f4d023d6f14969b2e1a56efe74a043 Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Mon, 16 Mar 2026 19:32:11 +0100
Subject: [PATCH 14/17] lint
---
.../Editor/Runners/PythonRunner/OutputViewToggle.jsx | 4 ++--
src/components/Menus/Sidebar/Sidebar.jsx | 4 ++--
src/utils/ResizableWithHandle.js | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/components/Editor/Runners/PythonRunner/OutputViewToggle.jsx b/src/components/Editor/Runners/PythonRunner/OutputViewToggle.jsx
index fe76de2da..ef640237b 100644
--- a/src/components/Editor/Runners/PythonRunner/OutputViewToggle.jsx
+++ b/src/components/Editor/Runners/PythonRunner/OutputViewToggle.jsx
@@ -38,8 +38,8 @@ const OutputViewToggle = () => {
isMobile
? null
: isSplitView
- ? t("outputViewToggle.buttonTabLabel")
- : t("outputViewToggle.buttonSplitLabel")
+ ? t("outputViewToggle.buttonTabLabel")
+ : t("outputViewToggle.buttonSplitLabel")
}
disabled={codeRunTriggered || drawTriggered}
label={
diff --git a/src/components/Menus/Sidebar/Sidebar.jsx b/src/components/Menus/Sidebar/Sidebar.jsx
index 86037eef1..994b5ed87 100644
--- a/src/components/Menus/Sidebar/Sidebar.jsx
+++ b/src/components/Menus/Sidebar/Sidebar.jsx
@@ -139,8 +139,8 @@ const Sidebar = ({ options = [], plugins = [], allowMobileView = true }) => {
autoOpenPlugin
? autoOpenPlugin.name
: instructionsEditable || instructionsSteps
- ? "instructions"
- : "file",
+ ? "instructions"
+ : "file",
);
const hasInstructions = instructionsSteps && instructionsSteps.length > 0;
diff --git a/src/utils/ResizableWithHandle.js b/src/utils/ResizableWithHandle.js
index 796f5f7e5..fd66d9a76 100644
--- a/src/utils/ResizableWithHandle.js
+++ b/src/utils/ResizableWithHandle.js
@@ -56,8 +56,8 @@ const ResizableWithHandle = (props) => {
let handleComponent = ["right", "left"].includes(handleDirection)
? { [handleDirection]: }
: ["top", "bottom"].includes(handleDirection)
- ? { [handleDirection]: }
- : {};
+ ? { [handleDirection]: }
+ : {};
let handleWrapperClass = `resizable-with-handle__handle resizable-with-handle__handle--${handleDirection}`;
From 0b1136d80adac0d2f6095d34fa5c96c831fcf418 Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Mon, 16 Mar 2026 19:40:10 +0100
Subject: [PATCH 15/17] copilot comments to invert the issue
---
src/containers/WebComponentLoader.jsx | 4 +++-
src/utils/dedupeDesignSystemWarnings.js | 2 +-
src/utils/dedupeScratchWarnings.js | 2 +-
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/containers/WebComponentLoader.jsx b/src/containers/WebComponentLoader.jsx
index 5f6e2d30a..b452ccb29 100644
--- a/src/containers/WebComponentLoader.jsx
+++ b/src/containers/WebComponentLoader.jsx
@@ -39,7 +39,9 @@ const TOAST_CONTAINER_DEFAULTS = {
// react-toastify v8 uses defaultProps on a function component, which React
// warns about in development. We pass the same defaults explicitly instead.
// We should upgrade to version 10 in a different commit, this removes the warning
-ToastContainer.defaultProps = undefined;
+if (process.env.NODE_ENV === "development") {
+ ToastContainer.defaultProps = undefined;
+}
const WebComponentLoader = (props) => {
const {
diff --git a/src/utils/dedupeDesignSystemWarnings.js b/src/utils/dedupeDesignSystemWarnings.js
index 6cdc23985..0f8dfda7a 100644
--- a/src/utils/dedupeDesignSystemWarnings.js
+++ b/src/utils/dedupeDesignSystemWarnings.js
@@ -4,7 +4,7 @@ const designSystemIconWarning =
const dedupeDesignSystemWarnings = () => {
if (
- process.env.NODE_ENV === "production" ||
+ process.env.NODE_ENV !== "development" ||
typeof window !== "object" ||
window[designSystemWarningsKey]
) {
diff --git a/src/utils/dedupeScratchWarnings.js b/src/utils/dedupeScratchWarnings.js
index 168361b08..5a372ef1b 100644
--- a/src/utils/dedupeScratchWarnings.js
+++ b/src/utils/dedupeScratchWarnings.js
@@ -33,7 +33,7 @@ const scratchWarningMatchers = {
const dedupeScratchWarnings = () => {
if (
- process.env.NODE_ENV === "production" ||
+ process.env.NODE_ENV !== "development" ||
typeof window !== "object" ||
window[scratchWarningsKey]
) {
From ec5d060046014ac05f95a464725333080e083358 Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Tue, 17 Mar 2026 11:35:15 +0100
Subject: [PATCH 16/17] remove webpack console, probably not needed after prop
changes
---
src/components/ScratchEditor/ScratchIntegrationHOC.jsx | 4 ----
src/web-component.html | 3 ---
2 files changed, 7 deletions(-)
diff --git a/src/components/ScratchEditor/ScratchIntegrationHOC.jsx b/src/components/ScratchEditor/ScratchIntegrationHOC.jsx
index 927560748..1ff3938d6 100644
--- a/src/components/ScratchEditor/ScratchIntegrationHOC.jsx
+++ b/src/components/ScratchEditor/ScratchIntegrationHOC.jsx
@@ -43,10 +43,6 @@ const ScratchIntegrationHOC = function (WrappedComponent) {
return;
}
- if (event.data?.type === "webpackOk") {
- return;
- }
-
switch (event.data.type) {
case "scratch-gui-download":
this.handleDownload(event);
diff --git a/src/web-component.html b/src/web-component.html
index 4ccd277d4..0611083eb 100644
--- a/src/web-component.html
+++ b/src/web-component.html
@@ -77,13 +77,10 @@
// subscribe to the 'codeChanged' custom event which is pushed by the project react component
document.addEventListener("editor-codeChanged", function (e) {
- console.log("listener in index html");
const code = webComp.editorCode;
- console.log(code);
});
document.addEventListener("editor-runCompleted", (e) => {
- console.log(e.detail);
document.getElementById("results").innerText = JSON.stringify(e.detail);
});
From bac78c5bb202c165055c15713d4ac0c4ec4234c3 Mon Sep 17 00:00:00 2001
From: abcampo-iry <261805581+abcampo-iry@users.noreply.github.com>
Date: Tue, 17 Mar 2026 16:26:32 +0100
Subject: [PATCH 17/17] re-enable message
---
src/components/ScratchEditor/ScratchIntegrationHOC.jsx | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/components/ScratchEditor/ScratchIntegrationHOC.jsx b/src/components/ScratchEditor/ScratchIntegrationHOC.jsx
index 1ff3938d6..338ee5fcb 100644
--- a/src/components/ScratchEditor/ScratchIntegrationHOC.jsx
+++ b/src/components/ScratchEditor/ScratchIntegrationHOC.jsx
@@ -42,6 +42,9 @@ const ScratchIntegrationHOC = function (WrappedComponent) {
);
return;
}
+ if (event.data?.type === "webpackOk") {
+ return;
+ }
switch (event.data.type) {
case "scratch-gui-download":