coding-playground
TypeScript icon, indicating that this package has built-in type declarations

1.2.1 • Public • Published

Coding Playground Library

A reusable React component library for building coding playgrounds with Monaco editor integration, syntax highlighting, and test execution capabilities.

✨ Features

  • 🎨 Monaco Editor Integration: Full-featured code editor with syntax highlighting, IntelliSense, and error checking
  • 🔤 Multi-language Support: Built-in support for Python, JavaScript, C++, and Java
  • ✅ Test Case Execution: Run and validate code against predefined test cases
  • ⚡ Real-time Feedback: Instant feedback on code execution with detailed test results
  • 📐 Split-panel Layout: Resizable panels for problem description, code editor, and results
  • 📝 Markdown Support: Rich text rendering with math support (LaTeX/KaTeX)
  • ⏱️ Built-in Timer: Track time spent on problems
  • 🎭 Modern UI: Clean, dark theme with customizable components
  • 📦 TypeScript: Full type safety and IntelliSense support

🚀 Installation

npm install coding-playground
# or
yarn add coding-playground
# or
pnpm add coding-playground

📋 Prerequisites

Make sure you have the following peer dependencies installed:

npm install react react-dom

🎯 Quick Start

import React from 'react';
import { Playground } from 'coding-playground';
import type { Problem } from 'coding-playground';

const problems: Problem[] = [
  {
    id: "two-sum",
    title: "Two Sum",
    description: "# Two Sum\n\nGiven an array of integers and a target sum, return indices of two numbers that add up to the target.",
    functionSignature: "def two_sum(nums, target):",
    testCases: [
      {
        input: "[2,7,11,15] 9",
        expected: "[0,1]"
      },
      {
        input: "[3,2,4] 6",
        expected: "[1,2]"
      }
    ]
  }
];

function App() {
  return (
    <div className="h-screen">
      <Playground problems={problems} />
    </div>
  );
}

export default App;

📖 Complete Example

Here's a comprehensive example showing how to set up the coding playground with multiple problems and a custom execution handler:

import React from 'react';
import { Playground, Problem, ExecutionHandler } from 'coding-playground';

// Example problems data
const sampleProblems: Problem[] = [
  {
    id: "two-sum",
    title: "Two Sum",
    description: `# Two Sum

Given an array of integers \`nums\` and an integer \`target\`, return indices of the two numbers such that they add up to \`target\`.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

## Example 1:
- **Input:** nums = [2,7,11,15], target = 9
- **Output:** [0,1]
- **Explanation:** Because nums[0] + nums[1] == 9, we return [0, 1].

## Constraints:
- 2 ≤ nums.length ≤ 10^4
- -10^9 ≤ nums[i] ≤ 10^9
- -10^9 ≤ target ≤ 10^9`,
    functionSignature: "def two_sum(nums, target):",
    testCases: [
      { input: "[2,7,11,15] 9", expected: "[0,1]" },
      { input: "[3,2,4] 6", expected: "[1,2]" },
      { input: "[3,3] 6", expected: "[0,1]" }
    ]
  },
  {
    id: "palindrome-check",
    title: "Valid Palindrome",
    description: `# Valid Palindrome

A phrase is a **palindrome** if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward.

Given a string \`s\`, return \`true\` if it is a palindrome, or \`false\` otherwise.

## Example 1:
- **Input:** s = "A man, a plan, a canal: Panama"
- **Output:** true
- **Explanation:** "amanaplanacanalpanama" is a palindrome.`,
    functionSignature: "def is_palindrome(s):",
    testCases: [
      { input: '"A man, a plan, a canal: Panama"', expected: 'true' },
      { input: '"race a car"', expected: 'false' },
      { input: '""', expected: 'true' }
    ]
  }
];

// Example execution handler - in a real app, this would connect to your code execution backend
const handleExecution: ExecutionHandler = async (code, language, testCases, isSubmit) => {
  // This is a mock implementation
  // In a real app, you would send this to your backend service
  console.log('Executing code:', { code, language, testCases, isSubmit });
  
  // Simulate execution delay
  await new Promise(resolve => setTimeout(resolve, 1000));
  
  // Mock response - in reality, this would come from your code execution service
  return {
    stdout: 'Code executed successfully',
    stderr: '',
    exitCode: 0,
    runtime: 150,
    testResults: testCases.map((testCase, index) => ({
      passed: index === 0, // Mock: first test passes, others fail
      actual: index === 0 ? testCase.expected : 'Wrong answer'
    }))
  };
};

function App() {
  return (
    <div className="h-screen bg-slate-900 text-white">
      {/* Include required CSS in your app:
          - Tailwind CSS
          - import 'katex/dist/katex.min.css';
          - import 'highlight.js/styles/github-dark.css';
      */}
      <Playground 
        problems={sampleProblems}
        onExecute={handleExecution}
      />
    </div>
  );
}

export default App;

🧩 Components

Playground

The main component that provides the complete coding playground experience.

import { Playground, Problem } from 'coding-playground';

interface PlaygroundProps {
  problems: Problem[];
}

CodeEditor

A standalone Monaco editor component.

import { CodeEditor } from 'coding-playground';

<CodeEditor
  language="python"
  value={code}
  onChange={setCode}
  height="400px"
/>

MarkdownRenderer

Render markdown content with syntax highlighting and math support.

import { MarkdownRenderer } from 'coding-playground';

<MarkdownRenderer 
  content="# Hello World\n\nThis supports **markdown** and $\\LaTeX$ math!"
/>

Timer

A simple timer component for tracking time.

import { Timer } from 'coding-playground';

<Timer />

🏷️ Types

Problem

interface Problem {
  id: string;
  title: string;
  description: string;           // Markdown content
  testCases: TestCase[];
  functionSignature: string;     // Starting code template
}

TestCase

interface TestCase {
  input: string;
  expected: string;
}

LanguageConfig

interface LanguageConfig {
  name: string;
  pistonLanguage: string;        // For API execution
  monacoLanguage: string;        // For editor syntax highlighting
  defaultCode: string;
}

⚙️ Configuration

Supported Languages

The library comes with built-in support for:

import { LANGUAGES } from 'coding-playground';

// Available languages:
// - Python
// - JavaScript
// - C++
// - Java

Custom Language Support

Extend the language support by providing your own language configurations:

import { LanguageConfig } from 'coding-playground';

const customLanguage: LanguageConfig = {
  name: 'Go',
  pistonLanguage: 'go',
  monacoLanguage: 'go',
  defaultCode: 'package main\n\nfunc solve() int {\n    // Your code here\n    return 0\n}'
};

🎨 Styling

The library is built with Tailwind CSS and uses CSS variables for theming. Make sure to include Tailwind CSS in your project:

npm install -D tailwindcss

Required CSS

Import the required styles for syntax highlighting and math rendering:

/* In your main CSS file */
@import 'katex/dist/katex.min.css';
@import 'highlight.js/styles/github-dark.css';

Tailwind Configuration

Add the library paths to your Tailwind config:

// tailwind.config.js
module.exports = {
  content: [
    // ... your existing paths
    './node_modules/coding-playground/dist/**/*.{js,ts,jsx,tsx}',
  ],
  // ... rest of your config
};

🔧 Code Execution

The library includes utilities for wrapping user code with test harnesses:

import { wrapCode, TestCase } from 'coding-playground';

const testCases: TestCase[] = [
  { input: "[1,2,3] 5", expected: "[1,4]" }
];

const wrappedCode = wrapCode('python', userCode, testCases);
// Execute wrappedCode with your preferred execution engine

📚 Advanced Usage

Custom Execution Handler

Implement your own code execution logic:

interface ExecutionResult {
  stdout: string;
  stderr: string;
  exitCode: number;
  runtime: number;
  testResults?: TestResult[];
}

// Implement your execution logic
const executeCode = async (
  code: string, 
  language: string, 
  testCases: TestCase[]
): Promise<ExecutionResult> => {
  // Your implementation here
};

Component Composition

Use individual components to build custom layouts:

import { 
  CodeEditor, 
  MarkdownRenderer, 
  Timer, 
  Button, 
  Tabs, 
  TabsContent, 
  TabsList, 
  TabsTrigger 
} from 'coding-playground';

function CustomPlayground() {
  return (
    <div className="grid grid-cols-2 h-screen">
      <div className="p-4">
        <MarkdownRenderer content={problem.description} />
      </div>
      <div className="flex flex-col">
        <div className="p-4 border-b flex justify-between">
          <Button>Run Code</Button>
          <Timer />
        </div>
        <CodeEditor
          language="python"
          value={code}
          onChange={setCode}
        />
      </div>
    </div>
  );
}

📦 Build from Source

# Clone the repository
git clone https://github.com/aronnogh/coding-playground.git
cd coding-playground

# Install dependencies
npm install

# Build the library
npm run build

# The built files will be in the dist/ directory

🤝 Contributing

  1. Fork the repository
  2. Create your feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'Add some amazing feature'
  4. Push to the branch: git push origin feature/amazing-feature
  5. Open a pull request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

Package Sidebar

Install

npm i coding-playground

Weekly Downloads

11

Version

1.2.1

License

MIT

Unpacked Size

280 kB

Total Files

112

Last publish

Collaborators

  • aronnogh647433