chore: docs

This commit is contained in:
mathuo 2024-01-05 15:39:20 +00:00
parent 4b616c5578
commit 32d668f69d
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
5 changed files with 1026 additions and 847 deletions

View File

@ -395,7 +395,6 @@ props.containerApi.addPopoutGroup(props.api.group);
react={DockviewPopoutGroup} react={DockviewPopoutGroup}
/> />
## Maximized Groups ## Maximized Groups
To maximize a group you can all To maximize a group you can all
@ -563,18 +562,37 @@ api.removePanel(panel);
### Panel Rendering ### Panel Rendering
#### Render Mode
Dockview has two rendering modes `onlyWhenVisible` (default) and `always`. A rendering mode can be defined through the `renderer` prop to `DockviewReact` or at an individual panel level when added where
the panel declaration takes precedence if both are defined. Rendering modes defined at the panel level are persisted, those defined at the `DockviewReact` level are not persisted.
- `onlyWhenVisible` mode is the default mode. In this mode when a panel is no longer visible through either it's visiblity being hidden or it not being the active panel within a group the panels HTMLElement is removed
from the DOM and any DOM state such as scrollbar positions will be lost. If you are using any ResizeObservers to measure size this will result both zero height and width as the HTMLElement no longer belongs to the DOM.
This design allows for maximum performance at some cost.
- `always` mode. In this mode when panels become hidden the HTMLElement is not destroyed so all DOM state such as scrollbar positions will be maintained. This is implemented by rendering each panel as an absolutely positioned
HTMLElement and hidden the HTMLElement with `display: none` when it should be hidden.
<MultiFrameworkContainer
height={500}
sandboxId="rendermode-dockview"
react={DockviewRenderMode}
/>
####
By default `DockviewReact` only adds to the DOM those panels that are visible, By default `DockviewReact` only adds to the DOM those panels that are visible,
if a panel is not the active tab and not shown the contents of the hidden panel will be removed from the DOM. if a panel is not the active tab and not shown the contents of the hidden panel will be removed from the DOM.
However the React Components associated with each panel are only created once and will always exist for as long as the panel exists, hidden or not. When a panel is in `onlyWhenVisible` render mode this only affects the contents within the DOM. The lifecycle of that panel instance is still maintained.
The React Components associated with each panel are only created once and will always exist for as long as the panel exists, hidden or not.
> For example this means that any hooks in those components will run whether the panel is visible or not which may lead to excessive background work depending > e.g. This means that any hooks in those components will run whether the panel is visible or not which may lead to excessive background work depending
> on the panels implementation. > on the panels implementation.
This is the default behaviour to ensure the greatest flexibility for the user but through the panels `props.api` you can listen to the visiblity state of the panel You can listen to the visiblity state of the panel and write additional logic to optimize your application if required, although this is an advanced case.
and write additional logic to optimize your application.
For example if you wanted to unmount the React Components when the panel is not visible you could create a Higher-Order-Component that listens to the panels If you wanted to unmount the React Components when the panel is not visible you could create a Higher-Order-Component that listens to the panels
visiblity state and only renders the panel when visible. visiblity state and only renders the panel when visible.
```tsx title="Only rendering the React Component when the panel is visible, otherwise rendering a null React Component" ```tsx title="Only rendering the React Component when the panel is visible, otherwise rendering a null React Component"
@ -615,6 +633,7 @@ const components = { default: RenderWhenVisible(MyComponent) };
Toggling the checkbox you can see that when you only render those panels which are visible the underling React component is destroyed when it becomes hidden and re-created when it becomes visible. Toggling the checkbox you can see that when you only render those panels which are visible the underling React component is destroyed when it becomes hidden and re-created when it becomes visible.
<MultiFrameworkContainer <MultiFrameworkContainer
sandboxId="rendering-dockview" sandboxId="rendering-dockview"
react={RenderingDockview} react={RenderingDockview}
@ -851,23 +870,6 @@ api.group.api.setConstraints(...)
react={DockviewConstraints} react={DockviewConstraints}
/> />
## Render Mode
Dockview has two rendering modes `destructive` (default) and `gready`. A rendering mode can be defined through the `renderer` prop to `DockviewReact` or at an individual panel level when added where
the panel declaration takes precedence if both are defined. Rendering modes defined at the panel level are persisted, those defined at the `DockviewReact` level are not persisted.
destructive
- Destructive mode is the default mode. In this mode when a panel is no longer visible through either it's visiblity being hidden or it not being the active panel within a group the panels HTMLElement is removed
from the DOM and any DOM state such as scrollbar positions will be lost. If you are using any ResizeObservers to measure size this will result both zero height and width as the HTMLElement no longer belongs to the DOM.
This design allows for maximum performance at some cost.
- Gready mode. In this mode when panels become hidden the HTMLElement is not destroyed so all DOM state such as scrollbar positions will be maintained. This is implemented by rendering each panel as an absolutely positioned
HTMLElement and hidden the HTMLElement with `display: none` when it should be hidden.
<MultiFrameworkContainer
height={500}
sandboxId="rendermode-dockview"
react={DockviewRenderMode}
/>
## iFrames ## iFrames

View File

@ -145,7 +145,7 @@ export const DockviewPersistance = (props: { theme?: string }) => {
style={{ style={{
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
height: '400px', height: '100%',
}} }}
> >
<div style={{ height: '25px' }}> <div style={{ height: '25px' }}>

View File

@ -17,9 +17,9 @@ type DocsComment = {
type DocsJson = { type DocsJson = {
[index: string]: Array<{ [index: string]: Array<{
name: string; name: string;
signature: string; code: string;
comment?: DocsComment; comment?: DocsComment;
type: string; kind: 'accessor' | 'property' | 'method';
}>; }>;
}; };
@ -150,7 +150,7 @@ export const DocRef = (props: DocRefProps) => {
)} )}
</div> </div>
<CodeBlock language="tsx"> <CodeBlock language="tsx">
{doc.signature} {doc.code}
</CodeBlock> </CodeBlock>
</div> </div>
</th> </th>

File diff suppressed because it is too large Load Diff

View File

@ -71,287 +71,149 @@ const declarations = [dockviewCore, dockview]
item.children.filter((child) => DOCUMENT_LIST.includes(child.name)) item.children.filter((child) => DOCUMENT_LIST.includes(child.name))
) )
.filter(Boolean); .filter(Boolean);
/**
* #region parsing of TypeDoc output
*/
function findType(type, packageName) { function parseTypeArguments(args) {
if (EXPORT_REMAPPING[type]) { if (Array.isArray(args.typeArguments)) {
type = EXPORT_REMAPPING[type]; return `<${args.typeArguments.map(parseType).join(', ')}>`;
} }
return '';
const packageObject = content.children.find(
(child) => child.name === packageName
);
const typeObject = packageObject.children.find(
(child) => child.name === type
);
return getFunction(typeObject, [], { includeMetadata: false });
} }
// minimal parsing logic, add cases as required function parseType(obj) {
function getType(type, metadata, options) { switch (obj.type) {
switch (type.type) {
case 'union': case 'union':
return { return obj.types.map(parseType).reverse().join(' | ');
signature: [...type.types]
.reverse()
.map((t) => getType(t, metadata, options).signature)
.join(' | '),
};
case 'intrinsic': case 'intrinsic':
return { signature: type.name }; return obj.name;
case 'reference':
if (
options.includeMetadata &&
type.package &&
typeof type.target !== 'object'
) {
metadata.push({ name: type.name, package: type.package });
}
if (Array.isArray(type.typeArguments)) {
return {
signature: `${type.name}<${type.typeArguments
.map((typeArgument) => {
return getType(typeArgument, metadata, options)
.signature;
})
.join(', ')}>`,
};
}
return { signature: `${type.name}` };
case 'array':
return {
signature: `${
getType(type.elementType, metadata, options).signature
}[]`,
};
case 'reflection':
if (type.declaration.children) {
return {
signature: `{ ${type.declaration.children
.map(
(child) =>
`${child.name}: ${
getType(child.type, metadata, options)
.signature
}`
)
.join(', ')} }`,
};
}
if (type.declaration.signatures) {
if (type.declaration.signatures.length > 1) {
// code this case if it ever happens
throw new Error(`unhandled signatures.length > 1`);
}
if (type.declaration.signatures[0].parameters) {
let _parameters = '';
const { parameters } = type.declaration.signatures[0];
for (let i = 0; i < parameters.length; i++) {
const { type, name, flags, defaultValue } =
parameters[i];
const isOptional = flags.isOptional === true;
const { signature } = getType(type, metadata, options);
_parameters += `${name}${
isOptional ? '?' : ''
}: ${signature}${
defaultValue !== undefined
? ` = ${defaultValue}`
: ''
}`;
if (i !== parameters.length - 1) {
_parameters += ', ';
}
}
return {
signature: `(${_parameters}): ${
getType(
type.declaration.signatures[0].type,
metadata,
options
).signature
}`,
};
}
return {
signature: getType(
type.declaration.signatures[0].type,
metadata,
options
).signature,
};
}
if (type.declaration.indexSignature) {
let _parameters = '';
const { parameters } = type.declaration.indexSignature;
for (let i = 0; i < parameters.length; i++) {
const { type, name, flags, defaultValue } = parameters[i];
const isOptional = flags.isOptional === true;
_parameters += `${name}${isOptional ? '?' : ''}: ${
getType(type, metadata, options).signature
}${defaultValue !== undefined ? ` = ${defaultValue}` : ''}`;
if (i !== parameters.length - 1) {
_parameters += ', ';
}
}
return {
signature: `{ [${parameters}]: ${getType(
type.declaration.indexSignature.type,
metadata,
options
)}}`,
};
}
throw new Error('unhandled case');
case 'literal': case 'literal':
return { signature: `'${type.value}'` }; return `'${obj.value}'`;
case 'reflection':
return parse(obj.declaration).code;
case 'reference':
return `${obj.qualifiedName ?? obj.name}${parseTypeArguments(obj)}`;
case 'array':
return `${parseType(obj.elementType)}[]`;
default: default:
throw new Error(`unhandled type ${type.type}`); throw new Error(`unhandled type ${obj.type}`);
} }
} }
// minimal parsing logic, add cases as required function parse(data) {
function getFunction( const { name, comment, flags } = data;
method,
metadata = [],
options = { includeMetadata: true }
) {
switch (method.kind) {
case ReflectionKind.Accessor: {
const { getSignature, name } = method;
const { type, comment } = getSignature;
const metadata = [];
const { signature } = getType(type, metadata, options);
return {
name,
signature,
comment,
type: 'accessor',
metadata: metadata.length > 0 ? metadata : undefined,
};
}
case ReflectionKind.Property: {
const { type, name, comment } = method;
const metadata = [];
const { signature } = getType(type, metadata, options);
return {
name,
signature,
comment,
type: 'property',
metadata: metadata.length > 0 ? metadata : undefined,
};
}
case ReflectionKind.Interface: {
const { type, name, comment, children } = method;
let signature = `interface ${name} {`; let code = '';
if (children) { switch (data.kind) {
for (const child of children) { case ReflectionKind.Accessor: // 262144
signature += `\n\t${ const getSignature = parse(data.getSignature);
child.flags.isReadonly ? 'readonly ' : '' code += getSignature.code;
}${child.name}: ${
getFunction(child, metadata, options).signature
};`;
}
}
signature += `\n}`;
return { return {
name, name,
signature, code,
comment, kind: 'accessor',
type: 'interface', comment: getSignature.comment,
metadata: metadata.length > 0 ? metadata : undefined,
}; };
} case ReflectionKind.Method: // 2048
case ReflectionKind.Method: { if (data.signatures.length > 1) {
const { signatures } = method; throw new Error('unhandled');
if (signatures.length > 1) {
throw new Error(`signatures.length > 1`);
}
const { name, parameters, type, typeParameter, comment } =
signatures[0];
let _typeParameter = '';
if (Array.isArray(typeParameter)) {
for (let i = 0; i < typeParameter.length; i++) {
const item = typeParameter[i];
const { signature } = getType(item.type, metadata, options);
_typeParameter += `<${item.name}`;
if (item.type) {
_typeParameter += ` extends ${signature}`;
}
if (item.default) {
_typeParameter += ` = ${
getType(item.default, metadata, options).signature
}`;
}
_typeParameter += `>`;
if (i !== typeParameter.length - 1) {
_typeParameter += ', ';
}
}
} }
let _parameters = ''; const signature = parse(data.signatures[0]);
if (Array.isArray(parameters)) { code += signature.code;
for (let i = 0; i < parameters.length; i++) {
const { type, name, flags, defaultValue } = parameters[i];
const isOptional = flags.isOptional === true; return { name, code, kind: 'method', comment: signature.comment };
case ReflectionKind.Property: // 1024
code += parseType(data.type);
const { signature } = getType(type, metadata, options); return { name, code, kind: 'property', flags, comment };
case ReflectionKind.Constructor: // 512
// don't care for constrcutors
return null;
case ReflectionKind.Parameter: // 32768
code += `${name}`;
_parameters += `${name}${ if (flags.isOptional) {
isOptional ? '?' : '' code += '?';
}: ${signature}${
defaultValue !== undefined ? ` = ${defaultValue}` : ''
}`;
if (i !== parameters.length - 1) {
_parameters += ', ';
}
}
} }
code += ': ';
code += parseType(data.type);
return {
name,
code,
};
case ReflectionKind.TypeLiteral: // 65536
if (Array.isArray(data.children)) {
code += `{ `;
code += data.children
.map((child) => {
let code = `${child.name}`;
if (child.flags.isOptional) {
code += '?';
}
code += `: ${parse(child).code}`;
return code;
})
.join(', ');
code += ` }`;
}
if (Array.isArray(data.signatures)) {
code += data.signatures
.map((signature) => parse(signature).code)
.join(', ');
}
return { name, code };
case ReflectionKind.CallSignature: // 4096
// don't care for constrcutors
if (Array.isArray(data.typeParameter)) {
code += `<${data.typeParameter.map((typeParameter) => {
let type = `${typeParameter.name} extends ${parseType(
typeParameter.type
)}`;
if (typeParameter.default) {
type += ` = ${typeParameter.default.name}`;
}
return type;
})}>`;
}
code += '(';
if (Array.isArray(data.parameters)) {
code += `${data.parameters
.map((parameter) => parse(parameter).code)
.join(', ')}`;
}
code += '): ';
code += parseType(data.type);
return { return {
name, name,
comment, comment,
signature: `${_typeParameter}(${_parameters}): ${ code,
getType(type, metadata, options).signature
}`,
type: 'method',
metadata: metadata.length > 0 ? metadata : undefined,
}; };
} case ReflectionKind.GetSignature: // 524288
code += parseType(data.type);
return {
name,
comment,
code,
};
default:
throw new Error(`unhandled kind ${data.kind}`);
} }
} }
@ -371,23 +233,12 @@ function createDocument(declarations) {
continue; continue;
} }
const documentationPart = getFunction(child, [], { const output = parse(child);
includeMetadata: false, if (output) {
}); documentation[name].push(output);
if (documentationPart) {
if (documentationPart.metadata) {
documentationPart.metadata = documentationPart.metadata
.filter(({ name }) => !SKIP_DOC.includes(name))
.map((item) => {
return findType(item.name, item.package);
});
}
documentation[name].push(documentationPart);
} }
} catch (err) { } catch (err) {
console.error('error', err, child); console.error('error', err, JSON.stringify(child, null, 4));
process.exit(-1); process.exit(-1);
} }
} }