chore: docs (#527)

* chore: docs
This commit is contained in:
mathuo 2024-03-02 21:49:09 +00:00 committed by GitHub
parent f00b3d88e1
commit 0634f4fe52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
52 changed files with 31843 additions and 4414 deletions

View File

@ -667,21 +667,29 @@ export class DockviewApi implements CommonApi<SerializedDockview> {
} }
/** /**
* Invoked before an overlay is shown indicating a drop target.
* *
* Calling `event.preventDefault()` will prevent the overlay being shown and prevent
* the any subsequent drop event.
*/ */
get onWillShowOverlay(): Event<WillShowOverlayLocationEvent> { get onWillShowOverlay(): Event<WillShowOverlayLocationEvent> {
return this.component.onWillShowOverlay; return this.component.onWillShowOverlay;
} }
/** /**
* Invoked before a group is dragged. Exposed for custom Drag'n'Drop functionality. * Invoked before a group is dragged.
*
* Calling `event.nativeEvent.preventDefault()` will prevent the group drag starting.
*
*/ */
get onWillDragGroup(): Event<GroupDragEvent> { get onWillDragGroup(): Event<GroupDragEvent> {
return this.component.onWillDragGroup; return this.component.onWillDragGroup;
} }
/** /**
* Invoked before a panel is dragged. Exposed for custom Drag'n'Drop functionality. * Invoked before a panel is dragged.
*
* Calling `event.nativeEvent.preventDefault()` will prevent the panel drag starting.
*/ */
get onWillDragPanel(): Event<TabDragEvent> { get onWillDragPanel(): Event<TabDragEvent> {
return this.component.onWillDragPanel; return this.component.onWillDragPanel;

View File

@ -6,6 +6,10 @@ sidebar_position: 3
import { DocRef } from '@site/src/components/ui/reference/docRef'; import { DocRef } from '@site/src/components/ui/reference/docRef';
:::info
You may want to combine this with `locked={true}` to provide a locked grid with no dnd funtionality. See [Locked](/docs/core/locked) for more.
:::
<FrameworkSpecific framework="JavaScript"> <FrameworkSpecific framework="JavaScript">
<DocRef declaration="DockviewComponentOptions" methods={["disableDnd"]} /> <DocRef declaration="DockviewComponentOptions" methods={["disableDnd"]} />
</FrameworkSpecific> </FrameworkSpecific>

View File

@ -5,7 +5,6 @@ sidebar_position: 1
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import { MultiFrameworkContainer } from '@site/src/components/ui/container'; import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import DndDockview from '@site/sandboxes/dnd-dockview/src/app';
import DockviewExternalDnd from '@site/sandboxes/externaldnd-dockview/src/app'; import DockviewExternalDnd from '@site/sandboxes/externaldnd-dockview/src/app';
import LiveExample from '@site/src/components/ui/exampleFrame'; import LiveExample from '@site/src/components/ui/exampleFrame';
@ -16,7 +15,7 @@ The dock makes heavy use of drag and drop functionalities.
<DocRef declaration="DockviewApi" <DocRef declaration="DockviewApi"
methods={[ methods={[
'onWillDragPanel', 'onWillDragGroup', 'onWillDragPanel', 'onWillDragGroup',
'onWillDrop', 'onDidDrop', 'onWillShowOverlay' 'onWillDrop', 'onWillShowOverlay'
]} ]}
/> />
@ -79,12 +78,6 @@ return (
); );
``` ```
## Intercepting Drag Events
You can intercept drag events to attach your own metadata using the `onWillDragPanel` and `onWillDragGroup` api methods.
<MultiFrameworkContainer sandboxId="dnd-dockview" react={DndDockview} />
## Third Party Dnd Libraries ## Third Party Dnd Libraries
This shows a simple example of a third-party library used inside a panel that relies on drag This shows a simple example of a third-party library used inside a panel that relies on drag

View File

@ -0,0 +1,31 @@
---
title: 'External Dnd Events'
sidebar_position: 3
---
External Dnd events can be intercepted through a number of utilities.
import { DocRef } from '@site/src/components/ui/reference/docRef';
import LiveExample from '@site/src/components/ui/exampleFrame';
<DocRef declaration="DockviewApi"
methods={['onDidDrop']}
/>
<FrameworkSpecific framework='React'>
<DocRef declaration="IDockviewReactProps" methods={['showDndOverlay']} />
</FrameworkSpecific>
<FrameworkSpecific framework='JavaScript'>
<DocRef declaration="DockviewComponentOptions"
methods={['showDndOverlay']}
/>
</FrameworkSpecific>
## Intercepting Drag Events
You can intercept drag events to attach your own metadata using the `onWillDragPanel` and `onWillDragGroup` api methods.
<LiveExample framework='react' id="dockview/dnd-external" />

View File

@ -4,11 +4,6 @@ sidebar_position: 0
--- ---
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import { MultiFrameworkContainer } from '@site/src/components/ui/container';
import DndDockview from '@site/sandboxes/dnd-dockview/src/app';
import DockviewExternalDnd from '@site/sandboxes/externaldnd-dockview/src/app';
import { DocRef } from '@site/src/components/ui/reference/docRef';
Dockview supports a wide variety of built-in Drag and Drop possibilities. Dockview supports a wide variety of built-in Drag and Drop possibilities.

View File

@ -9,4 +9,8 @@ import LiveExample from '@site/src/components/ui/exampleFrame';
This section describes how to lock the dock to prevent movement. This section describes how to lock the dock to prevent movement.
:::info
You may want to combine this with `disableDnd={true}` to provide a locked grid with no dnd funtionality. See [Disable Dnd](/docs/core/dnd/disable) for more.
:::
<LiveExample framework='react' id='dockview/locked'/> <LiveExample framework='react' id='dockview/locked'/>

View File

@ -3,5 +3,15 @@ title: Overview
sidebar_position: 0 sidebar_position: 0
--- ---
import LiveExample from '@site/src/components/ui/exampleFrame';
import { DocRef } from '@site/src/components/ui/reference/docRef';
The implementation of the dock is a collection of nested *splitview* controls forming a *gridview* The implementation of the dock is a collection of nested *splitview* controls forming a *gridview*
which is exposed as a seperate component to be used independantly. which is exposed as a seperate component to be used independantly.
<DocRef declaration="IGridviewReactProps"/>
## Live Example
<LiveExample framework='react' id='gridview/simple' />

View File

@ -2,5 +2,13 @@
title: Overview title: Overview
sidebar_position: 0 sidebar_position: 0
--- ---
import LiveExample from '@site/src/components/ui/exampleFrame';
import { DocRef } from '@site/src/components/ui/reference/docRef';
A *splitview* control where each panel contains a header and collapsable content. A *splitview* control where each panel contains a header and collapsable content.
<DocRef declaration="IPaneviewReactProps"/>
## Live Example
<LiveExample framework='react' id='paneview/simple' />

View File

@ -5,3 +5,12 @@ sidebar_position: 0
The implementation of the dock is a collection of nested *splitview* controls The implementation of the dock is a collection of nested *splitview* controls
which is exposed as a seperate component to be used independantly. which is exposed as a seperate component to be used independantly.
import LiveExample from '@site/src/components/ui/exampleFrame';
import { DocRef } from '@site/src/components/ui/reference/docRef';
<DocRef declaration="ISplitviewReactProps"/>
## Live Example
<LiveExample framework='react' id='splitview/simple' height={200} />

View File

@ -0,0 +1,10 @@
---
title: Tabview
sidebar_position: 3
---
A *tabview* can be created using a dock and preventing some default behaviours.
import LiveExample from '@site/src/components/ui/exampleFrame';
<LiveExample framework='react' id='dockview/tabview' />

View File

@ -35,6 +35,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background-color: #1c254a; background-color: #1c254a;
color: white;
border: none; border: none;
cursor: pointer; cursor: pointer;
outline: 1px solid #4c65d4; outline: 1px solid #4c65d4;

View File

@ -28,7 +28,7 @@ const components = {
position: 'relative', position: 'relative',
}} }}
> >
<Table data={metadata} /> {/* <Table data={metadata} /> */}
<span <span
style={{ style={{
position: 'absolute', position: 'absolute',
@ -68,8 +68,20 @@ const headerComponents = {
}, },
}; };
const colors = [
'rgba(255,0,0,0.2)',
'rgba(0,255,0,0.2)',
'rgba(0,0,255,0.2)',
'rgba(255,255,0,0.2)',
'rgba(0,255,255,0.2)',
'rgba(255,0,255,0.2)',
];
let count = 0;
const DockviewDemo = (props: { theme?: string }) => { const DockviewDemo = (props: { theme?: string }) => {
const [logLines, setLogLines] = React.useState<any[]>([]); const [logLines, setLogLines] = React.useState<
{ text: string; timestamp?: Date; backgroundColor?: string }[]
>([]);
const [panels, setPanels] = React.useState<string[]>([]); const [panels, setPanels] = React.useState<string[]>([]);
const [groups, setGroups] = React.useState<string[]>([]); const [groups, setGroups] = React.useState<string[]>([]);
@ -78,16 +90,39 @@ const DockviewDemo = (props: { theme?: string }) => {
const [activePanel, setActivePanel] = React.useState<string>(); const [activePanel, setActivePanel] = React.useState<string>();
const [activeGroup, setActiveGroup] = React.useState<string>(); const [activeGroup, setActiveGroup] = React.useState<string>();
const [pending, setPending] = React.useState<
{ text: string; timestamp?: Date }[]
>([]);
const addLogLine = (message: string) => {
setPending((line) => [
{ text: message, timestamp: new Date() },
...line,
]);
};
React.useLayoutEffect(() => {
if (pending.length === 0) {
return;
}
const color = colors[count++ % colors.length];
setLogLines((lines) => [
...pending.map((_) => ({ ..._, backgroundColor: color })),
...lines,
]);
setPending([]);
}, [pending]);
const onReady = (event: DockviewReadyEvent) => { const onReady = (event: DockviewReadyEvent) => {
setApi(event.api); setApi(event.api);
event.api.onDidAddPanel((event) => { event.api.onDidAddPanel((event) => {
setPanels((_) => [..._, event.id]); setPanels((_) => [..._, event.id]);
setLogLines((line) => [`Panel Added ${event.id}`, ...line]); addLogLine(`Panel Added ${event.id}`);
}); });
event.api.onDidActivePanelChange((event) => { event.api.onDidActivePanelChange((event) => {
setActivePanel(event?.id); setActivePanel(event?.id);
setLogLines((line) => [`Panel Activated ${event?.id}`, ...line]); addLogLine(`Panel Activated ${event?.id}`);
}); });
event.api.onDidRemovePanel((event) => { event.api.onDidRemovePanel((event) => {
setPanels((_) => { setPanels((_) => {
@ -99,12 +134,12 @@ const DockviewDemo = (props: { theme?: string }) => {
return next; return next;
}); });
setLogLines((line) => [`Panel Removed ${event.id}`, ...line]); addLogLine(`Panel Removed ${event.id}`);
}); });
event.api.onDidAddGroup((event) => { event.api.onDidAddGroup((event) => {
setGroups((_) => [..._, event.id]); setGroups((_) => [..._, event.id]);
setLogLines((line) => [`Group Added ${event.id}`, ...line]); addLogLine(`Group Added ${event.id}`);
}); });
event.api.onDidRemoveGroup((event) => { event.api.onDidRemoveGroup((event) => {
@ -117,12 +152,12 @@ const DockviewDemo = (props: { theme?: string }) => {
return next; return next;
}); });
setLogLines((line) => [`Group Removed ${event.id}`, ...line]); addLogLine(`Group Removed ${event.id}`);
}); });
event.api.onDidActiveGroupChange((event) => { event.api.onDidActiveGroupChange((event) => {
setActiveGroup(event?.id); setActiveGroup(event?.id);
setLogLines((line) => [`Group Activated ${event?.id}`, ...line]); addLogLine(`Group Activated ${event?.id}`);
}); });
const state = localStorage.getItem('dv-demo-state'); const state = localStorage.getItem('dv-demo-state');
@ -146,6 +181,9 @@ const DockviewDemo = (props: { theme?: string }) => {
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
flexGrow: 1, flexGrow: 1,
padding: '8px',
backgroundColor: 'rgba(0,0,50,0.25)',
borderRadius: '8px',
}} }}
> >
<div> <div>
@ -167,6 +205,7 @@ const DockviewDemo = (props: { theme?: string }) => {
overflow: 'hidden', overflow: 'hidden',
// flexBasis: 0 // flexBasis: 0
height: 0, height: 0,
display: 'flex',
}} }}
> >
<DockviewReact <DockviewReact
@ -178,10 +217,10 @@ const DockviewDemo = (props: { theme?: string }) => {
onReady={onReady} onReady={onReady}
className={props.theme || 'dockview-theme-abyss'} className={props.theme || 'dockview-theme-abyss'}
/> />
</div>
<div <div
style={{ style={{
height: '200px', // height: '200px',
width: '300px',
backgroundColor: 'black', backgroundColor: 'black',
color: 'white', color: 'white',
overflow: 'auto', overflow: 'auto',
@ -189,24 +228,53 @@ const DockviewDemo = (props: { theme?: string }) => {
> >
{logLines.map((line, i) => { {logLines.map((line, i) => {
return ( return (
<div key={i}> <div
style={{
height: '30px',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
fontSize: '13px',
display: 'flex',
alignItems: 'center',
backgroundColor: line.backgroundColor,
}}
key={i}
>
<span <span
style={{ style={{
display: 'inline-block', display: 'inline-block',
width: '30px', width: '20px',
color: 'gray', color: 'gray',
borderRight: '1px solid gray', borderRight: '1px solid gray',
marginRight: '4px', marginRight: '4px',
paddingLeft: '2px',
height: '100%',
}} }}
> >
{logLines.length - i} {logLines.length - i}
</span> </span>
<span>{line}</span> <span>
{line.timestamp && (
<span
style={{
fontSize: '0.7em',
padding: '0px 2px',
}}
>
{line.timestamp
.toISOString()
.substring(11, 23)}
</span>
)}
<span>{line.text}</span>
</span>
</div> </div>
); );
})} })}
</div> </div>
</div> </div>
</div>
); );
}; };

View File

@ -11,7 +11,7 @@ export const nextId = (() => {
export function defaultConfig(api: DockviewApi) { export function defaultConfig(api: DockviewApi) {
const panel1 = api.addPanel({ const panel1 = api.addPanel({
id: 'panel_1', id: 'panel_1',
component: 'iframe', component: 'default',
renderer: 'always', renderer: 'always',
title: 'Panel 1', title: 'Panel 1',
}); });

View File

@ -0,0 +1,32 @@
{
"name": "dockview.dnd-external",
"description": "",
"keywords": [
"dockview"
],
"version": "1.0.0",
"main": "src/index.tsx",
"dependencies": {
"dockview": "*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"typescript": "^4.9.5",
"react-scripts": "*"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}

View File

@ -1,7 +1,7 @@
import { import {
DockviewApi, DockviewApi,
DockviewDndOverlayEvent, DockviewDndOverlayEvent,
DockviewDropEvent, DockviewDidDropEvent,
DockviewReact, DockviewReact,
DockviewReadyEvent, DockviewReadyEvent,
IDockviewPanelProps, IDockviewPanelProps,
@ -123,7 +123,7 @@ const DndDockview = (props: { renderVisibleOnly: boolean; theme?: string }) => {
setApi(event.api); setApi(event.api);
}; };
const onDidDrop = (event: DockviewDropEvent) => { const onDidDrop = (event: DockviewDidDropEvent) => {
event.api.addPanel({ event.api.addPanel({
id: 'test', id: 'test',
component: 'default', component: 'default',

View File

@ -1,5 +1,5 @@
{ {
"name": "dnd-dockview", "name": "dockview.tabview",
"description": "", "description": "",
"keywords": [ "keywords": [
"dockview" "dockview"

View File

@ -0,0 +1,82 @@
import {
DockviewApi,
DockviewReact,
DockviewReadyEvent,
IDockviewPanelProps,
} from 'dockview';
import * as React from 'react';
const Default = (props: IDockviewPanelProps) => {
return (
<div style={{ height: '100%' }}>
<div>{props.api.title}</div>
</div>
);
};
const components = {
default: Default,
};
const Component = (props: { theme?: string }) => {
const [api, setApi] = React.useState<DockviewApi>();
React.useEffect(() => {
if (!api) {
return;
}
const disposables = [
api.onWillShowOverlay((e) => {
if (e.kind === 'header_space' || e.kind === 'tab') {
return;
}
e.preventDefault();
}),
];
return () => {
disposables.forEach((disposable) => {
disposable.dispose();
});
};
}, [api]);
const onReady = (event: DockviewReadyEvent) => {
setApi(event.api);
event.api.addPanel({
id: 'panel_1',
component: 'default',
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
});
event.api.addPanel({
id: 'panel_4',
component: 'default',
});
event.api.addPanel({
id: 'panel_5',
component: 'default',
});
};
return (
<DockviewReact
className={`${props.theme || 'dockview-theme-abyss'}`}
onReady={onReady}
components={components}
disableFloatingGroups={true}
/>
);
};
export default Component;

View File

@ -1,5 +1,5 @@
{ {
"name": "simple-gridview", "name": "gridview.simple",
"description": "", "description": "",
"keywords": [ "keywords": [
"dockview" "dockview"

View File

@ -1,5 +1,5 @@
{ {
"name": "simple-paneview", "name": "paneview.simple",
"description": "", "description": "",
"keywords": [ "keywords": [
"dockview" "dockview"

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -0,0 +1,20 @@
import { StrictMode } from 'react';
import * as ReactDOMClient from 'react-dom/client';
import './styles.css';
import 'dockview/dist/styles/dockview.css';
import App from './app';
const rootElement = document.getElementById('root');
if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement);
root.render(
<StrictMode>
<div className="app">
<App />
</div>
</StrictMode>
);
}

View File

@ -0,0 +1,16 @@
body {
margin: 0px;
color: white;
font-family: sans-serif;
text-align: center;
}
#root {
height: 100vh;
width: 100vw;
}
.app {
height: 100%;
}

View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"outDir": "build/dist",
"module": "esnext",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true
}
}

View File

@ -0,0 +1,32 @@
{
"name": "splitview.simple",
"description": "",
"keywords": [
"dockview"
],
"version": "1.0.0",
"main": "src/index.tsx",
"dependencies": {
"dockview": "*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"typescript": "^4.9.5",
"react-scripts": "*"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -0,0 +1,59 @@
import {
SplitviewReact,
SplitviewReadyEvent,
ISplitviewPanelProps,
} from 'dockview';
import * as React from 'react';
const components = {
default: (props: ISplitviewPanelProps<{ title: string }>) => {
return (
<div
style={{
padding: '10px',
height: '100%',
}}
>
{props.params.title}
</div>
);
},
};
export const App: React.FC = (props: { theme?: string }) => {
const onReady = (event: SplitviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
component: 'default',
params: {
title: 'Panel 1',
},
});
event.api.addPanel({
id: 'panel_2',
component: 'default',
params: {
title: 'Panel 2',
},
});
event.api.addPanel({
id: 'panel_3',
component: 'default',
params: {
title: 'Panel 3',
},
});
};
return (
<SplitviewReact
components={components}
onReady={onReady}
className={props.theme || 'dockview-theme-abyss'}
/>
);
};
export default App;

View File

@ -0,0 +1,20 @@
import { StrictMode } from 'react';
import * as ReactDOMClient from 'react-dom/client';
import './styles.css';
import 'dockview/dist/styles/dockview.css';
import App from './app';
const rootElement = document.getElementById('root');
if (rootElement) {
const root = ReactDOMClient.createRoot(rootElement);
root.render(
<StrictMode>
<div className="app">
<App />
</div>
</StrictMode>
);
}

View File

@ -0,0 +1,16 @@
body {
margin: 0px;
color: white;
font-family: sans-serif;
text-align: center;
}
#root {
height: 100vh;
width: 100vw;
}
.app {
height: 100%;
}

View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"outDir": "build/dist",
"module": "esnext",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true
}
}

View File

@ -1,6 +1,7 @@
import BrowserOnly from '@docusaurus/BrowserOnly'; import BrowserOnly from '@docusaurus/BrowserOnly';
import { DockviewEmitter } from 'dockview'; import { DockviewEmitter } from 'dockview';
import * as React from 'react'; import * as React from 'react';
import { IS_PROD } from '../flags';
const frameworks = [ const frameworks = [
{ value: 'JavaScript', label: 'JavaScript' }, { value: 'JavaScript', label: 'JavaScript' },
@ -35,7 +36,7 @@ function useActiveFramework(): [string, (value: string) => void] {
activeFrameworkGlobal.fire(value); activeFrameworkGlobal.fire(value);
}, []); }, []);
return [value, setter]; return [IS_PROD ? frameworks[1].value : value, setter];
} }
const FrameworkSelector1 = () => { const FrameworkSelector1 = () => {
@ -45,6 +46,10 @@ const FrameworkSelector1 = () => {
setActiveFramework(event.target.value), setActiveFramework(event.target.value),
]; ];
if (IS_PROD) {
return null;
}
return ( return (
<select onChange={onChange} value={activeFramework}> <select onChange={onChange} value={activeFramework}>
{frameworks.map((framework) => { {frameworks.map((framework) => {

View File

@ -8,6 +8,7 @@ export interface DocRefProps {
} }
import docsJson_ from '../../../generated/api.output.json'; import docsJson_ from '../../../generated/api.output.json';
import { ExportedTypeFile, TypeSystem, codify, firstLevel } from './types';
const docsJson = docsJson_ as any as DocsJson; const docsJson = docsJson_ as any as DocsJson;
type DocsContent = { kind: string; text: string; tag?: string }; type DocsContent = { kind: string; text: string; tag?: string };
@ -16,19 +17,57 @@ type DocsComment = {
summary?: DocsContent[]; summary?: DocsContent[];
blockTags?: DocsTag[]; blockTags?: DocsTag[];
}; };
type Piece = {
kind: 'return' | 'paramter' | 'signature' | 'typearg' | 'typearg_default';
value: string;
};
type Doc = { type Doc = {
name: string; name: string;
code: string; code: string;
comment?: DocsComment; comment?: DocsComment;
kind: 'accessor' | 'property' | 'method'; kind: 'accessor' | 'property' | 'method';
pieces: string[]; pieces: Piece[];
}; };
type DocsJson = {
[index: string]: { type DocJson = {
kind: string; kind: string;
metadata?: Doc; metadata?: Doc;
children: Doc[]; children: Doc[];
}; };
type DocsJson = {
[index: string]: DocJson;
};
const newJson = docsJson_ as ExportedTypeFile;
export const DocumentRef = (props: { value: TypeSystem.Type }) => {
const code = React.useMemo(() => {
if (!props.value) {
return null;
}
switch (props.value.kind) {
case 'typeAlias':
return codify(props.value);
case 'interface':
return codify(props.value);
case 'class':
return codify(props.value);
case 'function':
return codify(props.value);
default:
return null;
}
}, [props.value]);
if (!code) {
return null;
}
return <CodeBlock language="tsx">{code}</CodeBlock>;
}; };
export const Text = (props: { content: DocsContent[] }) => { export const Text = (props: { content: DocsContent[] }) => {
@ -81,25 +120,11 @@ export const Markdown = (props: { children: string }) => {
return <span>{props.children}</span>; return <span>{props.children}</span>;
}; };
const Piece = (props: { piece: string }) => { const Row = (props: { doc: TypeSystem.Type }) => {
const item = docsJson[props.piece]; const comment =
props.doc.kind === 'accessor'
if (!item) { ? props.doc.value.comment
return; : props.doc.comment;
}
if (item.kind === 'interface') {
return;
}
if (!item.metadata?.code) {
return;
}
return <CodeBlock language="tsx">{item.metadata.code}</CodeBlock>;
};
const Row = (props: { doc: Doc }) => {
return ( return (
<tr> <tr>
<th <th
@ -151,12 +176,8 @@ const Row = (props: { doc: Doc }) => {
<th style={{ width: '60%' }}> <th style={{ width: '60%' }}>
{/* <div>{'-'}</div> */} {/* <div>{'-'}</div> */}
<div> <div>
<div> <div>{comment && <Summary summary={comment} />}</div>
{props.doc.comment && ( <CodeBlock language="tsx">{codify(props.doc)}</CodeBlock>
<Summary summary={props.doc.comment} />
)}
</div>
<CodeBlock language="tsx">{props.doc.code}</CodeBlock>
</div> </div>
</th> </th>
</tr> </tr>
@ -165,18 +186,23 @@ const Row = (props: { doc: Doc }) => {
export const DocRef = (props: DocRefProps) => { export const DocRef = (props: DocRefProps) => {
const docs = React.useMemo( const docs = React.useMemo(
() => (docsJson as DocsJson)[props.declaration], () => newJson[props.declaration],
[props.declaration] [props.declaration]
); );
const filteredDocs = React.useMemo( const filteredDocs = React.useMemo(
() => () =>
docs?.children?.filter((child) => { docs.kind === 'class' || docs.kind === 'interface'
if (props.methods && !props.methods.includes(child.name)) { ? docs.children.filter((child) => {
if (
props.methods &&
!props.methods.includes(child.name)
) {
return false; return false;
} }
return true; return true;
}), })
: [],
[docs] [docs]
); );
@ -191,6 +217,13 @@ export const DocRef = (props: DocRefProps) => {
return ( return (
<> <>
<Row key={i} doc={doc} /> <Row key={i} doc={doc} />
{/* <th colSpan={2}>
{firstLevel(doc).map((x) => (
<span style={{ padding: '0px 2px' }}>
<DocumentRef value={newJson[x]} />
</span>
))}
</th> */}
{/* {doc.pieces?.map((piece) => ( {/* {doc.pieces?.map((piece) => (
<tr> <tr>
<th colSpan={2}> <th colSpan={2}>

View File

@ -0,0 +1,446 @@
export type ExportedTypeFile = Record<string, TypeSystem.Type>;
export function firstLevelTypes(value: TypeDescriptor.Type | null) {
if (!value) {
return null;
}
switch (value.type) {
case 'array':
return firstLevelTypes(value.value);
case 'literal':
return [];
case 'intrinsic':
return [];
case 'or':
return value.values.flatMap(firstLevelTypes);
case 'intersection':
return value.values.flatMap(firstLevelTypes);
case 'predicate':
return [];
case 'reference': {
const result = [];
if (
value.source.startsWith('dockview') &&
!value.refersToTypeParameter
) {
result.push(value.value);
}
if (value.typeArguments) {
result.push(...value.typeArguments.flatMap(firstLevelTypes));
}
return result;
}
case 'reflection':
return firstLevel(value.value);
case 'tuple':
return value.value.map(codifyType);
default:
throw new Error('unreachable');
}
}
export function firstLevel(value: TypeSystem.Type | null) {
const results: string[] = [];
switch (value.kind) {
case null:
break;
case 'property':
results.push(...firstLevelTypes(value.type));
break;
case 'accessor':
results.push(...firstLevelTypes(value.value.returnType));
break;
case 'method':
results.push(...value.signature.flatMap(firstLevel));
break;
case 'constructor':
break;
case 'typeLiteral':
if (value.properties) {
results.push(...value.properties.flatMap(firstLevel));
}
if (value.signatures) {
results.push(...value.signatures.flatMap(firstLevel));
}
break;
case 'callSignature':
results.push(
...firstLevelTypes(value.returnType),
...value.typeParameters.flatMap((_) => {
return [...firstLevelTypes(_.extends)];
}),
...value.parameters.flatMap(firstLevel)
);
break;
case 'parameter':
results.push(...firstLevelTypes(value.type));
break;
default:
console.log('test', value);
throw new Error('unreachable');
}
return Array.from(new Set(results));
}
export function codifyType(value: TypeDescriptor.Type | null, tabs = 0) {
if (!value) {
return null;
}
switch (value.type) {
case 'array':
return `${codifyType(value.value)}[]`;
case 'literal':
return `'${value.value}'`;
case 'intrinsic':
return value.value;
case 'or':
return `${value.values
.map((_) => {
const isComparator =
_.type === 'or' || _.type === 'intersection';
const code = codifyType(_);
return isComparator ? `(${code})` : code;
})
.join(' | ')}`;
case 'intersection':
return `${value.values
.map((_) => {
const isComparator =
_.type === 'or' || _.type === 'intersection';
const code = codifyType(_);
return isComparator ? `(${code})` : code;
})
.join(' & ')}`;
case 'predicate':
return `${value.lhs} is ${value.rhs}`;
case 'reference': {
if (value.typeArguments) {
return `${value.value}<${value.typeArguments.map(codifyType)}>`;
}
return `${value.value}`;
}
case 'reflection':
return codify(value.value, tabs);
case 'tuple':
return `[${value.value.map(codifyType).join(', ')}]`;
default:
throw new Error('unreachable');
}
}
export function codify(value: TypeSystem.Type | null, tabs = 0) {
if (!value) {
return null;
}
if (value.kind === 'accessor') {
const signature = value.value;
return `${'\t'.repeat(tabs)}${signature.name}: ${codifyType(
signature.returnType
)}`;
}
if (value.kind === 'property') {
let code = '\t'.repeat(tabs);
if (value.flags.isProtected) {
code += 'protected ';
}
if (value.flags.isReadonly) {
code += 'readonly ';
}
code += value.name;
if (value.flags.isOptional) {
code += '?';
}
code += `: ${codifyType(value.type, tabs + 1)}`;
return code;
}
if (value.kind === 'method') {
return `${'\t'.repeat(tabs)}${value.name}${value.signature
.map(codify)
.join('\n')}`;
}
if (value.kind === 'callSignature') {
let code = ``;
if (value.typeParameters.length > 0) {
code += '<';
code += value.typeParameters.map((typeParameter) => {
let typeCode = `${typeParameter.name}`;
if (typeParameter.extends) {
typeCode += ' extends';
typeCode += ` ${codifyType(typeParameter.extends)}`;
}
if (typeParameter.default) {
typeCode += ' =';
typeCode += ` ${typeParameter.default}`;
}
return typeCode;
});
code += '>';
}
code += '(';
code += value.parameters
.map((parameter) => {
return codify(parameter, tabs + 1);
})
.join(', ');
code += `): ${codifyType(value.returnType)}`;
return code;
}
if (value.kind === 'parameter') {
return `${value.name}: ${codifyType(value.type, tabs + 1)}`;
}
if (value.kind === 'typeLiteral') {
if (value.properties) {
return `{\n${value.properties
.map((_) => codify(_, tabs))
.join(',\n')}\n${'\t'.repeat(Math.max(0, tabs - 1))}}`;
}
if (value.signatures) {
return value.signatures.map(codify).join('\n');
}
}
if (value.kind === 'constructor') {
return '';
}
if (value.kind === 'interface') {
return `interface ${value.name} {\n${value.children
.map((_) => codify(_, tabs + 1))
.join(';\n')};\n}`;
}
if (value.kind === 'class') {
return `interface ${value.name} {\n${value.children
.filter((_) => _.kind !== 'constructor')
.map((_) => codify(_, tabs + 1))
.join(';\n')};\n}`;
}
if (value.kind === 'typeAlias') {
return `type ${value.name} = ${codifyType(value.type)}`;
}
console.log('unreachable', value);
throw new Error(`unreachable`);
}
export namespace TypeSystem {
export type Comment = any;
export type TypeParameter = {
name: string;
extends: TypeDescriptor.Type;
default: string;
comment?: Comment;
};
export type Accessor = {
name: string;
kind: 'accessor';
comment?: Comment;
value: TypeSystem.GetSignature;
};
export type GetSignature = {
kind: 'getSignature';
name: string;
returnType: TypeDescriptor.Type;
comment?: Comment;
};
export type CallSignature = {
kind: 'callSignature';
typeParameters: TypeSystem.TypeParameter[];
parameters: TypeSystem.Type[];
returnType: TypeDescriptor.Type;
name: string;
comment?: Comment;
};
export type Method = {
name: string;
kind: 'method';
signature: TypeSystem.CallSignature[];
comment?: Comment;
};
export type Function = {
name: string;
kind: 'function';
signature: TypeSystem.CallSignature;
comment?: Comment;
};
export type Property = {
kind: 'property';
name: string;
type: TypeDescriptor.Type;
flags: TypeDescriptor.Flags;
comment?: Comment;
};
export type TypeAlias = {
name: string;
kind: 'typeAlias';
typeParameters: TypeSystem.TypeParameter[];
type: TypeDescriptor.Type;
comment?: Comment;
};
export type Enum = {
name: string;
kind: 'enum';
children: TypeSystem.EnumMember[];
comment?: Comment;
};
export type EnumMember = {
kind: 'enumMember';
name: string;
comment?: Comment;
};
export type Class = {
name: string;
kind: 'class';
children: TypeSystem.Type[];
comment?: Comment;
};
export type Interface = {
name: string;
kind: 'interface';
children: TypeSystem.Type[];
comment?: Comment;
};
export type Parameter = {
name: string;
kind: 'parameter';
type: TypeDescriptor.Type;
comment?: Comment;
};
export type Constructor = {
kind: 'constructor';
name: string;
comment?: Comment;
};
export type ConstructorSignature = {
kind: 'constructorSignature';
name: string;
comment?: Comment;
};
export type TypeLiteral = {
kind: 'typeLiteral';
name: string;
signatures?: (ConstructorSignature | TypeSystem.CallSignature)[];
properties?: TypeSystem.Property[];
comment?: Comment;
};
export type Type =
| TypeSystem.Accessor
| TypeSystem.GetSignature
| TypeSystem.CallSignature
| TypeSystem.Method
| TypeSystem.Property
| TypeSystem.TypeAlias
| TypeSystem.Enum
| TypeSystem.EnumMember
| TypeSystem.Class
| TypeSystem.Constructor
| TypeSystem.ConstructorSignature
| TypeSystem.TypeLiteral
| TypeSystem.Parameter
| TypeSystem.Interface
| TypeSystem.Function;
}
export namespace TypeDescriptor {
export interface Union {
type: 'or';
values: TypeDescriptor.Type[];
}
export interface Intrinsic {
type: 'intrinsic';
value: string;
}
export interface Literal {
type: 'literal';
value: string;
}
export type Reflection = { type: 'reflection'; value: TypeSystem.Type };
export interface Reference {
type: 'reference';
value: string;
source: string;
typeArguments?: TypeDescriptor.Type[];
refersToTypeParameter?: boolean;
}
export interface Array {
type: 'array';
value: TypeDescriptor.Type;
}
export interface Intersection {
type: 'intersection';
values: TypeDescriptor.Type[];
}
export interface Predicate {
type: 'predicate';
lhs: string;
rhs: TypeDescriptor.Type;
}
export interface Tuple {
type: 'tuple';
value: TypeDescriptor.Type[];
}
export type Type =
| TypeDescriptor.Union
| TypeDescriptor.Intrinsic
| TypeDescriptor.Literal
| TypeDescriptor.Reflection
| TypeDescriptor.Reference
| TypeDescriptor.Array
| TypeDescriptor.Intersection
| TypeDescriptor.Predicate
| TypeDescriptor.Tuple;
export type Flags = {
isReadonly?: boolean;
isProtected?: boolean;
isOptional?: boolean;
};
}

View File

@ -154,6 +154,7 @@
} }
code { code {
// white-space: pre-wrap;
.token { .token {
&.maybe-class-name { &.maybe-class-name {
color: #cf8cff; color: #cf8cff;

View File

@ -0,0 +1 @@
export const IS_PROD = true;

File diff suppressed because it is too large Load Diff

View File

@ -2,23 +2,15 @@ import React from 'react';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
import { themeConfig } from '../config/theme.config'; import { themeConfig } from '../config/theme.config';
import ExampleFrame from '../components/ui/exampleFrame'; import ExampleFrame from '../components/ui/exampleFrame';
import BrowserOnly from '@docusaurus/BrowserOnly';
export default function Popout() { const ThemeToggle: React.FC = () => {
// const [theme, setTheme] = React.useState<string>( const [theme, setTheme] = React.useState<string>(
// new URLSearchParams(location.search).get('theme') ?? themeConfig[3].id new URLSearchParams(location.search).get('theme') ?? themeConfig[3].id
// ); );
return ( return (
<Layout noFooter={true}> <>
<div
style={{
height: 'calc(100% - var(--ifm-navbar-height))',
flexGrow: 1,
padding: '10px',
display: 'flex',
flexDirection: 'column',
}}
>
<div <div
style={{ style={{
height: '40px', height: '40px',
@ -32,20 +24,36 @@ export default function Popout() {
url.searchParams.set('theme', event.target.value); url.searchParams.set('theme', event.target.value);
window.location.href = url.toString(); window.location.href = url.toString();
}} }}
// value={theme} value={theme}
> >
{themeConfig.map((theme) => { {themeConfig.map((theme) => {
return <option>{theme.id}</option>; return <option>{theme.id}</option>;
})} })}
</select> </select>
</div> </div>
<ExampleFrame <ExampleFrame
// theme={theme} theme={theme}
framework="react" framework="react"
height="100%" height="100%"
id="dockview/demo-dockview" id="dockview/demo-dockview"
/> />
</>
);
};
export default function Popout() {
return (
<Layout noFooter={true}>
<div
style={{
height: 'calc(100% - var(--ifm-navbar-height))',
flexGrow: 1,
padding: '10px',
display: 'flex',
flexDirection: 'column',
}}
>
<BrowserOnly>{() => <ThemeToggle />}</BrowserOnly>
</div> </div>
</Layout> </Layout>
); );

View File

@ -105,9 +105,89 @@ function parseType(obj) {
} }
} }
function parseComplexType(obj) {
switch (obj.type) {
case 'union':
return {
type: 'or',
values: obj.types.map(parseComplexType).reverse(),
};
case 'intrinsic':
return { type: obj.type, value: obj.name };
case 'literal':
return { type: obj.type, value: obj.value };
case 'reflection':
return { type: obj.type, value: parse(obj.declaration) };
case 'reference': {
if (obj.refersToTypeParameter) {
return {
type: obj.type,
value: obj.name,
source: obj.package,
refersToTypeParameter: true,
};
}
if (obj.qualifiedName) {
return {
type: obj.type,
value: obj.qualifiedName,
source: obj.sourceFileName
? obj.sourceFileName.startsWith('packages/dockview')
? 'dockview'
: 'external'
: obj.package,
typeArguments: obj.typeArguments?.map(parseComplexType),
};
}
return {
type: obj.type,
value: obj.name,
source: obj.package,
typeArguments: obj.typeArguments?.map(parseComplexType),
};
}
case 'array':
return {
type: obj.type,
value: parseComplexType(obj.elementType),
};
case 'intersection':
return {
type: obj.type,
values: obj.types.map(parseComplexType).reverse(),
};
case 'predicate':
return {
type: obj.type,
lhs: obj.name,
rhs: parseComplexType(obj.targetType),
};
case 'tuple':
return {
type: obj.type,
values: obj.elements.map(parseComplexType),
};
default:
throw new Error(`unhandled type ${obj.type}`);
}
}
function extractPiecesFromType(obj) { function extractPiecesFromType(obj) {
if (obj.type === 'reference' && obj.package?.startsWith('dockview-')) { if (obj.type === 'reference' && obj.package?.startsWith('dockview-')) {
return obj.name; let result = { name: obj.name };
if (Array.isArray(obj.typeArguments)) {
const typeArgs = obj.typeArguments
.map(extractPiecesFromType)
.filter(Boolean);
if (typeArgs.length > 0) {
result.typeArgs = typeArgs;
}
}
return result;
} }
return null; return null;
} }
@ -126,14 +206,15 @@ function parse(data) {
const getSignature = parse(data.getSignature); const getSignature = parse(data.getSignature);
code += getSignature.code; code += getSignature.code;
pieces.push(...getSignature.pieces); // pieces.push(...getSignature.pieces);
return { return {
name, name,
code, code,
kind: 'accessor', kind: 'accessor',
value: getSignature,
comment: getSignature.comment, comment: getSignature.comment,
pieces, // pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.Method: // 2048 case ReflectionKind.Method: // 2048
const methodSignature = data.signatures.map((signature) => const methodSignature = data.signatures.map((signature) =>
@ -149,20 +230,25 @@ function parse(data) {
name, name,
code, code,
kind: 'method', kind: 'method',
signature: methodSignature,
comment: data.signatures[0].comment, comment: data.signatures[0].comment,
pieces, // pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.Property: // 1024 case ReflectionKind.Property: // 1024
code += parseType(data.type); code += parseType(data.type);
pieces.push(extractPiecesFromType(data.type)); pieces.push({
kind: 'property',
value: extractPiecesFromType(data.type),
});
return { return {
name, name,
code, code,
kind: 'property', kind: 'property',
type: parseComplexType(data.type),
flags, flags,
comment, comment,
pieces, // pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.Parameter: // 32768 case ReflectionKind.Parameter: // 32768
@ -174,14 +260,21 @@ function parse(data) {
code += ': '; code += ': ';
code += parseType(data.type); code += parseType(data.type);
pieces.push(extractPiecesFromType(data.type)); pieces.push({
kind: 'parameter',
value: extractPiecesFromType(data.type),
});
return { return {
name, name,
code, code,
pieces, type: parseComplexType(data.type),
kind: 'parameter',
// pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.TypeLiteral: // 65536 case ReflectionKind.TypeLiteral: // 65536
let result = {};
if (Array.isArray(data.children)) { if (Array.isArray(data.children)) {
code += `{ `; code += `{ `;
code += data.children code += data.children
@ -192,46 +285,91 @@ function parse(data) {
code += '?'; code += '?';
} }
const childData = parse(child); const childData = parse(child);
pieces.push(...childData.pieces); // pieces.push(...childData.pieces);
code += `: ${childData.code}`; code += `: ${childData.code}`;
return code; return code;
}) })
.join(', '); .join(', ');
code += ` }`; code += ` }`;
result.properties = data.children.map((_) => {
const result = parse(_);
if (result.kind !== 'property') {
throw new Error(`invalid ${result.kind}`);
}
return result;
});
} }
if (Array.isArray(data.signatures)) { if (Array.isArray(data.signatures)) {
const signatures = data.signatures.map((signature) => const signatures = data.signatures.map((signature) => {
parse(signature) const result = parse(signature);
);
if (
result.kind !== 'callSignature' &&
result.kind !== 'constructorSignature'
) {
throw new Error(`invalid ${result.kind}`);
}
return result;
});
code += signatures code += signatures
.map((signature) => signature.code) .map((signature) => signature.code)
.join(', '); .join(', ');
pieces.push(...signatures.flatMap((_) => _.pieces)); // pieces.push(...signatures.flatMap((_) => _.pieces));
if (result.type) {
throw new Error('anc');
} }
return { name, code, pieces }; result.signatures = signatures;
}
return {
name,
code,
// pieces,
kind: 'typeLiteral',
properties: result.properties,
signatures: result.signatures,
};
case ReflectionKind.CallSignature: // 4096 case ReflectionKind.CallSignature: // 4096
// don't care for constrcutors const typeParameters = [];
let _parameters = [];
if (Array.isArray(data.typeParameter)) { if (Array.isArray(data.typeParameter)) {
code += `<${data.typeParameter.map((typeParameter) => { code += `<${data.typeParameter.map((typeParameter) => {
let type = `${typeParameter.name}`; let type = `${typeParameter.name}`;
const result = { name: type };
if (typeParameter.type) { if (typeParameter.type) {
type += ` extends ${parseType(typeParameter.type)}`; type += ` extends ${parseType(typeParameter.type)}`;
pieces.push(extractPiecesFromType(typeParameter.type)); result.extends = parseComplexType(typeParameter.type);
pieces.push({
kind: 'typearg',
value: extractPiecesFromType(typeParameter.type),
});
} }
if (typeParameter.default) { if (typeParameter.default) {
type += ` = ${typeParameter.default.name}`; type += ` = ${typeParameter.default.name}`;
pieces.push( pieces.push({
extractPiecesFromType(typeParameter.default) kind: 'typearg_default',
); value: extractPiecesFromType(typeParameter.default),
});
result.default = typeParameter.default.name;
} }
typeParameters.push(result);
return type; return type;
})}>`; })}>`;
} }
@ -242,113 +380,155 @@ function parse(data) {
const parameters = data.parameters.map((parameter) => const parameters = data.parameters.map((parameter) =>
parse(parameter) parse(parameter)
); );
_parameters = parameters;
code += `${parameters code += `${parameters
.map((parameter) => parameter.code) .map((parameter) => parameter.code)
.join(', ')}`; .join(', ')}`;
pieces.push(...parameters.flatMap((_) => _.pieces)); // pieces.push(...parameters.flatMap((_) => _.pieces));
} }
code += '): '; code += '): ';
code += parseType(data.type); code += parseType(data.type);
pieces.push(extractPiecesFromType(data.type)); pieces.push({
kind: 'return',
value: extractPiecesFromType(data.type),
});
return { return {
name, name,
comment, comment,
typeParameters,
parameters: _parameters,
returnType: parseComplexType(data.type),
code, code,
pieces, kind: 'callSignature',
// pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.GetSignature: // 524288 case ReflectionKind.GetSignature: // 524288
code += parseType(data.type); code += parseType(data.type);
pieces.push(extractPiecesFromType(data.type)); pieces.push({
kind: 'signature',
value: extractPiecesFromType(data.type),
});
return { return {
name, name,
comment, comment,
code, code,
pieces, kind: 'getSignature',
returnType: parseComplexType(data.type),
// pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.Function: // 64 case ReflectionKind.Function: // 64
if (data.signatures.length > 1) { if (data.signatures.length > 1) {
throw new Error('unhandled'); throw new Error('unhandled');
} }
const functionSignature = parse(data.signatures[0]); const functionSignature = parse(data.signatures[0]);
pieces.push(...functionSignature.pieces); // pieces.push(...functionSignature.pieces);
code += functionSignature.code; code += functionSignature.code;
return { return {
name, name,
comment, comment,
code, code,
pieces, signature: parse(data.signatures[0]),
kind: 'function',
// pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.Variable: // 32 case ReflectionKind.Variable: // 32
return { return {
name, name,
comment, comment,
code, code,
pieces, kind: 'variable',
// pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.EnumMember: // 16 case ReflectionKind.EnumMember: // 16
return { return {
name, name,
comment, comment,
code, code,
pieces, kind: 'enumMember',
// pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.Interface: // 16 case ReflectionKind.Interface: // 16
return { return {
name, name,
comment, comment,
code, code,
pieces, kind: 'interface',
// pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.ConstructorSignature: // 16384 case ReflectionKind.ConstructorSignature: // 16384
return { return {
name, name,
comment, comment,
code, code,
pieces, kind: 'constructorSignature',
// pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.Constructor: // 512 case ReflectionKind.Constructor: // 512
// don't care for constrcutors // don't care for constrcutors
return { return {
name, name,
comment, comment,
kind: 'constructor',
code, code,
pieces, // pieces: pieces.filter((_) => _.value !== null),
}; };
case ReflectionKind.TypeAlias: // 2097152 case ReflectionKind.TypeAlias: // 2097152
const typeParameters1 = [];
if (Array.isArray(data.typeParameter)) { if (Array.isArray(data.typeParameter)) {
code += `<${data.typeParameter.map((typeParameter) => { code += `<${data.typeParameter.map((typeParameter) => {
let type = `${typeParameter.name}`; let type = `${typeParameter.name}`;
const result = { name: typeParameter.name };
if (typeParameter.type) { if (typeParameter.type) {
type += ` extends ${parseType(typeParameter.type)}`; type += ` extends ${parseType(typeParameter.type)}`;
pieces.push(extractPiecesFromType(typeParameter.type)); result.extends = parseComplexType(typeParameter.type);
pieces.push({
kind: 'typearg',
value: extractPiecesFromType(typeParameter.type),
});
} }
if (typeParameter.default) { if (typeParameter.default) {
type += ` = ${typeParameter.default.name}`; type += ` = ${typeParameter.default.name}`;
pieces.push( pieces.push({
extractPiecesFromType(typeParameter.default) kind: 'typearg_default',
); value: extractPiecesFromType(typeParameter.default),
});
result.default = typeParameter.default.name;
} }
typeParameters1.push(result);
return type; return type;
})}>`; })}>`;
} }
code += parseType(data.type); code += parseType(data.type);
pieces.push(extractPiecesFromType(data.type)); pieces.push({
kind: 'typearg',
value: extractPiecesFromType(data.type),
});
return { return {
name, name,
comment, comment,
code, code,
pieces, typeParameters: typeParameters1,
type: parseComplexType(data.type),
kind: 'typeAlias',
// pieces: pieces.filter((_) => _.value !== null),
}; };
default: default:
throw new Error(`unhandled kind ${data.kind}`); throw new Error(`unhandled kind ${data.kind}`);
@ -395,11 +575,15 @@ function createDocument(declarations) {
documentation[name] = { documentation[name] = {
...metadata, ...metadata,
name,
children: [], children: [],
}; };
if (!children) { if (!children) {
documentation[name].metadata = parse(declaration); documentation[name] = {
...parse(declaration),
};
// documentation[name].metadata = parse(declaration);
} }
if (children) { if (children) {
@ -417,6 +601,8 @@ function createDocument(declarations) {
output.pieces = Array.from(new Set(output.pieces)) output.pieces = Array.from(new Set(output.pieces))
.filter(Boolean) .filter(Boolean)
.sort(); .sort();
delete output.pieces;
// delete output.comment;
documentation[name].children.push(output); documentation[name].children.push(output);
} }