1.2.5 • Published 6 months ago

javascript-playgrounds v1.2.5

Weekly downloads
2,715
License
BSD-3-Clause
Repository
github
Last release
6 months ago

Overview

This project provides a quick, visual way to experiment with JavaScript code. It's designed to be loaded as an iframe for easy inclusion in any webpage.

There are a variety of configuration options, including a React preset and a React Native preset.

I use this sandbox in my free educational guides:

Usage

The sandbox may be included on your site in one of two ways:

For legacy React Native-specific docs, see the v1 branch

As a React Component

If you're using React:

npm install --save javascript-playgrounds

# or

yarn add javascript-playgrounds

Then:

import Playground from 'javascript-playgrounds'

export default function App() {
  return <Playground style={{ width: 800, height: 500 }} />
}

This component is a wrapper around the iframe that handles encoding parameters for you. While it passes most props along to the iframe, it has a few extra props:

TitleDescriptionDefault
styleThe style of the div which wraps the iframe (the iframe has 100% width and height).undefined
classNameThe className of the div which wraps the iframeundefined
baseURLOptionally, specify a custom url to load the player from. This url should not include a hash.unpkg.com (see unpkg)

As an iframe

If you're not using React, include the sandbox in an iframe.

<iframe
  width="880"
  height="425"
  frameborder="0"
  src="//unpkg.com/javascript-playgrounds@^1.0.0/public/index.html"
></iframe>

Configuration parameters should be passed as part of the hash string, after #data=. They should be JSON-encoded and then URI-encoded:

const parameters = { code: `console.log('Hello, world!')` }
const hashString = '#data=' + encodeURIComponent(JSON.stringify(parameters))

When used as an iframe, the easiest way to set the code parameter is to edit the code in the sandbox and copy and paste the url when you're done (the url updates automatically as you type).

For convenience, you may optionally pass the preset parameter in the url string directly, e.g. #preset=react&data=....

Parameters

The sandbox accepts the following props/parameters.

TitleDescriptionDefault
presetThis sets reasonable defaults for other parameters. Options are javascript, react, and react-native. Experimental options are html and python (make sure to lock down your javascript-playgrounds library version when using experimental presets).'javascript'
titleAn optional title for the editor pane.''
codeThe code to show/run in the player.The sample app
filesA map of { [filename]: code }. This will take precedence over code if given.undefined
entryThe filename of the file that runs first. This is only relevant when showing multiple files with the files parameter. Defaults to index.js, or index.tsx if TypeScript is enabled.'index.js' or 'index.tsx'
initialTabThe filename of the tab to show by default. This is only relevant when showing multiple files with the files parameter. Defaults to the value of entry.entry
modulesAn array of external modules to make available to the sandbox. Each object in the array should be an object containing a name and url. As a shorthand, pass a string name to load a module from unpkg (https://unpkg.com/${name}). More detail below.[]
cssAn optional CSS string to apply within the workspace iframe.''
stylesAn map of inline style objects, applied to various elements to customize the style of the UI. Example: { header: { backgroundColor: 'red' } }{}
stringsA map of strings that appear in the UI. Example: { loading: 'Loading dependencies...' }{}
sharedEnvironmentThis affects how the iframes share data with one another, mainly for the "playgrounds" feature. When true, iframes will pass JavaScript objects back and forth, while when false, they'll pass serialized JSON.false
detectDependenciesShould the player scan code files for imports and try to fetch them from unpkg? Only modules imported in the initial code are fetched (not those added while typing in the sandbox).true
fullscreenShow a button to enable fullscreen editing (in most configurations of panes). Note that the iframe must have the allowfullscreen attribute for this to work.false
compilerSettings for Babel{}
compiler.maxLoopIterationsThrow an error if a loop iterates more than a certain amount of times. Set to 0 to disable.1000
playgroundSettings for playgrounds (inline widgets that display runtime values){}
playground.enabledTurn on playgrounds?false
playground.renderReactElementsRender React elements? If false, will print the React element object, e.g. { type, props, key }, rather than render it.true
playground.debounceDurationHow frequently widgets update. A little delay helps keep the UI feeling smoother.200 (milliseconds)
typescriptTypeScript settings{}
typescript.enabledTurn on TypeScript hover tooltip info? Defaults to falsefalse
typescript.libsAn array of default libraries to include, e.g. 'dom' and 'es2015'. We don't include some newer/esoteric ones by default, to reduce download size.See source code
typescript.typesAn array of additional type files to download. Each should be an object { name, url }.[]
workspacesAdd a tutorial-like sequence of sets of files, highlighting changes between each set. Each object in this array can contain: { title, description, workspace: { title, files, entry, initialTab } }. Properties in the workspace object will override those given as top level parameters.[]
panesAn array of UI panes to display. To display a pane without options, use a string. Otherwise, use an object with a type property. The available panes are: 'stack', 'editor', 'transpiler', 'player', 'workspaces', 'console'. Note that there must be a player pane for any code to run. For pane options, see below.['editor', 'player']
responsivePaneSetsAn array of { maxWidth, panes } objects to show at different responsive breakpoints. The iframe will use the first set where the maxWidth is greater than the current window width. The top-level panes parameter has maxWidth: Infinity so that it's used by default if there's no matching set of panes.[]
targetOriginIf passed, the sandbox will call parent.postMessage(JSON.stringify(data), targetOrigin) on code changes.undefined
Examples of loading modules:
  • To load a CommonJS require-style module, the name is the require(name) name, and the second is the source url. E.g. to load moment.js: set modules to the value [{ name: 'moment', url: 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.14.1/moment.min.js' }]
  • To load a component as a property on window, also pass a globalName, which will be the window property name (e.g. window.moment). E.g. to load moment.js this way: set modules to the value [{ name: 'moment', globalName: 'moment', url: 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.14.1/moment.min.js' }]

Pane options

All panes support the following options:

TitleDescriptionDefault
styleThe inline styles for this specific pane, merged with those passed in the top-level styles object if given.undefined
titleAn optional title for this pane. If used on an 'editor' pane, this will override a top-level title, if one was given.''

Each pane additionally supports pane-specific options. For more detail:

The player pane

Display the running app, optionally with the image of a phone around it.

TitleDescriptionDefault
platformOne of ios, android, or web. When web, no phone image is displayed.'ios'
widthThe width of the device. This has no effect if the platform is web.210px
scaleZoom the device screen. This has no effect if the platform is web.1
assetRootSpecifies the root url for asset requires. E.g. to require http://localhost:8080/images/hello.png, you could set assetRoot to 'http://localhost:8080/' and write require('./images/hello.png') in your code.''
cssAn optional CSS string to apply within the player's iframe.''
styleSheetOne of reset or none. When reset, the meyerweb CSS reset is applied to the player's iframe.'reset'
statusBarHeightDisplay a rectangle at the top of the phone screen, mimicking a status bar.0px
statusBarColorThe color of the fake status bar.'black'
preludeJavaScript code that runs before the entry file.''
modulesPane-specific modules, in addition to those passed at the top level.[]
consoleDisplay an embedded console in this pane. See the console options below. Additionally, the embedded version of the console has the following properties...{}
console.visibleShow the console?false
console.maximizedShow the console over the entire player?false
console.collapsibleAllow collapsing the console via a toggle button.true

The console pane

Show the output console.log, similar to the Chrome inspector. This can be a separate pane, or embedded in the player pane.

TitleDescriptionDefault
showFileNameShow the file name containing the console.log.false
showLineNumberShow the line number of the console.log.true
renderReactElementsRender React elements, instead of displaying element JSON.false

The stack pane

A nested stack of panes.

TitleDescriptionDefault
childrenAn array of panes, just like the top level panes parameter.[]

The editor pane

None at the moment.

The transpiler pane

None at the moment.

The workspaces pane

None at the moment.

Hosting

This project contains static assets that run standalone in the browser. You don't need a server, unless you want to host the assets yourself.

unpkg

The recommended host is https://unpkg.com, which is a CDN that serves content from the npm registry. The examples in this README all point to:

<iframe
  width="880"
  height="425"
  frameborder="0"
  src="//unpkg.com/javascript-playgrounds@^1.0.0/public/index.html"
></iframe>

Note that unpkg resolves semver versions in the url

Examples

These examples were created by loading the demo page and running roughly the following JS in the console:

location.href.slice(0, location.href.indexOf('#')) +
  '#data=' +
  encodeURIComponent(
    JSON.stringify({
      title: 'Custom title',
      panes: [
        'editor',
        { type: 'player', platform: 'android', modules: ['moment'] },
      ],
    })
  )

Development

Run

yarn
yarn dev
# => localhost:8080

Build

yarn build

Contributing

Contributions are welcome, but if you're planning to add features, I recommend opening an issue describing the change first.

I maintain this project specifically for my educational guides, so if it's a feature I wouldn't use, I might not want to maintain it. It also may take me a little while to get to reviewing.

License

3-Clause BSD

https://opensource.org/licenses/BSD-3-Clause

1.2.5

6 months ago

1.2.0

2 years ago

1.2.3

2 years ago

1.2.2

2 years ago

1.2.1

2 years ago

1.1.4

3 years ago

1.1.3

3 years ago

1.1.2

3 years ago

1.1.1

3 years ago

1.1.0

4 years ago

1.0.5

4 years ago

1.0.4

4 years ago

1.0.3

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago

0.1.4

4 years ago

0.1.6

4 years ago

0.1.5

4 years ago

0.1.3

4 years ago

0.1.0

4 years ago

0.1.1

4 years ago

0.0.1

4 years ago