docusaurus-live-brython 3.0.0-beta.11 → 3.0.0-beta.5
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.
- package/lib/index.d.ts +7 -0
- package/lib/index.js +0 -15
- package/lib/theme/CodeBlock/index.jsx +2 -2
- package/lib/theme/CodeEditor/Actions/DownloadCode.jsx +2 -2
- package/lib/theme/CodeEditor/Actions/Reset.jsx +2 -2
- package/lib/theme/CodeEditor/Actions/RunCode.d.ts +1 -1
- package/lib/theme/CodeEditor/Actions/RunCode.jsx +2 -2
- package/lib/theme/CodeEditor/Actions/ShowRaw.jsx +2 -2
- package/lib/theme/CodeEditor/Actions/ShowSyncStatus.jsx +3 -3
- package/lib/theme/CodeEditor/BrythonCommunicator.jsx +2 -2
- package/lib/theme/CodeEditor/Button/index.d.ts +2 -2
- package/lib/theme/CodeEditor/Button/index.jsx +1 -1
- package/lib/theme/CodeEditor/CodeHistory/index.jsx +2 -2
- package/lib/theme/CodeEditor/Editor/EditorAce.jsx +2 -2
- package/lib/theme/CodeEditor/Editor/Header/index.d.ts +1 -1
- package/lib/theme/CodeEditor/Editor/Header/index.jsx +6 -6
- package/lib/theme/CodeEditor/Editor/Result/Graphics/Canvas.d.ts +2 -2
- package/lib/theme/CodeEditor/Editor/Result/Graphics/Canvas.jsx +7 -7
- package/lib/theme/CodeEditor/Editor/Result/Graphics/Turtle.d.ts +2 -2
- package/lib/theme/CodeEditor/Editor/Result/Graphics/Turtle.jsx +8 -8
- package/lib/theme/CodeEditor/Editor/Result/Graphics/index.d.ts +3 -3
- package/lib/theme/CodeEditor/Editor/Result/Graphics/index.jsx +6 -6
- package/lib/theme/CodeEditor/Editor/Result/index.d.ts +3 -1
- package/lib/theme/CodeEditor/Editor/Result/index.jsx +3 -2
- package/lib/theme/CodeEditor/Editor/index.d.ts +1 -1
- package/lib/theme/CodeEditor/Editor/index.jsx +11 -11
- package/lib/theme/CodeEditor/Editor/utils/saveSvg.js +1 -1
- package/lib/theme/CodeEditor/Icon/index.d.ts +2 -2
- package/lib/theme/CodeEditor/Icon/index.jsx +1 -1
- package/lib/theme/CodeEditor/WithScript/Storage.d.ts +1 -1
- package/lib/theme/CodeEditor/WithScript/Store.d.ts +7 -1
- package/lib/theme/CodeEditor/WithScript/Store.jsx +235 -2
- package/lib/theme/CodeEditor/WithScript/Types.d.ts +0 -1
- package/lib/theme/CodeEditor/index.d.ts +3 -3
- package/lib/theme/CodeEditor/index.jsx +6 -6
- package/lib/types.d.ts +28 -0
- package/lib/types.js +1 -0
- package/package.json +20 -74
- package/src/index.ts +0 -10
- package/src/theme/CodeBlock/index.tsx +3 -2
- package/src/theme/CodeEditor/Actions/DownloadCode.tsx +2 -2
- package/src/theme/CodeEditor/Actions/Reset.tsx +2 -2
- package/src/theme/CodeEditor/Actions/RunCode.tsx +3 -3
- package/src/theme/CodeEditor/Actions/ShowRaw.tsx +2 -2
- package/src/theme/CodeEditor/Actions/ShowSyncStatus.tsx +3 -3
- package/src/theme/CodeEditor/BrythonCommunicator.tsx +3 -3
- package/src/theme/CodeEditor/Button/index.tsx +3 -3
- package/src/theme/CodeEditor/CodeHistory/index.tsx +2 -2
- package/src/theme/CodeEditor/Editor/EditorAce.tsx +2 -2
- package/src/theme/CodeEditor/Editor/Header/index.tsx +7 -7
- package/src/theme/CodeEditor/Editor/Result/Graphics/Canvas.tsx +7 -7
- package/src/theme/CodeEditor/Editor/Result/Graphics/Turtle.tsx +8 -8
- package/src/theme/CodeEditor/Editor/Result/Graphics/index.tsx +7 -7
- package/src/theme/CodeEditor/Editor/Result/index.tsx +6 -2
- package/src/theme/CodeEditor/Editor/index.tsx +15 -13
- package/src/theme/CodeEditor/Editor/utils/saveSvg.ts +1 -1
- package/src/theme/CodeEditor/Editor/utils/svgWithoutAnimations.ts +1 -1
- package/src/theme/CodeEditor/Icon/index.tsx +2 -2
- package/src/theme/CodeEditor/WithScript/Storage.ts +1 -1
- package/src/theme/CodeEditor/WithScript/Store.tsx +269 -3
- package/src/theme/CodeEditor/WithScript/Types.ts +0 -1
- package/src/theme/CodeEditor/index.tsx +8 -8
- package/src/types.ts +29 -0
- package/lib/theme/CodeEditor/WithScript/createStore.d.ts +0 -2
- package/lib/theme/CodeEditor/WithScript/createStore.js +0 -223
- package/lib/theme/CodeEditor/hooks/index.d.ts +0 -2
- package/lib/theme/CodeEditor/hooks/index.js +0 -2
- package/lib/theme/CodeEditor/hooks/useScript.d.ts +0 -4
- package/lib/theme/CodeEditor/hooks/useScript.js +0 -10
- package/lib/theme/CodeEditor/hooks/useStore.d.ts +0 -2
- package/lib/theme/CodeEditor/hooks/useStore.js +0 -4
- package/src/theme/CodeEditor/WithScript/createStore.ts +0 -247
- package/src/theme/CodeEditor/hooks/index.ts +0 -2
- package/src/theme/CodeEditor/hooks/useScript.ts +0 -15
- package/src/theme/CodeEditor/hooks/useStore.ts +0 -9
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { DOM_ELEMENT_IDS } from '
|
|
3
|
-
import
|
|
2
|
+
import { DOM_ELEMENT_IDS } from '../../../constants';
|
|
3
|
+
import GraphicsResult from '.';
|
|
4
4
|
import styles from './styles.module.css';
|
|
5
|
-
import { useScript, useStore } from '
|
|
6
|
-
import Button from '
|
|
5
|
+
import { useScript, useStore } from '../../../WithScript/Store';
|
|
6
|
+
import Button from '../../../Button';
|
|
7
7
|
|
|
8
8
|
const downloadCanvas = (canvasId: string) => {
|
|
9
9
|
const canvas = document.getElementById(canvasId) as HTMLCanvasElement;
|
|
@@ -25,13 +25,13 @@ const downloadCanvas = (canvasId: string) => {
|
|
|
25
25
|
document.body.removeChild(downloadLink);
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const
|
|
28
|
+
const CanvasResult = () => {
|
|
29
29
|
const { store } = useScript();
|
|
30
30
|
// const { codeId } = useStore(store, (state) => ({codeId: state.codeId}));
|
|
31
31
|
const codeId = useStore(store, (state) => state.codeId);
|
|
32
32
|
|
|
33
33
|
return (
|
|
34
|
-
<
|
|
34
|
+
<GraphicsResult
|
|
35
35
|
controls={
|
|
36
36
|
<Button
|
|
37
37
|
icon='Download'
|
|
@@ -58,4 +58,4 @@ const Canvas = () => {
|
|
|
58
58
|
)
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
-
export default
|
|
61
|
+
export default CanvasResult;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import styles from './styles.module.css';
|
|
3
|
-
import { DOM_ELEMENT_IDS } from '
|
|
4
|
-
import
|
|
5
|
-
import { saveSvg } from '
|
|
6
|
-
import { useScript, useStore } from '
|
|
7
|
-
import Button from '
|
|
3
|
+
import { DOM_ELEMENT_IDS } from '../../../constants';
|
|
4
|
+
import GraphicsResult from '.';
|
|
5
|
+
import { saveSvg } from '../../utils/saveSvg';
|
|
6
|
+
import { useScript, useStore } from '../../../WithScript/Store';
|
|
7
|
+
import Button, { Color } from '../../../Button';
|
|
8
8
|
import clsx from 'clsx';
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const TurtleResult = () => {
|
|
11
11
|
const { store } = useScript();
|
|
12
12
|
const codeId = useStore(store, (state) => state.codeId);
|
|
13
13
|
const code = useStore(store, (state) => state.code);
|
|
14
14
|
return (
|
|
15
|
-
<
|
|
15
|
+
<GraphicsResult
|
|
16
16
|
controls={
|
|
17
17
|
<React.Fragment>
|
|
18
18
|
<Button
|
|
@@ -45,4 +45,4 @@ const Turtle = () => {
|
|
|
45
45
|
)
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
export default
|
|
48
|
+
export default TurtleResult;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import styles from './styles.module.css';
|
|
3
|
-
import { DOM_ELEMENT_IDS } from '
|
|
3
|
+
import { DOM_ELEMENT_IDS } from '../../../constants';
|
|
4
4
|
import Draggable from 'react-draggable';
|
|
5
|
-
import { checkForButtonClick } from '
|
|
6
|
-
import { useScript, useStore } from '
|
|
7
|
-
import Button from '
|
|
5
|
+
import { checkForButtonClick } from '../../utils/checkForButtonClick';
|
|
6
|
+
import { useScript, useStore } from '../../../WithScript/Store';
|
|
7
|
+
import Button from '../../../Button';
|
|
8
8
|
import clsx from 'clsx';
|
|
9
|
-
|
|
9
|
+
interface Props {
|
|
10
10
|
controls?: JSX.Element;
|
|
11
11
|
main?: JSX.Element;
|
|
12
12
|
}
|
|
13
|
-
const
|
|
13
|
+
const GraphicsResult = (props: Props) => {
|
|
14
14
|
const { store } = useScript();
|
|
15
15
|
const codeId = useStore(store, (state) => state.codeId);
|
|
16
16
|
return (
|
|
@@ -44,4 +44,4 @@ const Graphics = (props: Props) => {
|
|
|
44
44
|
);
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
export default
|
|
47
|
+
export default GraphicsResult;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import styles from './styles.module.css';
|
|
3
|
+
// @ts-ignore
|
|
3
4
|
import CodeBlock from '@theme/CodeBlock';
|
|
4
|
-
import { useScript, useStore } from '
|
|
5
|
+
import { useScript, useStore } from '../../WithScript/Store';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
interface Props {
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const Result = (props: Props) => {
|
|
7
11
|
const { store } = useScript();
|
|
8
12
|
const logs = useStore(store, (state) => state.logs);
|
|
9
13
|
if (logs.length === 0) {
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
import styles from "./styles.module.css";
|
|
2
4
|
import {
|
|
3
5
|
DOM_ELEMENT_IDS,
|
|
4
|
-
} from "
|
|
5
|
-
import { useScript, useStore } from '
|
|
6
|
-
import Result from "
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import Header from "
|
|
11
|
-
import EditorAce from "
|
|
6
|
+
} from "../constants";
|
|
7
|
+
import { useScript, useStore } from '../WithScript/Store';
|
|
8
|
+
import Result from "./Result";
|
|
9
|
+
import TurtleResult from "./Result/Graphics/Turtle";
|
|
10
|
+
import CanvasResult from "./Result/Graphics/Canvas";
|
|
11
|
+
import GraphicsResult from "./Result/Graphics";
|
|
12
|
+
import Header from "./Header";
|
|
13
|
+
import EditorAce from "./EditorAce";
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
interface Props {
|
|
14
16
|
slim: boolean;
|
|
15
17
|
title: string;
|
|
16
18
|
resettable: boolean;
|
|
@@ -52,13 +54,13 @@ const Editor = (props: Props) => {
|
|
|
52
54
|
{isGraphicsmodalOpen && (
|
|
53
55
|
<>
|
|
54
56
|
{hasTurtleOutput && (
|
|
55
|
-
<
|
|
57
|
+
<TurtleResult />
|
|
56
58
|
)}
|
|
57
59
|
{hasCanvasOutput && (
|
|
58
|
-
<
|
|
60
|
+
<CanvasResult />
|
|
59
61
|
)}
|
|
60
62
|
{!hasCanvasOutput && !hasTurtleOutput && (
|
|
61
|
-
<
|
|
63
|
+
<GraphicsResult />
|
|
62
64
|
)}
|
|
63
65
|
</>
|
|
64
66
|
)}
|
|
@@ -68,4 +70,4 @@ const Editor = (props: Props) => {
|
|
|
68
70
|
);
|
|
69
71
|
};
|
|
70
72
|
|
|
71
|
-
export default Editor;
|
|
73
|
+
export default Editor;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import * as Icons from '
|
|
2
|
+
import * as Icons from './icons';
|
|
3
3
|
import styles from './styles.module.css';
|
|
4
4
|
import clsx from 'clsx';
|
|
5
5
|
|
|
@@ -13,7 +13,7 @@ export enum Color {
|
|
|
13
13
|
Link = 'var(--ifm-color-link)'
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
interface Props {
|
|
17
17
|
icon: keyof typeof Icons;
|
|
18
18
|
size?: number | string;
|
|
19
19
|
spin?: boolean;
|
|
@@ -1,10 +1,264 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useCallback } from "react";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import { checkCanvasOutput, checkGraphicsOutput, checkTurtleOutput, getPreCode, sanitizePyScript } from "./helpers";
|
|
5
|
+
import { ReactContextError, createStorageSlot } from "@docusaurus/theme-common";
|
|
2
6
|
import { usePluginData } from "@docusaurus/useGlobalData";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
7
|
+
import { DOM_ELEMENT_IDS } from "../constants";
|
|
8
|
+
import throttle from 'lodash/throttle';
|
|
9
|
+
import { getStorageScript, syncStorageScript } from "./Storage";
|
|
10
|
+
import { type InitState, type LogMessage, type Script, Status, type Store, type StoredScript, type Version } from "./Types";
|
|
11
|
+
export const createStore = (props: InitState, libDir: string, syncMaxOnceEvery: number): Store => {
|
|
12
|
+
const canSave = !!props.id;
|
|
13
|
+
const id = props.id || uuidv4();
|
|
14
|
+
const codeId = `code.${props.title || props.lang}.${id}`.replace(/(-|\.)/g, '_');
|
|
15
|
+
const createdAt = new Date();
|
|
16
|
+
const storageKey = `code.${props.title || 'code_block'}.${id}`;
|
|
17
|
+
const storage = createStorageSlot(storageKey);
|
|
18
|
+
storage.listen((e) => {
|
|
19
|
+
if (e.key === storageKey) {
|
|
20
|
+
try {
|
|
21
|
+
if (e.newValue) {
|
|
22
|
+
const script = JSON.parse(e.newValue) as StoredScript;
|
|
23
|
+
if (new Date(script.updatedAt) > state.updatedAt) {
|
|
24
|
+
loadData(storage);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
} catch (err) {
|
|
28
|
+
console.warn(err);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const loadData = (store) => {
|
|
34
|
+
setState((s) => ({...s, status: canSave ? Status.SYNCING : s.status}));
|
|
35
|
+
const script = getStorageScript(store);
|
|
36
|
+
const loadedCode = script?.code ? prepareCode(script.code, { codeOnly: true }) : {};
|
|
37
|
+
addVersion.cancel();
|
|
38
|
+
if (!state.isLoaded) {
|
|
39
|
+
setState((s) => ({
|
|
40
|
+
...s,
|
|
41
|
+
isLoaded: true,
|
|
42
|
+
...(script || {}),
|
|
43
|
+
...loadedCode,
|
|
44
|
+
versions: script?.versions || [],
|
|
45
|
+
versionsLoaded: true,
|
|
46
|
+
status: canSave ? Status.SUCCESS : s.status
|
|
47
|
+
}));
|
|
48
|
+
return Status.SUCCESS;
|
|
49
|
+
}
|
|
50
|
+
if (script) {
|
|
51
|
+
setState((s) => ({...s, ...script, ...loadedCode, status: canSave ? Status.SUCCESS : s.status, versionsLoaded: true}));
|
|
52
|
+
return Status.SUCCESS;
|
|
53
|
+
}
|
|
54
|
+
setState((s) => ({...s, status: canSave ? Status.ERROR : s.status}));
|
|
55
|
+
return Status.ERROR;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
const prepareCode = (raw: string, config: { codeOnly?: boolean, stateNotInitialized?: boolean } = {}) => {
|
|
60
|
+
const { pre, code } = config.codeOnly
|
|
61
|
+
? { pre: getPreCode(state.pristineCode).pre, code: raw }
|
|
62
|
+
: getPreCode(raw);
|
|
63
|
+
const hasEdits = code !== (config.stateNotInitialized ? getPreCode(props.raw).code : state.pristineCode);
|
|
64
|
+
const updatedAt = new Date();
|
|
65
|
+
const hasCanvasOutput = checkCanvasOutput(raw);
|
|
66
|
+
const hasTurtleOutput = checkTurtleOutput(raw);
|
|
67
|
+
const hasGraphicsOutput = checkGraphicsOutput(raw);
|
|
68
|
+
if (props.versioned && !config.stateNotInitialized) {
|
|
69
|
+
addVersion({code: code, createdAt: updatedAt, version: state.versions.length + 1});
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
code: code,
|
|
73
|
+
preCode: pre,
|
|
74
|
+
hasCanvasOutput: hasCanvasOutput,
|
|
75
|
+
hasTurtleOutput: hasTurtleOutput,
|
|
76
|
+
hasGraphicsOutput: hasGraphicsOutput,
|
|
77
|
+
hasEdits: hasEdits,
|
|
78
|
+
updatedAt: updatedAt
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const setCode = (raw: string, action?: 'insert' | 'remove' | string) => {
|
|
83
|
+
if (state.isPasted && action === 'remove') {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const data = prepareCode(raw);
|
|
87
|
+
setState(
|
|
88
|
+
(state) => ({
|
|
89
|
+
...state,
|
|
90
|
+
...data
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
if (props.id) {
|
|
94
|
+
const toStore: StoredScript = {code: data.code, createdAt: state.createdAt, updatedAt: data.updatedAt, versions: state.versions};
|
|
95
|
+
if (state.isPasted) {
|
|
96
|
+
addVersion.flush();
|
|
97
|
+
if (toStore.versions.length > 0) {
|
|
98
|
+
toStore.versions[toStore.versions.length - 1].pasted = true;
|
|
99
|
+
}
|
|
100
|
+
set(toStore);
|
|
101
|
+
set.flush();
|
|
102
|
+
state.isPasted = false;
|
|
103
|
+
} else {
|
|
104
|
+
set(toStore);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const execScript = () => {
|
|
110
|
+
const toExec = `${state.code}`;
|
|
111
|
+
const lineShift = state.preCode.split(/\n/).length;
|
|
112
|
+
const src = `from brython_runner import run
|
|
113
|
+
run("""${sanitizePyScript(toExec || '')}""", '${codeId}', ${lineShift})
|
|
114
|
+
`;
|
|
115
|
+
if (!(window as any).__BRYTHON__) {
|
|
116
|
+
alert('Brython not loaded');
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
setState((s) => ({...s, isExecuting: true, isGraphicsmodalOpen: state.hasGraphicsOutput}));
|
|
120
|
+
const active = document.getElementById(DOM_ELEMENT_IDS.communicator(state.codeId));
|
|
121
|
+
active.setAttribute('data--start-time', `${Date.now()}`);
|
|
122
|
+
/**
|
|
123
|
+
* ensure that the script is executed after the current event loop.
|
|
124
|
+
* Otherwise, the brython script will not be able to access the graphics output.
|
|
125
|
+
*/
|
|
126
|
+
setTimeout(() => {
|
|
127
|
+
(window as any).__BRYTHON__.runPythonSource(
|
|
128
|
+
src,
|
|
129
|
+
{
|
|
130
|
+
pythonpath: [libDir]
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
}, 0);
|
|
134
|
+
};
|
|
135
|
+
const load = async () => {
|
|
136
|
+
return loadData(storage);
|
|
137
|
+
};
|
|
138
|
+
const _set = async (script: StoredScript) => {
|
|
139
|
+
setState((s) => ({...s, status: canSave ? Status.SYNCING : s.status}));
|
|
140
|
+
if (syncStorageScript(script, storage)) {
|
|
141
|
+
setState((s) => ({...s, status: canSave ? Status.SUCCESS : s.status}));
|
|
142
|
+
return Status.SUCCESS;
|
|
143
|
+
}
|
|
144
|
+
setState((s) => ({...s, status: canSave ? Status.ERROR : s.status}));
|
|
145
|
+
return Status.ERROR;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const set = throttle(
|
|
149
|
+
_set,
|
|
150
|
+
syncMaxOnceEvery,
|
|
151
|
+
{leading: false, trailing: true}
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const _addVersion = (version: Version) => {
|
|
155
|
+
if (!props.versioned || !props.id) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const versions = [...state.versions];
|
|
159
|
+
versions.push(version);
|
|
160
|
+
setState((s) => ({...s, versions: versions}));
|
|
161
|
+
}
|
|
162
|
+
const addVersion = throttle(
|
|
163
|
+
_addVersion,
|
|
164
|
+
syncMaxOnceEvery,
|
|
165
|
+
{leading: false, trailing: true}
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const saveNow = async () => {
|
|
169
|
+
addVersion.flush();
|
|
170
|
+
return set.flush();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const del = async () => {
|
|
174
|
+
storage.del();
|
|
175
|
+
return Status.SUCCESS;
|
|
176
|
+
}
|
|
177
|
+
const codeData = prepareCode(props.raw, { stateNotInitialized: true });
|
|
178
|
+
const setExecuting = (isExecuting: boolean) => {
|
|
179
|
+
setState((s) => ({...s, isExecuting: isExecuting}))
|
|
180
|
+
};
|
|
181
|
+
const addLogMessage = (log: LogMessage) => {
|
|
182
|
+
setState((s) => ({...s, logs: [...s.logs, log]}));
|
|
183
|
+
};
|
|
184
|
+
const clearLogMessages = () => {
|
|
185
|
+
setState((s) => ({...s, logs: []}));
|
|
186
|
+
};
|
|
187
|
+
const closeGraphicsModal = () => {
|
|
188
|
+
setState((s) => ({...s, isGraphicsmodalOpen: false}));
|
|
189
|
+
};
|
|
190
|
+
const stopScript = () => {
|
|
191
|
+
const code = document.getElementById(DOM_ELEMENT_IDS.communicator(state.codeId));
|
|
192
|
+
if (code) {
|
|
193
|
+
code.removeAttribute('data--start-time');
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
let state: Script = {
|
|
197
|
+
id: id,
|
|
198
|
+
codeId: codeId,
|
|
199
|
+
lang: props.lang,
|
|
200
|
+
showRaw: false,
|
|
201
|
+
pristineCode: codeData.code,
|
|
202
|
+
isExecuting: false,
|
|
203
|
+
logs: [],
|
|
204
|
+
isGraphicsmodalOpen: false,
|
|
205
|
+
hasEdits: false,
|
|
206
|
+
createdAt: createdAt,
|
|
207
|
+
isLoaded: false,
|
|
208
|
+
status: Status.IDLE,
|
|
209
|
+
versions: [],
|
|
210
|
+
versionsLoaded: false,
|
|
211
|
+
isPasted: false,
|
|
212
|
+
...codeData
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
const getState = () => state;
|
|
217
|
+
const listeners = new Set<() => void>();
|
|
218
|
+
const setState = (fn: (state: Script) => Script) => {
|
|
219
|
+
state = fn(state);
|
|
220
|
+
listeners.forEach((l) => l());
|
|
221
|
+
};
|
|
222
|
+
const subscribe = (listener: () => void) => {
|
|
223
|
+
listeners.add(listener);
|
|
224
|
+
return () => listeners.delete(listener);
|
|
225
|
+
};
|
|
226
|
+
const loadVersions = async () => {
|
|
227
|
+
// noop
|
|
228
|
+
state.isLoaded = false;
|
|
229
|
+
load();
|
|
230
|
+
setState((s) => ({...s, versionsLoaded: true}));
|
|
231
|
+
return Promise.resolve();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
getState,
|
|
236
|
+
setState,
|
|
237
|
+
subscribe,
|
|
238
|
+
saveNow,
|
|
239
|
+
addLogMessage,
|
|
240
|
+
clearLogMessages,
|
|
241
|
+
closeGraphicsModal,
|
|
242
|
+
setCode,
|
|
243
|
+
execScript,
|
|
244
|
+
setExecuting,
|
|
245
|
+
stopScript,
|
|
246
|
+
load,
|
|
247
|
+
loadVersions
|
|
248
|
+
} satisfies Store;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
type Selector<T, R> = (state: T) => R;
|
|
252
|
+
export const useStore = <T, R>(store: Store<T>, selector: Selector<T, R>): R => {
|
|
253
|
+
return useSyncExternalStore(
|
|
254
|
+
store.subscribe,
|
|
255
|
+
useCallback(() => selector(store.getState()), [store, selector])
|
|
256
|
+
);
|
|
257
|
+
}
|
|
5
258
|
|
|
6
259
|
export const Context = React.createContext<{store: Store} | undefined>(undefined);
|
|
7
260
|
|
|
261
|
+
|
|
8
262
|
const ScriptContext = (props: InitState & { children: React.ReactNode; }) => {
|
|
9
263
|
const {libDir, syncMaxOnceEvery} = usePluginData('docusaurus-live-brython') as {libDir: string, syncMaxOnceEvery: number};
|
|
10
264
|
const [store, setStore] = React.useState<Store | null>(null);
|
|
@@ -25,4 +279,16 @@ const ScriptContext = (props: InitState & { children: React.ReactNode; }) => {
|
|
|
25
279
|
);
|
|
26
280
|
}
|
|
27
281
|
|
|
282
|
+
export function useScript(): {store: Store} {
|
|
283
|
+
const context = React.useContext(Context);
|
|
284
|
+
if (context === null) {
|
|
285
|
+
throw new ReactContextError(
|
|
286
|
+
'ScriptContextProvider',
|
|
287
|
+
'The Component must be a child of the CodeContextProvider component',
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
return context;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
|
|
28
294
|
export default ScriptContext;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import styles from './styles.module.css';
|
|
3
|
-
import Editor from '
|
|
4
|
-
import BrythonCommunicator from '
|
|
3
|
+
import Editor from './Editor';
|
|
4
|
+
import BrythonCommunicator from './BrythonCommunicator';
|
|
5
5
|
import clsx from 'clsx';
|
|
6
|
-
import
|
|
6
|
+
import useIsBrowser from '@docusaurus/useIsBrowser';
|
|
7
|
+
import { useScript, useStore } from './WithScript/Store';
|
|
7
8
|
import BrowserOnly from '@docusaurus/BrowserOnly';
|
|
8
|
-
import CodeHistory from '
|
|
9
|
+
import CodeHistory from './CodeHistory';
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
interface Props {
|
|
11
12
|
slim: boolean;
|
|
12
13
|
readonly: boolean;
|
|
13
14
|
children: React.ReactNode;
|
|
@@ -23,7 +24,7 @@ export interface Props {
|
|
|
23
24
|
noHistory: boolean;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
const
|
|
27
|
+
const PyAceEditor = (props: Props) => {
|
|
27
28
|
const { store } = useScript();
|
|
28
29
|
const lang = useStore(store, (state) => state.lang);
|
|
29
30
|
return (
|
|
@@ -53,5 +54,4 @@ const CodeEditor = (props: Props) => {
|
|
|
53
54
|
);
|
|
54
55
|
};
|
|
55
56
|
|
|
56
|
-
export default
|
|
57
|
-
|
|
57
|
+
export default PyAceEditor;
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
export type ThemeOptions = {
|
|
3
|
+
/**
|
|
4
|
+
* The path to the brython source file.
|
|
5
|
+
* @default 'https://raw.githack.com/brython-dev/brython/master/www/src/brython.js
|
|
6
|
+
*/
|
|
7
|
+
brython_src?: string;
|
|
8
|
+
/**
|
|
9
|
+
* The path to the brython standard library source file.
|
|
10
|
+
* @default 'https://raw.githack.com/brython-dev/brython/master/www/src/brython_stdlib.js'
|
|
11
|
+
*/
|
|
12
|
+
brython_stdlib_src?: string;
|
|
13
|
+
/**
|
|
14
|
+
* The folder path to brython specific libraries.
|
|
15
|
+
* When a python file imports a module, the module is searched in the libDir directory.
|
|
16
|
+
* By default, the libDir is created in the static folder and the needed python files are copied there.
|
|
17
|
+
* This can be changed by setting skipCopyAssetsToLibDir to true and setting libDir to a custom path.
|
|
18
|
+
* Make sure to copy the needed python files to the custom libDir.
|
|
19
|
+
* @default '/bry-libs/'
|
|
20
|
+
*/
|
|
21
|
+
libDir?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Skip copying the brython specific libraries to the libDir.
|
|
24
|
+
* Make sure to copy the needed python files to the custom libDir yourself.
|
|
25
|
+
* @ref [needed python files](https://github.com/lebalz/docusaurus-live-brython/tree/main/src/assets)
|
|
26
|
+
* @default false
|
|
27
|
+
*/
|
|
28
|
+
skipCopyAssetsToLibDir?: boolean;
|
|
29
|
+
}
|