npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-contest-editor

v0.1.0

Published

A lightweight React-based code editor for live coding contests, built on monaco-ext.

Readme

React Contest Editor

A lightweight React-based code editor for live coding contests, built on monaco-ext.

Features

  • Multiple File Support - Edit multiple files with easy tab navigation
  • Monaco Editor Integration - Powered by Monaco Editor with syntax highlighting for different languages
  • Terminal Integration - Interactive terminal with command history
  • Split Layout - Information panel, code editor, and terminal in one component
  • Test Case Visualization - View test case results with pass/fail status
  • Code Line Highlighting - Ability to highlight specific lines of code
  • Customizable Themes - Light and dark themes available
  • Read-Only Support - Set specific lines or entire files as read-only
  • Rich Contest Information - Display problem statements and hints

Installation

npm install react-contest-editor --save

Basic Usage

import React, { useRef } from 'react';
import ContestEditor from 'react-contest-editor';
import { FaPlay } from 'react-icons/fa';

const MyContestApp = () => {
  const contestEditorRef = useRef(null);

  const files = [
    {
      filename: "main.py",
      initialContent: "def solution():\n    # Your code here\n    pass",
      language: "python",
      readOnly: [1] // Line 1 will be read-only
    }
  ];

  const contestData = {
    problem: [
      {
        type: "Markdown",
        content: "# Problem Title\n\nProblem description goes here..."
      }
    ],
    hint: [
      {
        type: "Markdown",
        content: "### Hint\nHelpful hints for solving the problem..."
      }
    ]
  };

  const handleSubmit = async (editorContents) => {
    // Process the submission
    // Return a response object with compile and evaluate results
    return {
      compile: { isPass: true },
      evaluate: {
        isPass: true,
        testcases: [
          {
            title: "Test Case 1",
            description: "Basic test",
            isPass: true,
            stdout: "Expected output"
          }
        ]
      }
    };
  };

  return (
    <ContestEditor
      ref={contestEditorRef}
      files={files}
      contest={contestData}
      onSubmit={handleSubmit}
      submitButtonText="Run"
      SubmitIcon={FaPlay}
      height="600px"
    />
  );
};

Props

Core Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | files | Array | | Array of file objects to be displayed in the editor | | editorTheme | String | 'github-dark' | Theme for the editor ('github-light', 'github-dark', 'solarized-light', 'solarized-dark') | | height | String | '600px' | Height of the overall component | | contest | Object | { problem: [], hint: [] } | Contest data containing problem statements and hints |

Editor Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | onSubmit | Function | | Callback function when code is submitted, should return a Promise | | isSubmitting | Boolean | false | Indicator if submission is in progress | | submitButtonText | String | 'Submit' | Text for the submit button | | submittingButtonText | String | 'Submitting...' | Text shown during submission | | SubmitIcon | Component | FaPaperPlane | Icon component for the submit button |

Terminal Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | terminalTitle | String | 'Terminal' | Title for the terminal panel | | initialTerminalHistory | Array | [] | Initial entries in the terminal | | onCommand | Function | null | Callback for handling terminal commands | | terminalPrompt | String | '$ ' | Prompt displayed in the terminal | | terminalReadOnly | Boolean | false | Whether terminal is in read-only mode |

TabPanel Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | leftTabs | Array | null | Custom tabs for the left panel (default: Info and Test Cases) | | initialActiveTab | Number | 0 | Index of initially active tab | | onTabChange | Function | null | Callback when tab is changed | | onTabPanelFoldChange | Function | null | Callback when tab panel is folded/unfolded | | onTerminalFoldChange | Function | null | Callback when terminal is folded/unfolded |

File Object Structure

Each file in the files array should have the following structure:

{
  filename: "main.py",         // Required: Name of the file
  initialContent: "...",       // Required: Initial content
  language: "python",          // Required: Language for syntax highlighting
  lock: false,                 // Optional: If true, file is fully read-only
  readOnly: [1, 2, 4]          // Optional: Array of line numbers (0-based) that are read-only
}

Contest Data Structure

The contest object contains problem statements and hints:

{
  problem: [
    {
      type: "Markdown",
      content: "# Problem Title\n\nDescription..."
    }
  ],
  hint: [
    {
      type: "Markdown",
      content: "### Hint\nHelpful tips..."
    }
  ]
}

Submission Response Format

The onSubmit callback should return a Promise that resolves to an object with the following structure:

{
  compile: {
    isPass: true // Whether compilation succeeded
  },
  evaluate: {
    isPass: true, // Whether all test cases passed
    testcases: [
      {
        title: "Test Case 1",
        description: "Basic test",
        isPass: true,
        executionTime: "12189513", // Optional: execution time in nanoseconds
        stdout: "8", // Optional: actual output
        stdin: "5 3", // Optional: input provided
        expectedStdout: "8", // Optional: expected output
        hidden: false // Optional: if test case details should be hidden
      }
    ]
  },
  error: "Error message" // Optional: error message if any
}

Methods (using ref)

| Method | Parameters | Description | |--------|------------|-------------| | switchTab | (tabIndex) | Switch to tab at specified index | | getActiveTabIndex | | Get current active tab index | | findTabIndexByLabel | (label) | Find tab index by label | | addTerminalEntry | (entry) | Add single entry to terminal | | addTerminalEntries | (entries) | Add multiple entries to terminal | | clearTerminal | | Clear terminal history | | toggleTerminalFold | | Toggle terminal fold state | | isTerminalFolded | | Get terminal fold state | | highlight | (filename, lines) | Highlight specific lines in a file |

Terminal Entry Format

{
  type: 'output', // 'output', 'error', 'input'
  content: 'Output text'
}

Example Use Cases

Creating Custom Terminal Commands

const handleTerminalCommand = (command, callback) => {
  switch(command.toLowerCase()) {
    case 'help':
      callback([
        'Available commands:',
        '  help    - Display this help message',
        '  run     - Simulate running the code',
        '  clear   - Clear the terminal'
      ]);
      break;
    case 'clear':
      contestEditorRef.current.clearTerminal();
      callback(null); // No output needed
      break;
    default:
      callback([`Command not found: ${command}`]);
  }
};

Highlighting Code Lines

// Highlight specific lines in a file
contestEditorRef.current.highlight("main.py", [2, 3, 4]);

// Clear highlights
contestEditorRef.current.highlight("main.py", []);

Switching Tabs Programmatically

// Switch to Test Cases tab
const testCasesTabIndex = contestEditorRef.current.findTabIndexByLabel('Test Cases');
if (testCasesTabIndex !== -1) {
  contestEditorRef.current.switchTab(testCasesTabIndex);
}

Dependencies

  • @duongtdn/react-scrollbox: Scrollable container for terminal
  • monaco-ext: Extended Monaco Editor with additional features
  • react-icons: Icons used throughout the interface
  • react-markdown: Markdown rendering for problem statements
  • react-syntax-highlighter: Syntax highlighting for code snippets in Info panel

License

MIT