@gpichot/spectacle-deck 1.0.8 → 1.1.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.
Files changed (65) hide show
  1. package/dist/components/DocumentationItem.d.ts +10 -0
  2. package/{index.cjs → dist/index.cjs} +288 -141
  3. package/{index.d.ts → dist/index.d.ts} +4 -6
  4. package/{index.mjs → dist/index.mjs} +287 -140
  5. package/dist/layouts/QuoteLayout.d.ts +6 -0
  6. package/{layouts → dist/layouts}/index.d.ts +2 -0
  7. package/dist/package.json +30 -0
  8. package/package.json +20 -16
  9. package/scripts/bundle.ts +84 -0
  10. package/src/components/CodeStepper/CodeStepper.tsx +223 -0
  11. package/src/components/CodeStepper/code-directives.test.ts +58 -0
  12. package/src/components/CodeStepper/code-directives.ts +129 -0
  13. package/src/components/DocumentationItem.tsx +85 -0
  14. package/src/components/FilePane.tsx +18 -0
  15. package/src/components/HorizontalList.tsx +140 -0
  16. package/src/components/IconBox.tsx +31 -0
  17. package/src/components/Image.tsx +34 -0
  18. package/src/components/ItemsColumn.tsx +56 -0
  19. package/src/components/Timeline.styled.tsx +24 -0
  20. package/src/components/Timeline.tsx +157 -0
  21. package/src/components/map.tsx +115 -0
  22. package/src/components/styled.tsx +73 -0
  23. package/src/front.png +0 -0
  24. package/src/index.tsx +109 -0
  25. package/src/layouts/CenteredLayout.tsx +40 -0
  26. package/src/layouts/Default3Layout.tsx +159 -0
  27. package/src/layouts/MainSectionLayout.tsx +31 -0
  28. package/src/layouts/QuoteLayout.tsx +99 -0
  29. package/src/layouts/SectionLayout.tsx +14 -0
  30. package/src/layouts/SideCodeLayout.tsx +44 -0
  31. package/src/layouts/SideImageLayout.tsx +72 -0
  32. package/src/layouts/SideLayout.tsx +31 -0
  33. package/src/layouts/columns.tsx +56 -0
  34. package/src/layouts/index.tsx +19 -0
  35. package/src/layouts/styled.ts +7 -0
  36. package/src/layouts/utils.ts +65 -0
  37. package/src/node.d.ts +5 -0
  38. package/src/style.d.ts +10 -0
  39. package/src/template.tsx +25 -0
  40. package/src/theme.ts +24 -0
  41. package/test.js +106 -0
  42. package/tsconfig.json +29 -0
  43. /package/{components → dist/components}/CodeStepper/CodeStepper.d.ts +0 -0
  44. /package/{components → dist/components}/CodeStepper/code-directives.d.ts +0 -0
  45. /package/{components → dist/components}/FilePane.d.ts +0 -0
  46. /package/{components → dist/components}/HorizontalList.d.ts +0 -0
  47. /package/{components → dist/components}/IconBox.d.ts +0 -0
  48. /package/{components → dist/components}/Image.d.ts +0 -0
  49. /package/{components → dist/components}/ItemsColumn.d.ts +0 -0
  50. /package/{components → dist/components}/Timeline.d.ts +0 -0
  51. /package/{components → dist/components}/Timeline.styled.d.ts +0 -0
  52. /package/{components → dist/components}/map.d.ts +0 -0
  53. /package/{components → dist/components}/styled.d.ts +0 -0
  54. /package/{layouts → dist/layouts}/CenteredLayout.d.ts +0 -0
  55. /package/{layouts → dist/layouts}/Default3Layout.d.ts +0 -0
  56. /package/{layouts → dist/layouts}/MainSectionLayout.d.ts +0 -0
  57. /package/{layouts → dist/layouts}/SectionLayout.d.ts +0 -0
  58. /package/{layouts → dist/layouts}/SideCodeLayout.d.ts +0 -0
  59. /package/{layouts → dist/layouts}/SideImageLayout.d.ts +0 -0
  60. /package/{layouts → dist/layouts}/SideLayout.d.ts +0 -0
  61. /package/{layouts → dist/layouts}/columns.d.ts +0 -0
  62. /package/{layouts → dist/layouts}/styled.d.ts +0 -0
  63. /package/{layouts → dist/layouts}/utils.d.ts +0 -0
  64. /package/{template.d.ts → dist/template.d.ts} +0 -0
  65. /package/{theme.d.ts → dist/theme.d.ts} +0 -0
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+ export declare function QuoteLayout({ children, author, url, }: {
3
+ children: React.ReactNode;
4
+ author: string;
5
+ url?: string;
6
+ }): React.JSX.Element;
@@ -1,5 +1,6 @@
1
1
  /// <reference types="react" />
2
2
  /// <reference types="react" />
3
+ import { QuoteLayout } from "./QuoteLayout";
3
4
  import { SidedCodeLayout } from "./SideCodeLayout";
4
5
  import { SideLayout } from "./SideLayout";
5
6
  declare const _default: {
@@ -11,6 +12,7 @@ declare const _default: {
11
12
  children: import("react").ReactNode;
12
13
  position?: "left" | "right";
13
14
  }) => import("react").JSX.Element;
15
+ quote: typeof QuoteLayout;
14
16
  sidedCode: typeof SidedCodeLayout;
15
17
  sidedImage: ({ children, image, position, height, }: {
16
18
  children: import("react").ReactNode;
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@gpichot/spectacle-deck",
3
+ "version": "1.1.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "main": "index.cjs",
7
+ "types": "index.d.ts",
8
+ "module": "index.mjs",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./index.d.ts",
12
+ "require": "./index.cjs",
13
+ "import": "./index.mjs"
14
+ }
15
+ },
16
+ "keywords": [
17
+ "spectacle"
18
+ ],
19
+ "dependencies": {
20
+ "@fontsource/bitter": "^5.0.15",
21
+ "@mdx-js/react": "^3.0.0",
22
+ "react": "^18.2.0",
23
+ "react-dom": "^18.2.0",
24
+ "react-is": "^18.2.0",
25
+ "react-spring": "^9.7.3",
26
+ "react-syntax-highlighter": "^15.5.0",
27
+ "spectacle": "^10.1.6",
28
+ "styled-components": "^6.1.0"
29
+ }
30
+ }
package/package.json CHANGED
@@ -1,21 +1,12 @@
1
1
  {
2
2
  "name": "@gpichot/spectacle-deck",
3
- "version": "1.0.8",
4
- "license": "MIT",
5
- "type": "module",
6
- "main": "index.cjs",
7
- "types": "index.d.ts",
8
- "module": "index.mjs",
9
- "exports": {
10
- ".": {
11
- "types": "./index.d.ts",
12
- "require": "./index.cjs",
13
- "import": "./index.mjs"
14
- }
15
- },
16
- "keywords": [
17
- "spectacle"
18
- ],
3
+ "version": "1.1.0",
4
+ "description": "",
5
+ "module": "src/index.tsx",
6
+ "types": "src/index.d.ts",
7
+ "keywords": [],
8
+ "author": "",
9
+ "license": "ISC",
19
10
  "dependencies": {
20
11
  "@fontsource/bitter": "^5.0.15",
21
12
  "@mdx-js/react": "^3.0.0",
@@ -26,5 +17,18 @@
26
17
  "react-syntax-highlighter": "^15.5.0",
27
18
  "spectacle": "^10.1.6",
28
19
  "styled-components": "^6.1.0"
20
+ },
21
+ "devDependencies": {
22
+ "@arnaud-barre/tnode": "^0.19.2",
23
+ "@types/react": "^18.2.34",
24
+ "@types/react-dom": "^18.2.14",
25
+ "@types/react-is": "^18.2.3",
26
+ "@types/react-syntax-highlighter": "^15.5.9",
27
+ "esbuild": "^0.19.5",
28
+ "typescript": "^5.2.2"
29
+ },
30
+ "scripts": {
31
+ "test": "echo \"Error: no test specified\" && exit 1",
32
+ "build": "tnode scripts/bundle.ts"
29
33
  }
30
34
  }
@@ -0,0 +1,84 @@
1
+ import { rmSync, writeFileSync, copyFileSync } from "node:fs";
2
+ import { execSync } from "node:child_process";
3
+ import { build, BuildOptions, context } from "esbuild";
4
+
5
+ import packageJSON from "../package.json";
6
+
7
+ const dev = process.argv.includes("--dev");
8
+
9
+ rmSync("dist", { force: true, recursive: true });
10
+
11
+ const serverOptions: BuildOptions = {
12
+ bundle: true,
13
+ platform: "node",
14
+ target: "node14",
15
+ legalComments: "inline",
16
+ loader: {
17
+ ".png": "dataurl",
18
+ },
19
+ external: Object.keys(packageJSON.peerDependencies || {}).concat(
20
+ Object.keys(packageJSON.dependencies || {})
21
+ ),
22
+ };
23
+
24
+ const buildOrWatch = async (options: BuildOptions) => {
25
+ if (!dev) return build(options);
26
+ const ctx = await context(options);
27
+ await ctx.watch();
28
+ await ctx.rebuild();
29
+ };
30
+
31
+ Promise.all([
32
+ buildOrWatch({
33
+ ...serverOptions,
34
+ stdin: {
35
+ contents: `import * as mod from "./src";
36
+ module.exports = mod;
37
+ `,
38
+ resolveDir: ".",
39
+ },
40
+ outfile: "dist/index.cjs",
41
+ logOverride: { "empty-import-meta": "silent" },
42
+ }),
43
+ buildOrWatch({
44
+ ...serverOptions,
45
+ entryPoints: ["src/index.tsx"],
46
+ format: "esm",
47
+ outfile: "dist/index.mjs",
48
+ }),
49
+ ]).then(() => {
50
+ // copyFileSync("LICENSE", "dist/LICENSE");
51
+ // copyFileSync("README.md", "dist/README.md");
52
+
53
+ execSync(
54
+ "tsc src/index.tsx --declaration --jsx react --emitDeclarationOnly --outDir dist --module es2020 --target es2020 --allowSyntheticDefaultImports --skipLibCheck --moduleResolution node --types ./src/node.d.ts,./src/style.d.ts",
55
+ { stdio: "inherit" }
56
+ );
57
+
58
+ writeFileSync(
59
+ "dist/package.json",
60
+ JSON.stringify(
61
+ {
62
+ name: "@gpichot/spectacle-deck",
63
+ version: packageJSON.version,
64
+ license: "MIT",
65
+ type: "module",
66
+ main: "index.cjs",
67
+ types: "index.d.ts",
68
+ module: "index.mjs",
69
+ exports: {
70
+ ".": {
71
+ types: "./index.d.ts",
72
+ require: "./index.cjs",
73
+ import: "./index.mjs",
74
+ },
75
+ },
76
+ keywords: ["spectacle"],
77
+ peerDependencies: packageJSON.peerDependencies,
78
+ dependencies: packageJSON.dependencies,
79
+ },
80
+ null,
81
+ 2
82
+ )
83
+ );
84
+ });
@@ -0,0 +1,223 @@
1
+ import React from "react";
2
+ import ReactIs from "react-is";
3
+ import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
4
+ import { gruvboxDark } from "react-syntax-highlighter/dist/esm/styles/prism";
5
+ import { Stepper } from "spectacle";
6
+ import styled from "styled-components";
7
+
8
+ import { parseStepDirectives, Step } from "./code-directives";
9
+
10
+ const Highlighter = SyntaxHighlighter as unknown as React.ElementType;
11
+
12
+ const CodeContainer = styled.div`
13
+ pre {
14
+ padding: 1rem 0rem !important;
15
+ background-color: transparent !important;
16
+ }
17
+ .linenumber {
18
+ min-width: 2rem !important;
19
+ }
20
+ [data-highlight-line="true"] {
21
+ &:before {
22
+ content: " ";
23
+ position: absolute;
24
+ background-color: #f4967688;
25
+ }
26
+
27
+ &[data-step-active="true"]:before {
28
+ background-color: #f49676;
29
+ }
30
+ }
31
+ `;
32
+
33
+ function useCodeSteps(code: string) {
34
+ return React.useMemo(() => {
35
+ const prefixes = code.match(/(?:\/\/|<!--) @.*\n/g) || ([] as string[]);
36
+ const prefixesLength = prefixes.reduce(
37
+ (acc, prefix) => acc + prefix.length,
38
+ 0
39
+ );
40
+
41
+ const codeWithoutPrefixes = code.slice(prefixesLength);
42
+
43
+ const hasDirectives = prefixes.length > 0;
44
+ const allDirectives = hasDirectives ? [...prefixes] : [];
45
+ const steps = parseStepDirectives(allDirectives);
46
+
47
+ return {
48
+ steps,
49
+ code: codeWithoutPrefixes,
50
+ prefixes,
51
+ hasSteps: Boolean(steps.length),
52
+ hasName: steps.some((step) => step.name),
53
+ };
54
+ }, [code]);
55
+ }
56
+
57
+ function getCodeDetails(children: React.ReactNode) {
58
+ const child = React.Children.toArray(children)[0];
59
+
60
+ if (!React.isValidElement(child)) {
61
+ return {
62
+ language: "",
63
+ code: ReactIs.isFragment(child) ? "" : String(child || ""),
64
+ };
65
+ }
66
+
67
+ const result = {
68
+ language: (String(child.props.className) || "").replace("language-", ""),
69
+ code: (child.props.children as string).trim(),
70
+ };
71
+
72
+ return result;
73
+ }
74
+
75
+ function CodeWrapper({
76
+ name,
77
+ stepName,
78
+ hasName,
79
+ children,
80
+ }: {
81
+ name?: string;
82
+ stepName?: string;
83
+ hasName?: boolean;
84
+ children: React.ReactNode;
85
+ }) {
86
+ return (
87
+ <div
88
+ style={{
89
+ boxSizing: "border-box",
90
+ margin: "0.5rem 1rem",
91
+ backgroundColor: "rgb(38,39,40)",
92
+ borderRadius: "4px",
93
+ }}
94
+ >
95
+ {name && (
96
+ <span
97
+ style={{
98
+ fontFamily: 'Consolas, Monaco, "Andale Mono", monospace',
99
+ fontSize: "1rem",
100
+ color: "#ffffffbb",
101
+ backgroundColor: "#33333388",
102
+ display: "inline-block",
103
+ padding: "8px 8px",
104
+ width: "100%",
105
+ boxSizing: "border-box",
106
+ }}
107
+ >
108
+ {name}
109
+ </span>
110
+ )}
111
+ {children}
112
+ {hasName && (
113
+ <span
114
+ style={{
115
+ fontFamily: 'Consolas, Monaco, "Andale Mono", monospace',
116
+ fontSize: "0.8rem",
117
+ color: "#ffffffaa",
118
+ backgroundColor: "#33333388",
119
+ display: "inline-block",
120
+ padding: "4px 8px",
121
+ width: "100%",
122
+ boxSizing: "border-box",
123
+ fontStyle: "italic",
124
+ }}
125
+ >
126
+ {stepName || <span style={{ visibility: "hidden" }}>Step</span>}
127
+ </span>
128
+ )}
129
+ </div>
130
+ );
131
+ }
132
+
133
+ export default function CodeStepper({
134
+ priority,
135
+ name,
136
+ ...props
137
+ }: React.ComponentProps<"pre"> & {
138
+ priority?: number;
139
+ name?: string;
140
+ }) {
141
+ const { language, code } = React.useMemo(() => {
142
+ return getCodeDetails(props.children);
143
+ }, [props.children]);
144
+
145
+ const {
146
+ steps,
147
+ code: codeNormalized,
148
+ prefixes,
149
+ hasSteps,
150
+ hasName,
151
+ } = useCodeSteps(code);
152
+ return (
153
+ <CodeContainer>
154
+ {import.meta.env.DEV && Boolean(prefixes?.length) && (
155
+ <div style={{ position: "absolute", top: 0, opacity: 0.5, left: 0 }}>
156
+ <Highlighter language={language} style={gruvboxDark}>
157
+ {prefixes.join("")}
158
+ </Highlighter>
159
+ </div>
160
+ )}
161
+ <Stepper
162
+ values={steps}
163
+ alwaysVisible={!hasSteps}
164
+ priority={priority ? priority + 1 : undefined}
165
+ >
166
+ {(step, _, isActive) => (
167
+ <CodeWrapper
168
+ name={name}
169
+ stepName={(step as Step | null)?.name}
170
+ hasName={hasName}
171
+ >
172
+ <Highlighter
173
+ language={language}
174
+ wrapLines
175
+ showLineNumbers
176
+ style={gruvboxDark}
177
+ lineNumberStyle={(lineNumber: number) => {
178
+ const { highlight = [] } = (step as Step) || {};
179
+ const isHighlighted = highlight.includes(lineNumber);
180
+
181
+ return {
182
+ fontWeight: isHighlighted ? "bold" : "normal",
183
+ };
184
+ }}
185
+ lineProps={(lineNumber: number) => {
186
+ const { hiddenLines = [], highlight = [] } =
187
+ (step as Step) || {};
188
+ const isVisible =
189
+ hasSteps && isActive
190
+ ? !hiddenLines.includes(lineNumber)
191
+ : isActive || !hasSteps;
192
+ const isHighlighted = highlight.includes(lineNumber);
193
+ const getOpacity = () => {
194
+ if (!isVisible) return 0;
195
+ if (isHighlighted || !highlight.length) return 1;
196
+ return 0.8;
197
+ };
198
+
199
+ return {
200
+ ...(isHighlighted && {
201
+ "data-highlight-line": isHighlighted,
202
+ "data-step-active": isActive,
203
+ }),
204
+ style: {
205
+ opacity: getOpacity(),
206
+ transition: "all 0.3s ease",
207
+ display: "block",
208
+ width: "100%",
209
+ backgroundColor: isHighlighted ? "#f4967622" : "",
210
+ },
211
+ };
212
+ }}
213
+ >
214
+ {codeNormalized}
215
+ </Highlighter>
216
+ </CodeWrapper>
217
+ )}
218
+ </Stepper>
219
+ </CodeContainer>
220
+ );
221
+ }
222
+
223
+ CodeStepper.mdxType = "CodeStepper";
@@ -0,0 +1,58 @@
1
+ import { parseStepDirectives } from './code-directives';
2
+
3
+ function splitDirectives(str: string): string[] {
4
+ return str.trim().split('\n');
5
+ }
6
+
7
+ describe('parseStepDirectives', () => {
8
+ it('should reduce properly with showLines', () => {
9
+ const directives = splitDirectives(`
10
+ // @step showLines(1-3) highlight(1-3)
11
+ // @step showLines(4-6) highlight(4-6)
12
+ `);
13
+
14
+ const result = parseStepDirectives(directives);
15
+ expect(result[0]).toEqual({ hiddenLines: [4, 5, 6], highlight: [1, 2, 3] });
16
+ expect(result[1]).toEqual({ hiddenLines: [], highlight: [4, 5, 6] });
17
+ });
18
+
19
+ it('should reduce properly with highlight', () => {
20
+ const directives = splitDirectives(`
21
+ // @step highlight(3)
22
+ // @step showLines(4) highlight(4)
23
+ `);
24
+
25
+ const result = parseStepDirectives(directives);
26
+ expect(result).toHaveLength(2);
27
+ expect(result[0]).toEqual({ hiddenLines: [4], highlight: [3] });
28
+ expect(result[1]).toEqual({ hiddenLines: [], highlight: [4] });
29
+ });
30
+
31
+ it('parse only highlights', () => {
32
+ const directives = splitDirectives(`
33
+ // @step highlight(6)
34
+ // @step highlight(7-9)
35
+ // @step highlight(10)
36
+ `);
37
+
38
+ const result = parseStepDirectives(directives);
39
+ expect(result).toHaveLength(3);
40
+ expect(result[0]).toEqual({ hiddenLines: [], highlight: [6] });
41
+ expect(result[1]).toEqual({ hiddenLines: [], highlight: [7, 8, 9] });
42
+ expect(result[2]).toEqual({ hiddenLines: [], highlight: [10] });
43
+ });
44
+
45
+ it('parses typescript lines', () => {
46
+ const directives = splitDirectives(`
47
+ // @step highlight(3) name("(string|number)[]")
48
+ `);
49
+
50
+ const result = parseStepDirectives(directives);
51
+ expect(result).toHaveLength(1);
52
+ expect(result[0]).toEqual({
53
+ hiddenLines: [],
54
+ highlight: [3],
55
+ name: '(string|number)[]',
56
+ });
57
+ });
58
+ });
@@ -0,0 +1,129 @@
1
+ /**
2
+ * The Code Stepper component is a component that allows you to step through
3
+ * the code using familiar directives.
4
+ *
5
+ * @example "@step showLines(1-3)" will show lines 1-3
6
+ * @example "@step highlight(1-3)" will highlight lines 1-3
7
+ *
8
+ */
9
+
10
+ function range(start: number, end: number) {
11
+ return Array.from({ length: end - start + 1 }, (_, i) => i + start);
12
+ }
13
+
14
+ /**
15
+ * Function parse ranges list
16
+ */
17
+ function parseRangeList(str: string): number[] {
18
+ return str.split(',').reduce((acc, line) => {
19
+ if (!line.includes('-')) return [...acc, parseInt(line, 10)];
20
+
21
+ const [start, end] = line.split('-').map(Number);
22
+ return [...acc, ...range(start, end)];
23
+ }, [] as number[]);
24
+ }
25
+
26
+ /**
27
+ * Parse showLines fn
28
+ *
29
+ * "showLines(1-3)" => [1, 2, 3]
30
+ * "showLines(1,3)" => [1,3]
31
+ * "showLines(1-2,4-5)" => [1,2,4,5]
32
+ */
33
+ function parseShowLines(directive: string): { showLines: number[] } | null {
34
+ const match = directive.match(/showLines\((.*)\)/);
35
+ if (!match) return null;
36
+
37
+ const lines = parseRangeList(match[1]);
38
+
39
+ return { showLines: lines };
40
+ }
41
+
42
+ /**
43
+ * Parse highlight fn
44
+ *
45
+ * "highlight(1-3)" => [1,2,3]
46
+ * etc.
47
+ */
48
+ function parseHighlight(directive: string): { highlight: number[] } | null {
49
+ const match = directive.match(/highlight\((.*)\)/);
50
+ if (!match) return null;
51
+
52
+ const lines = parseRangeList(match[1]);
53
+
54
+ return { highlight: lines };
55
+ }
56
+
57
+ type StepDirective = {
58
+ showLines?: number[];
59
+ highlight?: number[];
60
+ name?: string;
61
+ };
62
+
63
+ /**
64
+ * Parse name fn
65
+ *
66
+ * "name("my name")" => "my name"
67
+ */
68
+ function parseName(directive: string): { name: string } | null {
69
+ const match = directive.match(/name\("(.*)"\)/);
70
+ if (!match) return null;
71
+
72
+ return { name: match[1] };
73
+ }
74
+
75
+ /**
76
+ * Parse step directive
77
+ *
78
+ * @example "@step showLines(1-3) highlight(1-3)"
79
+ * @example "@step showLines(1-3)"
80
+ * @example "@step highlight(1-3)"
81
+ */
82
+ function parseStepDirective(directive: string): StepDirective {
83
+ // Should match a showLines(1-3) or highlight(1-3) directive
84
+ // Should match name("(string)")
85
+ const regex = /showLines\([^)]+\)|highlight\([^)]+\)|name\("(.*)"\)/g;
86
+
87
+ const directives = directive.match(regex) || [];
88
+
89
+ const name = directives.map(parseName).find(Boolean);
90
+ const showLines = directives.map(parseShowLines).find(Boolean);
91
+ const highlight = directives.map(parseHighlight).find(Boolean);
92
+
93
+ return { ...showLines, ...highlight, ...name };
94
+ }
95
+
96
+ export type Step = {
97
+ hiddenLines: number[];
98
+ highlight: number[];
99
+ name?: string;
100
+ };
101
+
102
+ /**
103
+ * Reduce steps directives
104
+ */
105
+ export function combineStepDirectives(directives: StepDirective[]): Step[] {
106
+ let hiddenLines = directives.reduce((acc, { showLines }) => {
107
+ if (!showLines) return acc;
108
+
109
+ return [...acc, ...showLines];
110
+ }, [] as number[]);
111
+
112
+ return directives.map(({ highlight, showLines, name }) => {
113
+ hiddenLines = hiddenLines.filter((line) => !showLines?.includes(line));
114
+ return {
115
+ highlight: highlight || [],
116
+ hiddenLines,
117
+ name,
118
+ };
119
+ });
120
+ }
121
+
122
+ /**
123
+ * Parse step directives
124
+ */
125
+ export function parseStepDirectives(directives: string[]): Step[] {
126
+ const parsedDirectives = directives.map(parseStepDirective);
127
+
128
+ return combineStepDirectives(parsedDirectives);
129
+ }
@@ -0,0 +1,85 @@
1
+ import React from "react";
2
+
3
+ import styled from "styled-components";
4
+
5
+ const DocWrapper = styled.div`
6
+ position: absolute;
7
+ bottom: 0;
8
+ right: 0;
9
+ z-index: 10000;
10
+
11
+ .docContent {
12
+ display: none;
13
+ }
14
+
15
+ &:hover .docContent {
16
+ display: flex;
17
+ }
18
+ `;
19
+
20
+ const DocContainer = styled.div`
21
+ margin: 2rem 1rem;
22
+ background-color: #333;
23
+ border: 1px solid #333;
24
+ padding: 0.5rem 1rem;
25
+ border-radius: 1.5rem;
26
+ `;
27
+
28
+ const DocLink = styled.a`
29
+ text-decoration: none;
30
+ font-weight: normal;
31
+ font-family: Bitter, "Helvetica Neue", Helvetica, Arial, sans-serif;
32
+ color: #f49676;
33
+ `;
34
+
35
+ const DocLinkItem = styled(DocLink)`
36
+ width: fit-content;
37
+ display: inline-block;
38
+ background-color: #333;
39
+ border: 1px solid #333;
40
+ padding: 0.5rem 1rem;
41
+ border-radius: 1.5rem;
42
+ margin: 0.25rem 0;
43
+ `;
44
+
45
+ const DocContent = styled.div`
46
+ display: flex;
47
+ flex-flow: column-reverse nowrap;
48
+ position: absolute;
49
+ right: 1rem;
50
+ bottom: 4.5rem;
51
+ text-align: right;
52
+ border-radius: 0.5rem;
53
+ align-items: flex-end;
54
+ `;
55
+
56
+ export function Doc({
57
+ label,
58
+ link,
59
+ children,
60
+ }: {
61
+ label: string;
62
+ link: string;
63
+ children: React.ReactNode;
64
+ }) {
65
+ return (
66
+ <DocWrapper>
67
+ <DocContainer>
68
+ {children && <DocContent>{children}</DocContent>}
69
+ <div>
70
+ <DocLink target="_blank" rel="noopener noreferrer" href={link}>
71
+ {label}
72
+ </DocLink>
73
+ </div>
74
+ </DocContainer>
75
+ </DocWrapper>
76
+ );
77
+ }
78
+
79
+ export function DocItem({ label, link }: { label: string; link: string }) {
80
+ return (
81
+ <DocLinkItem target="_blank" rel="noopener noreferrer" href={link}>
82
+ {label}
83
+ </DocLinkItem>
84
+ );
85
+ }
@@ -0,0 +1,18 @@
1
+ import React from "react";
2
+
3
+ export default function FilePane({
4
+ name,
5
+ children,
6
+ priority,
7
+ ...divProps
8
+ }: React.ComponentProps<"div"> & { name: string; priority?: number }) {
9
+ return React.isValidElement(children)
10
+ ? React.cloneElement(children, {
11
+ // @ts-expect-error cloning
12
+ priority,
13
+ name,
14
+ })
15
+ : children;
16
+ }
17
+
18
+ FilePane.mdxType = "FilePane";