@code-hike/mdx
Advanced tools
Comparing version 0.3.0--canary.77.979e373.0 to 0.3.0--canary.77.bd15ff1.0
@@ -1,10 +0,13 @@ | ||
import { Node, Parent } from "unist"; | ||
/// <reference types="react" /> | ||
import { Node } from "unist"; | ||
import { NodeInfo } from "./unist-utils"; | ||
import { EditorProps } from "@code-hike/mini-editor"; | ||
export declare function transformCodeNodes(tree: Node, { theme }: { | ||
theme: any; | ||
}): Promise<void>; | ||
declare type NodeInfo = { | ||
node: Node; | ||
index: number; | ||
parent: Parent; | ||
}; | ||
export declare function Code(props: EditorProps): JSX.Element; | ||
export declare function isEditorNode(node: Node): boolean; | ||
export declare function mapAnyCodeNode(nodeInfo: NodeInfo, config: { | ||
theme: any; | ||
}): Promise<EditorProps>; | ||
export declare function transformEditor(nodeInfo: NodeInfo, config: { | ||
@@ -15,18 +18,2 @@ theme: any; | ||
theme: any; | ||
}): Promise<{ | ||
northPanel: { | ||
tabs: any; | ||
active: any; | ||
heightRatio: number; | ||
}; | ||
southPanel: { | ||
tabs: any; | ||
active: any; | ||
heightRatio: number; | ||
} | null; | ||
files: any; | ||
codeConfig: { | ||
theme: any; | ||
}; | ||
}>; | ||
export {}; | ||
}): Promise<EditorProps>; |
@@ -1,3 +0,6 @@ | ||
/// <reference types="react" /> | ||
import { Section, SectionLink, SectionCode } from "./section"; | ||
import { Code } from "./code"; | ||
import { CodeLink } from "./links"; | ||
import { Spotlight } from "./spotlight"; | ||
import { Scrollycoding } from "./scrollycoding"; | ||
export declare const CH: { | ||
@@ -8,10 +11,5 @@ Code: typeof Code; | ||
SectionCode: typeof SectionCode; | ||
CodeLink: typeof CodeLink; | ||
Spotlight: typeof Spotlight; | ||
Scrollycoding: typeof Scrollycoding; | ||
}; | ||
declare type EditorSerializedProps = { | ||
northPanel: any; | ||
southPanel?: any; | ||
files: any; | ||
codeConfig: any; | ||
}; | ||
export declare function Code(serializedProps: EditorSerializedProps): JSX.Element; | ||
export {}; |
@@ -5,13 +5,15 @@ 'use strict'; | ||
var visit = require('unist-util-visit'); | ||
var highlighter = require('@code-hike/highlighter'); | ||
var estreeUtilValueToEstree = require('estree-util-value-to-estree'); | ||
var React = require('react'); | ||
var visit = require('unist-util-visit'); | ||
var isPlainObject = require('is-plain-obj'); | ||
var smoothCode = require('@code-hike/smooth-code'); | ||
var miniEditor = require('@code-hike/mini-editor'); | ||
var scroller = require('@code-hike/scroller'); | ||
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
var React__default = /*#__PURE__*/_interopDefaultLegacy(React); | ||
var visit__default = /*#__PURE__*/_interopDefaultLegacy(visit); | ||
var React__default = /*#__PURE__*/_interopDefaultLegacy(React); | ||
var isPlainObject__default = /*#__PURE__*/_interopDefaultLegacy(isPlainObject); | ||
@@ -117,2 +119,9 @@ /*! ***************************************************************************** | ||
function CodeLink(_a) { | ||
var children = _a.children, data = _a.data; | ||
return (React__default['default'].createElement("a", { href: data.url, target: "_blank", rel: "noopener noreferrer", title: data.title, style: { | ||
textDecoration: "underline", | ||
textDecorationStyle: "dotted", | ||
} }, children)); | ||
} | ||
function extractLinks(node, index, parent, code) { | ||
@@ -126,3 +135,3 @@ var annotations = []; | ||
annotations.push({ | ||
type: "link", | ||
Component: CodeLink, | ||
focus: focus, | ||
@@ -161,2 +170,194 @@ data: { | ||
/** | ||
* Convert a value to an ESTree node | ||
* | ||
* @param value - The value to convert | ||
* @param options - Additional options to configure the output. | ||
* @returns The ESTree node. | ||
*/ | ||
function valueToEstree(value, options) { | ||
if (options === void 0) { options = {}; } | ||
if (value === undefined) { | ||
return { type: "Identifier", name: "undefined" }; | ||
} | ||
if (value == null) { | ||
return { type: "Literal", value: null, raw: "null" }; | ||
} | ||
if (value === Number.POSITIVE_INFINITY) { | ||
return { type: "Identifier", name: "Infinity" }; | ||
} | ||
if (Number.isNaN(value)) { | ||
return { type: "Identifier", name: "NaN" }; | ||
} | ||
if (typeof value === "boolean") { | ||
return { type: "Literal", value: value, raw: String(value) }; | ||
} | ||
if (typeof value === "bigint") { | ||
return value >= 0 | ||
? { | ||
type: "Literal", | ||
value: value, | ||
raw: value + "n", | ||
bigint: String(value), | ||
} | ||
: { | ||
type: "UnaryExpression", | ||
operator: "-", | ||
prefix: true, | ||
argument: valueToEstree(-value, options), | ||
}; | ||
} | ||
if (typeof value === "number") { | ||
return value >= 0 | ||
? { type: "Literal", value: value, raw: String(value) } | ||
: { | ||
type: "UnaryExpression", | ||
operator: "-", | ||
prefix: true, | ||
argument: valueToEstree(-value, options), | ||
}; | ||
} | ||
if (typeof value === "string") { | ||
return { | ||
type: "Literal", | ||
value: value, | ||
raw: JSON.stringify(value), | ||
}; | ||
} | ||
if (typeof value === "symbol") { | ||
if (value.description && | ||
value === Symbol["for"](value.description)) { | ||
return { | ||
type: "CallExpression", | ||
optional: false, | ||
callee: { | ||
type: "MemberExpression", | ||
computed: false, | ||
optional: false, | ||
object: { type: "Identifier", name: "Symbol" }, | ||
property: { type: "Identifier", name: "for" }, | ||
}, | ||
arguments: [ | ||
valueToEstree(value.description, options), | ||
], | ||
}; | ||
} | ||
throw new TypeError("Only global symbols are supported, got: " + String(value)); | ||
} | ||
if (Array.isArray(value)) { | ||
var elements = []; | ||
for (var i = 0; i < value.length; i += 1) { | ||
elements.push(i in value ? valueToEstree(value[i], options) : null); | ||
} | ||
return { type: "ArrayExpression", elements: elements }; | ||
} | ||
if (value instanceof RegExp) { | ||
return { | ||
type: "Literal", | ||
value: value, | ||
raw: String(value), | ||
regex: { pattern: value.source, flags: value.flags }, | ||
}; | ||
} | ||
if (value instanceof Date) { | ||
return { | ||
type: "NewExpression", | ||
callee: { type: "Identifier", name: "Date" }, | ||
arguments: [valueToEstree(value.getTime(), options)], | ||
}; | ||
} | ||
if (value instanceof Map) { | ||
return { | ||
type: "NewExpression", | ||
callee: { type: "Identifier", name: "Map" }, | ||
arguments: [ | ||
valueToEstree(__spread(value.entries()), options), | ||
], | ||
}; | ||
} | ||
if (value instanceof BigInt64Array || | ||
value instanceof BigUint64Array || | ||
value instanceof Float32Array || | ||
value instanceof Float64Array || | ||
value instanceof Int8Array || | ||
value instanceof Int16Array || | ||
value instanceof Int32Array || | ||
value instanceof Set || | ||
value instanceof Uint8Array || | ||
value instanceof Uint8ClampedArray || | ||
value instanceof Uint16Array || | ||
value instanceof Uint32Array) { | ||
return { | ||
type: "NewExpression", | ||
callee: { | ||
type: "Identifier", | ||
name: value.constructor.name, | ||
}, | ||
arguments: [valueToEstree(__spread(value), options)], | ||
}; | ||
} | ||
if (value instanceof URL || | ||
value instanceof URLSearchParams) { | ||
return { | ||
type: "NewExpression", | ||
callee: { | ||
type: "Identifier", | ||
name: value.constructor.name, | ||
}, | ||
arguments: [valueToEstree(String(value), options)], | ||
}; | ||
} | ||
if (options.instanceAsObject || isPlainObject__default['default'](value)) { | ||
return { | ||
type: "ObjectExpression", | ||
// @ts-expect-error: looks like an object. | ||
properties: Object.entries(value).map(function (_a) { | ||
var _b = __read(_a, 2), name = _b[0], val = _b[1]; | ||
return ({ | ||
type: "Property", | ||
method: false, | ||
shorthand: false, | ||
computed: false, | ||
kind: "init", | ||
key: valueToEstree(name, options), | ||
value: valueToEstree(val, options), | ||
}); | ||
}), | ||
}; | ||
} | ||
// code hike annotations patch | ||
if (value === CodeLink) { | ||
return { | ||
type: "MemberExpression", | ||
object: { | ||
type: "Identifier", | ||
name: "CH", | ||
}, | ||
property: { | ||
type: "Identifier", | ||
name: "CodeLink", | ||
}, | ||
computed: false, | ||
optional: false, | ||
}; | ||
} | ||
throw new TypeError("Unsupported value: " + String(value)); | ||
} | ||
function splitChildren(parent, type) { | ||
var splits = []; | ||
var i = 0; | ||
parent.children.forEach(function (node, index) { | ||
if (node.type === type) { | ||
i++; | ||
} | ||
else { | ||
if (!splits[i]) { | ||
splits[i] = []; | ||
} | ||
splits[i].push({ node: node, index: index, parent: parent }); | ||
} | ||
}); | ||
return splits; | ||
} | ||
function visitAsync(tree, type, visitor) { | ||
@@ -184,26 +385,33 @@ return __awaiter(this, void 0, void 0, function () { | ||
function toJSX(node, _a) { | ||
var _b = _a.type, type = _b === void 0 ? "mdxJsxFlowElement" : _b, props = _a.props, name = _a.name; | ||
var _b = _a.type, type = _b === void 0 ? "mdxJsxFlowElement" : _b, props = _a.props, name = _a.name, _c = _a.appendProps, appendProps = _c === void 0 ? false : _c; | ||
// console.log(`transforming ${node.name} to ${name}`) | ||
node.type = type; | ||
node.name = name; | ||
node.attributes = Object.keys(props).map(function (key) { return ({ | ||
type: "mdxJsxAttribute", | ||
name: key, | ||
value: { | ||
type: "mdxJsxAttributeValueExpression", | ||
value: JSON.stringify(props[key]), | ||
data: { | ||
estree: { | ||
type: "Program", | ||
body: [ | ||
{ | ||
type: "ExpressionStatement", | ||
expression: estreeUtilValueToEstree.valueToEstree(props[key]), | ||
}, | ||
], | ||
sourceType: "module", | ||
if (name) { | ||
node.name = name; | ||
} | ||
if (!appendProps) { | ||
node.attributes = []; | ||
} | ||
Object.keys(props).forEach(function (key) { | ||
node.attributes.push({ | ||
type: "mdxJsxAttribute", | ||
name: key, | ||
value: { | ||
type: "mdxJsxAttributeValueExpression", | ||
value: JSON.stringify(props[key]), | ||
data: { | ||
estree: { | ||
type: "Program", | ||
body: [ | ||
{ | ||
type: "ExpressionStatement", | ||
expression: valueToEstree(props[key]), | ||
}, | ||
], | ||
sourceType: "module", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}); }); | ||
}); | ||
}); | ||
} | ||
@@ -234,2 +442,56 @@ | ||
} | ||
function Code(props) { | ||
if (!props.southPanel && | ||
props.files.length === 1 && | ||
!props.files[0].name) { | ||
return (React__default['default'].createElement(smoothCode.CodeSpring, { className: "ch-code", config: props.codeConfig, step: props.files[0] })); | ||
} | ||
else { | ||
return React__default['default'].createElement(miniEditor.EditorSpring, __assign({}, props)); | ||
} | ||
} | ||
// remark: | ||
function isEditorNode(node) { | ||
return (node.type === "code" || | ||
(node.type === "mdxJsxFlowElement" && | ||
node.name === "CH.Code")); | ||
} | ||
function mapAnyCodeNode(nodeInfo, config) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var node; | ||
return __generator(this, function (_a) { | ||
node = nodeInfo.node; | ||
if (node.type === "code") { | ||
return [2 /*return*/, mapCode(nodeInfo, config)]; | ||
} | ||
else { | ||
return [2 /*return*/, mapEditor(nodeInfo, config)]; | ||
} | ||
}); | ||
}); | ||
} | ||
function mapCode(nodeInfo, config) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var file, props; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, mapFile(nodeInfo, config)]; | ||
case 1: | ||
file = _a.sent(); | ||
props = { | ||
northPanel: { | ||
tabs: [file.name], | ||
active: file.name, | ||
heightRatio: 1, | ||
}, | ||
files: [file], | ||
codeConfig: { | ||
theme: config.theme, | ||
}, | ||
}; | ||
return [2 /*return*/, props]; | ||
} | ||
}); | ||
}); | ||
} | ||
function transformCode(nodeInfo, config) { | ||
@@ -283,7 +545,7 @@ return __awaiter(this, void 0, void 0, function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _b, northNodes, southNodes, northFiles, southFiles, allFiles, northActive, southActive, northLines, southLines, northRatio, southRatio, props; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
var _b, northNodes, _c, southNodes, northFiles, southFiles, allFiles, northActive, southActive, northLines, southLines, northRatio, southRatio, props; | ||
return __generator(this, function (_d) { | ||
switch (_d.label) { | ||
case 0: | ||
_b = __read(splitChildren(node, "thematicBreak"), 2), northNodes = _b[0], southNodes = _b[1]; | ||
_b = __read(splitChildren(node, "thematicBreak"), 2), northNodes = _b[0], _c = _b[1], southNodes = _c === void 0 ? [] : _c; | ||
return [4 /*yield*/, Promise.all(northNodes | ||
@@ -296,3 +558,3 @@ .filter(function (_a) { | ||
case 1: | ||
northFiles = _c.sent(); | ||
northFiles = _d.sent(); | ||
return [4 /*yield*/, Promise.all(southNodes | ||
@@ -305,3 +567,3 @@ .filter(function (_a) { | ||
case 2: | ||
southFiles = _c.sent(); | ||
southFiles = _d.sent(); | ||
allFiles = __spread(northFiles, southFiles); | ||
@@ -315,3 +577,3 @@ northActive = northFiles.find(function (f) { return f.active; }) || northFiles[0]; | ||
northRatio = southActive | ||
? (northLines + 3.33) / (southLines + northLines + 6.66) | ||
? (northLines + 2) / (southLines + northLines + 4) | ||
: 1; | ||
@@ -331,3 +593,3 @@ southRatio = 1 - northRatio; | ||
} | ||
: null, | ||
: undefined, | ||
files: allFiles, | ||
@@ -343,5 +605,2 @@ codeConfig: { | ||
} | ||
// should I edit the node or return the file? | ||
// i think return file | ||
// this will be called from transEditor and transCode | ||
function mapFile(_a, config) { | ||
@@ -364,4 +623,3 @@ var node = _a.node, index = _a.index, parent = _a.parent; | ||
options = parseMetastring(typeof node.meta === "string" ? node.meta : ""); | ||
file = __assign(__assign({}, options), { code: code, | ||
annotations: annotations }); | ||
file = __assign(__assign({}, options), { focus: options.focus || "", code: code, name: options.name || "", annotations: annotations }); | ||
return [2 /*return*/, file]; | ||
@@ -372,19 +630,2 @@ } | ||
} | ||
function splitChildren(parent, type) { | ||
var north = []; | ||
var south = []; | ||
var breakNode = false; | ||
parent.children.forEach(function (node, index) { | ||
if (node.type === type) { | ||
breakNode = true; | ||
} | ||
else if (breakNode) { | ||
south.push({ node: node, index: index, parent: parent }); | ||
} | ||
else { | ||
north.push({ node: node, index: index, parent: parent }); | ||
} | ||
}); | ||
return [north, south]; | ||
} | ||
function parseMetastring(metastring) { | ||
@@ -406,3 +647,3 @@ var params = metastring.split(" "); | ||
}); | ||
return __assign({ name: name }, options); | ||
return __assign({ name: name || "" }, options); | ||
} | ||
@@ -437,50 +678,2 @@ | ||
var CH = { | ||
Code: Code, | ||
Section: Section, | ||
SectionLink: SectionLink, | ||
SectionCode: SectionCode, | ||
}; | ||
function Code(serializedProps) { | ||
var props = parseEditorProps(serializedProps); | ||
return React__default['default'].createElement(ParsedEditor, __assign({}, props)); | ||
} | ||
function parseEditorProps(_a) { | ||
var northPanel = _a.northPanel, southPanel = _a.southPanel, files = _a.files, codeConfig = _a.codeConfig; | ||
return { | ||
northPanel: northPanel, | ||
southPanel: southPanel, | ||
files: parseFiles(files), | ||
codeConfig: codeConfig, | ||
}; | ||
} | ||
function ParsedEditor(props) { | ||
if (!props.southPanel && | ||
props.files.length === 1 && | ||
!props.files[0].name) { | ||
return (React__default['default'].createElement(smoothCode.CodeSpring, { config: props.codeConfig, step: props.files[0] })); | ||
} | ||
else { | ||
return React__default['default'].createElement(miniEditor.EditorSpring, __assign({}, props)); | ||
} | ||
} | ||
function parseFiles(filesWithoutAnnotations) { | ||
return filesWithoutAnnotations.map(function (data) { | ||
return __assign(__assign({}, data), { annotations: parseAnnotations(data.annotations) }); | ||
}); | ||
} | ||
function parseAnnotations(annotations) { | ||
return (annotations || []).map(function (_a) { | ||
_a.type; var rest = __rest(_a, ["type"]); | ||
return (__assign({ Component: CodeLink }, rest)); | ||
}); | ||
} | ||
function CodeLink(_a) { | ||
var children = _a.children, data = _a.data; | ||
return (React__default['default'].createElement("a", { href: data.url, target: "_blank", rel: "noopener noreferrer", title: data.title, style: { | ||
textDecoration: "underline", | ||
textDecorationStyle: "dotted", | ||
} }, children)); | ||
} | ||
var SectionContext = React__default['default'].createContext({ props: null, setFocus: function () { } }); | ||
@@ -588,2 +781,233 @@ function Section(_a) { | ||
// extend steps with info from previous steps | ||
function reduceSteps(baseStep, extraStep) { | ||
var files = reduceFiles(baseStep.files, extraStep.files); | ||
return __assign(__assign(__assign({}, baseStep), extraStep), { files: files, northPanel: reducePanel(baseStep.northPanel, extraStep.northPanel, extraStep.southPanel), southPanel: reducePanel(baseStep.southPanel, extraStep.southPanel, extraStep.northPanel) }); | ||
} | ||
function reducePanel(oldPanel, newPanel, otherNewPanel) { | ||
var _a, _b; | ||
if (!newPanel) { | ||
return newPanel; | ||
} | ||
var oldTabsStillThere = ((_a = oldPanel === null || oldPanel === void 0 ? void 0 : oldPanel.tabs) === null || _a === void 0 ? void 0 : _a.filter(function (name) { var _a; return !((_a = otherNewPanel === null || otherNewPanel === void 0 ? void 0 : otherNewPanel.tabs) === null || _a === void 0 ? void 0 : _a.includes(name)); })) || []; | ||
var realNewTabs = ((_b = newPanel === null || newPanel === void 0 ? void 0 : newPanel.tabs) === null || _b === void 0 ? void 0 : _b.filter(function (name) { var _a; return !((_a = oldPanel === null || oldPanel === void 0 ? void 0 : oldPanel.tabs) === null || _a === void 0 ? void 0 : _a.includes(name)); })) || []; | ||
return __assign(__assign(__assign({}, oldPanel), newPanel), { tabs: __spread(oldTabsStillThere, realNewTabs) }); | ||
} | ||
function reduceFiles(baseFiles, extraFiles) { | ||
var filesMap = {}; | ||
baseFiles.forEach(function (f) { return (filesMap[f.name] = f); }); | ||
extraFiles.forEach(function (ef) { | ||
var bf = filesMap[ef.name]; | ||
if (!bf) { | ||
filesMap[ef.name] = ef; | ||
return; | ||
} | ||
// merge old and new files | ||
var code = ef.code, rest = __rest(ef, ["code"]); | ||
if (isEmpty(code)) { | ||
filesMap[ef.name] = __assign(__assign({}, bf), rest); | ||
} | ||
else { | ||
filesMap[ef.name] = ef; | ||
} | ||
}); | ||
var result = []; | ||
baseFiles.forEach(function (f) { | ||
result.push(filesMap[f.name]); | ||
delete filesMap[f.name]; | ||
}); | ||
extraFiles.forEach(function (f) { return filesMap[f.name] && result.push(filesMap[f.name]); }); | ||
return result; | ||
} | ||
function isEmpty(code) { | ||
var anyContent = code.lines.some(function (l) { | ||
return l.tokens.some(function (t) { return t.content.trim() == ""; }); | ||
}); | ||
return !anyContent; | ||
} | ||
// extract step info | ||
function extractStepsInfo(parent, config, merge) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var steps, stepIndex, children, i, child, step, _a, editorStep, baseStep; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
steps = []; | ||
stepIndex = 0; | ||
children = parent.children || []; | ||
i = 0; | ||
_b.label = 1; | ||
case 1: | ||
if (!(i < children.length)) return [3 /*break*/, 5]; | ||
child = children[i]; | ||
if (child.type === "thematicBreak") { | ||
stepIndex++; | ||
return [3 /*break*/, 4]; | ||
} | ||
steps[stepIndex] = steps[stepIndex] || { children: [] }; | ||
step = steps[stepIndex]; | ||
if (!(!step.editorStep && isEditorNode(child))) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, mapAnyCodeNode({ node: child, parent: parent, index: i }, config)]; | ||
case 2: | ||
_a = _b.sent(), _a.codeConfig, editorStep = __rest(_a, ["codeConfig"]); | ||
if (stepIndex === 0) { | ||
// for the header props, keep it as it is | ||
step.editorStep = editorStep; | ||
} | ||
else { | ||
baseStep = merge === "merge steps with header" | ||
? steps[0].editorStep | ||
: steps[stepIndex - 1].editorStep; | ||
step.editorStep = reduceSteps(baseStep, editorStep); | ||
} | ||
return [3 /*break*/, 4]; | ||
case 3: | ||
step.children.push(child); | ||
_b.label = 4; | ||
case 4: | ||
i++; | ||
return [3 /*break*/, 1]; | ||
case 5: | ||
parent.children = steps.map(function (step) { | ||
return { | ||
type: "mdxJsxFlowElement", | ||
children: step.children, | ||
}; | ||
}); | ||
return [2 /*return*/, steps.map(function (step) { return step.editorStep; })]; | ||
} | ||
}); | ||
}); | ||
} | ||
function Spotlight(_a) { | ||
var _b; | ||
var children = _a.children, editorSteps = _a.editorSteps, codeConfig = _a.codeConfig, _c = _a.start, start = _c === void 0 ? 0 : _c; | ||
var stepsChildren = React__default['default'].Children.toArray(children); | ||
var _d = __read(React__default['default'].useState(start), 2), stepIndex = _d[0], setIndex = _d[1]; | ||
var tab = editorSteps[stepIndex]; | ||
var headerElement = stepsChildren[0]; | ||
return (React__default['default'].createElement("div", { className: "ch-spotlight" }, | ||
React__default['default'].createElement("div", { className: "ch-spotlight-tabs" }, | ||
((_b = headerElement === null || headerElement === void 0 ? void 0 : headerElement.props) === null || _b === void 0 ? void 0 : _b.children) ? (React__default['default'].createElement("div", null, stepsChildren[0])) : null, | ||
stepsChildren.map(function (children, i) { | ||
return i === 0 ? null : (React__default['default'].createElement("div", { key: i, onClick: function () { return setIndex(i); }, className: "ch-spotlight-tab", "data-selected": i === stepIndex ? "true" : undefined }, children)); | ||
})), | ||
React__default['default'].createElement("div", { className: "ch-spotlight-sticker" }, | ||
React__default['default'].createElement(Code, __assign({}, tab, { codeConfig: __assign(__assign({}, codeConfig), { htmlProps: { | ||
style: { | ||
minHeight: "100%", | ||
maxHeight: "80vh", | ||
}, | ||
} }) }))))); | ||
} | ||
function transformSpotlights(tree, config) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, visitAsync(tree, "mdxJsxFlowElement", function (node) { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (!(node.name === "CH.Spotlight")) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, transformSpotlight(node, config)]; | ||
case 1: | ||
_a.sent(); | ||
_a.label = 2; | ||
case 2: return [2 /*return*/]; | ||
} | ||
}); | ||
}); })]; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
} | ||
function transformSpotlight(node, _a) { | ||
var theme = _a.theme; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var editorSteps; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, extractStepsInfo(node, { theme: theme }, "merge steps with header")]; | ||
case 1: | ||
editorSteps = _b.sent(); | ||
toJSX(node, { | ||
props: { | ||
codeConfig: { theme: theme }, | ||
editorSteps: editorSteps, | ||
}, | ||
appendProps: true, | ||
}); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
} | ||
function Scrollycoding(_a) { | ||
var children = _a.children, editorSteps = _a.editorSteps, codeConfig = _a.codeConfig, _b = _a.start, start = _b === void 0 ? 0 : _b; | ||
var stepsChildren = React__default['default'].Children.toArray(children); | ||
var _c = __read(React__default['default'].useState(start), 2), stepIndex = _c[0], setIndex = _c[1]; | ||
var tab = editorSteps[stepIndex]; | ||
function onStepChange(index) { | ||
setIndex(index); | ||
} | ||
return (React__default['default'].createElement("section", { className: "ch-scrollycoding" }, | ||
React__default['default'].createElement("div", { className: "ch-scrollycoding-content" }, | ||
React__default['default'].createElement(scroller.Scroller, { onStepChange: onStepChange }, stepsChildren.map(function (children, i) { return (React__default['default'].createElement(scroller.Step, { as: "div", key: i, index: i, onClick: function () { return setIndex(i); }, className: "ch-scrollycoding-step-content", "data-selected": i === stepIndex ? "true" : undefined }, children)); }))), | ||
React__default['default'].createElement("div", { className: "ch-scrollycoding-sticker" }, | ||
React__default['default'].createElement(Code, __assign({}, tab, { codeConfig: codeConfig }))))); | ||
} | ||
function transformScrollycodings(tree, config) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, visitAsync(tree, "mdxJsxFlowElement", function (node) { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (!(node.name === "CH.Scrollycoding")) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, transformScrollycoding(node, config)]; | ||
case 1: | ||
_a.sent(); | ||
_a.label = 2; | ||
case 2: return [2 /*return*/]; | ||
} | ||
}); | ||
}); })]; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
} | ||
function transformScrollycoding(node, _a) { | ||
var theme = _a.theme; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var editorSteps; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, extractStepsInfo(node, { theme: theme }, "merge step with previous")]; | ||
case 1: | ||
editorSteps = _b.sent(); | ||
toJSX(node, { | ||
props: { | ||
codeConfig: { theme: theme }, | ||
editorSteps: editorSteps, | ||
}, | ||
appendProps: true, | ||
}); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
} | ||
function remarkCodeHike(_a) { | ||
@@ -593,27 +1017,39 @@ var _this = this; | ||
return function (tree) { return __awaiter(_this, void 0, void 0, function () { | ||
var useCodeComponent; | ||
var hasCodeHikeImport, e_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
useCodeComponent = false; | ||
hasCodeHikeImport = false; | ||
visit__default['default'](tree, "mdxjsEsm", function (node) { | ||
if ( | ||
// TODO too fragile: | ||
node.value === "import { CH } from \"@code-hike/mdx\"") { | ||
useCodeComponent = true; | ||
if (node.value.startsWith("import { CH } from \"@code-hike/mdx\"")) { | ||
hasCodeHikeImport = true; | ||
} | ||
}); | ||
if (!useCodeComponent) { | ||
return [2 /*return*/]; | ||
if (!hasCodeHikeImport) { | ||
addImportNode(tree); | ||
} | ||
return [4 /*yield*/, transformSections(tree, { theme: theme })]; | ||
_a.label = 1; | ||
case 1: | ||
_a.trys.push([1, 7, , 8]); | ||
return [4 /*yield*/, transformScrollycodings(tree, { theme: theme })]; | ||
case 2: | ||
_a.sent(); | ||
return [4 /*yield*/, transformSpotlights(tree, { theme: theme })]; | ||
case 3: | ||
_a.sent(); | ||
return [4 /*yield*/, transformSections(tree, { theme: theme })]; | ||
case 4: | ||
_a.sent(); | ||
return [4 /*yield*/, transformEditorNodes(tree, { theme: theme })]; | ||
case 2: | ||
case 5: | ||
_a.sent(); | ||
return [4 /*yield*/, transformCodeNodes(tree, { theme: theme })]; | ||
case 3: | ||
case 6: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
return [3 /*break*/, 8]; | ||
case 7: | ||
e_1 = _a.sent(); | ||
console.error("error running remarkCodeHike", e_1); | ||
throw e_1; | ||
case 8: return [2 /*return*/]; | ||
} | ||
@@ -623,4 +1059,49 @@ }); | ||
} | ||
function addImportNode(tree) { | ||
tree.children.unshift({ | ||
type: "mdxjsEsm", | ||
value: 'import { CH } from "@code-hike/mdx"', | ||
data: { | ||
estree: { | ||
type: "Program", | ||
body: [ | ||
{ | ||
type: "ImportDeclaration", | ||
specifiers: [ | ||
{ | ||
type: "ImportSpecifier", | ||
imported: { | ||
type: "Identifier", | ||
name: "CH", | ||
}, | ||
local: { | ||
type: "Identifier", | ||
name: "CH", | ||
}, | ||
}, | ||
], | ||
source: { | ||
type: "Literal", | ||
value: "@code-hike/mdx", | ||
raw: '"@code-hike/mdx"', | ||
}, | ||
}, | ||
], | ||
sourceType: "module", | ||
}, | ||
}, | ||
}); | ||
} | ||
var CH = { | ||
Code: Code, | ||
Section: Section, | ||
SectionLink: SectionLink, | ||
SectionCode: SectionCode, | ||
CodeLink: CodeLink, | ||
Spotlight: Spotlight, | ||
Scrollycoding: Scrollycoding, | ||
}; | ||
exports.CH = CH; | ||
exports.remarkCodeHike = remarkCodeHike; |
@@ -0,2 +1,3 @@ | ||
import "./index.scss"; | ||
export { remarkCodeHike } from "./plugin"; | ||
export { CH } from "./components"; |
@@ -1,7 +0,8 @@ | ||
import visit from 'unist-util-visit'; | ||
import { highlight } from '@code-hike/highlighter'; | ||
import { valueToEstree } from 'estree-util-value-to-estree'; | ||
import React from 'react'; | ||
import visit from 'unist-util-visit'; | ||
import isPlainObject from 'is-plain-obj'; | ||
import { CodeSpring } from '@code-hike/smooth-code'; | ||
import { EditorSpring } from '@code-hike/mini-editor'; | ||
import { Scroller, Step } from '@code-hike/scroller'; | ||
@@ -107,2 +108,9 @@ /*! ***************************************************************************** | ||
function CodeLink(_a) { | ||
var children = _a.children, data = _a.data; | ||
return (React.createElement("a", { href: data.url, target: "_blank", rel: "noopener noreferrer", title: data.title, style: { | ||
textDecoration: "underline", | ||
textDecorationStyle: "dotted", | ||
} }, children)); | ||
} | ||
function extractLinks(node, index, parent, code) { | ||
@@ -116,3 +124,3 @@ var annotations = []; | ||
annotations.push({ | ||
type: "link", | ||
Component: CodeLink, | ||
focus: focus, | ||
@@ -151,2 +159,194 @@ data: { | ||
/** | ||
* Convert a value to an ESTree node | ||
* | ||
* @param value - The value to convert | ||
* @param options - Additional options to configure the output. | ||
* @returns The ESTree node. | ||
*/ | ||
function valueToEstree(value, options) { | ||
if (options === void 0) { options = {}; } | ||
if (value === undefined) { | ||
return { type: "Identifier", name: "undefined" }; | ||
} | ||
if (value == null) { | ||
return { type: "Literal", value: null, raw: "null" }; | ||
} | ||
if (value === Number.POSITIVE_INFINITY) { | ||
return { type: "Identifier", name: "Infinity" }; | ||
} | ||
if (Number.isNaN(value)) { | ||
return { type: "Identifier", name: "NaN" }; | ||
} | ||
if (typeof value === "boolean") { | ||
return { type: "Literal", value: value, raw: String(value) }; | ||
} | ||
if (typeof value === "bigint") { | ||
return value >= 0 | ||
? { | ||
type: "Literal", | ||
value: value, | ||
raw: value + "n", | ||
bigint: String(value), | ||
} | ||
: { | ||
type: "UnaryExpression", | ||
operator: "-", | ||
prefix: true, | ||
argument: valueToEstree(-value, options), | ||
}; | ||
} | ||
if (typeof value === "number") { | ||
return value >= 0 | ||
? { type: "Literal", value: value, raw: String(value) } | ||
: { | ||
type: "UnaryExpression", | ||
operator: "-", | ||
prefix: true, | ||
argument: valueToEstree(-value, options), | ||
}; | ||
} | ||
if (typeof value === "string") { | ||
return { | ||
type: "Literal", | ||
value: value, | ||
raw: JSON.stringify(value), | ||
}; | ||
} | ||
if (typeof value === "symbol") { | ||
if (value.description && | ||
value === Symbol["for"](value.description)) { | ||
return { | ||
type: "CallExpression", | ||
optional: false, | ||
callee: { | ||
type: "MemberExpression", | ||
computed: false, | ||
optional: false, | ||
object: { type: "Identifier", name: "Symbol" }, | ||
property: { type: "Identifier", name: "for" }, | ||
}, | ||
arguments: [ | ||
valueToEstree(value.description, options), | ||
], | ||
}; | ||
} | ||
throw new TypeError("Only global symbols are supported, got: " + String(value)); | ||
} | ||
if (Array.isArray(value)) { | ||
var elements = []; | ||
for (var i = 0; i < value.length; i += 1) { | ||
elements.push(i in value ? valueToEstree(value[i], options) : null); | ||
} | ||
return { type: "ArrayExpression", elements: elements }; | ||
} | ||
if (value instanceof RegExp) { | ||
return { | ||
type: "Literal", | ||
value: value, | ||
raw: String(value), | ||
regex: { pattern: value.source, flags: value.flags }, | ||
}; | ||
} | ||
if (value instanceof Date) { | ||
return { | ||
type: "NewExpression", | ||
callee: { type: "Identifier", name: "Date" }, | ||
arguments: [valueToEstree(value.getTime(), options)], | ||
}; | ||
} | ||
if (value instanceof Map) { | ||
return { | ||
type: "NewExpression", | ||
callee: { type: "Identifier", name: "Map" }, | ||
arguments: [ | ||
valueToEstree(__spread(value.entries()), options), | ||
], | ||
}; | ||
} | ||
if (value instanceof BigInt64Array || | ||
value instanceof BigUint64Array || | ||
value instanceof Float32Array || | ||
value instanceof Float64Array || | ||
value instanceof Int8Array || | ||
value instanceof Int16Array || | ||
value instanceof Int32Array || | ||
value instanceof Set || | ||
value instanceof Uint8Array || | ||
value instanceof Uint8ClampedArray || | ||
value instanceof Uint16Array || | ||
value instanceof Uint32Array) { | ||
return { | ||
type: "NewExpression", | ||
callee: { | ||
type: "Identifier", | ||
name: value.constructor.name, | ||
}, | ||
arguments: [valueToEstree(__spread(value), options)], | ||
}; | ||
} | ||
if (value instanceof URL || | ||
value instanceof URLSearchParams) { | ||
return { | ||
type: "NewExpression", | ||
callee: { | ||
type: "Identifier", | ||
name: value.constructor.name, | ||
}, | ||
arguments: [valueToEstree(String(value), options)], | ||
}; | ||
} | ||
if (options.instanceAsObject || isPlainObject(value)) { | ||
return { | ||
type: "ObjectExpression", | ||
// @ts-expect-error: looks like an object. | ||
properties: Object.entries(value).map(function (_a) { | ||
var _b = __read(_a, 2), name = _b[0], val = _b[1]; | ||
return ({ | ||
type: "Property", | ||
method: false, | ||
shorthand: false, | ||
computed: false, | ||
kind: "init", | ||
key: valueToEstree(name, options), | ||
value: valueToEstree(val, options), | ||
}); | ||
}), | ||
}; | ||
} | ||
// code hike annotations patch | ||
if (value === CodeLink) { | ||
return { | ||
type: "MemberExpression", | ||
object: { | ||
type: "Identifier", | ||
name: "CH", | ||
}, | ||
property: { | ||
type: "Identifier", | ||
name: "CodeLink", | ||
}, | ||
computed: false, | ||
optional: false, | ||
}; | ||
} | ||
throw new TypeError("Unsupported value: " + String(value)); | ||
} | ||
function splitChildren(parent, type) { | ||
var splits = []; | ||
var i = 0; | ||
parent.children.forEach(function (node, index) { | ||
if (node.type === type) { | ||
i++; | ||
} | ||
else { | ||
if (!splits[i]) { | ||
splits[i] = []; | ||
} | ||
splits[i].push({ node: node, index: index, parent: parent }); | ||
} | ||
}); | ||
return splits; | ||
} | ||
function visitAsync(tree, type, visitor) { | ||
@@ -174,26 +374,33 @@ return __awaiter(this, void 0, void 0, function () { | ||
function toJSX(node, _a) { | ||
var _b = _a.type, type = _b === void 0 ? "mdxJsxFlowElement" : _b, props = _a.props, name = _a.name; | ||
var _b = _a.type, type = _b === void 0 ? "mdxJsxFlowElement" : _b, props = _a.props, name = _a.name, _c = _a.appendProps, appendProps = _c === void 0 ? false : _c; | ||
// console.log(`transforming ${node.name} to ${name}`) | ||
node.type = type; | ||
node.name = name; | ||
node.attributes = Object.keys(props).map(function (key) { return ({ | ||
type: "mdxJsxAttribute", | ||
name: key, | ||
value: { | ||
type: "mdxJsxAttributeValueExpression", | ||
value: JSON.stringify(props[key]), | ||
data: { | ||
estree: { | ||
type: "Program", | ||
body: [ | ||
{ | ||
type: "ExpressionStatement", | ||
expression: valueToEstree(props[key]), | ||
}, | ||
], | ||
sourceType: "module", | ||
if (name) { | ||
node.name = name; | ||
} | ||
if (!appendProps) { | ||
node.attributes = []; | ||
} | ||
Object.keys(props).forEach(function (key) { | ||
node.attributes.push({ | ||
type: "mdxJsxAttribute", | ||
name: key, | ||
value: { | ||
type: "mdxJsxAttributeValueExpression", | ||
value: JSON.stringify(props[key]), | ||
data: { | ||
estree: { | ||
type: "Program", | ||
body: [ | ||
{ | ||
type: "ExpressionStatement", | ||
expression: valueToEstree(props[key]), | ||
}, | ||
], | ||
sourceType: "module", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}); }); | ||
}); | ||
}); | ||
} | ||
@@ -224,2 +431,56 @@ | ||
} | ||
function Code(props) { | ||
if (!props.southPanel && | ||
props.files.length === 1 && | ||
!props.files[0].name) { | ||
return (React.createElement(CodeSpring, { className: "ch-code", config: props.codeConfig, step: props.files[0] })); | ||
} | ||
else { | ||
return React.createElement(EditorSpring, __assign({}, props)); | ||
} | ||
} | ||
// remark: | ||
function isEditorNode(node) { | ||
return (node.type === "code" || | ||
(node.type === "mdxJsxFlowElement" && | ||
node.name === "CH.Code")); | ||
} | ||
function mapAnyCodeNode(nodeInfo, config) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var node; | ||
return __generator(this, function (_a) { | ||
node = nodeInfo.node; | ||
if (node.type === "code") { | ||
return [2 /*return*/, mapCode(nodeInfo, config)]; | ||
} | ||
else { | ||
return [2 /*return*/, mapEditor(nodeInfo, config)]; | ||
} | ||
}); | ||
}); | ||
} | ||
function mapCode(nodeInfo, config) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var file, props; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, mapFile(nodeInfo, config)]; | ||
case 1: | ||
file = _a.sent(); | ||
props = { | ||
northPanel: { | ||
tabs: [file.name], | ||
active: file.name, | ||
heightRatio: 1, | ||
}, | ||
files: [file], | ||
codeConfig: { | ||
theme: config.theme, | ||
}, | ||
}; | ||
return [2 /*return*/, props]; | ||
} | ||
}); | ||
}); | ||
} | ||
function transformCode(nodeInfo, config) { | ||
@@ -273,7 +534,7 @@ return __awaiter(this, void 0, void 0, function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _b, northNodes, southNodes, northFiles, southFiles, allFiles, northActive, southActive, northLines, southLines, northRatio, southRatio, props; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
var _b, northNodes, _c, southNodes, northFiles, southFiles, allFiles, northActive, southActive, northLines, southLines, northRatio, southRatio, props; | ||
return __generator(this, function (_d) { | ||
switch (_d.label) { | ||
case 0: | ||
_b = __read(splitChildren(node, "thematicBreak"), 2), northNodes = _b[0], southNodes = _b[1]; | ||
_b = __read(splitChildren(node, "thematicBreak"), 2), northNodes = _b[0], _c = _b[1], southNodes = _c === void 0 ? [] : _c; | ||
return [4 /*yield*/, Promise.all(northNodes | ||
@@ -286,3 +547,3 @@ .filter(function (_a) { | ||
case 1: | ||
northFiles = _c.sent(); | ||
northFiles = _d.sent(); | ||
return [4 /*yield*/, Promise.all(southNodes | ||
@@ -295,3 +556,3 @@ .filter(function (_a) { | ||
case 2: | ||
southFiles = _c.sent(); | ||
southFiles = _d.sent(); | ||
allFiles = __spread(northFiles, southFiles); | ||
@@ -305,3 +566,3 @@ northActive = northFiles.find(function (f) { return f.active; }) || northFiles[0]; | ||
northRatio = southActive | ||
? (northLines + 3.33) / (southLines + northLines + 6.66) | ||
? (northLines + 2) / (southLines + northLines + 4) | ||
: 1; | ||
@@ -321,3 +582,3 @@ southRatio = 1 - northRatio; | ||
} | ||
: null, | ||
: undefined, | ||
files: allFiles, | ||
@@ -333,5 +594,2 @@ codeConfig: { | ||
} | ||
// should I edit the node or return the file? | ||
// i think return file | ||
// this will be called from transEditor and transCode | ||
function mapFile(_a, config) { | ||
@@ -354,4 +612,3 @@ var node = _a.node, index = _a.index, parent = _a.parent; | ||
options = parseMetastring(typeof node.meta === "string" ? node.meta : ""); | ||
file = __assign(__assign({}, options), { code: code, | ||
annotations: annotations }); | ||
file = __assign(__assign({}, options), { focus: options.focus || "", code: code, name: options.name || "", annotations: annotations }); | ||
return [2 /*return*/, file]; | ||
@@ -362,19 +619,2 @@ } | ||
} | ||
function splitChildren(parent, type) { | ||
var north = []; | ||
var south = []; | ||
var breakNode = false; | ||
parent.children.forEach(function (node, index) { | ||
if (node.type === type) { | ||
breakNode = true; | ||
} | ||
else if (breakNode) { | ||
south.push({ node: node, index: index, parent: parent }); | ||
} | ||
else { | ||
north.push({ node: node, index: index, parent: parent }); | ||
} | ||
}); | ||
return [north, south]; | ||
} | ||
function parseMetastring(metastring) { | ||
@@ -396,3 +636,3 @@ var params = metastring.split(" "); | ||
}); | ||
return __assign({ name: name }, options); | ||
return __assign({ name: name || "" }, options); | ||
} | ||
@@ -427,50 +667,2 @@ | ||
var CH = { | ||
Code: Code, | ||
Section: Section, | ||
SectionLink: SectionLink, | ||
SectionCode: SectionCode, | ||
}; | ||
function Code(serializedProps) { | ||
var props = parseEditorProps(serializedProps); | ||
return React.createElement(ParsedEditor, __assign({}, props)); | ||
} | ||
function parseEditorProps(_a) { | ||
var northPanel = _a.northPanel, southPanel = _a.southPanel, files = _a.files, codeConfig = _a.codeConfig; | ||
return { | ||
northPanel: northPanel, | ||
southPanel: southPanel, | ||
files: parseFiles(files), | ||
codeConfig: codeConfig, | ||
}; | ||
} | ||
function ParsedEditor(props) { | ||
if (!props.southPanel && | ||
props.files.length === 1 && | ||
!props.files[0].name) { | ||
return (React.createElement(CodeSpring, { config: props.codeConfig, step: props.files[0] })); | ||
} | ||
else { | ||
return React.createElement(EditorSpring, __assign({}, props)); | ||
} | ||
} | ||
function parseFiles(filesWithoutAnnotations) { | ||
return filesWithoutAnnotations.map(function (data) { | ||
return __assign(__assign({}, data), { annotations: parseAnnotations(data.annotations) }); | ||
}); | ||
} | ||
function parseAnnotations(annotations) { | ||
return (annotations || []).map(function (_a) { | ||
_a.type; var rest = __rest(_a, ["type"]); | ||
return (__assign({ Component: CodeLink }, rest)); | ||
}); | ||
} | ||
function CodeLink(_a) { | ||
var children = _a.children, data = _a.data; | ||
return (React.createElement("a", { href: data.url, target: "_blank", rel: "noopener noreferrer", title: data.title, style: { | ||
textDecoration: "underline", | ||
textDecorationStyle: "dotted", | ||
} }, children)); | ||
} | ||
var SectionContext = React.createContext({ props: null, setFocus: function () { } }); | ||
@@ -578,2 +770,233 @@ function Section(_a) { | ||
// extend steps with info from previous steps | ||
function reduceSteps(baseStep, extraStep) { | ||
var files = reduceFiles(baseStep.files, extraStep.files); | ||
return __assign(__assign(__assign({}, baseStep), extraStep), { files: files, northPanel: reducePanel(baseStep.northPanel, extraStep.northPanel, extraStep.southPanel), southPanel: reducePanel(baseStep.southPanel, extraStep.southPanel, extraStep.northPanel) }); | ||
} | ||
function reducePanel(oldPanel, newPanel, otherNewPanel) { | ||
var _a, _b; | ||
if (!newPanel) { | ||
return newPanel; | ||
} | ||
var oldTabsStillThere = ((_a = oldPanel === null || oldPanel === void 0 ? void 0 : oldPanel.tabs) === null || _a === void 0 ? void 0 : _a.filter(function (name) { var _a; return !((_a = otherNewPanel === null || otherNewPanel === void 0 ? void 0 : otherNewPanel.tabs) === null || _a === void 0 ? void 0 : _a.includes(name)); })) || []; | ||
var realNewTabs = ((_b = newPanel === null || newPanel === void 0 ? void 0 : newPanel.tabs) === null || _b === void 0 ? void 0 : _b.filter(function (name) { var _a; return !((_a = oldPanel === null || oldPanel === void 0 ? void 0 : oldPanel.tabs) === null || _a === void 0 ? void 0 : _a.includes(name)); })) || []; | ||
return __assign(__assign(__assign({}, oldPanel), newPanel), { tabs: __spread(oldTabsStillThere, realNewTabs) }); | ||
} | ||
function reduceFiles(baseFiles, extraFiles) { | ||
var filesMap = {}; | ||
baseFiles.forEach(function (f) { return (filesMap[f.name] = f); }); | ||
extraFiles.forEach(function (ef) { | ||
var bf = filesMap[ef.name]; | ||
if (!bf) { | ||
filesMap[ef.name] = ef; | ||
return; | ||
} | ||
// merge old and new files | ||
var code = ef.code, rest = __rest(ef, ["code"]); | ||
if (isEmpty(code)) { | ||
filesMap[ef.name] = __assign(__assign({}, bf), rest); | ||
} | ||
else { | ||
filesMap[ef.name] = ef; | ||
} | ||
}); | ||
var result = []; | ||
baseFiles.forEach(function (f) { | ||
result.push(filesMap[f.name]); | ||
delete filesMap[f.name]; | ||
}); | ||
extraFiles.forEach(function (f) { return filesMap[f.name] && result.push(filesMap[f.name]); }); | ||
return result; | ||
} | ||
function isEmpty(code) { | ||
var anyContent = code.lines.some(function (l) { | ||
return l.tokens.some(function (t) { return t.content.trim() == ""; }); | ||
}); | ||
return !anyContent; | ||
} | ||
// extract step info | ||
function extractStepsInfo(parent, config, merge) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var steps, stepIndex, children, i, child, step, _a, editorStep, baseStep; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
steps = []; | ||
stepIndex = 0; | ||
children = parent.children || []; | ||
i = 0; | ||
_b.label = 1; | ||
case 1: | ||
if (!(i < children.length)) return [3 /*break*/, 5]; | ||
child = children[i]; | ||
if (child.type === "thematicBreak") { | ||
stepIndex++; | ||
return [3 /*break*/, 4]; | ||
} | ||
steps[stepIndex] = steps[stepIndex] || { children: [] }; | ||
step = steps[stepIndex]; | ||
if (!(!step.editorStep && isEditorNode(child))) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, mapAnyCodeNode({ node: child, parent: parent, index: i }, config)]; | ||
case 2: | ||
_a = _b.sent(), _a.codeConfig, editorStep = __rest(_a, ["codeConfig"]); | ||
if (stepIndex === 0) { | ||
// for the header props, keep it as it is | ||
step.editorStep = editorStep; | ||
} | ||
else { | ||
baseStep = merge === "merge steps with header" | ||
? steps[0].editorStep | ||
: steps[stepIndex - 1].editorStep; | ||
step.editorStep = reduceSteps(baseStep, editorStep); | ||
} | ||
return [3 /*break*/, 4]; | ||
case 3: | ||
step.children.push(child); | ||
_b.label = 4; | ||
case 4: | ||
i++; | ||
return [3 /*break*/, 1]; | ||
case 5: | ||
parent.children = steps.map(function (step) { | ||
return { | ||
type: "mdxJsxFlowElement", | ||
children: step.children, | ||
}; | ||
}); | ||
return [2 /*return*/, steps.map(function (step) { return step.editorStep; })]; | ||
} | ||
}); | ||
}); | ||
} | ||
function Spotlight(_a) { | ||
var _b; | ||
var children = _a.children, editorSteps = _a.editorSteps, codeConfig = _a.codeConfig, _c = _a.start, start = _c === void 0 ? 0 : _c; | ||
var stepsChildren = React.Children.toArray(children); | ||
var _d = __read(React.useState(start), 2), stepIndex = _d[0], setIndex = _d[1]; | ||
var tab = editorSteps[stepIndex]; | ||
var headerElement = stepsChildren[0]; | ||
return (React.createElement("div", { className: "ch-spotlight" }, | ||
React.createElement("div", { className: "ch-spotlight-tabs" }, | ||
((_b = headerElement === null || headerElement === void 0 ? void 0 : headerElement.props) === null || _b === void 0 ? void 0 : _b.children) ? (React.createElement("div", null, stepsChildren[0])) : null, | ||
stepsChildren.map(function (children, i) { | ||
return i === 0 ? null : (React.createElement("div", { key: i, onClick: function () { return setIndex(i); }, className: "ch-spotlight-tab", "data-selected": i === stepIndex ? "true" : undefined }, children)); | ||
})), | ||
React.createElement("div", { className: "ch-spotlight-sticker" }, | ||
React.createElement(Code, __assign({}, tab, { codeConfig: __assign(__assign({}, codeConfig), { htmlProps: { | ||
style: { | ||
minHeight: "100%", | ||
maxHeight: "80vh", | ||
}, | ||
} }) }))))); | ||
} | ||
function transformSpotlights(tree, config) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, visitAsync(tree, "mdxJsxFlowElement", function (node) { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (!(node.name === "CH.Spotlight")) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, transformSpotlight(node, config)]; | ||
case 1: | ||
_a.sent(); | ||
_a.label = 2; | ||
case 2: return [2 /*return*/]; | ||
} | ||
}); | ||
}); })]; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
} | ||
function transformSpotlight(node, _a) { | ||
var theme = _a.theme; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var editorSteps; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, extractStepsInfo(node, { theme: theme }, "merge steps with header")]; | ||
case 1: | ||
editorSteps = _b.sent(); | ||
toJSX(node, { | ||
props: { | ||
codeConfig: { theme: theme }, | ||
editorSteps: editorSteps, | ||
}, | ||
appendProps: true, | ||
}); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
} | ||
function Scrollycoding(_a) { | ||
var children = _a.children, editorSteps = _a.editorSteps, codeConfig = _a.codeConfig, _b = _a.start, start = _b === void 0 ? 0 : _b; | ||
var stepsChildren = React.Children.toArray(children); | ||
var _c = __read(React.useState(start), 2), stepIndex = _c[0], setIndex = _c[1]; | ||
var tab = editorSteps[stepIndex]; | ||
function onStepChange(index) { | ||
setIndex(index); | ||
} | ||
return (React.createElement("section", { className: "ch-scrollycoding" }, | ||
React.createElement("div", { className: "ch-scrollycoding-content" }, | ||
React.createElement(Scroller, { onStepChange: onStepChange }, stepsChildren.map(function (children, i) { return (React.createElement(Step, { as: "div", key: i, index: i, onClick: function () { return setIndex(i); }, className: "ch-scrollycoding-step-content", "data-selected": i === stepIndex ? "true" : undefined }, children)); }))), | ||
React.createElement("div", { className: "ch-scrollycoding-sticker" }, | ||
React.createElement(Code, __assign({}, tab, { codeConfig: codeConfig }))))); | ||
} | ||
function transformScrollycodings(tree, config) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, visitAsync(tree, "mdxJsxFlowElement", function (node) { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (!(node.name === "CH.Scrollycoding")) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, transformScrollycoding(node, config)]; | ||
case 1: | ||
_a.sent(); | ||
_a.label = 2; | ||
case 2: return [2 /*return*/]; | ||
} | ||
}); | ||
}); })]; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
} | ||
function transformScrollycoding(node, _a) { | ||
var theme = _a.theme; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var editorSteps; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, extractStepsInfo(node, { theme: theme }, "merge step with previous")]; | ||
case 1: | ||
editorSteps = _b.sent(); | ||
toJSX(node, { | ||
props: { | ||
codeConfig: { theme: theme }, | ||
editorSteps: editorSteps, | ||
}, | ||
appendProps: true, | ||
}); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
} | ||
function remarkCodeHike(_a) { | ||
@@ -583,27 +1006,39 @@ var _this = this; | ||
return function (tree) { return __awaiter(_this, void 0, void 0, function () { | ||
var useCodeComponent; | ||
var hasCodeHikeImport, e_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
useCodeComponent = false; | ||
hasCodeHikeImport = false; | ||
visit(tree, "mdxjsEsm", function (node) { | ||
if ( | ||
// TODO too fragile: | ||
node.value === "import { CH } from \"@code-hike/mdx\"") { | ||
useCodeComponent = true; | ||
if (node.value.startsWith("import { CH } from \"@code-hike/mdx\"")) { | ||
hasCodeHikeImport = true; | ||
} | ||
}); | ||
if (!useCodeComponent) { | ||
return [2 /*return*/]; | ||
if (!hasCodeHikeImport) { | ||
addImportNode(tree); | ||
} | ||
return [4 /*yield*/, transformSections(tree, { theme: theme })]; | ||
_a.label = 1; | ||
case 1: | ||
_a.trys.push([1, 7, , 8]); | ||
return [4 /*yield*/, transformScrollycodings(tree, { theme: theme })]; | ||
case 2: | ||
_a.sent(); | ||
return [4 /*yield*/, transformSpotlights(tree, { theme: theme })]; | ||
case 3: | ||
_a.sent(); | ||
return [4 /*yield*/, transformSections(tree, { theme: theme })]; | ||
case 4: | ||
_a.sent(); | ||
return [4 /*yield*/, transformEditorNodes(tree, { theme: theme })]; | ||
case 2: | ||
case 5: | ||
_a.sent(); | ||
return [4 /*yield*/, transformCodeNodes(tree, { theme: theme })]; | ||
case 3: | ||
case 6: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
return [3 /*break*/, 8]; | ||
case 7: | ||
e_1 = _a.sent(); | ||
console.error("error running remarkCodeHike", e_1); | ||
throw e_1; | ||
case 8: return [2 /*return*/]; | ||
} | ||
@@ -613,3 +1048,48 @@ }); | ||
} | ||
function addImportNode(tree) { | ||
tree.children.unshift({ | ||
type: "mdxjsEsm", | ||
value: 'import { CH } from "@code-hike/mdx"', | ||
data: { | ||
estree: { | ||
type: "Program", | ||
body: [ | ||
{ | ||
type: "ImportDeclaration", | ||
specifiers: [ | ||
{ | ||
type: "ImportSpecifier", | ||
imported: { | ||
type: "Identifier", | ||
name: "CH", | ||
}, | ||
local: { | ||
type: "Identifier", | ||
name: "CH", | ||
}, | ||
}, | ||
], | ||
source: { | ||
type: "Literal", | ||
value: "@code-hike/mdx", | ||
raw: '"@code-hike/mdx"', | ||
}, | ||
}, | ||
], | ||
sourceType: "module", | ||
}, | ||
}, | ||
}); | ||
} | ||
var CH = { | ||
Code: Code, | ||
Section: Section, | ||
SectionLink: SectionLink, | ||
SectionCode: SectionCode, | ||
CodeLink: CodeLink, | ||
Spotlight: Spotlight, | ||
Scrollycoding: Scrollycoding, | ||
}; | ||
export { CH, remarkCodeHike }; |
import { Node, Parent } from "unist"; | ||
export declare function extractLinks(node: Node, index: number, parent: Parent, code: string): { | ||
type: "link"; | ||
focus: string; | ||
import React from "react"; | ||
export declare function CodeLink({ children, data, }: { | ||
data: { | ||
@@ -9,2 +8,4 @@ url: string; | ||
}; | ||
}[]; | ||
children: React.ReactNode; | ||
}): JSX.Element; | ||
export declare function extractLinks(node: Node, index: number, parent: Parent, code: string): import("@code-hike/smooth-code/dist/partial-step-parser").CodeAnnotation[]; |
import { Node, Parent } from "unist"; | ||
export declare type NodeInfo = { | ||
node: Node; | ||
index: number; | ||
parent: Parent; | ||
}; | ||
export declare function splitChildren(parent: Parent, type: string): NodeInfo[][]; | ||
export declare function visitAsync(tree: Node, type: string | string[], visitor: (node: Node, index: number, parent: Parent | undefined) => void | Promise<any>): Promise<void>; | ||
export declare function toJSX(node: Node, { type, props, name, }: { | ||
export declare function toJSX(node: Node, { type, props, name, appendProps, }: { | ||
type?: string; | ||
props: Record<string, any>; | ||
name: string; | ||
name?: string; | ||
appendProps?: boolean; | ||
}): void; |
{ | ||
"name": "@code-hike/mdx", | ||
"version": "0.3.0--canary.77.979e373.0", | ||
"version": "0.3.0--canary.77.bd15ff1.0", | ||
"main": "dist/index.cjs.js", | ||
@@ -16,3 +16,3 @@ "typings": "dist/index.d.ts", | ||
"devDependencies": { | ||
"@code-hike/script": "0.3.0--canary.77.979e373.0", | ||
"@code-hike/script": "0.3.0--canary.77.bd15ff1.0", | ||
"@types/react": "^16.9.38", | ||
@@ -22,6 +22,7 @@ "react": "^16.13.1" | ||
"dependencies": { | ||
"@code-hike/highlighter": "0.3.0--canary.77.979e373.0", | ||
"@code-hike/mini-editor": "0.3.0--canary.77.979e373.0", | ||
"@code-hike/smooth-code": "0.3.0--canary.77.979e373.0", | ||
"@code-hike/utils": "0.3.0--canary.77.979e373.0", | ||
"@code-hike/highlighter": "0.3.0--canary.77.bd15ff1.0", | ||
"@code-hike/mini-editor": "0.3.0--canary.77.bd15ff1.0", | ||
"@code-hike/scroller": "0.3.0--canary.77.bd15ff1.0", | ||
"@code-hike/smooth-code": "0.3.0--canary.77.bd15ff1.0", | ||
"@code-hike/utils": "0.3.0--canary.77.bd15ff1.0", | ||
"estree-util-value-to-estree": "^1.3.0", | ||
@@ -31,3 +32,3 @@ "unist-util-visit": "^2.0.0" | ||
"peerDependencies": { | ||
"react": ">=16.8" | ||
"react": "^16.8.3 || ^17 || ^18" | ||
}, | ||
@@ -48,3 +49,3 @@ "keywords": [ | ||
}, | ||
"gitHead": "979e3736f9c1202bac4f14cf192b3227271ec84f" | ||
"gitHead": "bd15ff1e743945b8559512b871387f978a599199" | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
102282
21
2248
0
8
+ Added@code-hike/classer@0.3.0--canary.77.bd15ff1.0(transitive)
+ Added@code-hike/highlighter@0.3.0--canary.77.bd15ff1.0(transitive)
+ Added@code-hike/mini-editor@0.3.0--canary.77.bd15ff1.0(transitive)
+ Added@code-hike/mini-frame@0.3.0--canary.77.bd15ff1.0(transitive)
+ Added@code-hike/mini-terminal@0.3.0--canary.77.bd15ff1.0(transitive)
+ Added@code-hike/scroller@0.3.0--canary.77.bd15ff1.0(transitive)
+ Added@code-hike/smooth-code@0.3.0--canary.77.bd15ff1.0(transitive)
+ Added@code-hike/utils@0.3.0--canary.77.bd15ff1.0(transitive)
- Removed@code-hike/classer@0.3.0--canary.77.979e373.0(transitive)
- Removed@code-hike/highlighter@0.3.0--canary.77.979e373.0(transitive)
- Removed@code-hike/mini-editor@0.3.0--canary.77.979e373.0(transitive)
- Removed@code-hike/mini-frame@0.3.0--canary.77.979e373.0(transitive)
- Removed@code-hike/mini-terminal@0.3.0--canary.77.979e373.0(transitive)
- Removed@code-hike/smooth-code@0.3.0--canary.77.979e373.0(transitive)
- Removed@code-hike/utils@0.3.0--canary.77.979e373.0(transitive)
- Removedreact@19.0.0(transitive)