Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d68b037
feat(docs): add JavaScript language documentation
m2y11138 Nov 10, 2025
66d2012
feat(livecodes/reveal.js): integrate livecodes with reveal.js plugin
m2y11138 Nov 12, 2025
c87b8da
feat(reveal): implement LiveCodes SDK core logic
m2y11138 Nov 13, 2025
2b8cde3
docs(reveal): add SDK usage documentation
m2y11138 Nov 13, 2025
0c629a6
test(reveal): add tests for LiveCodes SDK and iframe styling
m2y11138 Nov 13, 2025
7b322be
Keep the state in sync with upstream.
m2y11138 Nov 13, 2025
8be3f2b
style: format code according to Prettier
m2y11138 Nov 13, 2025
6810593
fix: correct package.json jsdelivr entry and update related documenta…
m2y11138 Nov 14, 2025
a6041b9
fix: correct package.json jsdelivr entry and update related documenta…
m2y11138 Nov 14, 2025
97a6504
fix: correct package.json jsdelivr entry and update related documenta…
m2y11138 Nov 14, 2025
73155ad
sync with the upstream
m2y11138 Nov 14, 2025
46168ce
fix(build): fix bug in build object parameters
m2y11138 Nov 14, 2025
5b6aef3
fix(docs): fix documentation errors
m2y11138 Nov 14, 2025
1d48425
test: improve functional tests
m2y11138 Nov 14, 2025
7c1dc7a
refactor(tests): extract helper functions to reduce duplication
m2y11138 Nov 14, 2025
42f9b6a
refactor(tests): extract helper functions to reduce duplication
m2y11138 Nov 14, 2025
07e3b8d
refactor(tests): extract helper functions to reduce duplication
m2y11138 Nov 14, 2025
26ae65e
refactor(tests): extract helper functions to reduce duplication
m2y11138 Nov 14, 2025
21b3768
refactor(tests): extract helper functions to reduce duplication
m2y11138 Nov 14, 2025
ced4f51
style: format reveal.test.ts with Prettier
m2y11138 Nov 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/docs/languages/javascript.mdx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# JavaScript

TODO...
TODO...
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Complete or remove placeholder documentation.

This file contains only "TODO..." which appears to be incomplete. If this is unrelated to the Reveal.js integration PR, consider removing this change from the PR to keep it focused.

If you need the JavaScript documentation completed, I can help generate appropriate content for this page.

πŸ€– Prompt for AI Agents
In docs/docs/languages/javascript.mdx lines 1-3, the file contains only a
placeholder "TODO..." which is incomplete and unrelated to the Reveal.js
integration PR; either remove this file change from the PR or replace the
placeholder with minimal, relevant JavaScript documentation for the docs site.
If removing: revert the file or remove it from the commit/PR. If keeping:
replace the placeholder with a short page summary describing the JavaScript
language docs purpose, primary supported features, and links to related pages
(e.g., setup, examples, Reveal.js notes) so the page is meaningful and
review-ready.

161 changes: 161 additions & 0 deletions docs/docs/sdk/reveal.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Reveal SDK

import LiveCodes from '../../src/components/LiveCodes.tsx';

The Reveal.js SDK is a lightweight plugin that integrates the JavaScript SDK into Reveal.js, allowing you to embed interactive playgrounds directly within your slides.

It has a very simple [implementation](https://github.com/live-codes/livecodes/blob/develop/src/sdk/reveal.ts) which you can easily modify in case you need.

## Installation

Please refer to the [SDK installation](./index.mdx#installation) section.

## Usage

To provide a mounting container, you just need to add the attribute data-livecodes to your container element, and then import the LiveCodes script.

```html
<div data-livecodes></div>
```

There are two ways you can import the LiveCodes script

1. Using a `<script>` tag

```html
<script src="https://cdn.jsdelivr.net/npm/reveal.js/dist/reveal.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/reveal.umd.js"></script>

<script>
Reveal.initialize({
plugins: [LiveCodes],
});
</script>
```

2. Using an ES module `import` statement
```js
import Reveal from "reveal.js";
import { LiveCodes } from "reveal.js-plugin-livecodes";

Reveal.initialize({
plugins: [LiveCodes],
});
```

### TypeScript Support

TypeScript types are exported from this module.

`LiveOptions` – Configuration options for an individual playground, including the optional sdkReady callback.

`GlobalLiveCodesOptions` – Global configuration for LiveCodes when used with Reveal.js, including optional customStyle.

`LiveCodesInstance` – The LiveCodes object itself, containing an id and an init method for initializing with a Reveal.js deck.

This allows TypeScript projects to import these types directly for full type safety and autocompletion:

```ts
import type { LiveOptions, GlobalLiveCodesOptions, LiveCodesInstance } from './node_modules/livecodes/reveal.js';
const myPlaygroundOptions: LiveOptions = {
sdkReady: (sdk) => {
console.log("Playground initialized:", sdk);
},
theme: "dark",
};

const deckOptions: GlobalLiveCodesOptions = {
livecodes: myPlaygroundOptions,
customStyle: {
border: "1px solid #ddd",
borderRadius: "8px",
},
controls: true,
slideNumber: true,
};
```

### Config

All [embed options](js-ts.mdx#embed-options) are available as config object with the corresponding key-values. If you don’t specify it, the default configuration object will be used.

Example:

```js
import { LiveCodes } from "./node_modules/livecodes/reveal.js";

const deck = new Reveal({
plugins: [LiveCodes, Markdown],
livecodes: {
markup: {
language: "markdown",
content: "# hello World!",
},
sdkReady: (item) => {
console.log(item);
},
}
});

deck.initialize();
```

You can provide an optional `sdkReady?: (sdk: Playground) => void` property, which will be called as a callback function after the initialization is complete. A callback function, that is provided with an instance of the JavaScript SDK representing the current playground. This allows making use of full capability of the SDK by calling SDK methods.

In addition, you can also pass a CSS object `customStyle` to specify the CSS properties of the editor.

Example:

```js
import { LiveCodes } from "./node_modules/livecodes"/reveal.js";

const deck = new Reveal({
plugins: [LiveCodes, Markdown],
livecodes: {
markup: {
language: "markdown",
content: "# hello World!",
},
},
customStyle: { border: "5px solid pink", borderRadius: "8px" },
});

deck.initialize();
```

The CSS properties in customStyle will be applied directly to the embedded iframe. For example, with the settings above, you will see rounded corners and a pink border on the iframe.

:::info
The customStyle object changes the CSS properties of the embedded iframe itself, not the outer container’s CSS properties.
:::

If you want to apply specific configurations to a particular LiveCode editor, you can write a stringified object that conforms to [JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#:~:text=The%20JSON.parse()%20static,object%20before%20it%20is%20returned.) into the data-config attribute of its container element.

Example:
```html
<section>
Slide 1
<div
data-livecodes
data-config='{"script":{"language":"javascript","content":"console.log(123)"}}'
></div>
</section>
```

## Demo

export const sdkDemo = {
html:'<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js/dist/reveal.css"/>\n<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js/dist/theme/black.css"/>\n<div class="reveal">\n <div class="slides">\n <section>Slide 1\n <div data-livecodes data-config=\'{"script":{"language":"javascript","content":"console.log(123)"}}\'></div>\n </section>\n <section>Slide 2\n <div data-livecodes></div>\n </section>\n </div>\n</div>\n<script src="https://cdn.jsdelivr.net/npm/reveal.js/dist/reveal.js"></script>\n<script src="https://cdn.jsdelivr.net/npm/[email protected]/reveal.umd.js"></script>\n<script>\n async function init() {\n const res = await Reveal.initialize({\n plugins: [LiveCodes],\n livecodes: {\n markup: {\n language: "markdown",\n content: "# Hello World!",\n },\n },\n customStyle: {\n backgroundColor: "rgba(255, 255, 255, 0.1)",\n },\n });\n }\n init();\n</script>'
};

<LiveCodes params={sdkDemo} height="80vh"/>

## Related

- [SDK Installation](./index.mdx#installation)
- [JS/TS SDK](./js-ts.mdx)
- [Vue SDK](./vue.mdx)
- [React SDK](./react.mdx)
- [Using SDK in Svelte](./svelte.mdx)
- [Using SDK in Solid](./solid.mdx)
- [Embedded Playgrounds](../features/embeds.mdx)
2 changes: 1 addition & 1 deletion docs/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const sidebars: SidebarsConfig = {
type: 'doc',
id: 'sdk/index',
},
items: ['sdk/js-ts', 'sdk/react', 'sdk/vue', 'sdk/svelte', 'sdk/solid', 'sdk/headless'],
items: ['sdk/js-ts', 'sdk/react', 'sdk/vue', 'sdk/svelte', 'sdk/solid', 'sdk/headless', "sdk/reveal"],
},
{
type: 'category',
Expand Down
27 changes: 27 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 24 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"monaco-editor": "0.48.0",
"patch-package": "7.0.2",
"prismjs": "1.29.0",
"reveal.js": "^5.2.1",
"split.js": "1.6.5",
"yjs": "13.5.40"
},
Expand All @@ -110,6 +111,7 @@
"@types/prettier": "2.1.6",
"@types/prismjs": "1.16.3",
"@types/react": "19.0.10",
"@types/reveal.js": "^5.2.1",
"@typescript-eslint/eslint-plugin": "8.24.1",
"@typescript-eslint/parser": "8.24.1",
"@typescript/vfs": "1.5.3",
Expand Down Expand Up @@ -158,15 +160,32 @@
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"plugins": ["prettier-plugin-organize-imports"]
"plugins": [
"prettier-plugin-organize-imports"
]
},
"jest": {
"preset": "ts-jest",
"testEnvironment": "jsdom",
"setupFiles": ["<rootDir>/.jest/setup.ts"],
"testPathIgnorePatterns": ["/node_modules/", "/build/", "/src/modules/"],
"collectCoverageFrom": ["src/**/*.ts", "!**/build/**", "!**/vendor/**", "!src/modules/**"],
"coverageReporters": ["json", "html", "lcov"],
"setupFiles": [
"<rootDir>/.jest/setup.ts"
],
"testPathIgnorePatterns": [
"/node_modules/",
"/build/",
"/src/modules/"
],
"collectCoverageFrom": [
"src/**/*.ts",
"!**/build/**",
"!**/vendor/**",
"!src/modules/**"
],
"coverageReporters": [
"json",
"html",
"lcov"
],
"resolveJsonModule": true
}
}
13 changes: 13 additions & 0 deletions scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@ const sdkBuild = async () => {
'@vue/runtime-core': 'vue',
},
}),
esbuild.build({
...sdkOptions,
entryPoints: [sdkSrcDir + 'reveal.ts'],
outdir: undefined,
outfile: path.resolve(outDir, sdkOutDir, 'reveal.umd.js'),
format: 'iife',
}),
esbuild.build({
...sdkOptions,
entryPoints: [sdkSrcDir + 'reveal.ts'],
outdir: undefined,
outfile: path.resolve(outDir, sdkOutDir, 'reveal.js'),
}),
]);
};

Expand Down
51 changes: 51 additions & 0 deletions src/sdk/__tests__/reveal.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { createPlayground } from '../index';
import { LiveCodes } from '../reveal';

jest.mock('../index', () => ({
createPlayground: jest.fn().mockImplementation((container) => {
const iframe = document.createElement('iframe');
iframe.className = 'livecodes';
container.appendChild(iframe);
return Promise.resolve({ playground: 'mocked' });
}),
}));

beforeEach(() => {
document.body.innerHTML = '';
jest.clearAllMocks();
});

test('should do nothing when no [data-livecodes] element exists', async () => {
const mockDeck = { getConfig: jest.fn().mockReturnValue({ livecodes: {} }) } as any;
LiveCodes.init(mockDeck);
expect(createPlayground).not.toHaveBeenCalled();
});

test('should initializes playground and triggers sdkReady when a livecodes container with config exists', async () => {
const sdkReady = jest.fn();
const container = document.createElement('div');
container.dataset.livecodes = '';
container.dataset.config = '{"script":{"language":"javascript","content":"console.log(123)"}}';
document.body.appendChild(container);
const mockDeck = {
getConfig: jest
.fn()
.mockReturnValue({
livecodes: { markup: { language: 'markdown', content: '# Hello world' }, sdkReady },
customStyle: { backgroundColor: 'rgba(255,255,255,0.1)' },
}),
} as any;
LiveCodes.init(mockDeck);
await new Promise(process.nextTick);
expect(createPlayground).toHaveBeenCalledTimes(1);
expect(sdkReady).toHaveBeenCalledTimes(1);
const calledWith = (createPlayground as jest.Mock).mock.calls[0][1];
const iframe = document.querySelector('.livecodes') as HTMLIFrameElement | null;
expect(calledWith.config.script.language).toBe('javascript');
expect(calledWith.config.script.content).toBe('console.log(123)');
expect(calledWith.config.markup.language).toBe('markdown');
expect(calledWith.config.markup.content).toBe('# Hello world');
expect(iframe?.style.maxWidth).toBe('100%');
expect(iframe?.style.maxHeight).toBe('100%');
expect(iframe?.style.backgroundColor).toBe('rgba(255, 255, 255, 0.1)');
});
1 change: 1 addition & 0 deletions src/sdk/package.sdk.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"module": "./livecodes.js",
"browser": "./livecodes.js",
"types": "./livecodes.d.ts",
"jsdelivr": "./livecodes.js",
"exports": {
".": {
"import": "./livecodes.js",
Expand Down
Loading
Loading