Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 77 additions & 63 deletions src/components/ApiDocs/display/ApiModal.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
import {
View,
Flex,
Heading,
Card,
Divider,
Button
} from '@aws-amplify/ui-react';
import { Badge, View, Flex, Grid, Card, Button } from '@aws-amplify/ui-react';

import { ApiModalBreadcrumbs } from './ApiModalBreadcrumbs';
import { IconX } from '../../Icons';
import { ParameterType } from './ParameterType';
import { ApiComment } from '../ApiComment';
import { TypeLink } from './TypeLink';
import { LinkDataType, TypeLinkInterface } from './TypeLink';
import references from '@/directory/apiReferences.json';

export const ApiModal = ({ data, showModal, close, breadCrumbs, clearBC }) => {
let name = data.name;
interface ApiModalInterface {
data: any;
showModal?: boolean;
close: () => void;
breadCrumbs: LinkDataType[];
clearBC: () => void;
}

export const ApiModal = ({
data,
showModal = false,
close,
breadCrumbs,
clearBC
}: ApiModalInterface) => {
if (data.type === 'reference') {
data = references[data.target];
}
Expand All @@ -24,6 +32,7 @@ export const ApiModal = ({ data, showModal, close, breadCrumbs, clearBC }) => {
close();
};

let name = data.name;
let typeParameters = data.typeArguments;
if (data?.typeObject?.type == 'alias' && data.typeObject.typeParameters) {
typeParameters = data.typeObject.typeParameters;
Expand All @@ -40,6 +49,7 @@ export const ApiModal = ({ data, showModal, close, breadCrumbs, clearBC }) => {
if (params && params.length) {
name += `<${params.join(',')}>`;
}

const typeData = data.typeObject || data.value;
// look for objects or interfaces to render additional data
const displayProperties = {};
Expand All @@ -66,60 +76,64 @@ export const ApiModal = ({ data, showModal, close, breadCrumbs, clearBC }) => {
}
recursivelyParseType(typeData, displayProperties);

const breadcrumbItems = breadCrumbs.length
? breadCrumbs.reduce((acc, breadcrumb, index) => {
const bcArray = breadCrumbs.slice(0, index + 1);
acc.push({ linkData: breadcrumb, breadCrumbs: bcArray });
return acc;
}, [] as TypeLinkInterface[])
: [];

return (
<View display={showModal ? 'flex' : 'none'} className="api-modal-container">
<View>
<Card
className="api-modal"
borderRadius="medium"
variation="outlined"
textAlign="center"
position="relative"
>
<View padding="xs" fontSize="large">
<Flex className={'bread-crumbs'}>
{breadCrumbs.length &&
breadCrumbs.reduce((acc, bc, idx) => {
const bcArray = breadCrumbs.slice(0, idx + 1);
const next = <TypeLink linkData={bc} breadCrumbs={bcArray} />;
if (idx > 0) {
acc.push(' > ');
}
acc.push(next);
return acc;
}, [])}
</Flex>
<Button
onClick={closeModal}
size="small"
variation="link"
className={'close-button'}
>
<IconX />
</Button>
<Flex justifyContent="space-between">
<Heading padding="large" level={2}>
{name}
</Heading>
</Flex>
<Divider padding="xs" />
<Flex justifyContent={'center'}>
<View as={'code'} fontSize="large" className={'parameter'}>
<ParameterType typeData={data.type || data} />
</View>
</Flex>
<View className={'description-wrapper'}>
<View className={'description'}>
{description && (
<>
<ApiComment apiComment={description} />
</>
)}
</View>
<View
aria-label={`${name} API Reference`}
className={`api-modal-container${showModal ? ' api-modal-container--open' : ''}`}
>
<Card as="dialog" className="api-modal" aria-modal="true">
<Flex className="api-model__header">
<ApiModalBreadcrumbs items={breadcrumbItems} />
<Button
onClick={closeModal}
size="small"
variation="link"
className="api-modal__close"
>
<IconX />
</Button>
</Flex>

<Grid as="dl" className="api-modal__content">
<dt>Name:</dt>
<Flex as="dd" className="api-modal__content__name">
<Badge size="small">
{data.type?.type ? data.type.type : 'interface'}{' '}
</Badge>
<span className="api-modal__api-name">{name}</span>
</Flex>
<dt>Value:</dt>
{/** This dd is not scrollable if the value is only a reference, because
* then it is a single link to an item (avoids having to tab again). It is
* scrollable for others because the code might overflow the container on smaller
* viewports.
*/}
<dd
className="api-modal__api-value"
tabIndex={data.type?.type === 'reference' ? -1 : 0}
>
<View as="code" className="parameter">
<ParameterType typeData={data.type || data} />
</View>
</View>
</Card>
</View>
</dd>
{description ? (
<>
<dt>Description:</dt>
<dd>
<ApiComment apiComment={description} />
</dd>
</>
) : null}
</Grid>
</Card>
</View>
);
};
55 changes: 55 additions & 0 deletions src/components/ApiDocs/display/ApiModalBreadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useEffect, useRef, Fragment } from 'react';
import { Text, Flex } from '@aws-amplify/ui-react';

import { TypeLink, TypeLinkInterface } from './TypeLink';

interface ApiModalBreadcrumbs {
items?: TypeLinkInterface[];
}

export const ApiModalBreadcrumbs = ({ items }: ApiModalBreadcrumbs) => {
const navRef = useRef<HTMLElement>(null);

useEffect(() => {
if (navRef.current) {
navRef.current.scrollLeft = navRef.current.scrollWidth;
}
}, [items]);

return (
<Flex
as="nav"
ref={navRef}
aria-label="API Type breadcrumbs"
className="api-modal__breadcrumbs"
tabIndex={0}
>
{items
? items.map((item, index) => {
return (
<Fragment key={`api-breadcrumb-${index}`}>
{index !== 0 ? (
<div
className="api-modal__breadcrumbs__separator"
aria-hidden="true"
>
/
</div>
) : null}{' '}
{index === items.length - 1 ? (
<Text as="span" className="api-modal__breadcrumbs__current">
{item.linkData.name}
</Text>
) : (
<TypeLink
linkData={item.linkData}
breadCrumbs={item.breadCrumbs}
/>
)}
</Fragment>
);
})
: null}
</Flex>
);
};
2 changes: 1 addition & 1 deletion src/components/ApiDocs/display/TypeLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface LinkDataType {

export interface TypeLinkInterface {
linkData: LinkDataType;
breadCrumbs?: [];
breadCrumbs?: LinkDataType[];
}

export const TypeLink = ({ linkData, breadCrumbs }: TypeLinkInterface) => {
Expand Down
103 changes: 66 additions & 37 deletions src/styles/reference.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,66 +11,95 @@
}

.api-modal-container {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 99999;
&--open {
display: flex;
}
}

.api-modal {
padding: 60px;
border-radius: 10px;
box-shadow: 0px 0px 10px #cccccc;
width: 80vw;
height: 80vh;
overflow: auto;
display: block;
color: var(--amplify-colors-font-primary);
.api-modal {
width: 800px;
max-width: 90vw;
max-height: 90vh;
border-radius: var(--amplify-radii-medium);
}

.close-button {
position: absolute;
top: 0;
right: 0;
padding: var(--amplify-space-small);
}
.api-model__header {
align-items: flex-start;
}

h2,
h3 {
text-align: center;
width: 100%;
}
.api-modal__breadcrumbs {
flex: 1 0 0;
padding-bottom: var(--amplify-space-medium);
margin-bottom: var(--amplify-space-xs);
overflow: scroll;
align-items: baseline;
gap: 2px;
}

.amplify-divider {
margin-bottom: var(--amplify-space-large);
}
.api-modal__breadcrumbs__current {
font-weight: bold;
}

.parameter {
min-width: 60%;
margin: var(--amplify-space-xs);
text-align: left;
}
.api-modal__content {
gap: var(--amplify-space-xxs);
grid-template-columns: 1fr;
grid-template-rows: auto;
align-items: baseline;
dt {
color: var(--amplify-colors-font-secondary);
}
dd {
padding-inline-start: var(--amplify-space-small);
}
&__name {
text-align: start;
color: var(--amplify-colors-neutral-90);
font-weight: bold;
align-items: baseline;
}
}

.object-type {
margin-left: var(--amplify-space-large);
}
.api-modal__api-name {
word-break: break-word;
flex: 1 0 0;
}

.bread-crumbs {
margin-bottom: var(--amplify-space-xs);
}
.api-modal__api-value {
overflow: scroll;

&:focus-visible {
outline: 2px solid var(--amplify-colors-border-focus);
outline-offset: 2px;
}
}

.description {
margin-top: var(--amplify-space-xl);
@media (min-width: 600px) {
.api-modal__content {
grid-template-columns: auto 1fr;
gap: var(--amplify-space-small);
dt {
text-align: end;
}
}
}

.object-type {
margin-inline-start: var(--amplify-space-medium);
}

.type-link {
cursor: pointer;
margin: 4px;
border: none;
padding: 0;
background: none;
Expand Down