@codecademy/codebytes 1.0.4-alpha.37044bcdd.0 → 1.0.4-alpha.41a141e2a.0
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/.eslintrc.json +35 -0
- package/CHANGELOG.md +14 -0
- package/babel.config.js +22 -0
- package/jest.config.ts +21 -0
- package/package.json +3 -8
- package/project.json +52 -0
- package/src/MonacoEditor/colorsDark.ts +54 -0
- package/src/MonacoEditor/index.tsx +56 -0
- package/src/MonacoEditor/theme.ts +65 -0
- package/src/MonacoEditor/types.ts +1 -0
- package/src/__tests__/codebyte.test.tsx +186 -0
- package/src/__tests__/editor.test.tsx +108 -0
- package/src/__tests__/helpers.test.tsx +39 -0
- package/src/__tests__/language-selection.test.tsx +14 -0
- package/src/api.ts +28 -0
- package/src/codeByteEditor.tsx +115 -0
- package/src/consts.ts +64 -0
- package/src/drawers.tsx +133 -0
- package/src/editor.tsx +162 -0
- package/src/helpers/index.ts +8 -0
- package/src/helpers/useEverInView.test.ts +29 -0
- package/src/helpers/useEverInView.ts +28 -0
- package/src/helpers/useIntersection.test.ts +87 -0
- package/src/helpers/useIntersection.ts +35 -0
- package/{dist/index.d.ts → src/index.ts} +3 -3
- package/src/languageSelection.tsx +26 -0
- package/src/libs/eventTracking.ts +18 -0
- package/src/theme.d.ts +5 -0
- package/src/types.ts +30 -0
- package/tsconfig.json +27 -0
- package/tsconfig.spec.json +21 -0
- package/dist/MonacoEditor/colorsDark.d.ts +0 -32
- package/dist/MonacoEditor/index.d.ts +0 -8
- package/dist/MonacoEditor/theme.d.ts +0 -2
- package/dist/MonacoEditor/types.d.ts +0 -1
- package/dist/api.d.ts +0 -12
- package/dist/codeByteEditor.d.ts +0 -4
- package/dist/consts.d.ts +0 -23
- package/dist/drawers.d.ts +0 -6
- package/dist/editor.d.ts +0 -15
- package/dist/helpers/index.d.ts +0 -2
- package/dist/helpers/useEverInView.d.ts +0 -5
- package/dist/helpers/useIntersection.d.ts +0 -2
- package/dist/index.cjs +0 -829
- package/dist/index.js +0 -741
- package/dist/languageSelection.d.ts +0 -6
- package/dist/libs/eventTracking.d.ts +0 -1
- package/dist/package.json +0 -44
- package/dist/types.d.ts +0 -22
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { act, renderHook } from '@testing-library/react-hooks/dom';
|
|
2
|
+
|
|
3
|
+
import { useIntersection } from './useIntersection';
|
|
4
|
+
|
|
5
|
+
const originalIntersectionObserver = window.IntersectionObserver;
|
|
6
|
+
const mockObserve = jest.fn();
|
|
7
|
+
const mockDisconnect = jest.fn();
|
|
8
|
+
const mockIntersectionObserver = jest.fn();
|
|
9
|
+
const mockIntersectionObserverInstance = {
|
|
10
|
+
observe: mockObserve,
|
|
11
|
+
disconnect: mockDisconnect,
|
|
12
|
+
};
|
|
13
|
+
const ref = { current: document.createElement('div') };
|
|
14
|
+
const options = {
|
|
15
|
+
root: null,
|
|
16
|
+
rootMargin: '0px',
|
|
17
|
+
threshold: 0.2,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
mockIntersectionObserver.mockReturnValue(mockIntersectionObserverInstance);
|
|
22
|
+
window.IntersectionObserver = mockIntersectionObserver;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
window.IntersectionObserver = originalIntersectionObserver;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('useIntersection', () => {
|
|
30
|
+
test('intersection observer is not called', async () => {
|
|
31
|
+
// We render useIntersection with ref.current = null,
|
|
32
|
+
// which should prevent our hook from calling intersectionObserver.
|
|
33
|
+
const hook = renderHook(() => useIntersection({ current: null }, options));
|
|
34
|
+
expect(mockObserve).not.toHaveBeenCalled();
|
|
35
|
+
|
|
36
|
+
hook.unmount();
|
|
37
|
+
expect(mockDisconnect).not.toHaveBeenCalled();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('intersection observer is called', async () => {
|
|
41
|
+
// We render useIntersection with ref.current = HTMLdivElement,
|
|
42
|
+
// which should make our hook call intersectionObserver.
|
|
43
|
+
const hook = renderHook(() => useIntersection(ref, options));
|
|
44
|
+
expect(mockObserve).toHaveBeenCalledWith(ref.current);
|
|
45
|
+
|
|
46
|
+
hook.unmount();
|
|
47
|
+
expect(mockDisconnect).toHaveBeenCalled();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('returns the IntersectionObserverEntry from the callback', async () => {
|
|
51
|
+
const fakeIntersectionObserverEntry = {};
|
|
52
|
+
let handler: Function = () => {
|
|
53
|
+
return null;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// We mock the insersectionObserver Implementation
|
|
57
|
+
// to grab the handler, which allows us to simulate
|
|
58
|
+
// the element getting scrolled into view.
|
|
59
|
+
mockIntersectionObserver.mockImplementationOnce((cb) => {
|
|
60
|
+
handler = cb;
|
|
61
|
+
|
|
62
|
+
return mockIntersectionObserverInstance;
|
|
63
|
+
});
|
|
64
|
+
const { result, rerender, unmount } = renderHook(() =>
|
|
65
|
+
useIntersection(ref, options)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// Element hasn't been scrolled into view and therefore
|
|
69
|
+
// results.current should be null.
|
|
70
|
+
expect(result.current).toBeNull();
|
|
71
|
+
|
|
72
|
+
// Simulate element being scrolled into view
|
|
73
|
+
act(() => {
|
|
74
|
+
handler([fakeIntersectionObserverEntry]);
|
|
75
|
+
});
|
|
76
|
+
expect(result.current).toEqual(fakeIntersectionObserverEntry);
|
|
77
|
+
|
|
78
|
+
// We expect the results to remain the same after a rerender
|
|
79
|
+
rerender();
|
|
80
|
+
expect(result.current).toEqual(fakeIntersectionObserverEntry);
|
|
81
|
+
|
|
82
|
+
// The results should be null after unmounting.
|
|
83
|
+
unmount();
|
|
84
|
+
rerender();
|
|
85
|
+
expect(result.current).toBeNull();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { RefObject, useEffect, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
export const useIntersection = (
|
|
4
|
+
ref: RefObject<HTMLElement>,
|
|
5
|
+
options: IntersectionObserverInit
|
|
6
|
+
): IntersectionObserverEntry | null => {
|
|
7
|
+
const [
|
|
8
|
+
intersectionObserverEntry,
|
|
9
|
+
setIntersectionObserverEntry,
|
|
10
|
+
] = useState<IntersectionObserverEntry | null>(null);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (ref.current && typeof IntersectionObserver === 'function') {
|
|
14
|
+
const handler = (entries: IntersectionObserverEntry[]) => {
|
|
15
|
+
setIntersectionObserverEntry(entries[0]);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const observer = new IntersectionObserver(handler, {
|
|
19
|
+
threshold: options.threshold,
|
|
20
|
+
root: options.root,
|
|
21
|
+
rootMargin: options.rootMargin,
|
|
22
|
+
});
|
|
23
|
+
observer.observe(ref.current);
|
|
24
|
+
|
|
25
|
+
return () => {
|
|
26
|
+
setIntersectionObserverEntry(null);
|
|
27
|
+
observer.disconnect();
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
31
|
+
return () => {};
|
|
32
|
+
}, [ref, options.threshold, options.root, options.rootMargin]);
|
|
33
|
+
|
|
34
|
+
return intersectionObserverEntry;
|
|
35
|
+
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from './codeByteEditor';
|
|
2
|
-
export * from './consts';
|
|
3
|
-
export * from './types';
|
|
1
|
+
export * from './codeByteEditor';
|
|
2
|
+
export * from './consts';
|
|
3
|
+
export * from './types';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Select, Text } from '@codecademy/gamut';
|
|
2
|
+
import { ColorMode } from '@codecademy/gamut-styles';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
|
|
5
|
+
import type { LanguageOption } from './consts';
|
|
6
|
+
import { LanguageOptions } from './consts';
|
|
7
|
+
|
|
8
|
+
export type LanguageSelectionProps = {
|
|
9
|
+
onChange: (newLanguage: LanguageOption) => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const LanguageSelection: React.FC<LanguageSelectionProps> = ({
|
|
13
|
+
onChange,
|
|
14
|
+
}) => {
|
|
15
|
+
return (
|
|
16
|
+
<ColorMode mode="dark" flex={1} px={16} pt={48}>
|
|
17
|
+
<Text mb={16}>Which language do you want to code in?</Text>
|
|
18
|
+
<Select
|
|
19
|
+
id="language-select"
|
|
20
|
+
aria-label="Select a language"
|
|
21
|
+
options={LanguageOptions}
|
|
22
|
+
onChange={(e) => onChange(e.target.value as LanguageOption)}
|
|
23
|
+
/>
|
|
24
|
+
</ColorMode>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createTracker } from '@codecademy/tracking';
|
|
2
|
+
|
|
3
|
+
const IS_DEV = process.env.NODE_ENV === 'development';
|
|
4
|
+
|
|
5
|
+
// TODO: confirm tracking details and implementation DISC-447
|
|
6
|
+
const tracker = createTracker({
|
|
7
|
+
apiBaseUrl:
|
|
8
|
+
typeof window === 'undefined'
|
|
9
|
+
? 'https://www.codecademy.com'
|
|
10
|
+
: window.location.origin,
|
|
11
|
+
verbose: IS_DEV,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const {
|
|
15
|
+
click: trackUserClick,
|
|
16
|
+
visit: trackUserVisit,
|
|
17
|
+
impression: trackUserImpression,
|
|
18
|
+
} = tracker;
|
package/src/theme.d.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BackgroundProps } from '@codecademy/gamut-styles';
|
|
2
|
+
import { UserClickData } from '@codecademy/tracking';
|
|
3
|
+
|
|
4
|
+
import { LanguageOption } from './consts';
|
|
5
|
+
|
|
6
|
+
export interface CodebytesChangeHandler {
|
|
7
|
+
(text: string, language: LanguageOption): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface CodebytesCopyFormatterParams {
|
|
11
|
+
text: string;
|
|
12
|
+
language: LanguageOption;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type CodebytesCopyFormatter = ({
|
|
16
|
+
text,
|
|
17
|
+
language,
|
|
18
|
+
}: CodebytesCopyFormatterParams) => string;
|
|
19
|
+
|
|
20
|
+
export interface CodeByteEditorProps extends Omit<BackgroundProps, 'bg'> {
|
|
21
|
+
text?: string;
|
|
22
|
+
language?: LanguageOption;
|
|
23
|
+
hideCopyButton?: boolean;
|
|
24
|
+
copyFormatter?: CodebytesCopyFormatter;
|
|
25
|
+
snippetsBaseUrl?: string;
|
|
26
|
+
onEdit?: CodebytesChangeHandler;
|
|
27
|
+
onLanguageChange?: CodebytesChangeHandler;
|
|
28
|
+
trackingData?: Omit<UserClickData, 'target'>;
|
|
29
|
+
trackFirstEdit?: boolean;
|
|
30
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "./dist",
|
|
5
|
+
"esModuleInterop": true,
|
|
6
|
+
"jsx": "react",
|
|
7
|
+
"allowJs": true,
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"noUnusedParameters": false,
|
|
10
|
+
"sourceMap": true,
|
|
11
|
+
"strictFunctionTypes": false,
|
|
12
|
+
"strictPropertyInitialization": false
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
15
|
+
"exclude": [
|
|
16
|
+
"./dist",
|
|
17
|
+
"jest.config.ts",
|
|
18
|
+
"**/*.spec.ts",
|
|
19
|
+
"**/*.test.ts",
|
|
20
|
+
"**/*.spec.tsx",
|
|
21
|
+
"**/*.test.tsx",
|
|
22
|
+
"**/*.spec.js",
|
|
23
|
+
"**/*.test.js",
|
|
24
|
+
"**/*.spec.jsx",
|
|
25
|
+
"**/*.test.jsx"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"types": ["jest", "node"]
|
|
7
|
+
},
|
|
8
|
+
"include": [
|
|
9
|
+
"jest.config.ts",
|
|
10
|
+
"**/*.test.ts",
|
|
11
|
+
"**/*.spec.ts",
|
|
12
|
+
"**/*.test.tsx",
|
|
13
|
+
"**/*.spec.tsx",
|
|
14
|
+
"**/*.test.js",
|
|
15
|
+
"**/*.spec.js",
|
|
16
|
+
"**/*.test.jsx",
|
|
17
|
+
"**/*.spec.jsx",
|
|
18
|
+
"**/*.d.ts",
|
|
19
|
+
"src/__tests__/mocks.ts"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export declare const syntax: {
|
|
2
|
-
attribute: "#b4d353";
|
|
3
|
-
annotation: "#ea6c8b";
|
|
4
|
-
atom: "#cc7bc2";
|
|
5
|
-
basic: "#ffffff";
|
|
6
|
-
comment: "#939598";
|
|
7
|
-
constant: "#ff8973";
|
|
8
|
-
decoration: "#ea6c8b";
|
|
9
|
-
invalid: "#ea6c8b";
|
|
10
|
-
key: "#83fff5";
|
|
11
|
-
keyword: "#b3ccff";
|
|
12
|
-
number: "#ea6c8b";
|
|
13
|
-
operator: "#ea6c8b";
|
|
14
|
-
predefined: "#ffffff";
|
|
15
|
-
property: "#ea6c8b";
|
|
16
|
-
regexp: "#b4d353";
|
|
17
|
-
string: "#ffe083";
|
|
18
|
-
tag: "#ea6c8b";
|
|
19
|
-
text: "#ff8973";
|
|
20
|
-
value: "#ffe083";
|
|
21
|
-
variable: "#b4d353";
|
|
22
|
-
};
|
|
23
|
-
export declare const ui: {
|
|
24
|
-
background: string;
|
|
25
|
-
text: "#ffffff";
|
|
26
|
-
indent: {
|
|
27
|
-
active: string;
|
|
28
|
-
inactive: string;
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
export declare type SyntaxColors = typeof syntax;
|
|
32
|
-
export declare type UIColors = typeof ui;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { EditorProps } from '@monaco-editor/react';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
export declare type SimpleMonacoEditorProps = {
|
|
4
|
-
value: string;
|
|
5
|
-
language: string;
|
|
6
|
-
onChange?: EditorProps['onChange'];
|
|
7
|
-
};
|
|
8
|
-
export declare const SimpleMonacoEditor: React.FC<SimpleMonacoEditorProps>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare type Monaco = typeof import('monaco-editor');
|
package/dist/api.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { LanguageOption } from './consts';
|
|
2
|
-
interface Response {
|
|
3
|
-
stderr: string;
|
|
4
|
-
stdout: string;
|
|
5
|
-
exit_code: number;
|
|
6
|
-
}
|
|
7
|
-
interface PostSnippetData {
|
|
8
|
-
language: LanguageOption;
|
|
9
|
-
code: string;
|
|
10
|
-
}
|
|
11
|
-
export declare const postSnippet: (data: PostSnippetData, snippetsBaseUrl?: string | undefined) => Promise<Response>;
|
|
12
|
-
export {};
|
package/dist/codeByteEditor.d.ts
DELETED
package/dist/consts.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export declare const LanguageOptions: {
|
|
2
|
-
'': string;
|
|
3
|
-
cpp: string;
|
|
4
|
-
csharp: string;
|
|
5
|
-
golang: string;
|
|
6
|
-
javascript: string;
|
|
7
|
-
php: string;
|
|
8
|
-
python: string;
|
|
9
|
-
ruby: string;
|
|
10
|
-
scheme: string;
|
|
11
|
-
};
|
|
12
|
-
export declare type LanguageOption = keyof typeof LanguageOptions;
|
|
13
|
-
export declare const validLanguages: ("cpp" | "csharp" | "golang" | "javascript" | "php" | "python" | "ruby" | "scheme")[];
|
|
14
|
-
export declare const helloWorld: {
|
|
15
|
-
readonly cpp: "#include <iostream>\nint main() {\n std::cout << \"Hello world!\";\n return 0;\n}";
|
|
16
|
-
readonly csharp: "namespace HelloWorld {\n class Hello {\n static void Main(string[] args) {\n System.Console.WriteLine(\"Hello world!\");\n }\n }\n}";
|
|
17
|
-
readonly golang: "package main\nimport \"fmt\"\nfunc main() {\n fmt.Println(\"Hello world!\")\n}";
|
|
18
|
-
readonly javascript: "console.log('Hello world!');";
|
|
19
|
-
readonly php: "<?php\n echo \"Hello world!\";\n?>";
|
|
20
|
-
readonly python: "print('Hello world!')";
|
|
21
|
-
readonly ruby: "puts \"Hello world!\"";
|
|
22
|
-
readonly scheme: "(begin\n (display \"Hello world!\")\n (newline))";
|
|
23
|
-
};
|
package/dist/drawers.d.ts
DELETED
package/dist/editor.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { UserClickData } from '@codecademy/tracking';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import type { LanguageOption } from './consts';
|
|
4
|
-
import { CodebytesCopyFormatter } from './types';
|
|
5
|
-
declare type EditorProps = {
|
|
6
|
-
hideCopyButton: boolean;
|
|
7
|
-
language: LanguageOption;
|
|
8
|
-
text: string;
|
|
9
|
-
onChange: (text: string) => void;
|
|
10
|
-
snippetsBaseUrl?: string;
|
|
11
|
-
copyFormatter?: CodebytesCopyFormatter;
|
|
12
|
-
trackingData?: Omit<UserClickData, 'target'>;
|
|
13
|
-
};
|
|
14
|
-
export declare const Editor: React.FC<EditorProps>;
|
|
15
|
-
export {};
|
package/dist/helpers/index.d.ts
DELETED