Skip to content

[WC-3348] Charts: restore highlighted JSON editor in playground#2310

Open
yordan-st wants to merge 5 commits into
mainfrom
fix/WC-3348-restore-playground-editor
Open

[WC-3348] Charts: restore highlighted JSON editor in playground#2310
yordan-st wants to merge 5 commits into
mainfrom
fix/WC-3348-restore-playground-editor

Conversation

@yordan-st

@yordan-st yordan-st commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Pull request type

Bug fix (non-breaking change which fixes an issue)


Description

Charts v6.3.0 shipped the playground editor on CodeMirror, which threw a bundling error and broke the playground. As a stopgap (to unblock WC-3345), CodeMirror was replaced with a plain <textarea> in 6.3.1 — losing syntax highlighting and any feedback on invalid JSON.

This restores a real editor without reintroducing a CodeMirror-class bundling dependency. CodeEditor now uses react-simple-code-editor + highlight.js (JSON), adapting the lightweight pattern already used in rich-text-web. It adds inline invalid-JSON feedback (a sticky error banner above the editor) and keeps the existing prop contract (value / onChange / readOnly / height) so both playground panels work unchanged.

Scope is intentionally limited to the editor component. Leo's earlier review findings on the already-merged custom-chart / playground rework are tracked separately in WC-3488.

  • Added deps: react-simple-code-editor, highlight.js (tree-shaken core + JSON language only)
  • New unit tests for CodeEditor (highlighting, JSON lint, readOnly, height, no-CodeMirror guard)

What should be covered while testing?

Put a chart (e.g. Line chart) on a page, set Show playground slot = Yes, drop the Chart playground widget into the slot, configure a Series, and run the app (F5). Click Toggle Editor to open the sidebar.

  1. Syntax highlighting — the JSON in the editable "Custom settings" panel is colored (keys/strings/numbers), not plain text.
  2. Invalid JSON feedback — break the JSON (e.g. delete a }); a red error banner appears at the top of the editor. Fix it → the banner disappears.
  3. Live chart update — with the dropdown on Layout, set { "title": { "text": "TEST" } }; the chart title updates live.
  4. Read-only panel — the lower "Settings from the Studio Pro" panel is not editable.
  5. Keyboard — Tab inserts spaces inside the editor; Esc then Tab moves focus out.
  6. No regression — no CodeMirror bundling error in the browser console; the playground loads.

@yordan-st yordan-st requested a review from a team as a code owner July 6, 2026 14:56
@yordan-st yordan-st changed the title [WC-3348]: restore highlighted JSON editor in charts playground [WC-3348] Charts: restore highlighted JSON editor in playground Jul 6, 2026
@github-actions

This comment has been minimized.

@yordan-st yordan-st force-pushed the fix/WC-3348-restore-playground-editor branch from eea1883 to cd6e358 Compare July 8, 2026 12:10
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

AI Code Review

⚠️ Approved with suggestions — low-severity items only, safe to merge


What was reviewed

File Change
packages/pluggableWidgets/chart-playground-web/src/components/CodeEditor.tsx Replaced <textarea> with react-simple-code-editor + highlight.js; added JSON lint banner
packages/pluggableWidgets/chart-playground-web/src/components/__tests__/CodeEditor.spec.tsx New unit test suite (8 tests)
packages/pluggableWidgets/chart-playground-web/src/ui/Playground.scss Added .widget-charts-playground-code-editor and -error styles
packages/pluggableWidgets/chart-playground-web/CHANGELOG.md Added Unreleased entry
packages/pluggableWidgets/chart-playground-web/package.json Added highlight.js and react-simple-code-editor deps
openspec/changes/fix-restore-playground-editor/ OpenSpec design/proposal/tasks artifacts

Skipped (out of scope): pnpm-lock.yaml


Findings

⚠️ Low — hljs.registerLanguage runs at module evaluation time (side effect on import)

File: packages/pluggableWidgets/chart-playground-web/src/components/CodeEditor.tsx line 7
Note: hljs.registerLanguage("json", json) is called at the top level of the module. This is a global mutation that executes as a side effect whenever the module is imported — including in test environments and server-side renders. It's benign here since highlight.js/lib/core is a clean instance (not the global hljs), but the pattern is fragile: if another module ever imports the same core instance, registration order becomes unpredictable. The rich-text-web equivalent (HighlightedCodeEditor) uses the same pattern, so this is consistent with the existing repo approach — but it's worth a note.
Fix (optional): Move registration inside the highlight() function with a once-guard, or use a module-level constant that guarantees one-time setup:

let registered = false;
function highlight(code: string): string {
    if (!registered) {
        hljs.registerLanguage("json", json);
        registered = true;
    }
    // ...
}

⚠️ Low — Hardcoded colour values in SCSS instead of Atlas UI tokens

File: packages/pluggableWidgets/chart-playground-web/src/ui/Playground.scss lines 34–37
Note: color: #c00, background: #fdecea, and border-bottom: 1px solid #f5c6cb are raw hex values. The existing playground SCSS already uses raw hex elsewhere (lines 13–14, 64–65), so this isn't a new regression, but the error banner is new code where Atlas variables ($color-feedback-danger, etc.) could be used if available. Not a blocker; consistent with the surrounding file.


⚠️ Low — readOnly test assertion couples to implementation detail (disabled attribute)

File: packages/pluggableWidgets/chart-playground-web/src/components/__tests__/CodeEditor.spec.tsx line 27
Note: The test asserts (element as HTMLTextAreaElement).disabled === true. react-simple-code-editor maps disabled to the <textarea> today, but this attribute name is an internal implementation choice of the library. A behavior-level assertion would be more resilient — verifying onChange is not called when the user attempts to type:

it("disables the editor when readOnly", () => {
    const onChange = jest.fn();
    render(<CodeEditor value="{}" readOnly onChange={onChange} />);
    fireEvent.input(screen.getByRole("textbox"), { target: { value: "x" } });
    expect(onChange).not.toHaveBeenCalled();
});

This is low-severity because disabled is a standard HTML attribute and stable in the current version, but the behavior test better matches "what matters."


⚠️ Low — height test queries parentElement two levels up from the intended container

File: packages/pluggableWidgets/chart-playground-web/src/components/__tests__/CodeEditor.spec.tsx lines 53–55
Note: The comment says "react-simple-code-editor applies the style prop to its container (parent of the textarea)," but screen.getByRole("textbox").parentElement may actually be the <pre> sibling wrapper inside the editor rather than the <div> that receives the style prop, depending on the version's DOM shape. Consider using a data-testid on the outer <div> or walking up with .closest(".widget-charts-playground-code-editor") to make the selector explicit and resilient.


Positives

  • Prop contract preserved exactlyvalue, onChange?, readOnly?, height? unchanged, so ComposedEditor callers (both editable and read-only panels) work without modification.
  • Tree-shaken highlight.js — imports highlight.js/lib/core and registers only the JSON language, keeping bundle impact minimal and following the existing rich-text-web pattern.
  • JSON lint is non-blocking — invalid JSON shows the error banner but does not blank the editor or throw, preserving the user's in-progress text.
  • role="alert" on the error banner — correct ARIA live-region semantics; screen readers will announce the error as it appears.
  • No CodeMirror guard as a unit test — pragmatic approach: asserts on package.json directly, which is the only real guarantee that bundling won't regress.
  • Changelog entry present in [Unreleased] with user-facing language.
  • ignoreTabKey={false} kept explicit, preserving Tab-in-editor behavior with the surrounding TabGuard / "Esc + Tab to move focus" hint.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant