mdx-forge 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +64 -0
- package/dist/components/base/styles/callout.css +64 -0
- package/dist/components/base/styles/collapsible.css +96 -0
- package/dist/components/base/styles/index.css +7 -0
- package/dist/components/base/styles/tabs.css +97 -0
- package/dist/components/docusaurus/styles.css +291 -0
- package/dist/components/generic/styles.css +102 -0
- package/dist/components/nextra/styles.css +500 -0
- package/dist/components/shared/callout-variants.css +81 -0
- package/dist/components/shared/index.css +6 -0
- package/dist/components/shared/tokens.css +105 -0
- package/dist/components/starlight/styles.css +602 -0
- package/dist/components/styles/docusaurus.css +2 -0
- package/dist/components/styles/generic.css +2 -0
- package/dist/components/styles/nextjs.css +1 -0
- package/dist/components/styles/nextra.css +2 -0
- package/dist/components/styles/starlight.css +2 -0
- package/dist/components/styles/tokens.css +1 -0
- package/dist/esm/browser/errors.js +48 -0
- package/dist/esm/browser/eval/evaluateModule.js +49 -0
- package/dist/esm/browser/index.js +147 -0
- package/dist/esm/browser/internal/constants.js +4 -0
- package/dist/esm/browser/internal/logger.js +9 -0
- package/dist/esm/browser/internal/lru-cache.js +139 -0
- package/dist/esm/browser/internal/module-id.js +7 -0
- package/dist/esm/browser/internal/runtime-config.js +35 -0
- package/dist/esm/browser/internal/semaphore.js +23 -0
- package/dist/esm/browser/internal/style-injector.js +32 -0
- package/dist/esm/browser/loader/circular.js +15 -0
- package/dist/esm/browser/loader/loadModule.js +175 -0
- package/dist/esm/browser/preload/core.js +16 -0
- package/dist/esm/browser/preload/index.js +77 -0
- package/dist/esm/browser/preload/shimLoader.js +88 -0
- package/dist/esm/browser/registry/DependencyTracker.js +154 -0
- package/dist/esm/browser/registry/ModuleCache.js +168 -0
- package/dist/esm/browser/registry/ModuleRegistry.js +156 -0
- package/dist/esm/browser/registry/StyleCache.js +94 -0
- package/dist/esm/browser/registry/index.js +4 -0
- package/dist/esm/browser/runtime/require.js +40 -0
- package/dist/esm/browser/styles/injectStyles.js +42 -0
- package/dist/esm/browser/types.js +8 -0
- package/dist/esm/compiler/index.js +9 -0
- package/dist/esm/compiler/internal/components.js +28 -0
- package/dist/esm/compiler/internal/logging.js +10 -0
- package/dist/esm/compiler/internal/path.js +17 -0
- package/dist/esm/compiler/internal/plugin-loader.js +23 -0
- package/dist/esm/compiler/internal/trust.js +16 -0
- package/dist/esm/compiler/pipeline/common/icon-registry.js +1 -0
- package/dist/esm/compiler/pipeline/common/mdx-common.js +61 -0
- package/dist/esm/compiler/pipeline/common/pipeline-config.js +163 -0
- package/dist/esm/compiler/pipeline/common/pipeline-warnings.js +125 -0
- package/dist/esm/compiler/pipeline/rehype/create-diagram-placeholder.js +79 -0
- package/dist/esm/compiler/pipeline/rehype/graphviz-placeholder.js +15 -0
- package/dist/esm/compiler/pipeline/rehype/lazy-images.js +19 -0
- package/dist/esm/compiler/pipeline/rehype/mermaid-placeholder.js +11 -0
- package/dist/esm/compiler/pipeline/rehype/plantuml-placeholder.js +11 -0
- package/dist/esm/compiler/pipeline/rehype/rehype-raw.js +33 -0
- package/dist/esm/compiler/pipeline/rehype/shiki-helpers.js +9 -0
- package/dist/esm/compiler/pipeline/rehype/shiki.js +318 -0
- package/dist/esm/compiler/pipeline/remark/admonitions.js +168 -0
- package/dist/esm/compiler/pipeline/remark/generic-components.js +56 -0
- package/dist/esm/compiler/pipeline/remark/github-alerts.js +121 -0
- package/dist/esm/compiler/pipeline/transforms/callout.js +78 -0
- package/dist/esm/compiler/pipeline/transforms/code-group.js +23 -0
- package/dist/esm/compiler/pipeline/transforms/collapsible.js +30 -0
- package/dist/esm/compiler/pipeline/transforms/index.js +12 -0
- package/dist/esm/compiler/pipeline/transforms/tabs.js +48 -0
- package/dist/esm/compiler/pipeline/transforms/utils.js +69 -0
- package/dist/esm/compiler/plugins/builder.js +54 -0
- package/dist/esm/compiler/plugins/index.js +3 -0
- package/dist/esm/compiler/plugins/loader.js +120 -0
- package/dist/esm/compiler/plugins/shared-plugins.js +56 -0
- package/dist/esm/compiler/plugins/utils.js +13 -0
- package/dist/esm/compiler/safe/compile.js +228 -0
- package/dist/esm/compiler/transforms/index.js +1 -0
- package/dist/esm/compiler/trusted/compile.js +134 -0
- package/dist/esm/compiler/trusted/component-mapper.js +85 -0
- package/dist/esm/compiler/trusted/hasDefaultExport.js +15 -0
- package/dist/esm/compiler/types/compiler.js +1 -0
- package/dist/esm/compiler/types/index.js +3 -0
- package/dist/esm/compiler/types/mdx.js +3 -0
- package/dist/esm/compiler/types/pipeline.js +18 -0
- package/dist/esm/components/base/BaseCallout.js +50 -0
- package/dist/esm/components/base/BaseCard.js +11 -0
- package/dist/esm/components/base/BaseCodeBlock.js +42 -0
- package/dist/esm/components/base/BaseTabs.js +168 -0
- package/dist/esm/components/base/CopyButton.js +12 -0
- package/dist/esm/components/base/createCollapsible.js +63 -0
- package/dist/esm/components/base/createIconComponent.js +31 -0
- package/dist/esm/components/base/extractTextContent.js +19 -0
- package/dist/esm/components/base/icons.js +49 -0
- package/dist/esm/components/base/index.js +15 -0
- package/dist/esm/components/base/useCopyToClipboard.js +17 -0
- package/dist/esm/components/base/useTabState.js +113 -0
- package/dist/esm/components/docusaurus/CodeBlock.js +13 -0
- package/dist/esm/components/docusaurus/Details.js +18 -0
- package/dist/esm/components/docusaurus/Tabs.js +15 -0
- package/dist/esm/components/docusaurus/index.js +3 -0
- package/dist/esm/components/generic/Callout.js +28 -0
- package/dist/esm/components/generic/CodeGroup.js +52 -0
- package/dist/esm/components/generic/Collapsible.js +21 -0
- package/dist/esm/components/generic/TabItem.js +8 -0
- package/dist/esm/components/generic/Tabs.js +13 -0
- package/dist/esm/components/generic/index.js +6 -0
- package/dist/esm/components/generic/types.js +5 -0
- package/dist/esm/components/index.js +8 -0
- package/dist/esm/components/internal/clipboard.js +9 -0
- package/dist/esm/components/internal/cn.js +4 -0
- package/dist/esm/components/internal/constants.js +1 -0
- package/dist/esm/components/nextjs/Image.js +36 -0
- package/dist/esm/components/nextjs/Link.js +28 -0
- package/dist/esm/components/nextjs/index.js +2 -0
- package/dist/esm/components/nextra/Bleed.js +18 -0
- package/dist/esm/components/nextra/Callout.js +30 -0
- package/dist/esm/components/nextra/Cards.js +25 -0
- package/dist/esm/components/nextra/FileTree.js +11 -0
- package/dist/esm/components/nextra/Steps.js +11 -0
- package/dist/esm/components/nextra/Tabs.js +28 -0
- package/dist/esm/components/nextra/createNextraWrapper.js +12 -0
- package/dist/esm/components/nextra/index.js +6 -0
- package/dist/esm/components/registry/index.js +4 -0
- package/dist/esm/components/registry/queries.js +69 -0
- package/dist/esm/components/registry/registry-data.js +357 -0
- package/dist/esm/components/registry/shim-config.js +187 -0
- package/dist/esm/components/registry/types.js +3 -0
- package/dist/esm/components/starlight/Aside.js +24 -0
- package/dist/esm/components/starlight/Badge.js +6 -0
- package/dist/esm/components/starlight/Card.js +28 -0
- package/dist/esm/components/starlight/CardGrid.js +6 -0
- package/dist/esm/components/starlight/Code.js +25 -0
- package/dist/esm/components/starlight/FileTree.js +148 -0
- package/dist/esm/components/starlight/LinkCard.js +8 -0
- package/dist/esm/components/starlight/Steps.js +6 -0
- package/dist/esm/components/starlight/Tabs.js +6 -0
- package/dist/esm/components/starlight/index.js +9 -0
- package/dist/esm/internal/callout.js +43 -0
- package/dist/esm/internal/errors.js +27 -0
- package/dist/esm/internal/icons.js +41 -0
- package/dist/types/browser/errors.d.ts +18 -0
- package/dist/types/browser/eval/evaluateModule.d.ts +2 -0
- package/dist/types/browser/index.d.ts +20 -0
- package/dist/types/browser/internal/constants.d.ts +4 -0
- package/dist/types/browser/internal/logger.d.ts +9 -0
- package/dist/types/browser/internal/lru-cache.d.ts +33 -0
- package/dist/types/browser/internal/module-id.d.ts +1 -0
- package/dist/types/browser/internal/runtime-config.d.ts +10 -0
- package/dist/types/browser/internal/semaphore.d.ts +7 -0
- package/dist/types/browser/internal/style-injector.d.ts +3 -0
- package/dist/types/browser/loader/circular.d.ts +4 -0
- package/dist/types/browser/loader/loadModule.d.ts +2 -0
- package/dist/types/browser/preload/core.d.ts +11 -0
- package/dist/types/browser/preload/index.d.ts +21 -0
- package/dist/types/browser/preload/shimLoader.d.ts +20 -0
- package/dist/types/browser/registry/DependencyTracker.d.ts +23 -0
- package/dist/types/browser/registry/ModuleCache.d.ts +30 -0
- package/dist/types/browser/registry/ModuleRegistry.d.ts +44 -0
- package/dist/types/browser/registry/StyleCache.d.ts +17 -0
- package/dist/types/browser/registry/index.d.ts +4 -0
- package/dist/types/browser/runtime/require.d.ts +1 -0
- package/dist/types/browser/styles/injectStyles.d.ts +3 -0
- package/dist/types/browser/types.d.ts +50 -0
- package/dist/types/compiler/index.d.ts +6 -0
- package/dist/types/compiler/internal/components.d.ts +21 -0
- package/dist/types/compiler/internal/logging.d.ts +3 -0
- package/dist/types/compiler/internal/path.d.ts +2 -0
- package/dist/types/compiler/internal/plugin-loader.d.ts +2 -0
- package/dist/types/compiler/internal/trust.d.ts +2 -0
- package/dist/types/compiler/pipeline/common/icon-registry.d.ts +1 -0
- package/dist/types/compiler/pipeline/common/mdx-common.d.ts +8 -0
- package/dist/types/compiler/pipeline/common/pipeline-config.d.ts +39 -0
- package/dist/types/compiler/pipeline/common/pipeline-warnings.d.ts +21 -0
- package/dist/types/compiler/pipeline/rehype/create-diagram-placeholder.d.ts +15 -0
- package/dist/types/compiler/pipeline/rehype/graphviz-placeholder.d.ts +2 -0
- package/dist/types/compiler/pipeline/rehype/lazy-images.d.ts +2 -0
- package/dist/types/compiler/pipeline/rehype/mermaid-placeholder.d.ts +2 -0
- package/dist/types/compiler/pipeline/rehype/plantuml-placeholder.d.ts +2 -0
- package/dist/types/compiler/pipeline/rehype/rehype-raw.d.ts +2 -0
- package/dist/types/compiler/pipeline/rehype/shiki-helpers.d.ts +2 -0
- package/dist/types/compiler/pipeline/rehype/shiki.d.ts +2 -0
- package/dist/types/compiler/pipeline/remark/admonitions.d.ts +2 -0
- package/dist/types/compiler/pipeline/remark/generic-components.d.ts +6 -0
- package/dist/types/compiler/pipeline/remark/github-alerts.d.ts +2 -0
- package/dist/types/compiler/pipeline/transforms/callout.d.ts +10 -0
- package/dist/types/compiler/pipeline/transforms/code-group.d.ts +3 -0
- package/dist/types/compiler/pipeline/transforms/collapsible.d.ts +3 -0
- package/dist/types/compiler/pipeline/transforms/index.d.ts +6 -0
- package/dist/types/compiler/pipeline/transforms/tabs.d.ts +4 -0
- package/dist/types/compiler/pipeline/transforms/utils.d.ts +6 -0
- package/dist/types/compiler/plugins/builder.d.ts +14 -0
- package/dist/types/compiler/plugins/index.d.ts +3 -0
- package/dist/types/compiler/plugins/loader.d.ts +4 -0
- package/dist/types/compiler/plugins/shared-plugins.d.ts +13 -0
- package/dist/types/compiler/plugins/utils.d.ts +4 -0
- package/dist/types/compiler/safe/compile.d.ts +2 -0
- package/dist/types/compiler/transforms/index.d.ts +1 -0
- package/dist/types/compiler/trusted/compile.d.ts +2 -0
- package/dist/types/compiler/trusted/component-mapper.d.ts +10 -0
- package/dist/types/compiler/trusted/hasDefaultExport.d.ts +2 -0
- package/dist/types/compiler/types/compiler.d.ts +83 -0
- package/dist/types/compiler/types/index.d.ts +3 -0
- package/dist/types/compiler/types/mdx.d.ts +36 -0
- package/dist/types/compiler/types/pipeline.d.ts +54 -0
- package/dist/types/components/base/BaseCallout.d.ts +26 -0
- package/dist/types/components/base/BaseCard.d.ts +11 -0
- package/dist/types/components/base/BaseCodeBlock.d.ts +23 -0
- package/dist/types/components/base/BaseTabs.d.ts +52 -0
- package/dist/types/components/base/CopyButton.d.ts +8 -0
- package/dist/types/components/base/createCollapsible.d.ts +27 -0
- package/dist/types/components/base/createIconComponent.d.ts +6 -0
- package/dist/types/components/base/extractTextContent.d.ts +2 -0
- package/dist/types/components/base/icons.d.ts +50 -0
- package/dist/types/components/base/index.d.ts +12 -0
- package/dist/types/components/base/useCopyToClipboard.d.ts +5 -0
- package/dist/types/components/base/useTabState.d.ts +43 -0
- package/dist/types/components/docusaurus/CodeBlock.d.ts +3 -0
- package/dist/types/components/docusaurus/Details.d.ts +4 -0
- package/dist/types/components/docusaurus/Tabs.d.ts +7 -0
- package/dist/types/components/docusaurus/index.d.ts +3 -0
- package/dist/types/components/generic/Callout.d.ts +8 -0
- package/dist/types/components/generic/CodeGroup.d.ts +4 -0
- package/dist/types/components/generic/Collapsible.d.ts +4 -0
- package/dist/types/components/generic/TabItem.d.ts +6 -0
- package/dist/types/components/generic/Tabs.d.ts +6 -0
- package/dist/types/components/generic/index.d.ts +6 -0
- package/dist/types/components/generic/types.d.ts +19 -0
- package/dist/types/components/index.d.ts +7 -0
- package/dist/types/components/internal/clipboard.d.ts +1 -0
- package/dist/types/components/internal/cn.d.ts +1 -0
- package/dist/types/components/internal/constants.d.ts +1 -0
- package/dist/types/components/nextjs/Image.d.ts +25 -0
- package/dist/types/components/nextjs/Link.d.ts +19 -0
- package/dist/types/components/nextjs/index.d.ts +2 -0
- package/dist/types/components/nextra/Bleed.d.ts +17 -0
- package/dist/types/components/nextra/Callout.d.ts +10 -0
- package/dist/types/components/nextra/Cards.d.ts +18 -0
- package/dist/types/components/nextra/FileTree.d.ts +4 -0
- package/dist/types/components/nextra/Steps.d.ts +4 -0
- package/dist/types/components/nextra/Tabs.d.ts +21 -0
- package/dist/types/components/nextra/createNextraWrapper.d.ts +14 -0
- package/dist/types/components/nextra/index.d.ts +6 -0
- package/dist/types/components/registry/index.d.ts +4 -0
- package/dist/types/components/registry/queries.d.ts +11 -0
- package/dist/types/components/registry/registry-data.d.ts +303 -0
- package/dist/types/components/registry/shim-config.d.ts +18 -0
- package/dist/types/components/registry/types.d.ts +25 -0
- package/dist/types/components/starlight/Aside.d.ts +6 -0
- package/dist/types/components/starlight/Badge.d.ts +9 -0
- package/dist/types/components/starlight/Card.d.ts +8 -0
- package/dist/types/components/starlight/CardGrid.d.ts +7 -0
- package/dist/types/components/starlight/Code.d.ts +11 -0
- package/dist/types/components/starlight/FileTree.d.ts +6 -0
- package/dist/types/components/starlight/LinkCard.d.ts +8 -0
- package/dist/types/components/starlight/Steps.d.ts +6 -0
- package/dist/types/components/starlight/Tabs.d.ts +2 -0
- package/dist/types/components/starlight/index.d.ts +9 -0
- package/dist/types/internal/callout.d.ts +7 -0
- package/dist/types/internal/errors.d.ts +3 -0
- package/dist/types/internal/icons.d.ts +50 -0
- package/package.json +150 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// packages/webview-app/src/components/shims/base/BaseTabs.tsx
|
|
3
|
+
// factory for creating framework-specific Tabs components w/ shared logic
|
|
4
|
+
import { createContext, useContext, useRef, useCallback, Children, isValidElement, } from 'react';
|
|
5
|
+
import { cn } from '../internal/cn.js';
|
|
6
|
+
import { useTabState, useIndexTabs, } from './useTabState.js';
|
|
7
|
+
// factory function to create framework-specific Tabs components
|
|
8
|
+
// all implementations share the same core logic via useTabState hook
|
|
9
|
+
export function createTabs(config) {
|
|
10
|
+
const { classPrefix, wrapperClass, supportsGroupId = false, tabItemClassName = `${classPrefix}-item`, contextName, } = config;
|
|
11
|
+
// create a unique context for this tabs implementation
|
|
12
|
+
const TabsContext = createContext(false);
|
|
13
|
+
TabsContext.displayName = `${contextName}Context`;
|
|
14
|
+
// the Tabs component
|
|
15
|
+
function Tabs({ children, defaultValue, values, className, groupId, }) {
|
|
16
|
+
const { activeValue, setActiveValue, tabs, tabItems } = useTabState({
|
|
17
|
+
children,
|
|
18
|
+
defaultValue,
|
|
19
|
+
values,
|
|
20
|
+
});
|
|
21
|
+
// refs for tab buttons to enable focus management
|
|
22
|
+
const tabRefs = useRef([]);
|
|
23
|
+
// handle keyboard navigation for tabs
|
|
24
|
+
const handleKeyDown = useCallback((e, currentIndex) => {
|
|
25
|
+
const tabCount = tabs.length;
|
|
26
|
+
let newIndex = currentIndex;
|
|
27
|
+
switch (e.key) {
|
|
28
|
+
case 'ArrowLeft':
|
|
29
|
+
case 'ArrowUp':
|
|
30
|
+
newIndex = (currentIndex - 1 + tabCount) % tabCount;
|
|
31
|
+
break;
|
|
32
|
+
case 'ArrowRight':
|
|
33
|
+
case 'ArrowDown':
|
|
34
|
+
newIndex = (currentIndex + 1) % tabCount;
|
|
35
|
+
break;
|
|
36
|
+
case 'Home':
|
|
37
|
+
newIndex = 0;
|
|
38
|
+
break;
|
|
39
|
+
case 'End':
|
|
40
|
+
newIndex = tabCount - 1;
|
|
41
|
+
break;
|
|
42
|
+
default:
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
setActiveValue(tabs[newIndex].value);
|
|
47
|
+
tabRefs.current[newIndex]?.focus();
|
|
48
|
+
}, [tabs, setActiveValue]);
|
|
49
|
+
// build wrapper class
|
|
50
|
+
const wrapperClassName = wrapperClass
|
|
51
|
+
? `${wrapperClass}${className ? ` ${className}` : ''}`
|
|
52
|
+
: `${classPrefix}${className ? ` ${className}` : ''}`;
|
|
53
|
+
return (_jsx(TabsContext.Provider, { value: true, children: _jsxs("div", { className: wrapperClassName, "data-component": "tabs", "data-group-id": supportsGroupId ? groupId : undefined, children: [_jsx("div", { className: `${classPrefix}-header`, role: "tablist", children: tabs.map((tab, index) => (_jsx("button", { ref: (el) => {
|
|
54
|
+
tabRefs.current[index] = el;
|
|
55
|
+
}, role: "tab", className: `${classPrefix}-button${tab.value === activeValue ? ' active' : ''}`, "aria-selected": tab.value === activeValue, onClick: () => setActiveValue(tab.value), onKeyDown: (e) => handleKeyDown(e, index), tabIndex: tab.value === activeValue ? 0 : -1, children: tab.label }, tab.value))) }), _jsx("div", { className: `${classPrefix}-content`, children: tabItems.map((item) => (_jsx("div", { role: "tabpanel", className: `${classPrefix}-panel${item.value === activeValue ? ' active' : ''}`, hidden: item.value !== activeValue, children: item.content }, item.value))) })] }) }));
|
|
56
|
+
}
|
|
57
|
+
Tabs.displayName = contextName;
|
|
58
|
+
// provide TabItem for shared props extraction
|
|
59
|
+
function TabItem({ children }) {
|
|
60
|
+
const isInsideTabs = useContext(TabsContext);
|
|
61
|
+
// if used outside of Tabs context, render directly
|
|
62
|
+
if (!isInsideTabs) {
|
|
63
|
+
return _jsx("div", { className: tabItemClassName, children: children });
|
|
64
|
+
}
|
|
65
|
+
// render content via parent when inside Tabs
|
|
66
|
+
return _jsx(_Fragment, { children: children });
|
|
67
|
+
}
|
|
68
|
+
TabItem.displayName = `${contextName}TabItem`;
|
|
69
|
+
// hook to check if inside Tabs context
|
|
70
|
+
function useTabsContext() {
|
|
71
|
+
return useContext(TabsContext);
|
|
72
|
+
}
|
|
73
|
+
return { Tabs, TabItem, useTabsContext, TabsContext };
|
|
74
|
+
}
|
|
75
|
+
// factory for creating index-based Tabs components (Nextra style)
|
|
76
|
+
// use items array instead of extracting tabs from children
|
|
77
|
+
export function createIndexTabs(config, accessors) {
|
|
78
|
+
const { classPrefix, contextName } = config;
|
|
79
|
+
const { getLabel, isDisabled = () => false } = accessors;
|
|
80
|
+
const TabsContext = createContext(false);
|
|
81
|
+
TabsContext.displayName = `${contextName}Context`;
|
|
82
|
+
// tab subcomponent (compound component pattern)
|
|
83
|
+
function Tab({ children }) {
|
|
84
|
+
return _jsx(_Fragment, { children: children });
|
|
85
|
+
}
|
|
86
|
+
function TabsComponent({ children, items, defaultIndex = 0, selectedIndex: controlledIndex, storageKey, onChange, className, tabClassName, ...props }) {
|
|
87
|
+
const { activeIndex, setActiveIndex } = useIndexTabs({
|
|
88
|
+
items,
|
|
89
|
+
defaultIndex,
|
|
90
|
+
controlledIndex,
|
|
91
|
+
storageKey,
|
|
92
|
+
onChange,
|
|
93
|
+
isDisabled,
|
|
94
|
+
});
|
|
95
|
+
// refs for tab buttons to enable focus management
|
|
96
|
+
const tabRefs = useRef([]);
|
|
97
|
+
// handle keyboard navigation for tabs
|
|
98
|
+
const handleKeyDown = useCallback((e, currentIndex) => {
|
|
99
|
+
const tabCount = items.length;
|
|
100
|
+
let newIndex = currentIndex;
|
|
101
|
+
switch (e.key) {
|
|
102
|
+
case 'ArrowLeft':
|
|
103
|
+
case 'ArrowUp':
|
|
104
|
+
// find previous non-disabled tab
|
|
105
|
+
for (let i = 1; i <= tabCount; i++) {
|
|
106
|
+
const idx = (currentIndex - i + tabCount) % tabCount;
|
|
107
|
+
if (!isDisabled(items[idx])) {
|
|
108
|
+
newIndex = idx;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
break;
|
|
113
|
+
case 'ArrowRight':
|
|
114
|
+
case 'ArrowDown':
|
|
115
|
+
// find next non-disabled tab
|
|
116
|
+
for (let i = 1; i <= tabCount; i++) {
|
|
117
|
+
const idx = (currentIndex + i) % tabCount;
|
|
118
|
+
if (!isDisabled(items[idx])) {
|
|
119
|
+
newIndex = idx;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
case 'Home':
|
|
125
|
+
// find first non-disabled tab
|
|
126
|
+
for (let i = 0; i < tabCount; i++) {
|
|
127
|
+
if (!isDisabled(items[i])) {
|
|
128
|
+
newIndex = i;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
case 'End':
|
|
134
|
+
// find last non-disabled tab
|
|
135
|
+
for (let i = tabCount - 1; i >= 0; i--) {
|
|
136
|
+
if (!isDisabled(items[i])) {
|
|
137
|
+
newIndex = i;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
break;
|
|
142
|
+
default:
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
setActiveIndex(newIndex);
|
|
147
|
+
tabRefs.current[newIndex]?.focus();
|
|
148
|
+
}, [items, setActiveIndex]);
|
|
149
|
+
// get Tab children for content panels
|
|
150
|
+
const tabChildren = Children.toArray(children).filter((child) => isValidElement(child) && child.type === Tab);
|
|
151
|
+
return (_jsx(TabsContext.Provider, { value: true, children: _jsxs("div", { className: cn(classPrefix, className), ...props, children: [_jsx("div", { className: `${classPrefix}-header`, role: "tablist", children: items.map((item, index) => {
|
|
152
|
+
const label = getLabel(item);
|
|
153
|
+
const disabled = isDisabled(item);
|
|
154
|
+
const selected = index === activeIndex;
|
|
155
|
+
const customClass = tabClassName
|
|
156
|
+
? typeof tabClassName === 'function'
|
|
157
|
+
? tabClassName(index, selected)
|
|
158
|
+
: tabClassName
|
|
159
|
+
: undefined;
|
|
160
|
+
return (_jsx("button", { ref: (el) => {
|
|
161
|
+
tabRefs.current[index] = el;
|
|
162
|
+
}, role: "tab", "aria-selected": selected, "aria-disabled": disabled, tabIndex: selected ? 0 : -1, className: cn(`${classPrefix}-button`, selected && `${classPrefix}-button-active`, disabled && `${classPrefix}-button-disabled`, customClass), onClick: () => setActiveIndex(index), onKeyDown: (e) => handleKeyDown(e, index), disabled: disabled, children: label }, index));
|
|
163
|
+
}) }), _jsx("div", { className: `${classPrefix}-content`, children: tabChildren.map((child, index) => (_jsx("div", { role: "tabpanel", hidden: index !== activeIndex, className: `${classPrefix}-panel`, children: index === activeIndex && child }, index))) })] }) }));
|
|
164
|
+
}
|
|
165
|
+
const Tabs = Object.assign(TabsComponent, { Tab });
|
|
166
|
+
Tabs.displayName = contextName;
|
|
167
|
+
return { Tabs, TabsContext };
|
|
168
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCopyToClipboard } from './useCopyToClipboard.js';
|
|
3
|
+
import { COPY_ICONS } from './icons.js';
|
|
4
|
+
// reusable copy-to-clipboard button w/ visual feedback
|
|
5
|
+
export function CopyButton({ text, className = 'copy-button', copiedClassName = 'copied', }) {
|
|
6
|
+
const { copied, copy } = useCopyToClipboard();
|
|
7
|
+
const buttonClass = copied ? `${className} ${copiedClassName}` : className;
|
|
8
|
+
return (_jsx("button", { className: buttonClass, onClick: () => copy(text), title: copied ? 'Copied!' : 'Copy code', "aria-label": copied ? 'Copied!' : 'Copy code', children: _jsx("span", { dangerouslySetInnerHTML: {
|
|
9
|
+
__html: copied ? COPY_ICONS.check : COPY_ICONS.copy,
|
|
10
|
+
} }) }));
|
|
11
|
+
}
|
|
12
|
+
export default CopyButton;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// packages/webview-app/src/components/shims/base/createCollapsible.tsx
|
|
3
|
+
// factory for creating framework-specific collapsible/details components
|
|
4
|
+
import { useState, } from 'react';
|
|
5
|
+
import { cn } from '../internal/cn.js';
|
|
6
|
+
import { ChevronIcon } from './icons.js';
|
|
7
|
+
// preset class configurations for each framework
|
|
8
|
+
// class names for Generic Collapsible
|
|
9
|
+
export const GENERIC_COLLAPSIBLE_CLASSES = {
|
|
10
|
+
container: 'mdx-preview-generic-collapsible',
|
|
11
|
+
summary: 'mdx-preview-generic-collapsible-summary',
|
|
12
|
+
icon: 'mdx-preview-generic-collapsible-icon',
|
|
13
|
+
iconOpen: 'open',
|
|
14
|
+
title: 'mdx-preview-generic-collapsible-title',
|
|
15
|
+
content: 'mdx-preview-generic-collapsible-content',
|
|
16
|
+
};
|
|
17
|
+
// class names for Docusaurus Details
|
|
18
|
+
export const DOCUSAURUS_DETAILS_CLASSES = {
|
|
19
|
+
container: 'docusaurus-details',
|
|
20
|
+
summary: 'details-summary',
|
|
21
|
+
icon: 'details-toggle-icon',
|
|
22
|
+
iconOpen: 'expanded',
|
|
23
|
+
title: 'details-summary-text',
|
|
24
|
+
content: 'details-content',
|
|
25
|
+
};
|
|
26
|
+
// factory function to create framework-specific Collapsible components
|
|
27
|
+
export function createCollapsible(config) {
|
|
28
|
+
const { classNames, iconSize = 16, useNativeToggle = true, applyOpenClassToWrapper = true, defaultSummary = 'Details', } = config;
|
|
29
|
+
function Collapsible({ children, summary, title, defaultOpen = false, open, className, }) {
|
|
30
|
+
// resolve prop aliases
|
|
31
|
+
const effectiveSummary = summary ?? title ?? defaultSummary;
|
|
32
|
+
const effectiveDefaultOpen = open ?? defaultOpen;
|
|
33
|
+
const [isOpen, setIsOpen] = useState(effectiveDefaultOpen);
|
|
34
|
+
// native toggle handler (Docusaurus pattern)
|
|
35
|
+
const handleNativeToggle = useNativeToggle
|
|
36
|
+
? (e) => {
|
|
37
|
+
setIsOpen(e.target.open);
|
|
38
|
+
}
|
|
39
|
+
: undefined;
|
|
40
|
+
// custom click handler (Generic Collapsible pattern)
|
|
41
|
+
const handleSummaryClick = !useNativeToggle
|
|
42
|
+
? (e) => {
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
setIsOpen(!isOpen);
|
|
45
|
+
}
|
|
46
|
+
: undefined;
|
|
47
|
+
// prevent native toggle when using custom click handling
|
|
48
|
+
const handleDetailsClick = !useNativeToggle
|
|
49
|
+
? (e) => {
|
|
50
|
+
if (e.target.tagName === 'SUMMARY') {
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
: undefined;
|
|
55
|
+
// determine icon class based on applyOpenClassToWrapper
|
|
56
|
+
const iconWrapperClass = applyOpenClassToWrapper
|
|
57
|
+
? cn(classNames.icon, isOpen && classNames.iconOpen)
|
|
58
|
+
: classNames.icon;
|
|
59
|
+
const iconSvgClass = !applyOpenClassToWrapper && isOpen ? classNames.iconOpen : undefined;
|
|
60
|
+
return (_jsxs("details", { className: cn(classNames.container, className), "data-component": "collapsible", open: isOpen, onToggle: handleNativeToggle, onClick: handleDetailsClick, children: [_jsxs("summary", { className: classNames.summary, onClick: handleSummaryClick, children: [_jsx("span", { className: iconWrapperClass, children: _jsx(ChevronIcon, { size: iconSize, className: iconSvgClass }) }), _jsx("span", { className: classNames.title, children: effectiveSummary })] }), _jsx("div", { className: classNames.content, children: children })] }));
|
|
61
|
+
}
|
|
62
|
+
return Collapsible;
|
|
63
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// parse an SVG string to extract viewBox, style attributes & inner content
|
|
3
|
+
// called once per icon at module load time (not per-render)
|
|
4
|
+
function parseSvg(svgString) {
|
|
5
|
+
const viewBoxMatch = svgString.match(/viewBox="([^"]+)"/);
|
|
6
|
+
const fillMatch = svgString.match(/\sfill="([^"]+)"/);
|
|
7
|
+
const strokeMatch = svgString.match(/\sstroke="([^"]+)"/);
|
|
8
|
+
const strokeWidthMatch = svgString.match(/stroke-width="([^"]+)"/);
|
|
9
|
+
const strokeLinecapMatch = svgString.match(/stroke-linecap="([^"]+)"/);
|
|
10
|
+
const strokeLinejoinMatch = svgString.match(/stroke-linejoin="([^"]+)"/);
|
|
11
|
+
const innerMatch = svgString.match(/<svg[^>]*>([\s\S]*)<\/svg>/);
|
|
12
|
+
return {
|
|
13
|
+
viewBox: viewBoxMatch?.[1] ?? '0 0 24 24',
|
|
14
|
+
fill: fillMatch?.[1] ?? 'none',
|
|
15
|
+
stroke: strokeMatch?.[1],
|
|
16
|
+
strokeWidth: strokeWidthMatch?.[1],
|
|
17
|
+
strokeLinecap: strokeLinecapMatch?.[1],
|
|
18
|
+
strokeLinejoin: strokeLinejoinMatch?.[1],
|
|
19
|
+
innerHtml: innerMatch?.[1] ?? '',
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// create a React icon component from a shared SVG string
|
|
23
|
+
// parse the SVG once at module level for zero per-render overhead
|
|
24
|
+
// inner content rendered via dangerouslySetInnerHTML (safe: compile-time constants)
|
|
25
|
+
export function createIconComponent(svgString, defaultSize = 16) {
|
|
26
|
+
const parsed = parseSvg(svgString);
|
|
27
|
+
function IconComponent({ size = defaultSize, className, }) {
|
|
28
|
+
return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: parsed.viewBox, fill: parsed.fill, stroke: parsed.stroke, strokeWidth: parsed.strokeWidth, strokeLinecap: parsed.strokeLinecap, strokeLinejoin: parsed.strokeLinejoin, className: className, dangerouslySetInnerHTML: { __html: parsed.innerHtml } }));
|
|
29
|
+
}
|
|
30
|
+
return IconComponent;
|
|
31
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// packages/webview-app/src/components/shims/base/extractTextContent.ts
|
|
2
|
+
// shared utility for extracting plain text from React children
|
|
3
|
+
import { isValidElement } from 'react';
|
|
4
|
+
// extract plain text content from React children
|
|
5
|
+
export function extractTextContent(node) {
|
|
6
|
+
if (typeof node === 'string') {
|
|
7
|
+
return node;
|
|
8
|
+
}
|
|
9
|
+
if (typeof node === 'number') {
|
|
10
|
+
return String(node);
|
|
11
|
+
}
|
|
12
|
+
if (Array.isArray(node)) {
|
|
13
|
+
return node.map(extractTextContent).join('');
|
|
14
|
+
}
|
|
15
|
+
if (isValidElement(node)) {
|
|
16
|
+
return extractTextContent(node.props.children);
|
|
17
|
+
}
|
|
18
|
+
return '';
|
|
19
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { CALLOUT_ICONS as SHARED_CALLOUT_ICONS, GITHUB_ICONS as SHARED_GITHUB_ICONS, FILE_TREE_ICONS as SHARED_FILE_TREE_ICONS, LUCIDE_ICONS as SHARED_LUCIDE_ICONS, } from '../../internal/icons.js';
|
|
3
|
+
import { createIconComponent } from './createIconComponent.js';
|
|
4
|
+
// re-export SVG icon registries from shared package
|
|
5
|
+
export const CALLOUT_ICONS = SHARED_CALLOUT_ICONS;
|
|
6
|
+
export const FILE_TREE_ICONS = SHARED_FILE_TREE_ICONS;
|
|
7
|
+
export const GITHUB_ICONS = SHARED_GITHUB_ICONS;
|
|
8
|
+
export const LUCIDE_ICONS = SHARED_LUCIDE_ICONS;
|
|
9
|
+
// unified copy/check icons for clipboard functionality
|
|
10
|
+
// use GitHub Primer style for consistency w/ code blocks
|
|
11
|
+
export const COPY_ICONS = {
|
|
12
|
+
copy: GITHUB_ICONS.copy,
|
|
13
|
+
check: GITHUB_ICONS.check,
|
|
14
|
+
};
|
|
15
|
+
// JSX icon components derived from shared SVG strings
|
|
16
|
+
// eliminates SVG path duplication between shared & webview packages
|
|
17
|
+
// chevron icon (Lucide style) - used for collapsibles & tree views
|
|
18
|
+
export const ChevronIcon = createIconComponent(FILE_TREE_ICONS.chevron, 16);
|
|
19
|
+
// GitHub Primer style lightbulb icon - used for Nextra default callout
|
|
20
|
+
export const LightbulbIcon = createIconComponent(GITHUB_ICONS.lightbulb, 16);
|
|
21
|
+
// GitHub Primer style info icon - used for Nextra info callout
|
|
22
|
+
export const InfoIconGitHub = createIconComponent(GITHUB_ICONS.info, 16);
|
|
23
|
+
// GitHub Primer style warning icon - used for Nextra warning callout
|
|
24
|
+
export const WarningIconGitHub = createIconComponent(GITHUB_ICONS.warning, 16);
|
|
25
|
+
// GitHub Primer style error/octagon icon - used for Nextra error callout
|
|
26
|
+
export const ErrorIconGitHub = createIconComponent(GITHUB_ICONS.error, 16);
|
|
27
|
+
// GitHub Primer style comment/important icon - used for Nextra important callout
|
|
28
|
+
export const ImportantIconGitHub = createIconComponent(GITHUB_ICONS.important, 16);
|
|
29
|
+
// pre-create GitHub variant at module level (avoid per-render allocation)
|
|
30
|
+
const GitHubArrowIcon = createIconComponent(GITHUB_ICONS.arrowRight, 16);
|
|
31
|
+
const LucideArrowIcon = createIconComponent(LUCIDE_ICONS.arrowRight, 16);
|
|
32
|
+
// arrow icon - used for link cards & navigation
|
|
33
|
+
export function ArrowIcon({ size = 16, className, variant = 'lucide', }) {
|
|
34
|
+
if (variant === 'github') {
|
|
35
|
+
return _jsx(GitHubArrowIcon, { size: size, className: className });
|
|
36
|
+
}
|
|
37
|
+
return _jsx(LucideArrowIcon, { size: size, className: className });
|
|
38
|
+
}
|
|
39
|
+
// copy icon (Lucide style) - used for copy buttons
|
|
40
|
+
export const CopyIcon = createIconComponent(LUCIDE_ICONS.copy, 16);
|
|
41
|
+
// check icon (Lucide style) - used for copy confirmation
|
|
42
|
+
export const CheckIcon = createIconComponent(LUCIDE_ICONS.check, 16);
|
|
43
|
+
export const NEXTRA_CALLOUT_ICONS = {
|
|
44
|
+
default: LightbulbIcon,
|
|
45
|
+
info: InfoIconGitHub,
|
|
46
|
+
warning: WarningIconGitHub,
|
|
47
|
+
error: ErrorIconGitHub,
|
|
48
|
+
important: ImportantIconGitHub,
|
|
49
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// packages/webview-app/src/components/shims/base/index.ts
|
|
2
|
+
// barrel exports for base shim utilities
|
|
3
|
+
export { useTabState, extractTabItems, } from './useTabState.js';
|
|
4
|
+
export { createTabs, } from './BaseTabs.js';
|
|
5
|
+
export { BaseCard } from './BaseCard.js';
|
|
6
|
+
export { ArrowIcon } from './icons.js';
|
|
7
|
+
export { useCopyToClipboard, } from './useCopyToClipboard.js';
|
|
8
|
+
export { extractTextContent } from './extractTextContent.js';
|
|
9
|
+
export { CopyButton } from './CopyButton.js';
|
|
10
|
+
export { CALLOUT_ICONS, FILE_TREE_ICONS } from './icons.js';
|
|
11
|
+
export { createCallout, } from './BaseCallout.js';
|
|
12
|
+
export { createCodeBlock } from './BaseCodeBlock.js';
|
|
13
|
+
export { createCollapsible, GENERIC_COLLAPSIBLE_CLASSES, DOCUSAURUS_DETAILS_CLASSES, } from './createCollapsible.js';
|
|
14
|
+
// re-export generic callout normalization for discoverability
|
|
15
|
+
export { normalizeCalloutType } from '../generic/types.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// packages/webview-app/src/components/shims/base/useCopyToClipboard.ts
|
|
2
|
+
// shared hook for copy-to-clipboard functionality
|
|
3
|
+
import { useState, useCallback } from 'react';
|
|
4
|
+
import { copyToClipboard } from '../internal/clipboard.js';
|
|
5
|
+
import { CODE_COPY_FEEDBACK_DURATION_MS } from '../internal/constants.js';
|
|
6
|
+
// hook for copy-to-clipboard functionality w/ visual feedback
|
|
7
|
+
export function useCopyToClipboard() {
|
|
8
|
+
const [copied, setCopied] = useState(false);
|
|
9
|
+
const copy = useCallback(async (text) => {
|
|
10
|
+
const success = await copyToClipboard(text);
|
|
11
|
+
if (success) {
|
|
12
|
+
setCopied(true);
|
|
13
|
+
setTimeout(() => setCopied(false), CODE_COPY_FEEDBACK_DURATION_MS);
|
|
14
|
+
}
|
|
15
|
+
}, []);
|
|
16
|
+
return { copied, copy };
|
|
17
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// packages/webview-app/src/components/shims/base/useTabState.ts
|
|
2
|
+
// shared hook for tab state management across framework shims
|
|
3
|
+
import { useState, useCallback, isValidElement, Children, } from 'react';
|
|
4
|
+
// extract TabItem children w/ their props
|
|
5
|
+
export function extractTabItems(children) {
|
|
6
|
+
const items = [];
|
|
7
|
+
Children.forEach(children, (child) => {
|
|
8
|
+
if (!isValidElement(child)) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const props = child.props;
|
|
12
|
+
// accept either 'value' (Docusaurus) or 'label' (Starlight) as identifier
|
|
13
|
+
const value = props.value ?? props.label;
|
|
14
|
+
if (value !== undefined) {
|
|
15
|
+
items.push({
|
|
16
|
+
value,
|
|
17
|
+
label: props.label || value,
|
|
18
|
+
content: props.children,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
return items;
|
|
23
|
+
}
|
|
24
|
+
// find default tab value from children
|
|
25
|
+
function findDefaultFromChildren(children, tabItems) {
|
|
26
|
+
const childArray = Children.toArray(children);
|
|
27
|
+
for (const item of tabItems) {
|
|
28
|
+
const child = childArray.find((c) => isValidElement(c) && c.props.value === item.value);
|
|
29
|
+
if (child &&
|
|
30
|
+
isValidElement(child) &&
|
|
31
|
+
child.props.default) {
|
|
32
|
+
return item.value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
// hook for managing tab state
|
|
38
|
+
// extract tab items from children, determine initial active value
|
|
39
|
+
// & provide state management for tab selection
|
|
40
|
+
export function useTabState(options) {
|
|
41
|
+
const { children, defaultValue, values } = options;
|
|
42
|
+
// extract tab items from children
|
|
43
|
+
const tabItems = extractTabItems(children);
|
|
44
|
+
// use provided values or extracted ones
|
|
45
|
+
const tabs = values ||
|
|
46
|
+
tabItems.map((item) => ({
|
|
47
|
+
value: item.value,
|
|
48
|
+
label: item.label,
|
|
49
|
+
}));
|
|
50
|
+
// determine initial active value
|
|
51
|
+
const initialValue = defaultValue ||
|
|
52
|
+
findDefaultFromChildren(children, tabItems) ||
|
|
53
|
+
tabs[0]?.value ||
|
|
54
|
+
'';
|
|
55
|
+
const [activeValue, setActiveValue] = useState(initialValue);
|
|
56
|
+
// ensure activeValue is valid (in case tabs change)
|
|
57
|
+
const validActiveValue = tabs.find((t) => t.value === activeValue)
|
|
58
|
+
? activeValue
|
|
59
|
+
: tabs[0]?.value || '';
|
|
60
|
+
return {
|
|
61
|
+
activeValue: validActiveValue,
|
|
62
|
+
setActiveValue,
|
|
63
|
+
tabs,
|
|
64
|
+
tabItems,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export default useTabState;
|
|
68
|
+
// hook for index-based tab state management
|
|
69
|
+
export function useIndexTabs({ items, defaultIndex = 0, controlledIndex, storageKey, onChange, isDisabled = () => false, }) {
|
|
70
|
+
// get initial index from localStorage if storageKey is provided
|
|
71
|
+
const getInitialIndex = useCallback(() => {
|
|
72
|
+
if (storageKey && typeof window !== 'undefined') {
|
|
73
|
+
try {
|
|
74
|
+
const stored = localStorage.getItem(`nextra-tabs-${storageKey}`);
|
|
75
|
+
if (stored !== null) {
|
|
76
|
+
const parsed = parseInt(stored, 10);
|
|
77
|
+
if (!isNaN(parsed) && parsed >= 0 && parsed < items.length) {
|
|
78
|
+
return parsed;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// ignore localStorage errors
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return defaultIndex;
|
|
87
|
+
}, [storageKey, defaultIndex, items.length]);
|
|
88
|
+
const [internalIndex, setInternalIndex] = useState(getInitialIndex);
|
|
89
|
+
const activeIndex = controlledIndex ?? internalIndex;
|
|
90
|
+
// handle tab selection
|
|
91
|
+
const setActiveIndex = useCallback((index) => {
|
|
92
|
+
// check if tab is disabled
|
|
93
|
+
if (items[index] !== undefined && isDisabled(items[index], index)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// update internal state if not controlled
|
|
97
|
+
if (controlledIndex === undefined) {
|
|
98
|
+
setInternalIndex(index);
|
|
99
|
+
}
|
|
100
|
+
// save to localStorage if storageKey is provided
|
|
101
|
+
if (storageKey && typeof window !== 'undefined') {
|
|
102
|
+
try {
|
|
103
|
+
localStorage.setItem(`nextra-tabs-${storageKey}`, String(index));
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// ignore localStorage errors
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// call onChange callback
|
|
110
|
+
onChange?.(index);
|
|
111
|
+
}, [controlledIndex, items, isDisabled, onChange, storageKey]);
|
|
112
|
+
return { activeIndex, setActiveIndex };
|
|
113
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// packages/webview-app/src/components/shims/docusaurus/CodeBlock.tsx
|
|
2
|
+
// Docusaurus CodeBlock component shim for MDX Preview
|
|
3
|
+
// provide preview-compatible version of @theme/CodeBlock
|
|
4
|
+
import { createCodeBlock } from '../base/BaseCodeBlock.js';
|
|
5
|
+
// code block component using shared factory
|
|
6
|
+
export const CodeBlock = createCodeBlock({
|
|
7
|
+
classPrefix: 'docusaurus-codeblock',
|
|
8
|
+
codeAsString: false,
|
|
9
|
+
supportsFrames: false,
|
|
10
|
+
showLangBadgeWithTitle: true,
|
|
11
|
+
});
|
|
12
|
+
// default export for compatibility
|
|
13
|
+
export default CodeBlock;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// packages/webview-app/src/components/shims/docusaurus/Details.tsx
|
|
3
|
+
// Docusaurus Details component shim for MDX Preview
|
|
4
|
+
import { createCollapsible, DOCUSAURUS_DETAILS_CLASSES, } from '../base/createCollapsible.js';
|
|
5
|
+
// create base details w/ Docusaurus configuration
|
|
6
|
+
// use native toggle handling (more semantic)
|
|
7
|
+
const BaseDetails = createCollapsible({
|
|
8
|
+
classNames: DOCUSAURUS_DETAILS_CLASSES,
|
|
9
|
+
iconSize: 14,
|
|
10
|
+
useNativeToggle: true,
|
|
11
|
+
applyOpenClassToWrapper: false,
|
|
12
|
+
defaultSummary: 'Details',
|
|
13
|
+
});
|
|
14
|
+
// Docusaurus Details component
|
|
15
|
+
export function Details(props) {
|
|
16
|
+
return _jsx(BaseDetails, { ...props });
|
|
17
|
+
}
|
|
18
|
+
export default Details;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// packages/webview-app/src/components/shims/docusaurus/Tabs.tsx
|
|
2
|
+
// Docusaurus Tabs/TabItem component shim for MDX Preview
|
|
3
|
+
// provide preview-compatible versions of @theme/Tabs & @theme/TabItem
|
|
4
|
+
import { createTabs, } from '../base/index.js';
|
|
5
|
+
// create Docusaurus-compatible tabs using the factory
|
|
6
|
+
// use 'mdx-preview-tabs' class prefix w/ 'docusaurus-tabs' wrapper
|
|
7
|
+
// support groupId for tab synchronization
|
|
8
|
+
const { Tabs, TabItem, useTabsContext, TabsContext } = createTabs({
|
|
9
|
+
classPrefix: 'mdx-preview-tabs',
|
|
10
|
+
wrapperClass: 'docusaurus-tabs',
|
|
11
|
+
supportsGroupId: true,
|
|
12
|
+
contextName: 'DocusaurusTabs',
|
|
13
|
+
});
|
|
14
|
+
export { Tabs, TabItem, useTabsContext, TabsContext };
|
|
15
|
+
export default Tabs;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createCallout } from '../base/BaseCallout.js';
|
|
3
|
+
import { CALLOUT_TITLES, normalizeCalloutType } from './types.js';
|
|
4
|
+
import { CALLOUT_ICONS } from '../base/icons.js';
|
|
5
|
+
// create the base Callout using factory
|
|
6
|
+
const BaseCallout = createCallout({
|
|
7
|
+
classPrefix: 'mdx-preview-generic-callout',
|
|
8
|
+
types: ['note', 'tip', 'warning', 'danger', 'info', 'caution', 'important'],
|
|
9
|
+
defaultType: 'note',
|
|
10
|
+
icons: { type: 'svg', icons: CALLOUT_ICONS },
|
|
11
|
+
defaultTitles: CALLOUT_TITLES,
|
|
12
|
+
layout: 'header',
|
|
13
|
+
});
|
|
14
|
+
// callout component w/ type normalization
|
|
15
|
+
export function Callout(props) {
|
|
16
|
+
// normalize type aliases (success -> tip, error -> danger, etc.)
|
|
17
|
+
const normalizedType = normalizeCalloutType(props.type);
|
|
18
|
+
return _jsx(BaseCallout, { ...props, type: normalizedType });
|
|
19
|
+
}
|
|
20
|
+
// alert component (alias for Callout)
|
|
21
|
+
export function Alert(props) {
|
|
22
|
+
return _jsx(Callout, { ...props });
|
|
23
|
+
}
|
|
24
|
+
// admonition component (alias for Callout, Docusaurus style)
|
|
25
|
+
export function Admonition(props) {
|
|
26
|
+
return _jsx(Callout, { ...props });
|
|
27
|
+
}
|
|
28
|
+
export default Callout;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// packages/webview-app/src/components/shims/generic/CodeGroup.tsx
|
|
3
|
+
// Generic CodeGroup component shim for MDX Preview
|
|
4
|
+
// provide tabbed code blocks w/o framework dependency
|
|
5
|
+
import { Children, isValidElement, useState } from 'react';
|
|
6
|
+
// extract label from code block element
|
|
7
|
+
function extractLabelFromCodeBlock(child) {
|
|
8
|
+
const props = child.props;
|
|
9
|
+
// try various prop names used by different frameworks
|
|
10
|
+
if (typeof props.title === 'string') {
|
|
11
|
+
return props.title;
|
|
12
|
+
}
|
|
13
|
+
if (typeof props.label === 'string') {
|
|
14
|
+
return props.label;
|
|
15
|
+
}
|
|
16
|
+
if (typeof props.filename === 'string') {
|
|
17
|
+
return props.filename;
|
|
18
|
+
}
|
|
19
|
+
if (typeof props.language === 'string') {
|
|
20
|
+
return props.language;
|
|
21
|
+
}
|
|
22
|
+
if (typeof props.lang === 'string') {
|
|
23
|
+
return props.lang;
|
|
24
|
+
}
|
|
25
|
+
// try to get from className (e.g., "language-javascript")
|
|
26
|
+
if (typeof props.className === 'string') {
|
|
27
|
+
const match = props.className.match(/language-(\w+)/);
|
|
28
|
+
if (match) {
|
|
29
|
+
return match[1];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return 'Code';
|
|
33
|
+
}
|
|
34
|
+
// render tabbed code blocks from children
|
|
35
|
+
export function CodeGroup({ children, labels }) {
|
|
36
|
+
const childArray = Children.toArray(children).filter(isValidElement);
|
|
37
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
38
|
+
// extract tabs from children
|
|
39
|
+
const tabs = childArray.map((child, index) => {
|
|
40
|
+
const label = labels?.[index] || extractLabelFromCodeBlock(child);
|
|
41
|
+
return { label, content: child };
|
|
42
|
+
});
|
|
43
|
+
if (tabs.length === 0) {
|
|
44
|
+
return (_jsx("div", { className: "mdx-preview-generic-code-group-empty", children: children }));
|
|
45
|
+
}
|
|
46
|
+
// if only one code block, just render it directly
|
|
47
|
+
if (tabs.length === 1) {
|
|
48
|
+
return (_jsx("div", { className: "mdx-preview-generic-code-group", children: tabs[0].content }));
|
|
49
|
+
}
|
|
50
|
+
return (_jsxs("div", { className: "mdx-preview-generic-code-group", children: [_jsx("div", { className: "mdx-preview-generic-code-group-header", role: "tablist", children: tabs.map((tab, index) => (_jsx("button", { role: "tab", className: `mdx-preview-generic-code-group-button${index === activeIndex ? ' active' : ''}`, "aria-selected": index === activeIndex, onClick: () => setActiveIndex(index), tabIndex: index === activeIndex ? 0 : -1, children: tab.label }, index))) }), _jsx("div", { className: "mdx-preview-generic-code-group-content", children: tabs.map((tab, index) => (_jsx("div", { role: "tabpanel", className: `mdx-preview-generic-code-group-panel${index === activeIndex ? ' active' : ''}`, hidden: index !== activeIndex, children: tab.content }, index))) })] }));
|
|
51
|
+
}
|
|
52
|
+
export default CodeGroup;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// packages/webview-app/src/components/shims/generic/Collapsible.tsx
|
|
3
|
+
// Generic Collapsible/Accordion component shim for MDX Preview
|
|
4
|
+
import { createCollapsible, GENERIC_COLLAPSIBLE_CLASSES, } from '../base/createCollapsible.js';
|
|
5
|
+
// create base collapsible w/ generic configuration
|
|
6
|
+
// use custom click handling (prevent native toggle for more control)
|
|
7
|
+
const BaseCollapsible = createCollapsible({
|
|
8
|
+
classNames: GENERIC_COLLAPSIBLE_CLASSES,
|
|
9
|
+
iconSize: 16,
|
|
10
|
+
useNativeToggle: false,
|
|
11
|
+
applyOpenClassToWrapper: true,
|
|
12
|
+
});
|
|
13
|
+
// generic Collapsible component
|
|
14
|
+
export function Collapsible(props) {
|
|
15
|
+
return _jsx(BaseCollapsible, { ...props });
|
|
16
|
+
}
|
|
17
|
+
// accordion component (alias for Collapsible)
|
|
18
|
+
export function Accordion(props) {
|
|
19
|
+
return _jsx(Collapsible, { ...props });
|
|
20
|
+
}
|
|
21
|
+
export default Collapsible;
|