Skip to content

Commit

Permalink
remove api ref fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
luvkapur committed May 29, 2023
1 parent 79bc946 commit 69a4e8b
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 217 deletions.
253 changes: 62 additions & 191 deletions scopes/api-reference/renderers/api-node-details/api-node-details.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState, useRef, useEffect, useCallback } from 'react';
import { H6 } from '@teambit/documenter.ui.heading';
import { CodeEditor } from '@teambit/code.ui.code-editor';
import Editor from '@monaco-editor/react';
import { useLocation } from '@teambit/base-react.navigation.link';
import { defaultCodeEditorOptions } from '@teambit/api-reference.utils.code-editor-options';
import classnames from 'classnames';
Expand All @@ -10,8 +10,6 @@ import { APIRefQueryParams } from '@teambit/api-reference.hooks.use-api-ref-url'
import { useNavigate } from 'react-router-dom';
import { APINode } from '@teambit/api-reference.models.api-reference-model';
import { SchemaNodesIndex } from '@teambit/api-reference.renderers.schema-nodes-index';
import { OnMount, Monaco } from '@monaco-editor/react';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';

import styles from './api-node-details.module.scss';

Expand Down Expand Up @@ -44,41 +42,33 @@ export function APINodeDetails({
const routerLocation = useLocation();
const query = useQuery();
const navigate = useNavigate();

const signatureEditorRef = useRef<monaco.editor.IStandaloneCodeEditor>();
const signatureMonacoRef = useRef<Monaco>();

const exampleEditorRef = useRef<monaco.editor.IStandaloneCodeEditor>();
const exampleMonacoRef = useRef<Monaco>();

const editorRef = useRef<any>();
const monacoRef = useRef<any>();
const routeToAPICmdId = useRef<string | null>(null);
const apiUrlToRoute = useRef<string | null>(null);

const hoverProviderDispose = useRef<any>();

const rootRef = useRef() as React.MutableRefObject<HTMLDivElement>;
const apiRef = useRef<HTMLDivElement | null>(null);

const signatureContainerRef = useRef<HTMLDivElement | null>(null);
const exampleContainerRef = useRef<HTMLDivElement | null>(null);

const [signatureHeight, setSignatureHeight] = useState<string | undefined>();
const [exampleHeight, setExampleHeight] = useState<string | undefined>();

const [containerSize] = useState<{ width?: number; height?: number }>({
const currentQueryParams = query.toString();
const [containerSize, setContainerSize] = useState<{ width?: number; height?: number }>({
width: undefined,
height: undefined,
});

const currentQueryParams = query.toString();
const signatureHeightStyle = (!!signatureHeight && `calc(${signatureHeight} + 16px)`) || '250px';
const exampleHeightStyle = (!!exampleHeight && `calc(${exampleHeight} + 16px)`) || '250px';

const indexHidden = (containerSize.width ?? 0) < INDEX_THRESHOLD_WIDTH;

const example = (doc?.tags || []).find((tag) => tag.tagName === 'example');
const comment = doc?.comment;
const signature = displaySignature || defaultSignature;
/**
* @HACK
* Make Monaco responsive
* default line height: 18px;
* totalHeight: (no of lines * default line height)
*/
const exampleHeight = (example?.comment?.split('\n').length || 0) * 18;
const defaultSignatureHeight = 36 + ((signature?.split('\n').length || 0) - 1) * 18;

const [signatureHeight, setSignatureHeight] = useState<number>(defaultSignatureHeight);
const [isMounted, setIsMounted] = useState(false);

const getAPINodeUrl = useCallback((queryParams: APIRefQueryParams) => {
Expand Down Expand Up @@ -107,158 +97,54 @@ export function APINodeDetails({

useEffect(() => {
if (isMounted && signature) {
signatureMonacoRef.current?.languages.typescript.typescriptDefaults.setCompilerOptions({
jsx: signatureMonacoRef.current.languages.typescript.JsxEmit.Preserve,
target: signatureMonacoRef.current.languages.typescript.ScriptTarget.ES2020,
monacoRef.current.languages.typescript.typescriptDefaults.setCompilerOptions({
jsx: monacoRef.current.languages.typescript.JsxEmit.Preserve,
target: monacoRef.current.languages.typescript.ScriptTarget.ES2020,
esModuleInterop: true,
});
signatureMonacoRef.current?.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
``;
monacoRef.current.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
noSemanticValidation: true,
noSyntaxValidation: true,
});

routeToAPICmdId.current =
signatureEditorRef.current?.addCommand(0, () => {
apiUrlToRoute.current && navigate(apiUrlToRoute.current);
}) ?? null;

const container = editorRef.current.getDomNode();
editorRef.current.onDidContentSizeChange(({ contentHeight }) => {
if (container && isMounted && signature) {
const updatedHeight = Math.min(200, contentHeight + 18);
setSignatureHeight(updatedHeight);
}
});
routeToAPICmdId.current = editorRef.current.addCommand(0, () => {
apiUrlToRoute.current && navigate(apiUrlToRoute.current);
});
if (!hoverProviderDispose.current) {
hoverProviderDispose.current = signatureMonacoRef.current?.languages.registerHoverProvider('typescript', {
hoverProviderDispose.current = monacoRef.current.languages.registerHoverProvider('typescript', {
provideHover: hoverProvider,
});
}
}
}, [isMounted]);

const getDisplayedLineCount = (editorInstance, containerWidth) => {
if (!signatureMonacoRef.current) return 0;

const model = editorInstance.getModel();

if (!model) {
return 0;
}

const lineCount = model.getLineCount();

let displayedLines = 0;

const lineWidth = editorInstance.getOption(signatureMonacoRef.current.editor.EditorOption.wordWrapColumn);
const fontWidthApproximation = 8;

for (let lineNumber = 1; lineNumber <= lineCount; lineNumber += 1) {
const line = model.getLineContent(lineNumber);
const length = line.length || 1;
const lineFitsContainer = length * fontWidthApproximation <= containerWidth;
const wrappedLineCount = (lineFitsContainer ? 1 : Math.ceil(length / lineWidth)) || 1;
displayedLines += wrappedLineCount;
}

return displayedLines;
};

const updateEditorHeight =
(
setHeight: React.Dispatch<React.SetStateAction<string | undefined>>,
editorRef: React.MutableRefObject<monaco.editor.IStandaloneCodeEditor | undefined>
) =>
() => {
if (!signatureMonacoRef.current) return undefined;

const editor = editorRef.current;

if (!editor) {
return undefined;
}

const lineHeight = editor.getOption(signatureMonacoRef.current.editor.EditorOption.lineHeight);

const paddingTop = editor.getOption(signatureMonacoRef.current.editor.EditorOption.padding)?.top || 0;
const paddingBottom = editor.getOption(signatureMonacoRef.current.editor.EditorOption.padding)?.bottom || 0;
const glyphMargin = editor.getOption(signatureMonacoRef.current.editor.EditorOption.glyphMargin);
const lineNumbers = editor.getOption(signatureMonacoRef.current.editor.EditorOption.lineNumbers);

const glyphMarginHeight = glyphMargin ? lineHeight : 0;
const lineNumbersHeight = lineNumbers.renderType !== 0 ? lineHeight : 0;

const containerWidth = editor.getLayoutInfo().contentWidth;
const displayedLines = getDisplayedLineCount(editor, containerWidth);

const contentHeight =
displayedLines * lineHeight + paddingTop + paddingBottom + glyphMarginHeight + lineNumbersHeight;

const domNode = editor.getDomNode()?.parentElement;

if (!domNode) {
return undefined;
}

domNode.style.height = `${contentHeight}px`;
signatureEditorRef.current?.layout();
setHeight(() => `${contentHeight}px`);
return undefined;
};

const handleEditorDidMount: (
monacoRef: React.MutableRefObject<Monaco | undefined>,
editorRef: React.MutableRefObject<monaco.editor.IStandaloneCodeEditor | undefined>,
containerRef: React.MutableRefObject<HTMLDivElement | null>,
setHeight: React.Dispatch<React.SetStateAction<string | undefined>>
) => OnMount = (monacoRef, editorRef, containerRef, setHeight) => (editor, _monaco) => {
/**
* disable syntax check
* ts cant validate all types because imported files aren't available to the editor
*/
monacoRef.current = _monaco;
editorRef.current = editor;

monacoRef.current.languages?.typescript?.typescriptDefaults?.setDiagnosticsOptions({
noSemanticValidation: true,
noSyntaxValidation: true,
});

monaco.editor.defineTheme('bit', {
base: 'vs-dark',
inherit: true,
rules: [],
colors: {
'scrollbar.shadow': '#222222',
'diffEditor.insertedTextBackground': '#1C4D2D',
'diffEditor.removedTextBackground': '#761E24',
'editor.selectionBackground': '#5A5A5A',
'editor.overviewRulerBorder': '#6a57fd',
'editor.lineHighlightBorder': '#6a57fd',
},
const handleSize = useCallback(() => {
setContainerSize({
width: rootRef.current.offsetWidth,
height: rootRef.current.offsetHeight,
});
monaco.editor.setTheme('bit');
editor.onDidChangeModelDecorations(updateEditorHeight(setHeight, editorRef));
editor.onDidChangeModelDecorations(updateEditorHeight(setHeight, editorRef));
const containerElement = containerRef.current;
let resizeObserver: ResizeObserver | undefined;

if (containerElement) {
resizeObserver = new ResizeObserver(() => {
setTimeout(() => updateEditorHeight(setHeight, editorRef));
});
resizeObserver.observe(containerElement);
}

return () => containerElement && resizeObserver?.unobserve(containerElement);
};
}, []);

useEffect(() => {
updateEditorHeight(setSignatureHeight, signatureEditorRef)();
updateEditorHeight(setExampleHeight, exampleEditorRef)();

if (window) window.addEventListener('resize', handleSize);
// Call handler right away so state gets updated with initial container size
handleSize();
return () => {
hoverProviderDispose.current?.dispose();
if (window) window.removeEventListener('resize', handleSize);
setIsMounted(false);
};
}, []);

React.useLayoutEffect(() => {
updateEditorHeight(setSignatureHeight, signatureEditorRef)();
updateEditorHeight(setExampleHeight, exampleEditorRef)();
useEffect(() => {
handleSize();
}, [rootRef?.current?.offsetHeight, rootRef?.current?.offsetWidth]);

return (
Expand All @@ -278,53 +164,38 @@ export function APINodeDetails({
<div
key={`${signature}-${currentQueryParams}-api-signature-editor`}
className={classnames(styles.apiNodeDetailsSignatureContainer, styles.codeEditorContainer)}
ref={signatureContainerRef}
style={{
minHeight: signatureHeightStyle,
maxHeight: signatureHeightStyle,
height: signatureHeightStyle,
}}
>
<CodeEditor
<Editor
options={defaultCodeEditorOptions}
fileContent={signature}
filePath={`${currentQueryParams}-${filePath}`}
value={signature}
height={signatureHeight}
path={`${currentQueryParams}-${filePath}`}
className={styles.editor}
handleEditorBeforeMount={(_monaco) => {
signatureMonacoRef.current = _monaco;
beforeMount={(monaco) => {
monacoRef.current = monaco;
}}
onMount={(editor) => {
editorRef.current = editor;
const signatureContent = editorRef.current.getValue();
const updatedSignatureHeight = 36 + ((signatureContent?.split('\n').length || 0) - 1) * 18;
setIsMounted(true);
setSignatureHeight(updatedSignatureHeight);
}}
handleEditorDidMount={handleEditorDidMount(
signatureMonacoRef,
signatureEditorRef,
signatureContainerRef,
setSignatureHeight
)}
theme={'vs-dark'}
/>
</div>
)}
{example && example.comment && (
<div className={styles.apiNodeDetailsExample}>
<H6 className={styles.apiNodeDetailsExampleTitle}>Example</H6>
<div
className={styles.codeEditorContainer}
ref={exampleContainerRef}
style={{
minHeight: exampleHeightStyle,
maxHeight: exampleHeightStyle,
height: exampleHeightStyle,
}}
>
<CodeEditor
<div className={styles.codeEditorContainer}>
<Editor
options={defaultCodeEditorOptions}
fileContent={example.comment}
filePath={`${example?.location.line}:${example?.location.filePath}`}
value={example.comment}
path={`${example?.location.line}:${example?.location.filePath}`}
height={exampleHeight}
theme={'vs-dark'}
className={styles.editor}
handleEditorDidMount={handleEditorDidMount(
exampleMonacoRef,
exampleEditorRef,
exampleContainerRef,
setExampleHeight
)}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

.row {
grid-template-columns: 1fr 1fr 2fr;

&.isHovering {
background-color: #f4f5f6;
cursor: pointer;
Expand All @@ -45,7 +44,6 @@

.signatureDetails {
background-color: var(--bit-bg-heavy, #f4f5f6);
margin-left: 8px;
}

.returnContainer,
Expand Down
6 changes: 3 additions & 3 deletions scopes/api-reference/renderers/type-ref/type-ref.renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function TypeRefComponent(props: APINodeRenderProps) {

if (typeArgRenderer) {
return (
<React.Fragment key={`type-arg-renderer-container-${typeArg.__schema}-${typeArg.toString()}-${index}`}>
<React.Fragment key={`type-arg-container-${typeArg.__schema}-${typeArg.toString()}-${index}`}>
<typeArgRenderer.Component
{...props}
key={`type-arg-${typeArg.__schema}-${typeArg.toString()}-${index}`}
Expand All @@ -78,7 +78,7 @@ function TypeRefComponent(props: APINodeRenderProps) {
}

return (
<React.Fragment key={`type-arg-container-${typeArg.__schema}-${typeArg.toString()}-${index}`}>
<React.Fragment key={typeArg.toString()}>
{typeArg.toString()}
{(typeArgs?.length ?? 0) > 1 && index !== (typeArgs?.length ?? 0) - 1 ? ', ' : null}
</React.Fragment>
Expand Down Expand Up @@ -148,7 +148,7 @@ function getExportedTypeUrlFromAnotherComp({
componentId: ComponentID;
selectedAPI: string;
}) {
const componentUrl = ComponentUrl.toUrl(componentId, { useLocationOrigin: true });
const componentUrl = ComponentUrl.toUrl(componentId);
const [componentIdUrl, versionQuery] = componentUrl.split('?');

const exportedTypeUrl = `${componentIdUrl}/~api-reference?selectedAPI=${encodeURIComponent(
Expand Down
Loading

0 comments on commit 69a4e8b

Please sign in to comment.