radiant-docs 0.1.19 → 0.1.21
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/package.json
CHANGED
|
@@ -340,61 +340,60 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
340
340
|
</div>
|
|
341
341
|
</div>
|
|
342
342
|
</div>
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const script = document.currentScript;
|
|
348
|
-
if (!(script instanceof HTMLScriptElement)) return;
|
|
349
|
-
|
|
350
|
-
const root = script.previousElementSibling;
|
|
351
|
-
if (!(root instanceof HTMLElement)) return;
|
|
352
|
-
|
|
353
|
-
const copyButtons = root.querySelectorAll("[data-rd-copy-trigger='true']");
|
|
354
|
-
if (copyButtons.length === 0) return;
|
|
355
|
-
|
|
356
|
-
const setCopiedState = (button, copied) => {
|
|
357
|
-
const copyIcon = button.querySelector("[data-rd-copy-icon]");
|
|
358
|
-
const checkIcon = button.querySelector("[data-rd-copy-check]");
|
|
343
|
+
<script is:inline>
|
|
344
|
+
(() => {
|
|
345
|
+
const script = document.currentScript;
|
|
346
|
+
if (!(script instanceof HTMLScriptElement)) return;
|
|
359
347
|
|
|
360
|
-
|
|
348
|
+
const root = script.closest("[data-rd-code-block-root='true']");
|
|
349
|
+
if (!(root instanceof HTMLElement)) return;
|
|
361
350
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
copyIcon.classList.remove("scale-100", "opacity-100", "rotate-0");
|
|
351
|
+
const copyButtons = root.querySelectorAll("[data-rd-copy-trigger='true']");
|
|
352
|
+
if (copyButtons.length === 0) return;
|
|
365
353
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
copyIcon.classList.remove("scale-50", "opacity-0", "-rotate-6");
|
|
372
|
-
copyIcon.classList.add("scale-100", "opacity-100", "rotate-0");
|
|
354
|
+
const setCopiedState = (button, copied) => {
|
|
355
|
+
const copyIcon = button.querySelector("[data-rd-copy-icon]");
|
|
356
|
+
const checkIcon = button.querySelector("[data-rd-copy-check]");
|
|
373
357
|
|
|
374
|
-
|
|
375
|
-
checkIcon.classList.add("scale-50", "opacity-0", "rotate-6");
|
|
376
|
-
};
|
|
358
|
+
if (!copyIcon || !checkIcon) return;
|
|
377
359
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const encodedCopyValue =
|
|
382
|
-
button.getAttribute("data-rd-copy-content") ?? "";
|
|
383
|
-
const copyValue = decodeURIComponent(encodedCopyValue);
|
|
360
|
+
if (copied) {
|
|
361
|
+
copyIcon.classList.add("scale-50", "opacity-0", "-rotate-6");
|
|
362
|
+
copyIcon.classList.remove("scale-100", "opacity-100", "rotate-0");
|
|
384
363
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
364
|
+
checkIcon.classList.remove("scale-50", "opacity-0", "rotate-6");
|
|
365
|
+
checkIcon.classList.add("scale-110", "opacity-100", "rotate-0");
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
388
368
|
|
|
389
|
-
|
|
390
|
-
|
|
369
|
+
copyIcon.classList.remove("scale-50", "opacity-0", "-rotate-6");
|
|
370
|
+
copyIcon.classList.add("scale-100", "opacity-100", "rotate-0");
|
|
371
|
+
|
|
372
|
+
checkIcon.classList.remove("scale-110", "opacity-100", "rotate-0");
|
|
373
|
+
checkIcon.classList.add("scale-50", "opacity-0", "rotate-6");
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
copyButtons.forEach((button) => {
|
|
377
|
+
let timeoutId = null;
|
|
378
|
+
button.addEventListener("click", async () => {
|
|
379
|
+
const encodedCopyValue =
|
|
380
|
+
button.getAttribute("data-rd-copy-content") ?? "";
|
|
381
|
+
const copyValue = decodeURIComponent(encodedCopyValue);
|
|
382
|
+
|
|
383
|
+
try {
|
|
384
|
+
await navigator.clipboard.writeText(copyValue);
|
|
385
|
+
setCopiedState(button, true);
|
|
386
|
+
|
|
387
|
+
if (timeoutId) window.clearTimeout(timeoutId);
|
|
388
|
+
timeoutId = window.setTimeout(() => {
|
|
389
|
+
setCopiedState(button, false);
|
|
390
|
+
timeoutId = null;
|
|
391
|
+
}, 1200);
|
|
392
|
+
} catch {
|
|
391
393
|
setCopiedState(button, false);
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
} catch {
|
|
395
|
-
setCopiedState(button, false);
|
|
396
|
-
}
|
|
394
|
+
}
|
|
395
|
+
});
|
|
397
396
|
});
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
</
|
|
397
|
+
})();
|
|
398
|
+
</script>
|
|
399
|
+
</div>
|
|
@@ -56,170 +56,169 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
56
56
|
<div data-rd-code-group-content class="min-w-0">
|
|
57
57
|
<slot />
|
|
58
58
|
</div>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const script = document.currentScript;
|
|
64
|
-
if (!(script instanceof HTMLScriptElement)) return;
|
|
59
|
+
<script is:inline>
|
|
60
|
+
(() => {
|
|
61
|
+
const script = document.currentScript;
|
|
62
|
+
if (!(script instanceof HTMLScriptElement)) return;
|
|
65
63
|
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
const root = script.closest("[data-rd-code-group-root='true']");
|
|
65
|
+
if (!(root instanceof HTMLElement)) return;
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
const contentElement = root.querySelector("[data-rd-code-group-content]");
|
|
68
|
+
const tabsElement = root.querySelector("[data-rd-code-group-tabs]");
|
|
69
|
+
const pillElement = root.querySelector("[data-rd-code-group-pill]");
|
|
70
|
+
const copyButton = root.querySelector("[data-rd-copy-trigger='true']");
|
|
73
71
|
|
|
74
|
-
|
|
72
|
+
if (!contentElement || !tabsElement || !pillElement) return;
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
const codeItems = Array.from(
|
|
75
|
+
contentElement.querySelectorAll("[data-rd-code-group-item='true']"),
|
|
76
|
+
);
|
|
77
|
+
if (codeItems.length === 0) return;
|
|
80
78
|
|
|
81
|
-
|
|
79
|
+
let activeIndex = 0;
|
|
82
80
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
const setCopiedState = (button, copied) => {
|
|
82
|
+
const copyIcon = button.querySelector("[data-rd-copy-icon]");
|
|
83
|
+
const checkIcon = button.querySelector("[data-rd-copy-check]");
|
|
84
|
+
if (!copyIcon || !checkIcon) return;
|
|
87
85
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
if (copied) {
|
|
87
|
+
copyIcon.classList.add("scale-50", "opacity-0", "-rotate-6");
|
|
88
|
+
copyIcon.classList.remove("scale-100", "opacity-100", "rotate-0");
|
|
91
89
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
checkIcon.classList.remove("scale-50", "opacity-0", "rotate-6");
|
|
91
|
+
checkIcon.classList.add("scale-110", "opacity-100", "rotate-0");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
96
94
|
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
copyIcon.classList.remove("scale-50", "opacity-0", "-rotate-6");
|
|
96
|
+
copyIcon.classList.add("scale-100", "opacity-100", "rotate-0");
|
|
99
97
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
checkIcon.classList.remove("scale-110", "opacity-100", "rotate-0");
|
|
99
|
+
checkIcon.classList.add("scale-50", "opacity-0", "rotate-6");
|
|
100
|
+
};
|
|
103
101
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
102
|
+
const tabs = codeItems.map((itemElement, index) => {
|
|
103
|
+
const filename =
|
|
104
|
+
itemElement.getAttribute("data-rd-tab-filename") ??
|
|
105
|
+
`file-name-${index + 1}.txt`;
|
|
106
|
+
const tabIconTemplate = itemElement.querySelector(
|
|
107
|
+
"template[data-rd-code-group-tab-icon]",
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const tabWrapper = document.createElement("div");
|
|
111
|
+
tabWrapper.className = "relative z-10 text-xs font-medium";
|
|
112
|
+
|
|
113
|
+
const tabButton = document.createElement("button");
|
|
114
|
+
tabButton.type = "button";
|
|
115
|
+
tabButton.className =
|
|
116
|
+
"relative inline-flex h-9 items-center gap-2 border-0 bg-transparent px-3 py-1.5 text-xs font-medium text-neutral-600 transition-colors duration-150 focus:outline-none focus-visible:outline-none cursor-pointer";
|
|
117
|
+
tabButton.setAttribute("aria-label", filename);
|
|
118
|
+
tabButton.setAttribute("data-rd-code-group-tab", String(index));
|
|
119
|
+
|
|
120
|
+
const iconContainer = document.createElement("span");
|
|
121
|
+
iconContainer.className =
|
|
122
|
+
"pointer-events-none inline-flex shrink-0 items-center rounded-[4px] transition-opacity duration-150";
|
|
123
|
+
|
|
124
|
+
if (tabIconTemplate && tabIconTemplate.innerHTML.trim().length > 0) {
|
|
125
|
+
iconContainer.innerHTML = tabIconTemplate.innerHTML;
|
|
126
|
+
} else {
|
|
127
|
+
iconContainer.classList.add("hidden");
|
|
128
|
+
}
|
|
111
129
|
|
|
112
|
-
|
|
113
|
-
|
|
130
|
+
const labelElement = document.createElement("span");
|
|
131
|
+
labelElement.className = "whitespace-pre leading-none";
|
|
132
|
+
labelElement.textContent = filename;
|
|
133
|
+
|
|
134
|
+
tabButton.appendChild(iconContainer);
|
|
135
|
+
tabButton.appendChild(labelElement);
|
|
136
|
+
tabWrapper.appendChild(tabButton);
|
|
137
|
+
tabsElement.appendChild(tabWrapper);
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
itemElement,
|
|
141
|
+
tabWrapper,
|
|
142
|
+
tabButton,
|
|
143
|
+
iconContainer,
|
|
144
|
+
};
|
|
145
|
+
});
|
|
114
146
|
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
147
|
+
const syncPill = () => {
|
|
148
|
+
const activeTab = tabs[activeIndex]?.tabWrapper;
|
|
149
|
+
if (!activeTab) {
|
|
150
|
+
pillElement.classList.add("opacity-0");
|
|
151
|
+
pillElement.classList.remove("opacity-100");
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
121
154
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
155
|
+
const activeRect = activeTab.getBoundingClientRect();
|
|
156
|
+
const tabsRect = tabsElement.getBoundingClientRect();
|
|
157
|
+
const left = activeRect.left - tabsRect.left + tabsElement.scrollLeft;
|
|
158
|
+
const width = activeRect.width;
|
|
159
|
+
pillElement.style.left = `${left}px`;
|
|
160
|
+
pillElement.style.width = `${width}px`;
|
|
161
|
+
pillElement.classList.remove("opacity-0");
|
|
162
|
+
pillElement.classList.add("opacity-100");
|
|
163
|
+
};
|
|
125
164
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
165
|
+
const syncActiveTab = () => {
|
|
166
|
+
tabs.forEach(({ itemElement, tabButton, iconContainer }, index) => {
|
|
167
|
+
const isActive = index === activeIndex;
|
|
168
|
+
itemElement.style.display = isActive ? "" : "none";
|
|
169
|
+
tabButton.classList.toggle("text-neutral-900", isActive);
|
|
170
|
+
tabButton.classList.toggle("text-neutral-600", !isActive);
|
|
171
|
+
|
|
172
|
+
if (iconContainer.classList.contains("hidden")) return;
|
|
173
|
+
iconContainer.classList.toggle("opacity-100", isActive);
|
|
174
|
+
iconContainer.classList.toggle("opacity-80", !isActive);
|
|
175
|
+
});
|
|
176
|
+
syncPill();
|
|
177
|
+
};
|
|
131
178
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
179
|
+
tabs.forEach(({ tabButton }, index) => {
|
|
180
|
+
tabButton.addEventListener("click", () => {
|
|
181
|
+
if (activeIndex === index) return;
|
|
182
|
+
activeIndex = index;
|
|
183
|
+
syncActiveTab();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
135
186
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
187
|
+
if (copyButton) {
|
|
188
|
+
let timeoutId = null;
|
|
189
|
+
copyButton.addEventListener("click", async () => {
|
|
190
|
+
const activeItem = tabs[activeIndex]?.itemElement;
|
|
191
|
+
const encodedCopyValue =
|
|
192
|
+
activeItem?.getAttribute("data-rd-copy-content") ?? "";
|
|
193
|
+
const copyValue = decodeURIComponent(encodedCopyValue);
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
await navigator.clipboard.writeText(copyValue);
|
|
197
|
+
setCopiedState(copyButton, true);
|
|
198
|
+
|
|
199
|
+
if (timeoutId) window.clearTimeout(timeoutId);
|
|
200
|
+
timeoutId = window.setTimeout(() => {
|
|
201
|
+
setCopiedState(copyButton, false);
|
|
202
|
+
timeoutId = null;
|
|
203
|
+
}, 1200);
|
|
204
|
+
} catch {
|
|
205
|
+
setCopiedState(copyButton, false);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
140
209
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const syncPill = () => {
|
|
150
|
-
const activeTab = tabs[activeIndex]?.tabWrapper;
|
|
151
|
-
if (!activeTab) {
|
|
152
|
-
pillElement.classList.add("opacity-0");
|
|
153
|
-
pillElement.classList.remove("opacity-100");
|
|
154
|
-
return;
|
|
210
|
+
const resizeObserver =
|
|
211
|
+
typeof ResizeObserver !== "undefined"
|
|
212
|
+
? new ResizeObserver(() => syncPill())
|
|
213
|
+
: null;
|
|
214
|
+
if (resizeObserver) {
|
|
215
|
+
resizeObserver.observe(tabsElement);
|
|
155
216
|
}
|
|
156
217
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
pillElement.classList.add("opacity-100");
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const syncActiveTab = () => {
|
|
168
|
-
tabs.forEach(({ itemElement, tabButton, iconContainer }, index) => {
|
|
169
|
-
const isActive = index === activeIndex;
|
|
170
|
-
itemElement.style.display = isActive ? "" : "none";
|
|
171
|
-
tabButton.classList.toggle("text-neutral-900", isActive);
|
|
172
|
-
tabButton.classList.toggle("text-neutral-600", !isActive);
|
|
173
|
-
|
|
174
|
-
if (iconContainer.classList.contains("hidden")) return;
|
|
175
|
-
iconContainer.classList.toggle("opacity-100", isActive);
|
|
176
|
-
iconContainer.classList.toggle("opacity-80", !isActive);
|
|
177
|
-
});
|
|
178
|
-
syncPill();
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
tabs.forEach(({ tabButton }, index) => {
|
|
182
|
-
tabButton.addEventListener("click", () => {
|
|
183
|
-
if (activeIndex === index) return;
|
|
184
|
-
activeIndex = index;
|
|
185
|
-
syncActiveTab();
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
if (copyButton) {
|
|
190
|
-
let timeoutId = null;
|
|
191
|
-
copyButton.addEventListener("click", async () => {
|
|
192
|
-
const activeItem = tabs[activeIndex]?.itemElement;
|
|
193
|
-
const encodedCopyValue =
|
|
194
|
-
activeItem?.getAttribute("data-rd-copy-content") ?? "";
|
|
195
|
-
const copyValue = decodeURIComponent(encodedCopyValue);
|
|
196
|
-
|
|
197
|
-
try {
|
|
198
|
-
await navigator.clipboard.writeText(copyValue);
|
|
199
|
-
setCopiedState(copyButton, true);
|
|
200
|
-
|
|
201
|
-
if (timeoutId) window.clearTimeout(timeoutId);
|
|
202
|
-
timeoutId = window.setTimeout(() => {
|
|
203
|
-
setCopiedState(copyButton, false);
|
|
204
|
-
timeoutId = null;
|
|
205
|
-
}, 1200);
|
|
206
|
-
} catch {
|
|
207
|
-
setCopiedState(copyButton, false);
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const resizeObserver =
|
|
213
|
-
typeof ResizeObserver !== "undefined"
|
|
214
|
-
? new ResizeObserver(() => syncPill())
|
|
215
|
-
: null;
|
|
216
|
-
if (resizeObserver) {
|
|
217
|
-
resizeObserver.observe(tabsElement);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
tabsElement.addEventListener("scroll", syncPill, { passive: true });
|
|
221
|
-
window.addEventListener("resize", syncPill);
|
|
222
|
-
syncActiveTab();
|
|
223
|
-
requestAnimationFrame(syncPill);
|
|
224
|
-
})();
|
|
225
|
-
</script>
|
|
218
|
+
tabsElement.addEventListener("scroll", syncPill, { passive: true });
|
|
219
|
+
window.addEventListener("resize", syncPill);
|
|
220
|
+
syncActiveTab();
|
|
221
|
+
requestAnimationFrame(syncPill);
|
|
222
|
+
})();
|
|
223
|
+
</script>
|
|
224
|
+
</div>
|
|
@@ -134,19 +134,19 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
|
|
|
134
134
|
margin-bottom: 0.5714286em;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
.rd-component-
|
|
137
|
+
.rd-component-preview__code :global(.group\/prose-code) {
|
|
138
138
|
margin-top: 0 !important;
|
|
139
139
|
margin-bottom: 0 !important;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
.rd-component-
|
|
142
|
+
.rd-component-preview__code :global(.group\/prose-code > div) {
|
|
143
143
|
background-color: var(--color-neutral-50) !important;
|
|
144
144
|
border-top-left-radius: 0 !important;
|
|
145
145
|
border-top-right-radius: 0 !important;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
.rd-component-
|
|
149
|
-
.rd-component-
|
|
148
|
+
.rd-component-preview__code :global(.group\/prose-code pre),
|
|
149
|
+
.rd-component-preview__code :global(.group\/prose-code code) {
|
|
150
150
|
background-color: var(--color-neutral-50) !important;
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -275,6 +275,8 @@ function parseComponentPreviewChildren(rawCode: string): unknown[] {
|
|
|
275
275
|
mdastExtensions: [gfmFromMarkdown(), mdxFromMarkdown()],
|
|
276
276
|
}) as Root;
|
|
277
277
|
|
|
278
|
+
transformCodeBlockNodes(parsedTree);
|
|
279
|
+
|
|
278
280
|
return transformPreviewChildren(
|
|
279
281
|
Array.isArray(parsedTree.children) ? parsedTree.children : [],
|
|
280
282
|
);
|
|
@@ -322,135 +324,139 @@ function buildDefaultCodeGroupFileName(
|
|
|
322
324
|
return `file-name-${codeIndexInGroup + 1}.${extension}`;
|
|
323
325
|
}
|
|
324
326
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
327
|
+
function transformCodeBlockNodes(tree: Root): void {
|
|
328
|
+
visitParents(tree, "code", (node, ancestors) => {
|
|
329
|
+
const codeNode = node as CodeNode;
|
|
330
|
+
const parent = ancestors[ancestors.length - 1] as ParentNode | undefined;
|
|
331
|
+
const siblings = parent?.children;
|
|
332
|
+
if (!siblings) return;
|
|
333
|
+
|
|
334
|
+
const currentIndex = siblings.indexOf(node);
|
|
335
|
+
if (currentIndex < 0) return;
|
|
336
|
+
|
|
337
|
+
const nearestMdxFlowElementName = getNearestMdxJsxFlowElementName(
|
|
338
|
+
ancestors,
|
|
339
|
+
);
|
|
340
|
+
const isInsideCodeGroup = nearestMdxFlowElementName === "CodeGroup";
|
|
341
|
+
const isInsideComponentPreview =
|
|
342
|
+
nearestMdxFlowElementName === COMPONENT_PREVIEW_NAME;
|
|
343
|
+
const componentPreviewNode = isInsideComponentPreview
|
|
344
|
+
? getNearestMdxJsxFlowElement(ancestors, COMPONENT_PREVIEW_NAME)
|
|
345
|
+
: null;
|
|
346
|
+
const isInsideInlineMdx = isInsideMdxJsxTextElement(ancestors);
|
|
347
|
+
if (isInsideInlineMdx) return;
|
|
348
|
+
|
|
349
|
+
const meta = readMetaString(codeNode.meta);
|
|
350
|
+
const parsedMeta = parseParsedCodeMeta(meta);
|
|
351
|
+
const language =
|
|
352
|
+
typeof codeNode.lang === "string" && codeNode.lang.trim().length > 0
|
|
353
|
+
? codeNode.lang.trim()
|
|
354
|
+
: "plaintext";
|
|
355
|
+
const normalizedLanguage = language.trim().toLowerCase();
|
|
356
|
+
const rawCode = typeof codeNode.value === "string" ? codeNode.value : "";
|
|
357
|
+
const codeIndexInGroup = isInsideCodeGroup
|
|
358
|
+
? siblings
|
|
359
|
+
.slice(0, currentIndex)
|
|
360
|
+
.filter(
|
|
361
|
+
(sibling) => (sibling as { type?: string }).type === "code",
|
|
362
|
+
).length
|
|
363
|
+
: 0;
|
|
364
|
+
const fileName =
|
|
365
|
+
parsedMeta.filename.length > 0
|
|
366
|
+
? parsedMeta.filename
|
|
367
|
+
: isInsideCodeGroup
|
|
368
|
+
? buildDefaultCodeGroupFileName(language, codeIndexInGroup)
|
|
369
|
+
: "";
|
|
370
|
+
const showFilename = isInsideCodeGroup || fileName.length > 0;
|
|
371
|
+
|
|
372
|
+
const attributes: MdxJsxAttributeNode[] = [
|
|
373
|
+
createAttribute("language", language),
|
|
374
|
+
createAttribute("raw", rawCode),
|
|
375
|
+
createAttribute("showFilename", showFilename ? "true" : "false"),
|
|
376
|
+
createAttribute(
|
|
377
|
+
"showLineNumbers",
|
|
378
|
+
parsedMeta.showLineNumbers ? "true" : "false",
|
|
379
|
+
),
|
|
380
|
+
];
|
|
381
|
+
|
|
382
|
+
if (parsedMeta.hideLanguageIcon) {
|
|
383
|
+
attributes.push(createAttribute("hideLanguageIcon", "true"));
|
|
384
|
+
}
|
|
332
385
|
|
|
333
|
-
|
|
334
|
-
|
|
386
|
+
if (showFilename) {
|
|
387
|
+
attributes.push(createAttribute("filename", fileName));
|
|
388
|
+
}
|
|
335
389
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const isInsideCodeGroup = nearestMdxFlowElementName === "CodeGroup";
|
|
340
|
-
const isInsideComponentPreview =
|
|
341
|
-
nearestMdxFlowElementName === COMPONENT_PREVIEW_NAME;
|
|
342
|
-
const componentPreviewNode = isInsideComponentPreview
|
|
343
|
-
? getNearestMdxJsxFlowElement(ancestors, COMPONENT_PREVIEW_NAME)
|
|
344
|
-
: null;
|
|
345
|
-
const isInsideInlineMdx = isInsideMdxJsxTextElement(ancestors);
|
|
346
|
-
if (isInsideInlineMdx) return;
|
|
347
|
-
|
|
348
|
-
const meta = readMetaString(codeNode.meta);
|
|
349
|
-
const parsedMeta = parseParsedCodeMeta(meta);
|
|
350
|
-
const language =
|
|
351
|
-
typeof codeNode.lang === "string" && codeNode.lang.trim().length > 0
|
|
352
|
-
? codeNode.lang.trim()
|
|
353
|
-
: "plaintext";
|
|
354
|
-
const normalizedLanguage = language.trim().toLowerCase();
|
|
355
|
-
const rawCode = typeof codeNode.value === "string" ? codeNode.value : "";
|
|
356
|
-
const codeIndexInGroup = isInsideCodeGroup
|
|
357
|
-
? siblings
|
|
358
|
-
.slice(0, currentIndex)
|
|
359
|
-
.filter(
|
|
360
|
-
(sibling) => (sibling as { type?: string }).type === "code",
|
|
361
|
-
).length
|
|
362
|
-
: 0;
|
|
363
|
-
const fileName =
|
|
364
|
-
parsedMeta.filename.length > 0
|
|
365
|
-
? parsedMeta.filename
|
|
366
|
-
: isInsideCodeGroup
|
|
367
|
-
? buildDefaultCodeGroupFileName(language, codeIndexInGroup)
|
|
368
|
-
: "";
|
|
369
|
-
const showFilename = isInsideCodeGroup || fileName.length > 0;
|
|
370
|
-
|
|
371
|
-
const attributes: MdxJsxAttributeNode[] = [
|
|
372
|
-
createAttribute("language", language),
|
|
373
|
-
createAttribute("raw", rawCode),
|
|
374
|
-
createAttribute("showFilename", showFilename ? "true" : "false"),
|
|
375
|
-
createAttribute(
|
|
376
|
-
"showLineNumbers",
|
|
377
|
-
parsedMeta.showLineNumbers ? "true" : "false",
|
|
378
|
-
),
|
|
379
|
-
];
|
|
380
|
-
|
|
381
|
-
if (parsedMeta.hideLanguageIcon) {
|
|
382
|
-
attributes.push(createAttribute("hideLanguageIcon", "true"));
|
|
383
|
-
}
|
|
390
|
+
if (isInsideCodeGroup) {
|
|
391
|
+
attributes.push(createAttribute("inCodeGroup", "true"));
|
|
392
|
+
}
|
|
384
393
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
394
|
+
if (parsedMeta.highlightedLines.length > 0) {
|
|
395
|
+
attributes.push(
|
|
396
|
+
createAttribute("highlightedLines", parsedMeta.highlightedLines),
|
|
397
|
+
);
|
|
398
|
+
}
|
|
388
399
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
400
|
+
if (parsedMeta.collapsedLines.length > 0) {
|
|
401
|
+
attributes.push(
|
|
402
|
+
createAttribute("collapsedLines", parsedMeta.collapsedLines),
|
|
403
|
+
);
|
|
404
|
+
}
|
|
392
405
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
406
|
+
if (isInsideComponentPreview) {
|
|
407
|
+
if (!COMPONENT_PREVIEW_LANGUAGES.has(normalizedLanguage)) {
|
|
408
|
+
throw new Error(
|
|
409
|
+
`[USER_ERROR]: <${COMPONENT_PREVIEW_NAME}>: Fenced code blocks must use jsx, tsx, or mdx language (received "${language}")`,
|
|
396
410
|
);
|
|
397
411
|
}
|
|
398
412
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
413
|
+
let previewChildren: unknown[] = [];
|
|
414
|
+
try {
|
|
415
|
+
previewChildren = parseComponentPreviewChildren(rawCode);
|
|
416
|
+
} catch (error) {
|
|
417
|
+
const reason =
|
|
418
|
+
error instanceof Error && error.message.trim().length > 0
|
|
419
|
+
? ` -> ${error.message}`
|
|
420
|
+
: "";
|
|
421
|
+
throw new Error(
|
|
422
|
+
`[USER_ERROR]: <${COMPONENT_PREVIEW_NAME}>: Failed to parse fenced code block as MDX content${reason}`,
|
|
402
423
|
);
|
|
403
424
|
}
|
|
404
425
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
previewChildren = parseComponentPreviewChildren(rawCode);
|
|
415
|
-
} catch (error) {
|
|
416
|
-
const reason =
|
|
417
|
-
error instanceof Error && error.message.trim().length > 0
|
|
418
|
-
? ` -> ${error.message}`
|
|
419
|
-
: "";
|
|
420
|
-
throw new Error(
|
|
421
|
-
`[USER_ERROR]: <${COMPONENT_PREVIEW_NAME}>: Failed to parse fenced code block as MDX content${reason}`,
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const previewAttributes = attributes.filter(
|
|
426
|
-
(attribute) => attribute.name !== "inCodeGroup",
|
|
427
|
-
);
|
|
428
|
-
const showAllCode = readBooleanAttribute(
|
|
429
|
-
componentPreviewNode?.attributes,
|
|
430
|
-
"showAllCode",
|
|
431
|
-
);
|
|
432
|
-
if (showAllCode) {
|
|
433
|
-
previewAttributes.push(createAttribute("showAllCode", "true"));
|
|
434
|
-
}
|
|
435
|
-
const previewNode: MdxJsxFlowElementNode = {
|
|
436
|
-
type: "mdxJsxFlowElement",
|
|
437
|
-
name: COMPONENT_PREVIEW_BLOCK_NAME,
|
|
438
|
-
attributes: previewAttributes,
|
|
439
|
-
children: previewChildren,
|
|
440
|
-
};
|
|
441
|
-
siblings[currentIndex] = previewNode;
|
|
442
|
-
return;
|
|
426
|
+
const previewAttributes = attributes.filter(
|
|
427
|
+
(attribute) => attribute.name !== "inCodeGroup",
|
|
428
|
+
);
|
|
429
|
+
const showAllCode = readBooleanAttribute(
|
|
430
|
+
componentPreviewNode?.attributes,
|
|
431
|
+
"showAllCode",
|
|
432
|
+
);
|
|
433
|
+
if (showAllCode) {
|
|
434
|
+
previewAttributes.push(createAttribute("showAllCode", "true"));
|
|
443
435
|
}
|
|
444
|
-
|
|
445
|
-
const replacementNode: MdxJsxFlowElementNode = {
|
|
436
|
+
const previewNode: MdxJsxFlowElementNode = {
|
|
446
437
|
type: "mdxJsxFlowElement",
|
|
447
|
-
name:
|
|
448
|
-
attributes,
|
|
449
|
-
children:
|
|
438
|
+
name: COMPONENT_PREVIEW_BLOCK_NAME,
|
|
439
|
+
attributes: previewAttributes,
|
|
440
|
+
children: previewChildren,
|
|
450
441
|
};
|
|
442
|
+
siblings[currentIndex] = previewNode;
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
451
445
|
|
|
452
|
-
|
|
453
|
-
|
|
446
|
+
const replacementNode: MdxJsxFlowElementNode = {
|
|
447
|
+
type: "mdxJsxFlowElement",
|
|
448
|
+
name: INTERNAL_CODE_BLOCK_NAME,
|
|
449
|
+
attributes,
|
|
450
|
+
children: [],
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
siblings[currentIndex] = replacementNode;
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export const remarkCodeBlockComponent: Plugin<[], Root> = () => {
|
|
458
|
+
return (tree) => {
|
|
459
|
+
transformCodeBlockNodes(tree);
|
|
454
460
|
};
|
|
455
461
|
};
|
|
456
462
|
|