code-playpad 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/LICENSE +27 -0
  2. package/README.md +166 -0
  3. package/dist/THIRD-PARTY-NOTICES.txt +473 -0
  4. package/dist/config-B2qK2rdk.js +6 -0
  5. package/dist/config-DZqcFPEP.js +1 -0
  6. package/dist/dist-B5vq9x6M.js +6 -0
  7. package/dist/dist-BThnYaQ5.js +12 -0
  8. package/dist/dist-CnC1nMtN.js +6 -0
  9. package/dist/dist-CqpVTRAq.js +28 -0
  10. package/dist/dist-D0FPZcUi.js +8 -0
  11. package/dist/dist-DOsLUKSb.js +10 -0
  12. package/dist/dist-D_qJovVA.js +14 -0
  13. package/dist/dist-DlIO0dzi.js +6 -0
  14. package/dist/dist-DmrP6yta.js +6 -0
  15. package/dist/dist-XlpaG2JF.js +6 -0
  16. package/dist/editor.d.ts +33 -0
  17. package/dist/element-CJuhuMOP.js +288 -0
  18. package/dist/element.d.ts +63 -0
  19. package/dist/element.js +1 -0
  20. package/dist/index.d.ts +10 -0
  21. package/dist/index.js +1 -0
  22. package/dist/javascript-CLly2mXM.js +318 -0
  23. package/dist/javascript-DGFKR69i.js +323 -0
  24. package/dist/languages.d.ts +9 -0
  25. package/dist/progress.d.ts +17 -0
  26. package/dist/pyodide-IYKXKyDw.js +13 -0
  27. package/dist/pyodide-yv6x2HCQ.js +18 -0
  28. package/dist/react.d.ts +44 -0
  29. package/dist/react.js +1 -0
  30. package/dist/runtime/config.d.ts +29 -0
  31. package/dist/runtime/javascript.d.ts +3 -0
  32. package/dist/runtime/js-worker.d.ts +9 -0
  33. package/dist/runtime/pyodide.d.ts +3 -0
  34. package/dist/runtime/registry.d.ts +9 -0
  35. package/dist/runtime/worker-runtime.d.ts +71 -0
  36. package/dist/runtime/worker.d.ts +14 -0
  37. package/dist/standalone.d.ts +14 -0
  38. package/dist/standalone.js +293 -0
  39. package/dist/styles.d.ts +3 -0
  40. package/dist/types.d.ts +67 -0
  41. package/dist/worker-runtime-8Mnw4vAD.js +9 -0
  42. package/dist/worker-runtime-BZHszOA3.js +4 -0
  43. package/package.json +110 -0
@@ -0,0 +1,13 @@
1
+ import{i as e}from"./config-DZqcFPEP.js";import{t}from"./worker-runtime-BZHszOA3.js";var n=`let pyodide=null,stdinLines=[],stdinExhausted=!1,currentId=null,interactive=!1,inputWaitMs=0,nextRequest=1;const pendingLines=new Map,MOUNT="/home/pyodide/playground";let written=new Set,internals=null;const REFRESH=["import importlib, os, sys","MOUNT = "+JSON.stringify(MOUNT),"os.makedirs(MOUNT, exist_ok=True)","sys.path.insert(0, MOUNT) if MOUNT not in sys.path else None","os.chdir(MOUNT)","for _name, _mod in list(sys.modules.items()):",' _file = getattr(_mod, "__file__", None) or ""',' _paths = list(getattr(_mod, "__path__", None) or [])'," if _file.startswith(MOUNT) or any(str(p).startswith(MOUNT) for p in _paths):"," del sys.modules[_name]","importlib.invalidate_caches()"].join(\`
2
+ \`);function flushStreams(){try{pyodide.runPython(\`import sys
3
+ sys.stdout.flush()
4
+ sys.stderr.flush()\`,{globals:internals})}catch{}flushOutput()}const INPUT_OVERRIDE=["import builtins, sys, js","from pyodide.ffi import run_sync","",'def _pg_input(prompt=""):',' if prompt != "":'," sys.stdout.write(str(prompt))"," sys.stdout.flush()"," line = run_sync(js._pgReadLine())"," # Pyodide maps JS null to its own JsNull singleton, not None, so test"," # for what we want rather than for the several ways EOF can arrive."," if not isinstance(line, str):",' raise EOFError("EOF when reading a line")'," return line","",'_pg_input.__name__ = "input"','_pg_input.__qualname__ = "input"',"_pg_input.__doc__ = builtins.input.__doc__","builtins.input = _pg_input"].join(\`
5
+ \`);self._pgReadLine=async()=>{if(stdinLines.length){const s=stdinLines.shift();return writeOutput("echo",s+\`
6
+ \`),s}if(!interactive)return stdinExhausted=!0,null;const e=nextRequest++;flushOutput();const t=performance.now(),n=await new Promise(s=>{pendingLines.set(e,s),post({type:"stdin-request",id:currentId,request:e})});return inputWaitMs+=performance.now()-t,n===void 0?null:n};function syncFiles(e){const t=Object.keys(e);for(const n of written)if(t.indexOf(n)===-1)try{pyodide.FS.unlink(MOUNT+"/"+n)}catch{}written=new Set(t);for(const n of t){const s=MOUNT+"/"+n,i=s.slice(0,s.lastIndexOf("/"));pyodide.FS.mkdirTree(i),pyodide.FS.writeFile(s,e[n],{encoding:"utf8"})}pyodide.runPython(REFRESH,{globals:internals})}function post(e){self.postMessage(e)}const FLUSH_BYTES=8192,FLUSH_MS=16;let outputQueue=[],queuedChars=0,lastFlush=0;function writeOutput(e,t){const n=outputQueue[outputQueue.length-1];n&&n.type===e?n.text+=t:outputQueue.push({type:e,text:t}),queuedChars+=t.length;const s=performance.now();(queuedChars>=FLUSH_BYTES||s-lastFlush>=FLUSH_MS)&&flushOutput()}function flushOutput(){if(lastFlush=performance.now(),!outputQueue.length)return;const e=outputQueue;outputQueue=[],queuedChars=0;for(const t of e)post({type:t.type,id:currentId,text:t.text})}function formatError(e){let t=e&&e.message?e.message:String(e);const n=t.split(\`
7
+ \`);if(/^Traceback/.test(n[0])){let s=-1;for(let r=1;r<n.length;r++){const a=n[r].match(/^\\s*File "([^"]+)"/);if(a&&a[1].indexOf("/_pyodide/")===-1){s=r;break}}const i=s>1?[n[0]].concat(n.slice(s)):n,o=[];for(let r=0;r<i.length;r++){const a=i[r].match(/^\\s*File "[^"]*", line \\d+, in (.+)$/);if(a&&a[1]==="_pg_input"){for(;r+1<i.length&&/^ {4,}/.test(i[r+1]);)r++;continue}o.push(i[r])}t=o.join(\`
8
+ \`)}return t.split(MOUNT+"/").join("").replace(/\\s+$/,"")}async function importLoadPyodide(e){try{const t=await import(e+"pyodide.mjs");if(t&&t.loadPyodide)return t.loadPyodide}catch(t){if(typeof importScripts!="function")throw t}return importScripts(e+"pyodide.js"),self.loadPyodide}async function boot(e){post({type:"progress",phase:"booting",message:"Loading Python runtime"}),pyodide=await(await importLoadPyodide(e))({indexURL:e});const n=new TextDecoder,s=new TextDecoder;pyodide.setStdout({isatty:!0,write:o=>(writeOutput("stdout",n.decode(o,{stream:!0})),o.length)}),pyodide.setStderr({isatty:!0,write:o=>(writeOutput("stderr",s.decode(o,{stream:!0})),o.length)}),pyodide.setStdin({stdin:()=>{if(flushOutput(),stdinLines.length){const o=stdinLines.shift();return writeOutput("echo",o+\`
9
+ \`),o+\`
10
+ \`}return stdinExhausted=!0,null},autoEOF:!1});let i=pyodide.version;try{i=pyodide.runPython("import sys; '.'.join(str(p) for p in sys.version_info[:3])")}catch{}if(internals=pyodide.runPython("dict()"),typeof WebAssembly.Suspending=="function")try{pyodide.runPython(INPUT_OVERRIDE,{globals:internals}),interactive=!0}catch{interactive=!1}post({type:"ready",version:i,interactiveStdin:interactive})}async function run(e){let t=null;currentId=e.id,stdinLines=e.stdin?String(e.stdin).replace(/\\n$/,"").split(\`
11
+ \`):[],stdinExhausted=!1,inputWaitMs=0;for(const s of pendingLines.values())s(null);pendingLines.clear();const n=performance.now();try{e.files&&syncFiles(e.files);try{await pyodide.loadPackagesFromImports(e.code,{messageCallback:r=>post({type:"progress",id:e.id,phase:"packages",message:r}),errorCallback:()=>{}})}catch(r){post({type:"stderr",id:e.id,text:"Could not auto-install packages: "+formatError(r)+\`
12
+ \`})}t=pyodide.runPython('dict(__name__="__main__")'),e.entry&&t.set("__file__",e.entry);const s={globals:t};e.entry&&(s.filename=MOUNT+"/"+e.entry);const i=await pyodide.runPythonAsync(e.code,s);flushStreams();let o;if(i!=null)try{t.set("_pg_last",i),o=pyodide.runPython("repr(_pg_last)",{globals:t})}catch{o=String(i)}i&&typeof i.destroy=="function"&&i.destroy(),post({type:"result",id:e.id,value:o,durationMs:performance.now()-n-inputWaitMs})}catch(s){flushStreams();const i=formatError(s);post({type:"error",id:e.id,message:i,hint:stdinExhausted&&i.indexOf("EOFError")!==-1?"input() asked for a line that standard input did not have. Add one line per input() call in the box above, then run again.":void 0,durationMs:performance.now()-n-inputWaitMs})}finally{if(currentId=null,t){try{t.destroy()}catch{}t=null}}}self.onmessage=async e=>{const t=e.data;try{if(t.type==="init")await boot(t.indexURL);else if(t.type==="run")await run(t);else if(t.type==="stdin-response"){const n=pendingLines.get(t.request);n&&(pendingLines.delete(t.request),n(t.text===void 0?null:t.text))}}catch(n){post({type:"fatal",id:t&&t.id,message:formatError(n)})}};
13
+ `,r=new class extends t{id=`python`;get source(){return n}initPayload(){return{indexURL:e()}}get label(){return this.version?`Python ${this.version.split(`.`).slice(0,2).join(`.`)}`:`Python`}async editorLanguage(){let{python:e}=await import(`@codemirror/lang-python`);return e()}};export{r as pythonRuntime};
@@ -0,0 +1,18 @@
1
+ /*!
2
+ * code-playpad — MIT © 2026 Seung Hun Lee
3
+ * Bundles CodeMirror 6 and Lezer (MIT) © Marijn Haverbeke and others.
4
+ * Full third-party licences: THIRD-PARTY-NOTICES.txt in this package.
5
+ */
6
+ import{i as e}from"./config-B2qK2rdk.js";import{t}from"./worker-runtime-8Mnw4vAD.js";var n=`let pyodide=null,stdinLines=[],stdinExhausted=!1,currentId=null,interactive=!1,inputWaitMs=0,nextRequest=1;const pendingLines=new Map,MOUNT="/home/pyodide/playground";let written=new Set,internals=null;const REFRESH=["import importlib, os, sys","MOUNT = "+JSON.stringify(MOUNT),"os.makedirs(MOUNT, exist_ok=True)","sys.path.insert(0, MOUNT) if MOUNT not in sys.path else None","os.chdir(MOUNT)","for _name, _mod in list(sys.modules.items()):",' _file = getattr(_mod, "__file__", None) or ""',' _paths = list(getattr(_mod, "__path__", None) or [])'," if _file.startswith(MOUNT) or any(str(p).startswith(MOUNT) for p in _paths):"," del sys.modules[_name]","importlib.invalidate_caches()"].join(\`
7
+ \`);function flushStreams(){try{pyodide.runPython(\`import sys
8
+ sys.stdout.flush()
9
+ sys.stderr.flush()\`,{globals:internals})}catch{}flushOutput()}const INPUT_OVERRIDE=["import builtins, sys, js","from pyodide.ffi import run_sync","",'def _pg_input(prompt=""):',' if prompt != "":'," sys.stdout.write(str(prompt))"," sys.stdout.flush()"," line = run_sync(js._pgReadLine())"," # Pyodide maps JS null to its own JsNull singleton, not None, so test"," # for what we want rather than for the several ways EOF can arrive."," if not isinstance(line, str):",' raise EOFError("EOF when reading a line")'," return line","",'_pg_input.__name__ = "input"','_pg_input.__qualname__ = "input"',"_pg_input.__doc__ = builtins.input.__doc__","builtins.input = _pg_input"].join(\`
10
+ \`);self._pgReadLine=async()=>{if(stdinLines.length){const s=stdinLines.shift();return writeOutput("echo",s+\`
11
+ \`),s}if(!interactive)return stdinExhausted=!0,null;const e=nextRequest++;flushOutput();const t=performance.now(),n=await new Promise(s=>{pendingLines.set(e,s),post({type:"stdin-request",id:currentId,request:e})});return inputWaitMs+=performance.now()-t,n===void 0?null:n};function syncFiles(e){const t=Object.keys(e);for(const n of written)if(t.indexOf(n)===-1)try{pyodide.FS.unlink(MOUNT+"/"+n)}catch{}written=new Set(t);for(const n of t){const s=MOUNT+"/"+n,i=s.slice(0,s.lastIndexOf("/"));pyodide.FS.mkdirTree(i),pyodide.FS.writeFile(s,e[n],{encoding:"utf8"})}pyodide.runPython(REFRESH,{globals:internals})}function post(e){self.postMessage(e)}const FLUSH_BYTES=8192,FLUSH_MS=16;let outputQueue=[],queuedChars=0,lastFlush=0;function writeOutput(e,t){const n=outputQueue[outputQueue.length-1];n&&n.type===e?n.text+=t:outputQueue.push({type:e,text:t}),queuedChars+=t.length;const s=performance.now();(queuedChars>=FLUSH_BYTES||s-lastFlush>=FLUSH_MS)&&flushOutput()}function flushOutput(){if(lastFlush=performance.now(),!outputQueue.length)return;const e=outputQueue;outputQueue=[],queuedChars=0;for(const t of e)post({type:t.type,id:currentId,text:t.text})}function formatError(e){let t=e&&e.message?e.message:String(e);const n=t.split(\`
12
+ \`);if(/^Traceback/.test(n[0])){let s=-1;for(let r=1;r<n.length;r++){const a=n[r].match(/^\\s*File "([^"]+)"/);if(a&&a[1].indexOf("/_pyodide/")===-1){s=r;break}}const i=s>1?[n[0]].concat(n.slice(s)):n,o=[];for(let r=0;r<i.length;r++){const a=i[r].match(/^\\s*File "[^"]*", line \\d+, in (.+)$/);if(a&&a[1]==="_pg_input"){for(;r+1<i.length&&/^ {4,}/.test(i[r+1]);)r++;continue}o.push(i[r])}t=o.join(\`
13
+ \`)}return t.split(MOUNT+"/").join("").replace(/\\s+$/,"")}async function importLoadPyodide(e){try{const t=await import(e+"pyodide.mjs");if(t&&t.loadPyodide)return t.loadPyodide}catch(t){if(typeof importScripts!="function")throw t}return importScripts(e+"pyodide.js"),self.loadPyodide}async function boot(e){post({type:"progress",phase:"booting",message:"Loading Python runtime"}),pyodide=await(await importLoadPyodide(e))({indexURL:e});const n=new TextDecoder,s=new TextDecoder;pyodide.setStdout({isatty:!0,write:o=>(writeOutput("stdout",n.decode(o,{stream:!0})),o.length)}),pyodide.setStderr({isatty:!0,write:o=>(writeOutput("stderr",s.decode(o,{stream:!0})),o.length)}),pyodide.setStdin({stdin:()=>{if(flushOutput(),stdinLines.length){const o=stdinLines.shift();return writeOutput("echo",o+\`
14
+ \`),o+\`
15
+ \`}return stdinExhausted=!0,null},autoEOF:!1});let i=pyodide.version;try{i=pyodide.runPython("import sys; '.'.join(str(p) for p in sys.version_info[:3])")}catch{}if(internals=pyodide.runPython("dict()"),typeof WebAssembly.Suspending=="function")try{pyodide.runPython(INPUT_OVERRIDE,{globals:internals}),interactive=!0}catch{interactive=!1}post({type:"ready",version:i,interactiveStdin:interactive})}async function run(e){let t=null;currentId=e.id,stdinLines=e.stdin?String(e.stdin).replace(/\\n$/,"").split(\`
16
+ \`):[],stdinExhausted=!1,inputWaitMs=0;for(const s of pendingLines.values())s(null);pendingLines.clear();const n=performance.now();try{e.files&&syncFiles(e.files);try{await pyodide.loadPackagesFromImports(e.code,{messageCallback:r=>post({type:"progress",id:e.id,phase:"packages",message:r}),errorCallback:()=>{}})}catch(r){post({type:"stderr",id:e.id,text:"Could not auto-install packages: "+formatError(r)+\`
17
+ \`})}t=pyodide.runPython('dict(__name__="__main__")'),e.entry&&t.set("__file__",e.entry);const s={globals:t};e.entry&&(s.filename=MOUNT+"/"+e.entry);const i=await pyodide.runPythonAsync(e.code,s);flushStreams();let o;if(i!=null)try{t.set("_pg_last",i),o=pyodide.runPython("repr(_pg_last)",{globals:t})}catch{o=String(i)}i&&typeof i.destroy=="function"&&i.destroy(),post({type:"result",id:e.id,value:o,durationMs:performance.now()-n-inputWaitMs})}catch(s){flushStreams();const i=formatError(s);post({type:"error",id:e.id,message:i,hint:stdinExhausted&&i.indexOf("EOFError")!==-1?"input() asked for a line that standard input did not have. Add one line per input() call in the box above, then run again.":void 0,durationMs:performance.now()-n-inputWaitMs})}finally{if(currentId=null,t){try{t.destroy()}catch{}t=null}}}self.onmessage=async e=>{const t=e.data;try{if(t.type==="init")await boot(t.indexURL);else if(t.type==="run")await run(t);else if(t.type==="stdin-response"){const n=pendingLines.get(t.request);n&&(pendingLines.delete(t.request),n(t.text===void 0?null:t.text))}}catch(n){post({type:"fatal",id:t&&t.id,message:formatError(n)})}};
18
+ `,r=new class extends t{id=`python`;get source(){return n}initPayload(){return{indexURL:e()}}get label(){return this.version?`Python ${this.version.split(`.`).slice(0,2).join(`.`)}`:`Python`}async editorLanguage(){let{python:e}=await import(`./dist-D_qJovVA.js`);return e()}};export{r as pythonRuntime};
@@ -0,0 +1,44 @@
1
+ import type { CSSProperties } from 'react';
2
+ import { CodePlayPadElement } from './element.js';
3
+ import type { ErrorEventDetail, OutputEventDetail, RunEventDetail } from './element.js';
4
+ import type { Files } from './types.js';
5
+ export interface CodePlayPadProps {
6
+ /** Single-file shorthand. Ignored when `files` is given. */
7
+ code?: string;
8
+ /** Several files: modules, packages ("pkg/__init__.py"), data files. */
9
+ files?: Files;
10
+ /** Which file Run executes. Defaults to main.py, else the first file. */
11
+ entry?: string;
12
+ stdin?: string;
13
+ /** "python" (default), "javascript" or "typescript". */
14
+ language?: string;
15
+ height?: number | string;
16
+ theme?: 'light' | 'dark' | 'auto';
17
+ readOnly?: boolean;
18
+ autoRun?: boolean;
19
+ /** IndexedDB key: edits are restored on the student's next visit */
20
+ persist?: string;
21
+ className?: string;
22
+ style?: CSSProperties;
23
+ onReady?: (detail: {
24
+ language: string;
25
+ label: string;
26
+ }) => void;
27
+ onRun?: (detail: RunEventDetail) => void;
28
+ onOutput?: (detail: OutputEventDetail) => void;
29
+ onError?: (detail: ErrorEventDetail) => void;
30
+ }
31
+ /**
32
+ * Thin wrapper. Properties are assigned through the ref rather than JSX props,
33
+ * which keeps React 18 (no non-string prop support on custom elements) working
34
+ * the same as React 19.
35
+ */
36
+ export declare function CodePlayPad({ code, files, entry, stdin, language, height, theme, readOnly, autoRun, persist, className, style, onReady, onRun, onOutput, onError }: CodePlayPadProps): import("react").JSX.Element;
37
+ declare module 'react' {
38
+ namespace JSX {
39
+ interface IntrinsicElements {
40
+ 'code-playpad': React.DetailedHTMLProps<React.HTMLAttributes<CodePlayPadElement> & Record<string, unknown>, CodePlayPadElement>;
41
+ }
42
+ }
43
+ }
44
+ export default CodePlayPad;
package/dist/react.js ADDED
@@ -0,0 +1 @@
1
+ import{n as e}from"./element-CJuhuMOP.js";import{useEffect as t,useRef as n}from"react";import{jsx as r}from"react/jsx-runtime";e();function i({code:e=``,files:i,entry:a,stdin:o,language:s=`python`,height:c,theme:l=`auto`,readOnly:u,autoRun:d,persist:f,className:p,style:m,onReady:h,onRun:g,onOutput:_,onError:v}){let y=n(null),b=n({onReady:h,onRun:g,onOutput:_,onError:v});b.current={onReady:h,onRun:g,onOutput:_,onError:v},t(()=>{let e=y.current;if(!e)return;let t=(t,n)=>{let r=e=>n(b.current)?.(e.detail);return e.addEventListener(t,r),()=>e.removeEventListener(t,r)},n=[t(`py-ready`,e=>e.onReady),t(`py-run`,e=>e.onRun),t(`py-output`,e=>e.onOutput),t(`py-error`,e=>e.onError)];return()=>n.forEach(e=>e())},[]);let x=i?JSON.stringify(i):null;return t(()=>{let t=y.current;t&&(x?t.files=JSON.parse(x):e!==t.code&&(t.code=e))},[e,x]),t(()=>{y.current&&o!==void 0&&(y.current.stdin=o)},[o]),r(`code-playpad`,{ref:y,language:s,theme:l,class:p,style:m,...c===void 0?{}:{height:String(c)},...u?{readonly:``}:{},...d?{autorun:``}:{},...f?{persist:f}:{},...a?{entry:a}:{},children:i?null:e})}export{i as CodePlayPad,i as default};
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Runtime endpoints, kept in their own module on purpose.
3
+ *
4
+ * If `configurePython()` lived in pyodide.ts, then exporting it from the
5
+ * package root would statically pull the Python runtime into the main chunk and
6
+ * every page would download it — including pages that only run JavaScript.
7
+ * This module holds nothing but a few strings.
8
+ */
9
+ /** Pinned so the CDN response is cacheable forever. */
10
+ export declare const PYODIDE_VERSION = "314.0.5";
11
+ /** Point Python at your own origin — strongly recommended in production, so you
12
+ * control `Cache-Control` on the ~11MB of assets. Call before the first run. */
13
+ export declare function configurePython(options: {
14
+ indexURL: string;
15
+ }): void;
16
+ /** Point the TypeScript/JSX transform somewhere else (your own origin, a pinned
17
+ * CDN copy). Only fetched when a widget actually needs a transform. */
18
+ export declare function configureTypeScript(options: {
19
+ sucraseURL: string;
20
+ }): void;
21
+ export declare function getPyodideIndexURL(): string;
22
+ export declare function getSucraseURL(): string;
23
+ /** The files worth `<link rel="preload">`-ing in the document head, so the
24
+ * network fetch starts before app JS runs. Python only — JavaScript has
25
+ * nothing to preload, which is rather the point of it. */
26
+ export declare function pyodideAssetUrls(): {
27
+ url: string;
28
+ as: 'script' | 'fetch';
29
+ }[];
@@ -0,0 +1,3 @@
1
+ import type { Runtime } from '../types.js';
2
+ export declare const javascriptRuntime: Runtime;
3
+ export declare const typescriptRuntime: Runtime;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Source for the JavaScript / TypeScript worker.
3
+ *
4
+ * Unlike Python there is no runtime to download — the engine is already here.
5
+ * The only thing that may be fetched is a TypeScript transform, and only when
6
+ * the code actually needs one (a .ts file, JSX, or ES module syntax across
7
+ * several files). Plain single-file JavaScript costs nothing beyond this file.
8
+ */
9
+ export declare const JS_WORKER_SOURCE: string;
@@ -0,0 +1,3 @@
1
+ import type { Runtime } from '../types.js';
2
+ /** The one Python runtime for this document. */
3
+ export declare const pythonRuntime: Runtime;
@@ -0,0 +1,9 @@
1
+ import type { Runtime } from '../types.js';
2
+ type RuntimeLoader = () => Promise<Runtime>;
3
+ /** Add a language. Adding a second runtime should be a new file, not a rewrite. */
4
+ export declare function registerRuntime(id: string, loader: RuntimeLoader): void;
5
+ export declare function listRuntimes(): string[];
6
+ /** Lazily imports the runtime module, so a page with no Python widget never
7
+ * downloads the Python glue. Cached per id. */
8
+ export declare function getRuntime(id: string): Promise<Runtime>;
9
+ export {};
@@ -0,0 +1,71 @@
1
+ import type { LoadProgress, Result, RunOptions } from '../types.js';
2
+ /**
3
+ * Everything a Worker-backed runtime needs that has nothing to do with the
4
+ * language: boot, reboot, a single-file queue, streamed output, interactive
5
+ * stdin, and stop-by-terminate.
6
+ *
7
+ * Both runtimes speak the same message protocol, so this lives in one place —
8
+ * the bugs found in the Python path (errors never streaming, output arriving in
9
+ * the wrong run, prompts holding the queue) were all in code like this, and
10
+ * fixing them twice would be a mistake.
11
+ */
12
+ export type WorkerMessage = {
13
+ type: 'ready';
14
+ version: string;
15
+ interactiveStdin?: boolean;
16
+ } | {
17
+ type: 'progress';
18
+ id?: number;
19
+ phase: LoadProgress['phase'];
20
+ message: string;
21
+ } | {
22
+ type: 'stdout';
23
+ id: number;
24
+ text: string;
25
+ } | {
26
+ type: 'echo';
27
+ id: number;
28
+ text: string;
29
+ } | {
30
+ type: 'stdin-request';
31
+ id: number;
32
+ request: number;
33
+ } | {
34
+ type: 'stderr';
35
+ id: number;
36
+ text: string;
37
+ } | {
38
+ type: 'result';
39
+ id: number;
40
+ value?: string;
41
+ durationMs: number;
42
+ } | {
43
+ type: 'error';
44
+ id: number;
45
+ message: string;
46
+ hint?: string;
47
+ durationMs: number;
48
+ } | {
49
+ type: 'fatal';
50
+ id?: number;
51
+ message: string;
52
+ };
53
+ export declare abstract class WorkerRuntime {
54
+ #private;
55
+ /** Worker source for this language. */
56
+ protected abstract get source(): string;
57
+ /** Extra fields for the init message (e.g. where to fetch a runtime from). */
58
+ protected initPayload(): Record<string, unknown>;
59
+ get ready(): boolean;
60
+ get interactiveStdin(): boolean;
61
+ protected get version(): string;
62
+ load(onProgress?: (p: LoadProgress) => void): Promise<void>;
63
+ run(code: string, options?: RunOptions): Promise<Result>;
64
+ /**
65
+ * Hard stop. User code that never yields cannot be interrupted cooperatively
66
+ * without SharedArrayBuffer (which needs site-wide COOP/COEP), so we kill the
67
+ * worker and boot a fresh one. Queued runs survive and execute on the new one.
68
+ */
69
+ stop(): void;
70
+ abstract get label(): string;
71
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Source for the Pyodide worker.
3
+ *
4
+ * It ships as a string and is instantiated from a Blob URL so the package has
5
+ * no separate worker file to host, and works identically from npm, a CDN, or a
6
+ * bundler. Pyodide itself is pulled from the CDN at runtime, never bundled
7
+ * (hard constraint 3).
8
+ *
9
+ * The same source runs as a module worker or as a classic one: module workers
10
+ * get `pyodide.mjs` via dynamic import, classic workers get `pyodide.js` via
11
+ * `importScripts`. Environments block one or the other often enough to be
12
+ * worth supporting both.
13
+ */
14
+ export declare const WORKER_SOURCE: string;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Single-file build for CDN use: CodeMirror is bundled in, so a static HTML
3
+ * page needs one script tag and no import map.
4
+ *
5
+ * Pyodide is still fetched at runtime and never bundled — that is the whole
6
+ * reason this file is ~100KB gzipped instead of 11MB.
7
+ *
8
+ * <script type="module" src="https://cdn.jsdelivr.net/npm/code-playpad"></script>
9
+ * <code-playpad>print("hi")</code-playpad>
10
+ *
11
+ * Prefer the "." entry (with CodeMirror as peer dependencies) if you already
12
+ * use CodeMirror or a bundler — this build cannot share those copies.
13
+ */
14
+ export * from './index.js';
@@ -0,0 +1,293 @@
1
+ /*!
2
+ * code-playpad — MIT © 2026 Seung Hun Lee
3
+ * Bundles CodeMirror 6 and Lezer (MIT) © Marijn Haverbeke and others.
4
+ * Full third-party licences: THIRD-PARTY-NOTICES.txt in this package.
5
+ */
6
+ import{c as e,n as t,o as n,r,s as i,t as a}from"./config-B2qK2rdk.js";async function o(e){try{return await s(e)}catch(t){return console.warn(`[code-playpad] CodeMirror unavailable, using plain textarea:`,t),c(e)}}async function s(e){let[t,n,r,i,a,o]=await Promise.all([import(`./dist-BThnYaQ5.js`).then(e=>e.s),import(`./dist-DOsLUKSb.js`).then(e=>e.x),import(`./dist-CnC1nMtN.js`),import(`./dist-D0FPZcUi.js`),import(`./dist-DmrP6yta.js`),import(`./dist-DlIO0dzi.js`)]),{EditorView:s,keymap:c,lineNumbers:l,highlightActiveLine:u,highlightActiveLineGutter:d,highlightSpecialChars:f,drawSelection:p,rectangularSelection:m,crosshairCursor:h}=t,{EditorState:g,Compartment:_}=n,{defaultKeymap:v,history:y,historyKeymap:b,indentWithTab:x}=r,{syntaxHighlighting:S,defaultHighlightStyle:C,indentOnInput:w,bracketMatching:T,foldGutter:E,foldKeymap:D}=i,{autocompletion:O,closeBrackets:k,closeBracketsKeymap:A,completionKeymap:j}=a,M=new _,N=new _,P=new _,F=[s.theme({"&":{color:`#1f2328`,backgroundColor:`#ffffff`},".cm-gutters":{backgroundColor:`#f6f8fa`,color:`#8b949e`,border:`none`},".cm-activeLine":{backgroundColor:`#f6f8fa88`},".cm-activeLineGutter":{backgroundColor:`#eaeef2`},".cm-cursor":{borderLeftColor:`#1f2328`},"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, ::selection":{backgroundColor:`#cfe3ff`}}),S(C,{fallback:!0})],I=e=>e?o.oneDark:F,L=c.of([{key:`Mod-Enter`,preventDefault:!0,run:()=>(e.onRun?.(),!0)},{key:`Shift-Enter`,preventDefault:!0,run:()=>(e.onRun?.(),!0)}]),R=e.dark,z=e.readOnly,B=e.language??[],V=t=>g.create({doc:t,extensions:[l(),d(),f(),y(),E(),p(),g.allowMultipleSelections.of(!0),w(),T(),k(),O(),m(),h(),u(),L,c.of([...A,...v,...b,...D,...j,x]),s.lineWrapping,P.of(B),M.of(I(R)),N.of(g.readOnly.of(z)),s.updateListener.of(t=>{t.docChanged&&e.onChange?.(t.state.doc.toString())})]}),H=new s({parent:e.parent,state:V(e.doc)}),U=new Map,W=e.name??``;return{fallback:!1,getCode:()=>H.state.doc.toString(),setCode(e){H.dispatch({changes:{from:0,to:H.state.doc.length,insert:e}})},openFile(e,t){if(e===W)return;U.set(W,H.state);let n=U.get(e);H.setState(n??V(t)),W=e,n&&H.dispatch({effects:[M.reconfigure(I(R)),N.reconfigure(g.readOnly.of(z)),P.reconfigure(B)]})},fileCode(e,t){if(e===W)return H.state.doc.toString();let n=U.get(e);return n?n.doc.toString():t},forgetFiles(e){for(let t of[...U.keys()])e.includes(t)||U.delete(t)},setTheme(e){R=e,H.dispatch({effects:M.reconfigure(I(R))})},setReadOnly(e){z=e,H.dispatch({effects:N.reconfigure(g.readOnly.of(z))})},setLanguage(e){B=e,H.dispatch({effects:P.reconfigure(B)})},focus:()=>H.focus(),destroy:()=>H.destroy()}}function c(e){let t=document.createElement(`textarea`);t.className=`cp-fallback-editor`,t.spellcheck=!1,t.value=e.doc,t.readOnly=e.readOnly,t.addEventListener(`input`,()=>e.onChange?.(t.value)),t.addEventListener(`keydown`,t=>{(t.metaKey||t.ctrlKey)&&t.key===`Enter`&&(t.preventDefault(),e.onRun?.())}),e.parent.appendChild(t);let n=new Map,r=e.name??``;return{fallback:!0,getCode:()=>t.value,setCode:e=>{t.value=e},openFile(e,i){e!==r&&(n.set(r,t.value),t.value=n.get(e)??i,r=e)},fileCode(e,i){return e===r?t.value:n.get(e)??i},forgetFiles(e){for(let t of[...n.keys()])e.includes(t)||n.delete(t)},setTheme:()=>{},setReadOnly:e=>{t.readOnly=e},setLanguage:()=>{},focus:()=>t.focus(),destroy:()=>t.remove()}}var l=new Map,u=new Map;function d(e,t){l.set(e,t)}function f(){return[...l.keys()]}function p(e){let t=u.get(e);if(t)return t;let n=l.get(e);if(!n)return Promise.reject(Error(`Unknown runtime "${e}". Registered: ${f().join(`, `)||`none`}`));let r=n().catch(t=>{throw u.delete(e),t});return u.set(e,r),r}d(`python`,()=>import(`./pyodide-yv6x2HCQ.js`).then(e=>e.pythonRuntime)),d(`javascript`,()=>import(`./javascript-DGFKR69i.js`).then(e=>e.javascriptRuntime)),d(`typescript`,()=>import(`./javascript-DGFKR69i.js`).then(e=>e.typescriptRuntime));var m=String.raw`
7
+ :host {
8
+ --cp-bg: #ffffff;
9
+ --cp-fg: #1f2328;
10
+ --cp-muted: #656d76;
11
+ --cp-border: #d0d7de;
12
+ --cp-surface: #f6f8fa;
13
+ --cp-accent: #1f6feb;
14
+ --cp-accent-fg: #ffffff;
15
+ --cp-danger: #cf222e;
16
+ --cp-ok: #1a7f37;
17
+ --cp-radius: 8px;
18
+ --cp-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
19
+ --cp-font-ui: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
20
+
21
+ display: block;
22
+ margin: 1rem 0;
23
+ color-scheme: light;
24
+ contain: content;
25
+ }
26
+
27
+ :host([hidden]) { display: none; }
28
+
29
+ :host([data-resolved-theme="dark"]) {
30
+ --cp-bg: #0d1117;
31
+ --cp-fg: #e6edf3;
32
+ --cp-muted: #8b949e;
33
+ --cp-border: #30363d;
34
+ --cp-surface: #161b22;
35
+ --cp-accent: #388bfd;
36
+ --cp-danger: #ff7b72;
37
+ --cp-ok: #3fb950;
38
+ color-scheme: dark;
39
+ }
40
+
41
+ * { box-sizing: border-box; }
42
+
43
+ .cp-root {
44
+ border: 1px solid var(--cp-border);
45
+ border-radius: var(--cp-radius);
46
+ background: var(--cp-bg);
47
+ color: var(--cp-fg);
48
+ font-family: var(--cp-font-ui);
49
+ font-size: 14px;
50
+ overflow: hidden;
51
+ }
52
+
53
+ .cp-toolbar {
54
+ display: flex;
55
+ align-items: center;
56
+ gap: 8px;
57
+ padding: 6px 8px;
58
+ background: var(--cp-surface);
59
+ border-bottom: 1px solid var(--cp-border);
60
+ }
61
+
62
+ .cp-spacer { flex: 1 1 auto; }
63
+
64
+ .cp-status {
65
+ font-size: 12px;
66
+ color: var(--cp-muted);
67
+ white-space: nowrap;
68
+ overflow: hidden;
69
+ text-overflow: ellipsis;
70
+ max-width: 55%;
71
+ }
72
+ .cp-status[data-state="error"] { color: var(--cp-danger); }
73
+ .cp-status[data-state="ok"] { color: var(--cp-ok); }
74
+
75
+ button {
76
+ font: inherit;
77
+ font-size: 13px;
78
+ line-height: 1;
79
+ padding: 6px 12px;
80
+ border-radius: 6px;
81
+ border: 1px solid var(--cp-border);
82
+ background: var(--cp-bg);
83
+ color: var(--cp-fg);
84
+ cursor: pointer;
85
+ }
86
+ button:hover:not(:disabled) { border-color: var(--cp-accent); }
87
+ button:disabled { opacity: 0.5; cursor: default; }
88
+ button:focus-visible { outline: 2px solid var(--cp-accent); outline-offset: 1px; }
89
+
90
+ button.cp-primary {
91
+ background: var(--cp-accent);
92
+ border-color: var(--cp-accent);
93
+ color: var(--cp-accent-fg);
94
+ font-weight: 600;
95
+ }
96
+ button.cp-danger { color: var(--cp-danger); border-color: var(--cp-danger); }
97
+
98
+ .cp-tabs {
99
+ display: flex;
100
+ gap: 2px;
101
+ overflow-x: auto;
102
+ padding: 0 6px;
103
+ background: var(--cp-surface);
104
+ border-bottom: 1px solid var(--cp-border);
105
+ scrollbar-width: thin;
106
+ }
107
+ .cp-tabs[hidden] { display: none; }
108
+ .cp-tabs button {
109
+ border: 0;
110
+ border-bottom: 2px solid transparent;
111
+ border-radius: 0;
112
+ background: transparent;
113
+ color: var(--cp-muted);
114
+ font-family: var(--cp-font-mono);
115
+ font-size: 12px;
116
+ padding: 7px 10px;
117
+ white-space: nowrap;
118
+ }
119
+ .cp-tabs button:hover:not(:disabled) { color: var(--cp-fg); }
120
+ .cp-tabs button[aria-pressed='true'] {
121
+ color: var(--cp-fg);
122
+ border-bottom-color: var(--cp-accent);
123
+ background: var(--cp-bg);
124
+ }
125
+ .cp-tabs button.cp-entry::before {
126
+ content: '▸';
127
+ margin-right: 4px;
128
+ color: var(--cp-accent);
129
+ }
130
+
131
+ .cp-editor {
132
+ height: var(--cp-height, 220px);
133
+ overflow: hidden;
134
+ }
135
+ .cp-editor .cm-editor { height: 100%; }
136
+ .cp-editor .cm-scroller {
137
+ font-family: var(--cp-font-mono);
138
+ font-size: 13px;
139
+ line-height: 1.5;
140
+ }
141
+ .cp-editor .cm-editor.cm-focused { outline: none; }
142
+
143
+ .cp-fallback-editor {
144
+ width: 100%;
145
+ height: 100%;
146
+ border: 0;
147
+ padding: 8px;
148
+ resize: none;
149
+ background: var(--cp-bg);
150
+ color: var(--cp-fg);
151
+ font-family: var(--cp-font-mono);
152
+ font-size: 13px;
153
+ line-height: 1.5;
154
+ }
155
+ .cp-fallback-editor:focus { outline: none; }
156
+
157
+ .cp-stdin { border-top: 1px solid var(--cp-border); background: var(--cp-surface); }
158
+ .cp-stdin[hidden] { display: none; }
159
+ .cp-stdin.cp-attention {
160
+ box-shadow: inset 0 0 0 2px var(--cp-accent);
161
+ }
162
+ .cp-stdin label {
163
+ display: block;
164
+ padding: 6px 8px 0;
165
+ font-size: 11px;
166
+ text-transform: uppercase;
167
+ letter-spacing: 0.04em;
168
+ color: var(--cp-muted);
169
+ }
170
+ .cp-stdin textarea {
171
+ display: block;
172
+ width: 100%;
173
+ min-height: 52px;
174
+ border: 0;
175
+ padding: 4px 8px 8px;
176
+ background: transparent;
177
+ color: var(--cp-fg);
178
+ font-family: var(--cp-font-mono);
179
+ font-size: 13px;
180
+ resize: vertical;
181
+ }
182
+ .cp-stdin textarea:focus { outline: none; }
183
+
184
+ .cp-output {
185
+ border-top: 1px solid var(--cp-border);
186
+ padding: 8px 10px;
187
+ margin: 0;
188
+ max-height: 260px;
189
+ overflow: auto;
190
+ background: var(--cp-surface);
191
+ font-family: var(--cp-font-mono);
192
+ font-size: 13px;
193
+ line-height: 1.5;
194
+ white-space: pre-wrap;
195
+ word-break: break-word;
196
+ }
197
+ .cp-output[hidden] { display: none; }
198
+ .cp-output .cp-err { color: var(--cp-danger); }
199
+ .cp-output .cp-hint {
200
+ margin-top: 6px;
201
+ padding: 6px 8px;
202
+ border-left: 3px solid var(--cp-accent);
203
+ background: var(--cp-bg);
204
+ color: var(--cp-fg);
205
+ font-family: var(--cp-font-ui);
206
+ font-size: 12.5px;
207
+ white-space: normal;
208
+ }
209
+ .cp-output .cp-value { color: var(--cp-muted); }
210
+ .cp-output .cp-in { color: var(--cp-accent); }
211
+
212
+ .cp-prompt {
213
+ display: inline-flex;
214
+ align-items: center;
215
+ gap: 4px;
216
+ }
217
+ .cp-prompt input {
218
+ font: inherit;
219
+ color: var(--cp-accent);
220
+ background: transparent;
221
+ border: 0;
222
+ border-bottom: 1px solid var(--cp-accent);
223
+ padding: 0 2px;
224
+ min-width: 12ch;
225
+ caret-color: var(--cp-accent);
226
+ }
227
+ .cp-prompt input:focus { outline: none; }
228
+ .cp-prompt button {
229
+ padding: 1px 6px;
230
+ font-size: 11px;
231
+ line-height: 1.4;
232
+ border-radius: 4px;
233
+ color: var(--cp-muted);
234
+ font-family: var(--cp-font-mono);
235
+ }
236
+ .cp-prompt button.cp-send { color: var(--cp-accent); border-color: var(--cp-accent); }
237
+
238
+ table.cp-table {
239
+ border-collapse: collapse;
240
+ margin: 6px 0;
241
+ font-size: 12px;
242
+ }
243
+ table.cp-table th, table.cp-table td {
244
+ border: 1px solid var(--cp-border);
245
+ padding: 3px 8px;
246
+ text-align: left;
247
+ }
248
+ table.cp-table th { background: var(--cp-bg); }
249
+
250
+ .cp-progress {
251
+ height: 2px;
252
+ background: linear-gradient(90deg, transparent, var(--cp-accent), transparent);
253
+ background-size: 40% 100%;
254
+ background-repeat: no-repeat;
255
+ animation: cp-slide 1.1s ease-in-out infinite;
256
+ }
257
+ .cp-progress[hidden] { display: none; }
258
+
259
+ @keyframes cp-slide {
260
+ 0% { background-position: -40% 0; }
261
+ 100% { background-position: 140% 0; }
262
+ }
263
+
264
+ @media (prefers-reduced-motion: reduce) {
265
+ .cp-progress { animation: none; background-position: 0 0; background-size: 100% 100%; opacity: 0.4; }
266
+ }
267
+ `,h=e=>()=>import(`./dist-CqpVTRAq.js`).then(t=>t.javascript(e)),g={py:()=>import(`./dist-D_qJovVA.js`).then(e=>e.python()),pyi:()=>import(`./dist-D_qJovVA.js`).then(e=>e.python()),js:h({}),mjs:h({}),cjs:h({}),jsx:h({jsx:!0}),ts:h({typescript:!0}),mts:h({typescript:!0}),cts:h({typescript:!0}),tsx:h({typescript:!0,jsx:!0}),json:()=>import(`./dist-XlpaG2JF.js`).then(e=>e.json())};async function _(e){let t=g[e.includes(`.`)?e.slice(e.lastIndexOf(`.`)+1).toLowerCase():``];return t?t().catch(()=>null):null}var v=`code-playpad`,y=1,b=`snippets`,x=`progress`,S=null;function C(){return typeof indexedDB>`u`?Promise.reject(Error(`IndexedDB unavailable`)):(S||=new Promise((e,t)=>{let n=indexedDB.open(v,y);n.onupgradeneeded=()=>{let e=n.result;e.objectStoreNames.contains(b)||e.createObjectStore(b),e.objectStoreNames.contains(x)||e.createObjectStore(x,{keyPath:`id`})},n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)}).catch(e=>{throw S=null,e}),S)}function w(e,t,n){return C().then(r=>new Promise((i,a)=>{let o=n(r.transaction(e,t).objectStore(e));o.onsuccess=()=>i(o.result),o.onerror=()=>a(o.error)}))}function T(e,t){return w(b,`readwrite`,n=>n.put(t,e)).then(()=>void 0)}function E(e){return w(b,`readonly`,t=>t.get(e)).then(e=>e??null)}function D(e){return w(b,`readwrite`,t=>t.delete(e)).then(()=>void 0)}function O(e,t={}){let n={completed:!0,...t,id:e,updatedAt:Date.now()};return w(x,`readwrite`,e=>e.put(n)).then(()=>n)}function k(e){return w(x,`readonly`,t=>t.get(e)).then(e=>e??null)}function A(){return w(x,`readonly`,e=>e.getAll())}var j=`code-playpad`;function M(e){let t=e.replace(/\t/g,` `).split(`
268
+ `);for(;t.length&&t[0].trim()===``;)t.shift();for(;t.length&&t[t.length-1].trim()===``;)t.pop();let n=t.filter(e=>e.trim()!==``).reduce((e,t)=>Math.min(e,t.match(/^ */)[0].length),1/0);return(n===1/0?t:t.map(e=>e.slice(n))).join(`
269
+ `)}var N=2e5,P=`playpad-file`,F={python:`main.py`,javascript:`main.js`,typescript:`main.ts`};function I(e){return F[e]??`main.txt`}function L(e,t){let n={};for(let t of e.children){if(t.tagName.toLowerCase()!==P)continue;let e=t.getAttribute(`name`);e&&(n[e]=M(t.textContent??``))}if(Object.keys(n).length)return n;let r=M([...e.childNodes].filter(e=>e.nodeType!==Node.ELEMENT_NODE||e.tagName.toLowerCase()!==P).map(e=>e.textContent??``).join(``));return{[t]:r}}function R(e,t){try{let t=JSON.parse(e);if(t&&typeof t==`object`&&!Array.isArray(t)){let e=t;return Object.keys(e).length?e:null}}catch{}return e?{[t]:e}:null}var z=typeof HTMLElement>`u`?class{}:HTMLElement,B=class extends z{static get observedAttributes(){return[`language`,`height`,`theme`,`readonly`,`autorun`,`stdin`,`persist`,`entry`]}#e;#t;#n;#r;#i;#a;#o;#s;#c;#l;#u=null;#d=null;#f=null;#p=null;#m={};#h={};#g=`main.py`;#_=null;#v;#y=!1;#b=!1;#x=null;#S=null;#C=()=>this.#U();#w=null;#T=!0;#E=[];#D=null;#O=null;#k=null;#A=0;#j=!1;constructor(){super(),this.#e=this.attachShadow({mode:`open`})}get code(){return this.#u?this.#u.getCode():this.#m[this.#g]??``}set code(e){this.#m[this.#g]=e,this.#L()}get files(){return this.#z()}set files(e){let t=Object.keys(e);if(!t.length)return;let n=Object.keys(this.#h);n.length===1&&!this.#h[n[0]]&&(this.#h={...e}),this.#m={...e},t.includes(this.#g)||(this.#g=this.#R()),this.#u?.forgetFiles([]),this.#L(),this.#B(),this.#I()}get entry(){return this.#R()}set entry(e){this.setAttribute(`entry`,e)}openFile(e){e in this.#m&&(this.#u&&(this.#m[this.#g]=this.#u.getCode(),this.#u.openFile(e,this.#m[e]??``)),this.#g=e,this.#B(),this.#I())}get stdin(){return this.#l?this.#l.value:``}set stdin(e){this.#l&&(this.#l.value=e,this.#c.hidden=!1)}get language(){return this.getAttribute(`language`)||`python`}set language(e){this.setAttribute(`language`,e)}getCode(){return this.code}getFiles(){return this.#z()}reset(){this.#m={...this.#h},this.#g=this.#R(),this.#u?.forgetFiles([]),this.#L(),this.#B(),this.#K(),this.#s.hidden=!0,this.#G(this.#f?.ready?`${this.#f.label} ready`:``,`idle`)}async run(){if(this.#y)return;await this.#d;let e=this.#z(),t=this.#R(),n=e[t]??``;this.#y=!0,this.#n.disabled=!0,this.#r.hidden=!1,this.#K(),this.#s.hidden=!1,this.#$(`py-run`,{code:n,entry:t,files:e,language:this.language});try{let r=await this.#F();this.#G(`Queued…`,`busy`),this.#o.hidden=!1;let i=await r.run(n,{stdin:this.#l.value,files:e,entry:t,onStart:()=>this.#G(`Running…`,`busy`),onStdout:e=>this.#q(e),onStderr:e=>this.#q(e,`cp-err`),onEcho:e=>this.#q(e,`cp-in`),onStdinRequest:()=>this.#Y()});return i.table&&this.#Q(i.table),i.value!==void 0&&this.#q(`${i.value}\n`,`cp-value`),i.hint&&this.#Z(i.hint),i.stderr?(this.#G(`Error · ${i.durationMs} ms`,`error`),this.#$(`py-error`,{message:i.stderr,hint:i.hint,language:this.language})):this.#G(`Done in ${i.durationMs} ms`,`ok`),this.#$(`py-output`,{...i,language:this.language}),i}catch(e){if(e instanceof i)this.#q(`
270
+ [stopped]
271
+ `,`cp-err`),this.#G(`Stopped`,`error`);else{let t=e instanceof Error?e.message:String(e);this.#q(t+`
272
+ `,`cp-err`),this.#G(`Failed to start`,`error`),this.#$(`py-error`,{message:t,language:this.language})}return}finally{this.#X(null),this.#J(),this.#y=!1,this.#n.disabled=!1,this.#r.hidden=!0,this.#o.hidden=!0}}stop(){this.#f?.stop?.()}prewarm(){return this.#F()}connectedCallback(){if(this.#j){this.#P();return}if(!this.textContent?.trim()&&document.readyState===`loading`){document.addEventListener(`DOMContentLoaded`,()=>this.isConnected&&this.#M(),{once:!0});return}this.#M()}disconnectedCallback(){this.#x?.disconnect(),this.#x=null,this.#S?.removeEventListener(`change`,this.#C),this.#S=null,this.#w&&clearTimeout(this.#w),this.#X(null),setTimeout(()=>{this.isConnected||!this.#u||(this.#_=this.#z(),this.#u.destroy(),this.#u=null,this.#d=null,this.#j=!1)},0)}attributeChangedCallback(e,t,n){if(this.#j)switch(e){case`theme`:this.#U();break;case`height`:this.#W();break;case`readonly`:this.#u?.setReadOnly(n!==null);break;case`stdin`:this.#c.hidden=n===null&&!this.#l.value;break;case`entry`:this.#B();break;case`language`:this.#f=null,this.#p=null,this.#b=!1,this.#F().catch(()=>{})}}#M(){this.#j=!0,this.#h=L(this,I(this.language)),this.#m=this.#_??{...this.#h},this.#g=this.#R(),this.#N(),this.#U(),this.#W();let e=this.getAttribute(`persist`);this.#d=(async()=>{if(e&&this.#_==null){let t=await E(e).catch(()=>null),n=t==null?null:R(t,I(this.language));if(n){let e={};for(let t of Object.keys(this.#h))e[t]=n[t]??this.#h[t];this.#m=e,this.#g=this.#R()}}this.#B();let t=await p(this.language).catch(()=>null),n=t?await t.editorLanguage().catch(()=>null):null;this.#u=await o({parent:this.#t,doc:this.#m[this.#g]??``,name:this.#g,dark:this.#H(),readOnly:this.hasAttribute(`readonly`),language:n,onRun:()=>void this.run(),onChange:e=>this.#V(e)}),this.#_=null,this.#I()})(),this.#P()}#N(){let e=document.createElement(`style`);e.textContent=m;let t=document.createElement(`div`);t.className=`cp-root`,t.innerHTML=`
273
+ <div class="cp-toolbar">
274
+ <button class="cp-primary" part="run-button" data-action="run">Run</button>
275
+ <button class="cp-danger" part="stop-button" data-action="stop" hidden>Stop</button>
276
+ <button data-action="reset">Reset</button>
277
+ <span class="cp-spacer"></span>
278
+ <span class="cp-status" data-state="idle"></span>
279
+ </div>
280
+ <div class="cp-progress" hidden></div>
281
+ <div class="cp-tabs" part="tabs" hidden></div>
282
+ <div class="cp-editor"></div>
283
+ <div class="cp-stdin" hidden>
284
+ <label>Standard input — one value per line</label>
285
+ <textarea rows="2" spellcheck="false"></textarea>
286
+ </div>
287
+ <pre class="cp-output" part="output" hidden></pre>`,this.#e.replaceChildren(e,t),this.#n=t.querySelector(`[data-action="run"]`),this.#r=t.querySelector(`[data-action="stop"]`),this.#i=t.querySelector(`[data-action="reset"]`),this.#a=t.querySelector(`.cp-status`),this.#o=t.querySelector(`.cp-progress`),this.#v=t.querySelector(`.cp-tabs`),this.#t=t.querySelector(`.cp-editor`),this.#c=t.querySelector(`.cp-stdin`),this.#l=t.querySelector(`.cp-stdin textarea`),this.#s=t.querySelector(`.cp-output`),this.#c.hidden=!this.hasAttribute(`stdin`),this.#l.addEventListener(`input`,()=>this.#c.classList.remove(`cp-attention`)),this.#v.addEventListener(`click`,e=>{let t=e.target.closest(`button[data-file]`);t&&this.openFile(t.getAttribute(`data-file`))}),this.#n.addEventListener(`click`,()=>void this.run()),this.#r.addEventListener(`click`,()=>this.stop()),this.#i.addEventListener(`click`,()=>this.reset());let n=()=>void this.#F().catch(()=>{});this.#t.addEventListener(`pointerdown`,n,{once:!0}),this.#t.addEventListener(`focusin`,n,{once:!0})}#P(){this.#x||typeof IntersectionObserver>`u`||(this.#x=new IntersectionObserver(e=>{e.some(e=>e.isIntersecting)&&(this.#x?.disconnect(),this.#x=null,this.#F().then(()=>{this.hasAttribute(`autorun`)&&this.run()}).catch(()=>{}))},{rootMargin:`300px`}),this.#x.observe(this))}#F(){return this.#p||=(async()=>{let e=await p(this.language);this.#f=e,e.ready||(this.#o.hidden=!1,this.#G(`Loading ${e.label}…`,`busy`));try{await e.load(e=>{this.#y||this.#G(e.message,e.phase===`ready`?`ok`:`busy`)})}catch(e){this.#p=null,this.#G(`Runtime unavailable`,`error`);let t=e instanceof Error?e.message:String(e);throw this.#q(t+`
288
+ `,`cp-err`),this.#s.hidden=!1,e}finally{this.#o.hidden=!0}return this.#I(),this.#b||(this.#b=!0,this.#G(`${e.label} ready`,`ok`),this.#$(`py-ready`,{language:e.id,label:e.label})),e})(),this.#p}async#I(){if(!this.#u)return;let e=this.#g,t=await _(e);if(t){this.#g===e&&this.#u?.setLanguage(t);return}let n=e.includes(`.`)?null:await(this.#f??await p(this.language).catch(()=>null))?.editorLanguage().catch(()=>null);this.#g===e&&this.#u?.setLanguage(n??[])}#L(){if(this.#u){this.#u.setCode(this.#m[this.#g]??``);return}this.#d?.then(()=>{this.#u?.setCode(this.#m[this.#g]??``),this.#B()})}#R(){let e=Object.keys(this.#m),t=this.getAttribute(`entry`);if(t&&e.includes(t))return t;let n=I(this.language);return e.includes(n)?n:e[0]??n}#z(){let e={...this.#m};if(this.#u)for(let t of Object.keys(e))e[t]=this.#u.fileCode(t,e[t]);return e}#B(){let e=Object.keys(this.#m);if(this.#v.hidden=e.length<2,this.#v.hidden){this.#v.replaceChildren();return}let t=this.#R();this.#v.replaceChildren(...e.map(e=>{let n=document.createElement(`button`);return n.dataset.file=e,n.textContent=e,n.setAttribute(`aria-pressed`,String(e===this.#g)),e===t&&(n.classList.add(`cp-entry`),n.title=`entry point — this is the file Run executes`),n}))}#V(e){this.#m[this.#g]=e;let t=this.getAttribute(`persist`);if(!t)return;this.#w&&clearTimeout(this.#w);let n=JSON.stringify(this.#z());this.#w=setTimeout(()=>void T(t,n).catch(()=>{}),400)}#H(){let e=this.getAttribute(`theme`)??`auto`;return e===`dark`||e!==`light`&&!!this.#S?.matches}#U(){!this.#S&&typeof matchMedia==`function`&&(this.#S=matchMedia(`(prefers-color-scheme: dark)`),this.#S.addEventListener(`change`,this.#C));let e=this.#H();this.setAttribute(`data-resolved-theme`,e?`dark`:`light`),this.#u?.setTheme(e)}#W(){let e=this.getAttribute(`height`);e&&this.style.setProperty(`--cp-height`,/^\d+$/.test(e)?`${e}px`:e)}#G(e,t){this.#a.textContent=e,this.#a.dataset.state=t}#K(){this.#k&&clearTimeout(this.#k),this.#k=null,this.#E=[],this.#A=0,this.#s.replaceChildren(),this.#T=!0}#q(e,t){if(!e)return;let n=t===`cp-err`&&!this.#T?`\n${e}`:e;this.#T=n.endsWith(`
289
+ `),this.#E.push({text:n,className:t}),this.#k??=setTimeout(()=>this.#J(),16)}#J(){if(this.#k&&clearTimeout(this.#k),this.#k=null,!this.#E.length)return;let e=this.#E;this.#E=[];let t=document.createDocumentFragment(),n=``,r,i=()=>{if(!n)return;let e=document.createElement(`span`);r&&(e.className=r),e.textContent=n,t.appendChild(e),n=``};for(let t of e){if(this.#A>=N)break;let e=t.text;this.#A+e.length>N&&(e=e.slice(0,N-this.#A)+`
290
+ … output truncated for display — the full text is in the py-output event
291
+ `),this.#A+=t.text.length,r!==t.className&&(i(),r=t.className),n+=e}i(),this.#s.hidden=!1;let a=this.#s.querySelector(`.cp-prompt`);a?this.#s.insertBefore(t,a):this.#s.appendChild(t),this.#s.scrollTop=this.#s.scrollHeight}#Y(){return this.#J(),this.#X(null),new Promise(e=>{let t=document.createElement(`form`);t.className=`cp-prompt`;let n=document.createElement(`input`);n.type=`text`,n.setAttribute(`aria-label`,`Program input — press Enter to send`),n.autocapitalize=`off`,n.autocomplete=`off`,n.spellcheck=!1;let r=document.createElement(`button`);r.type=`submit`,r.className=`cp-send`,r.textContent=`⏎`,r.title=`Send this line (Enter)`;let i=document.createElement(`button`);i.type=`button`,i.className=`cp-eof`,i.textContent=`EOF`,i.title=`End of input (Ctrl-D) — makes input() raise EOFError`;let a=n=>{this.#D===e&&(this.#D=null,this.#O=null,t.remove(),n===null?this.#q(`
292
+ `,`cp-in`):this.#q(n+`
293
+ `,`cp-in`),this.#J(),e(n))};t.addEventListener(`submit`,e=>{e.preventDefault(),a(n.value)}),i.addEventListener(`click`,()=>a(null)),n.addEventListener(`keydown`,e=>{(e.key===`Escape`||e.key===`d`&&e.ctrlKey)&&(e.preventDefault(),a(null))}),t.append(n,r,i),this.#s.hidden=!1,this.#s.appendChild(t),this.#s.scrollTop=this.#s.scrollHeight,this.#D=e,this.#O=a,n.focus({preventScroll:!0})})}#X(e){this.#O?.(e),this.#O=null,this.#D=null}#Z(e){this.#J();let t=document.createElement(`div`);t.className=`cp-hint`,t.textContent=e,this.#s.hidden=!1,this.#s.appendChild(t),this.#s.scrollTop=this.#s.scrollHeight,this.#c.hidden=!1,this.#c.classList.add(`cp-attention`)}#Q(e){this.#J();let t=document.createElement(`table`);t.className=`cp-table`;let n=t.createTHead().insertRow();for(let t of e.columns){let e=document.createElement(`th`);e.textContent=t,n.appendChild(e)}let r=t.createTBody();for(let t of e.rows){let e=r.insertRow();for(let n of t)e.insertCell().textContent=n==null?``:String(n)}this.#s.hidden=!1,this.#s.appendChild(t)}#$(e,t){this.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,composed:!0}))}};function V(e=j){typeof window>`u`||typeof customElements>`u`||customElements.get(e)||customElements.define(e,B)}V();export{B as CodePlayPadElement,a as PYODIDE_VERSION,i as RunStopped,e as WorkerUnavailable,A as allProgress,D as clearSnippet,t as configurePython,r as configureTypeScript,o as createEditor,V as defineCodePlayPad,k as getProgress,p as getRuntime,f as listRuntimes,E as loadSnippet,n as pyodideAssetUrls,d as registerRuntime,T as saveSnippet,O as setProgress};
@@ -0,0 +1,3 @@
1
+ /** Shadow DOM CSS. Isolation runs both ways: the page cannot restyle the
2
+ * widget, and the widget cannot leak into the page. */
3
+ export declare const STYLES: string;