docusaurus-live-brython 3.0.0-beta.8 → 3.0.1

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 (175) hide show
  1. package/.devcontainer/devcontainer.json +38 -0
  2. package/.prettierignore +17 -0
  3. package/.prettierrc +9 -8
  4. package/CHANGELOG.md +5 -0
  5. package/README.md +7 -4
  6. package/lib/assets/py_back_trace.py +2 -1
  7. package/lib/index.d.ts +1 -7
  8. package/lib/index.d.ts.map +1 -0
  9. package/lib/index.js +94 -16
  10. package/lib/options.d.ts +1 -0
  11. package/lib/options.d.ts.map +1 -0
  12. package/lib/options.js +2 -2
  13. package/lib/theme/CodeBlock/index.d.ts +3 -3
  14. package/lib/theme/CodeBlock/index.d.ts.map +1 -0
  15. package/lib/theme/CodeBlock/index.jsx +24 -14
  16. package/lib/theme/CodeEditor/Actions/DownloadCode.d.ts +1 -0
  17. package/lib/theme/CodeEditor/Actions/DownloadCode.d.ts.map +1 -0
  18. package/lib/theme/CodeEditor/Actions/DownloadCode.jsx +8 -8
  19. package/lib/theme/CodeEditor/Actions/Reset.d.ts +1 -0
  20. package/lib/theme/CodeEditor/Actions/Reset.d.ts.map +1 -0
  21. package/lib/theme/CodeEditor/Actions/Reset.jsx +5 -5
  22. package/lib/theme/CodeEditor/Actions/RunCode.d.ts +2 -1
  23. package/lib/theme/CodeEditor/Actions/RunCode.d.ts.map +1 -0
  24. package/lib/theme/CodeEditor/Actions/RunCode.jsx +4 -4
  25. package/lib/theme/CodeEditor/Actions/ShowRaw.d.ts +1 -0
  26. package/lib/theme/CodeEditor/Actions/ShowRaw.d.ts.map +1 -0
  27. package/lib/theme/CodeEditor/Actions/ShowRaw.jsx +13 -7
  28. package/lib/theme/CodeEditor/Actions/ShowSyncStatus.d.ts +1 -0
  29. package/lib/theme/CodeEditor/Actions/ShowSyncStatus.d.ts.map +1 -0
  30. package/lib/theme/CodeEditor/Actions/ShowSyncStatus.jsx +21 -16
  31. package/lib/theme/CodeEditor/Actions/styles.module.css +2 -3
  32. package/lib/theme/CodeEditor/BrythonCommunicator.d.ts +2 -1
  33. package/lib/theme/CodeEditor/BrythonCommunicator.d.ts.map +1 -0
  34. package/lib/theme/CodeEditor/BrythonCommunicator.jsx +13 -9
  35. package/lib/theme/CodeEditor/Button/index.d.ts +3 -2
  36. package/lib/theme/CodeEditor/Button/index.d.ts.map +1 -0
  37. package/lib/theme/CodeEditor/Button/index.jsx +1 -1
  38. package/lib/theme/CodeEditor/Button/styles.module.css +1 -1
  39. package/lib/theme/CodeEditor/CodeHistory/index.d.ts +1 -0
  40. package/lib/theme/CodeEditor/CodeHistory/index.d.ts.map +1 -0
  41. package/lib/theme/CodeEditor/CodeHistory/index.jsx +26 -15
  42. package/lib/theme/CodeEditor/CodeHistory/styles.module.css +31 -31
  43. package/lib/theme/CodeEditor/ContextEditor/index.d.ts +22 -0
  44. package/lib/theme/CodeEditor/ContextEditor/index.d.ts.map +1 -0
  45. package/lib/theme/CodeEditor/ContextEditor/index.jsx +36 -0
  46. package/lib/theme/CodeEditor/Editor/EditorAce.d.ts +2 -1
  47. package/lib/theme/CodeEditor/Editor/EditorAce.d.ts.map +1 -0
  48. package/lib/theme/CodeEditor/Editor/EditorAce.jsx +17 -14
  49. package/lib/theme/CodeEditor/Editor/Header/index.d.ts +2 -1
  50. package/lib/theme/CodeEditor/Editor/Header/index.d.ts.map +1 -0
  51. package/lib/theme/CodeEditor/Editor/Header/index.jsx +12 -12
  52. package/lib/theme/CodeEditor/Editor/Header/styles.module.css +7 -7
  53. package/lib/theme/CodeEditor/Editor/HiddenCode/index.d.ts +8 -0
  54. package/lib/theme/CodeEditor/Editor/HiddenCode/index.d.ts.map +1 -0
  55. package/lib/theme/CodeEditor/Editor/HiddenCode/index.jsx +27 -0
  56. package/lib/theme/CodeEditor/Editor/HiddenCode/styles.module.css +52 -0
  57. package/lib/theme/CodeEditor/Editor/Result/Graphics/Canvas.d.ts +1 -0
  58. package/lib/theme/CodeEditor/Editor/Result/Graphics/Canvas.d.ts.map +1 -0
  59. package/lib/theme/CodeEditor/Editor/Result/Graphics/Canvas.jsx +8 -9
  60. package/lib/theme/CodeEditor/Editor/Result/Graphics/Turtle.d.ts +1 -0
  61. package/lib/theme/CodeEditor/Editor/Result/Graphics/Turtle.d.ts.map +1 -0
  62. package/lib/theme/CodeEditor/Editor/Result/Graphics/Turtle.jsx +11 -11
  63. package/lib/theme/CodeEditor/Editor/Result/Graphics/index.d.ts +4 -3
  64. package/lib/theme/CodeEditor/Editor/Result/Graphics/index.d.ts.map +1 -0
  65. package/lib/theme/CodeEditor/Editor/Result/Graphics/index.jsx +12 -10
  66. package/lib/theme/CodeEditor/Editor/Result/Graphics/styles.module.css +2 -2
  67. package/lib/theme/CodeEditor/Editor/Result/index.d.ts +2 -3
  68. package/lib/theme/CodeEditor/Editor/Result/index.d.ts.map +1 -0
  69. package/lib/theme/CodeEditor/Editor/Result/index.jsx +6 -9
  70. package/lib/theme/CodeEditor/Editor/Result/styles.module.css +15 -10
  71. package/lib/theme/CodeEditor/Editor/index.d.ts +6 -3
  72. package/lib/theme/CodeEditor/Editor/index.d.ts.map +1 -0
  73. package/lib/theme/CodeEditor/Editor/index.jsx +34 -28
  74. package/lib/theme/CodeEditor/Editor/styles.module.css +15 -7
  75. package/lib/theme/CodeEditor/Editor/utils/checkForButtonClick.d.ts +1 -0
  76. package/lib/theme/CodeEditor/Editor/utils/checkForButtonClick.d.ts.map +1 -0
  77. package/lib/theme/CodeEditor/Editor/utils/saveSvg.d.ts +1 -0
  78. package/lib/theme/CodeEditor/Editor/utils/saveSvg.d.ts.map +1 -0
  79. package/lib/theme/CodeEditor/Editor/utils/saveSvg.js +19 -8
  80. package/lib/theme/CodeEditor/Editor/utils/svgWithoutAnimations.d.ts +1 -0
  81. package/lib/theme/CodeEditor/Editor/utils/svgWithoutAnimations.d.ts.map +1 -0
  82. package/lib/theme/CodeEditor/Editor/utils/svgWithoutAnimations.js +43 -49
  83. package/lib/theme/CodeEditor/Icon/icons.d.ts +4 -1
  84. package/lib/theme/CodeEditor/Icon/icons.d.ts.map +1 -0
  85. package/lib/theme/CodeEditor/Icon/icons.js +3 -1
  86. package/lib/theme/CodeEditor/Icon/index.d.ts +4 -2
  87. package/lib/theme/CodeEditor/Icon/index.d.ts.map +1 -0
  88. package/lib/theme/CodeEditor/Icon/index.jsx +10 -3
  89. package/lib/theme/CodeEditor/Icon/styles.module.css +1 -1
  90. package/lib/theme/CodeEditor/WithScript/ScriptContext.d.ts +8 -0
  91. package/lib/theme/CodeEditor/WithScript/ScriptContext.d.ts.map +1 -0
  92. package/lib/theme/CodeEditor/WithScript/ScriptContext.jsx +27 -0
  93. package/lib/theme/CodeEditor/WithScript/Storage.d.ts +2 -1
  94. package/lib/theme/CodeEditor/WithScript/Storage.d.ts.map +1 -0
  95. package/lib/theme/CodeEditor/WithScript/Types.d.ts +12 -4
  96. package/lib/theme/CodeEditor/WithScript/Types.d.ts.map +1 -0
  97. package/lib/theme/CodeEditor/WithScript/bryRunner.d.ts +3 -0
  98. package/lib/theme/CodeEditor/WithScript/bryRunner.d.ts.map +1 -0
  99. package/lib/theme/CodeEditor/WithScript/bryRunner.js +29 -0
  100. package/lib/theme/CodeEditor/WithScript/createStore.d.ts +4 -0
  101. package/lib/theme/CodeEditor/WithScript/createStore.d.ts.map +1 -0
  102. package/lib/theme/CodeEditor/WithScript/{Store.jsx → createStore.js} +62 -74
  103. package/lib/theme/CodeEditor/WithScript/helpers.d.ts +1 -4
  104. package/lib/theme/CodeEditor/WithScript/helpers.d.ts.map +1 -0
  105. package/lib/theme/CodeEditor/WithScript/helpers.js +4 -14
  106. package/lib/theme/CodeEditor/constants.d.ts +1 -0
  107. package/lib/theme/CodeEditor/constants.d.ts.map +1 -0
  108. package/lib/theme/CodeEditor/hooks/index.d.ts +3 -0
  109. package/lib/theme/CodeEditor/hooks/index.d.ts.map +1 -0
  110. package/lib/theme/CodeEditor/hooks/index.js +2 -0
  111. package/lib/theme/CodeEditor/hooks/useScript.d.ts +3 -0
  112. package/lib/theme/CodeEditor/hooks/useScript.d.ts.map +1 -0
  113. package/lib/theme/CodeEditor/hooks/useScript.js +4 -0
  114. package/lib/theme/CodeEditor/hooks/useStore.d.ts +3 -0
  115. package/lib/theme/CodeEditor/hooks/useStore.d.ts.map +1 -0
  116. package/lib/theme/CodeEditor/hooks/useStore.js +10 -0
  117. package/lib/theme/CodeEditor/index.d.ts +24 -5
  118. package/lib/theme/CodeEditor/index.d.ts.map +1 -0
  119. package/lib/theme/CodeEditor/index.jsx +17 -16
  120. package/lib/theme/CodeEditor/styles.module.css +28 -30
  121. package/og-image.md +23 -0
  122. package/package.json +39 -20
  123. package/src/assets/py_back_trace.py +2 -1
  124. package/src/index.ts +96 -25
  125. package/src/options.ts +12 -12
  126. package/src/theme/CodeBlock/index.tsx +44 -68
  127. package/src/theme/CodeEditor/Actions/DownloadCode.tsx +23 -22
  128. package/src/theme/CodeEditor/Actions/Reset.tsx +14 -12
  129. package/src/theme/CodeEditor/Actions/RunCode.tsx +14 -11
  130. package/src/theme/CodeEditor/Actions/ShowRaw.tsx +17 -11
  131. package/src/theme/CodeEditor/Actions/ShowSyncStatus.tsx +32 -27
  132. package/src/theme/CodeEditor/Actions/styles.module.css +2 -3
  133. package/src/theme/CodeEditor/BrythonCommunicator.tsx +16 -19
  134. package/src/theme/CodeEditor/Button/index.tsx +17 -13
  135. package/src/theme/CodeEditor/Button/styles.module.css +1 -1
  136. package/src/theme/CodeEditor/CodeHistory/index.tsx +32 -20
  137. package/src/theme/CodeEditor/CodeHistory/styles.module.css +31 -31
  138. package/src/theme/CodeEditor/ContextEditor/index.tsx +74 -0
  139. package/src/theme/CodeEditor/Editor/EditorAce.tsx +20 -16
  140. package/src/theme/CodeEditor/Editor/Header/index.tsx +13 -19
  141. package/src/theme/CodeEditor/Editor/Header/styles.module.css +7 -7
  142. package/src/theme/CodeEditor/Editor/HiddenCode/index.tsx +49 -0
  143. package/src/theme/CodeEditor/Editor/HiddenCode/styles.module.css +52 -0
  144. package/src/theme/CodeEditor/Editor/Result/Graphics/Canvas.tsx +25 -22
  145. package/src/theme/CodeEditor/Editor/Result/Graphics/Turtle.tsx +23 -19
  146. package/src/theme/CodeEditor/Editor/Result/Graphics/index.tsx +16 -16
  147. package/src/theme/CodeEditor/Editor/Result/Graphics/styles.module.css +2 -2
  148. package/src/theme/CodeEditor/Editor/Result/index.tsx +7 -13
  149. package/src/theme/CodeEditor/Editor/Result/styles.module.css +15 -10
  150. package/src/theme/CodeEditor/Editor/index.tsx +67 -65
  151. package/src/theme/CodeEditor/Editor/styles.module.css +15 -7
  152. package/src/theme/CodeEditor/Editor/utils/checkForButtonClick.ts +5 -5
  153. package/src/theme/CodeEditor/Editor/utils/saveSvg.ts +63 -53
  154. package/src/theme/CodeEditor/Editor/utils/svgWithoutAnimations.ts +182 -201
  155. package/src/theme/CodeEditor/Icon/icons.ts +27 -13
  156. package/src/theme/CodeEditor/Icon/index.tsx +31 -11
  157. package/src/theme/CodeEditor/Icon/styles.module.css +1 -1
  158. package/src/theme/CodeEditor/WithScript/ScriptContext.tsx +36 -0
  159. package/src/theme/CodeEditor/WithScript/Storage.ts +3 -3
  160. package/src/theme/CodeEditor/WithScript/Types.ts +17 -11
  161. package/src/theme/CodeEditor/WithScript/bryRunner.ts +39 -0
  162. package/src/theme/CodeEditor/WithScript/createStore.ts +276 -0
  163. package/src/theme/CodeEditor/WithScript/helpers.ts +16 -26
  164. package/src/theme/CodeEditor/constants.ts +9 -11
  165. package/src/theme/CodeEditor/hooks/index.ts +2 -0
  166. package/src/theme/CodeEditor/hooks/useScript.ts +9 -0
  167. package/src/theme/CodeEditor/hooks/useStore.ts +15 -0
  168. package/src/theme/CodeEditor/index.tsx +45 -31
  169. package/src/theme/CodeEditor/styles.module.css +28 -30
  170. package/src/typings.d.ts +11 -0
  171. package/lib/theme/CodeEditor/WithScript/Store.d.ts +0 -15
  172. package/lib/types.d.ts +0 -28
  173. package/lib/types.js +0 -1
  174. package/src/theme/CodeEditor/WithScript/Store.tsx +0 -294
  175. package/src/types.ts +0 -29
@@ -1,16 +1,31 @@
1
1
  import * as React from 'react';
2
2
  import styles from './styles.module.css';
3
- import Editor from 'docusaurus-live-brython/theme/CodeEditor/Editor';
4
- import BrythonCommunicator from 'docusaurus-live-brython/theme/CodeEditor/BrythonCommunicator';
3
+ import Editor from '@theme/CodeEditor/Editor';
4
+ import BrythonCommunicator from '@theme/CodeEditor/BrythonCommunicator';
5
5
  import clsx from 'clsx';
6
- import { useScript, useStore } from 'docusaurus-live-brython/theme/CodeEditor/WithScript/Store';
6
+ import { useStore, useScript } from '@theme/CodeEditor/hooks';
7
7
  import BrowserOnly from '@docusaurus/BrowserOnly';
8
- import CodeHistory from 'docusaurus-live-brython/theme/CodeEditor/CodeHistory';
8
+ import CodeHistory from '@theme/CodeEditor/CodeHistory';
9
+ import CodeBlock from '@theme/CodeBlock';
9
10
 
10
- interface Props {
11
+ export interface MetaProps {
12
+ reference?: boolean;
13
+ live_jsx?: boolean;
14
+ live_py?: boolean;
15
+ id?: string;
16
+ slim?: boolean;
17
+ readonly?: boolean;
18
+ noReset?: boolean;
19
+ noDownload?: boolean;
20
+ versioned?: boolean;
21
+ noHistory?: boolean;
22
+ noCompare?: boolean;
23
+ maxLines?: string;
24
+ title?: string;
25
+ }
26
+ export interface Props {
11
27
  slim: boolean;
12
28
  readonly: boolean;
13
- children: React.ReactNode;
14
29
  noCompare: boolean;
15
30
  title: string;
16
31
  versioned: boolean;
@@ -18,40 +33,39 @@ interface Props {
18
33
  download: boolean;
19
34
  showLineNumbers: boolean;
20
35
  lang: string;
21
- precode: string;
36
+ preCode: string;
37
+ postCode: string;
38
+ code: string;
22
39
  maxLines?: number;
23
40
  noHistory: boolean;
41
+ className?: string;
42
+ onChange?: (code: string) => void;
24
43
  }
25
44
 
26
- const PyAceEditor = (props: Props) => {
27
- const { store } = useScript();
28
- const lang = useStore(store, (state) => state.lang);
45
+ const CodeEditor = (props: Props) => {
46
+ const store = useStore();
47
+ const lang = useScript(store, 'lang');
29
48
  return (
30
- <BrowserOnly
31
- fallback={<div>Loading...</div>}
32
- >
49
+ <BrowserOnly fallback={<CodeBlock language={props.lang}>{props.code}</CodeBlock>}>
33
50
  {() => {
34
- return (
35
- <div className={clsx(styles.wrapper, 'notranslate')}>
36
- <div
37
- className={clsx(
38
- styles.playgroundContainer,
39
- props.slim ? styles.containerSlim : styles.containerBig,
40
- 'live_py'
41
- )}
42
- >
43
- <Editor {...props} />
44
- {!props.noHistory && (
45
- <CodeHistory />
46
- )}
47
- </div>
48
- {lang === 'python' && <BrythonCommunicator />}
51
+ return (
52
+ <div className={clsx(styles.wrapper, 'notranslate', props.className)}>
53
+ <div
54
+ className={clsx(
55
+ styles.playgroundContainer,
56
+ props.slim ? styles.containerSlim : styles.containerBig,
57
+ 'live_py'
58
+ )}
59
+ >
60
+ <Editor {...props} />
61
+ {!props.noHistory && <CodeHistory />}
49
62
  </div>
50
- )
63
+ {lang === 'python' && <BrythonCommunicator />}
64
+ </div>
65
+ );
51
66
  }}
52
67
  </BrowserOnly>
53
68
  );
54
69
  };
55
70
 
56
- export default PyAceEditor;
57
-
71
+ export default CodeEditor;
@@ -1,43 +1,41 @@
1
1
  .containerBig {
2
- display: grid;
3
- flex-grow: 1;
4
- flex-shrink: 1;
5
- flex-basis: 250px;
6
- grid-template-columns: 100%;
7
- grid-template-rows: min-content 1fr min-content;
8
- gap: 0px 0px;
9
- grid-auto-flow: row;
10
- grid-template-areas: 'controls' 'editor' 'result';
2
+ display: grid;
3
+ flex-grow: 1;
4
+ flex-shrink: 1;
5
+ flex-basis: 250px;
6
+ grid-template-columns: 100%;
7
+ grid-template-rows: min-content 1fr min-content;
8
+ gap: 0px 0px;
9
+ grid-auto-flow: row;
10
+ grid-template-areas: 'controls' 'editor' 'result';
11
11
  }
12
12
 
13
13
  .containerSlim {
14
- display: grid;
15
- grid-template-columns: 1fr min-content;
16
- grid-template-rows: 1fr min-content;
17
- gap: 0px 0px;
18
- grid-auto-flow: row;
19
- grid-template-areas: 'editor controls' 'result result';
14
+ display: grid;
15
+ grid-template-columns: 1fr min-content;
16
+ grid-template-rows: 1fr min-content;
17
+ gap: 0px 0px;
18
+ grid-auto-flow: row;
19
+ grid-template-areas: 'editor controls' 'result result';
20
20
  }
21
21
 
22
-
23
22
  .containerSlim .headerButton {
24
- z-index: calc(var(--ifm-z-index-fixed) - 2);
25
- height: 100%;
26
- border-radius: 0px;
27
- padding: 2px 6px;
28
- margin: 0px;
23
+ z-index: calc(var(--ifm-z-index-fixed) - 2);
24
+ height: 100%;
25
+ border-radius: 0px;
26
+ padding: 2px 6px;
27
+ margin: 0px;
29
28
  }
30
29
 
31
-
32
30
  .wrapper:last-child .playgroundContainer {
33
- margin-bottom: inherit;
31
+ margin-bottom: inherit;
34
32
  }
35
33
 
36
34
  .playgroundContainer {
37
- margin-bottom: var(--ifm-leading);
38
- border-radius: var(--ifm-global-radius);
39
- box-shadow: var(--ifm-global-shadow-lw);
40
- overflow: hidden;
41
- flex-grow: 1;
42
- flex-shrink: 1;
43
- }
35
+ margin-bottom: var(--ifm-leading);
36
+ border-radius: var(--ifm-global-radius);
37
+ box-shadow: var(--ifm-global-shadow-lw);
38
+ overflow: hidden;
39
+ flex-grow: 1;
40
+ flex-shrink: 1;
41
+ }
@@ -0,0 +1,11 @@
1
+ /// <reference types="@docusaurus/module-type-aliases" />
2
+
3
+ declare module '@theme/Details' {
4
+ import { ReactNode } from 'react';
5
+ export interface Props {
6
+ readonly summary: ReactNode;
7
+ readonly children: ReactNode;
8
+ [key: string]: any;
9
+ }
10
+ export default function Details(props: Props): React.ReactNode;
11
+ }
@@ -1,15 +0,0 @@
1
- import React from "react";
2
- import { type InitState, type Store } from "./Types";
3
- export declare const createStore: (props: InitState, libDir: string, syncMaxOnceEvery: number) => Store;
4
- type Selector<T, R> = (state: T) => R;
5
- export declare const useStore: <T, R>(store: Store<T>, selector: Selector<T, R>) => R;
6
- export declare const Context: React.Context<{
7
- store: Store;
8
- }>;
9
- declare const ScriptContext: (props: InitState & {
10
- children: React.ReactNode;
11
- }) => React.JSX.Element;
12
- export declare function useScript(): {
13
- store: Store;
14
- };
15
- export default ScriptContext;
package/lib/types.d.ts DELETED
@@ -1,28 +0,0 @@
1
- export type ThemeOptions = {
2
- /**
3
- * The path to the brython source file.
4
- * @default 'https://raw.githack.com/brython-dev/brython/master/www/src/brython.js
5
- */
6
- brython_src?: string;
7
- /**
8
- * The path to the brython standard library source file.
9
- * @default 'https://raw.githack.com/brython-dev/brython/master/www/src/brython_stdlib.js'
10
- */
11
- brython_stdlib_src?: string;
12
- /**
13
- * The folder path to brython specific libraries.
14
- * When a python file imports a module, the module is searched in the libDir directory.
15
- * By default, the libDir is created in the static folder and the needed python files are copied there.
16
- * This can be changed by setting skipCopyAssetsToLibDir to true and setting libDir to a custom path.
17
- * Make sure to copy the needed python files to the custom libDir.
18
- * @default '/bry-libs/'
19
- */
20
- libDir?: string;
21
- /**
22
- * Skip copying the brython specific libraries to the libDir.
23
- * Make sure to copy the needed python files to the custom libDir yourself.
24
- * @ref [needed python files](https://github.com/lebalz/docusaurus-live-brython/tree/main/src/assets)
25
- * @default false
26
- */
27
- skipCopyAssetsToLibDir?: boolean;
28
- };
package/lib/types.js DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1,294 +0,0 @@
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 "docusaurus-live-brython/theme/CodeEditor/WithScript/helpers";
5
- import { ReactContextError, createStorageSlot } from "@docusaurus/theme-common";
6
- import { usePluginData } from "@docusaurus/useGlobalData";
7
- import { DOM_ELEMENT_IDS } from "docusaurus-live-brython/theme/CodeEditor/constants";
8
- import throttle from 'lodash/throttle';
9
- import { getStorageScript, syncStorageScript } from "docusaurus-live-brython/theme/CodeEditor/WithScript/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
- }
258
-
259
- export const Context = React.createContext<{store: Store} | undefined>(undefined);
260
-
261
-
262
- const ScriptContext = (props: InitState & { children: React.ReactNode; }) => {
263
- const {libDir, syncMaxOnceEvery} = usePluginData('docusaurus-live-brython') as {libDir: string, syncMaxOnceEvery: number};
264
- const [store, setStore] = React.useState<Store | null>(null);
265
- React.useEffect(() => {
266
- const store = createStore(props, libDir, syncMaxOnceEvery);
267
- setStore(store);
268
- store.load();
269
- }, [props.id, libDir]);
270
-
271
- if (!store) {
272
- return <div>Load</div>;
273
- }
274
-
275
- return (
276
- <Context.Provider value={{store: store}}>
277
- {props.children}
278
- </Context.Provider>
279
- );
280
- }
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
-
294
- export default ScriptContext;
package/src/types.ts DELETED
@@ -1,29 +0,0 @@
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
- }