Skip to content
Permalink
Browse files

fix: Correct behavior of the link closing isolated view (#1627)

Fixes #1479
  • Loading branch information
elevatebart committed Jul 22, 2020
1 parent 967ba9e commit 9b6b6f60051f170dcb7f548fb114420a48a8e1e9
Showing with 192 additions and 763 deletions.
  1. +10 −133 src/client/rsg-components/ComponentsList/ComponentsList.spec.tsx
  2. +3 −32 src/client/rsg-components/ComponentsList/ComponentsList.tsx
  3. +1 −0 src/client/rsg-components/ComponentsList/ComponentsListRenderer.tsx
  4. +1 −0 src/client/rsg-components/ReactComponent/ReactComponent.spec.tsx
  5. +2 −1 src/client/rsg-components/ReactComponent/ReactComponent.tsx
  6. +2 −2 src/client/rsg-components/Section/Section.spec.tsx
  7. +7 −17 src/client/rsg-components/SectionHeading/SectionHeading.spec.tsx
  8. +2 −6 src/client/rsg-components/SectionHeading/SectionHeading.tsx
  9. +2 −2 src/client/rsg-components/SectionHeading/SectionHeadingRenderer.tsx
  10. +1 −1 src/client/rsg-components/Sections/Sections.tsx
  11. +2 −2 src/client/rsg-components/StyleGuide/StyleGuide.spec.tsx
  12. +48 −71 src/client/rsg-components/TableOfContents/TableOfContents.spec.tsx
  13. +6 −24 src/client/rsg-components/TableOfContents/TableOfContents.tsx
  14. +0 −427 src/client/rsg-components/TableOfContents/__snapshots__/TableOfContents.spec.tsx.snap
  15. +3 −3 src/client/rsg-components/slots/IsolateButton.spec.tsx
  16. +7 −6 src/client/rsg-components/slots/IsolateButton.tsx
  17. +3 −3 src/client/utils/__tests__/getUrl.spec.ts
  18. +19 −8 src/client/utils/__tests__/processComponents.spec.ts
  19. +11 −8 src/client/utils/__tests__/processSections.spec.ts
  20. +4 −4 src/client/utils/getUrl.ts
  21. +20 −1 src/client/utils/processComponents.ts
  22. +32 −8 src/client/utils/processSections.ts
  23. +3 −1 src/client/utils/renderStyleguide.tsx
  24. +2 −0 src/typings/RsgSection.ts
  25. +1 −3 test/cypress/integration/component_spec.js
@@ -13,115 +13,6 @@ const context = {

const Provider = (props: any) => <Context.Provider value={context} {...props} />;

it('should set the correct href for items', () => {
const components = [
{
visibleName: 'Button',
name: 'Button',
slug: 'button',
},
{
visibleName: 'Input',
name: 'Input',
slug: 'input',
},
];

const { getAllByRole } = render(
<Provider>
<ComponentsList items={components} />
</Provider>
);

expect(Array.from(getAllByRole('link')).map(node => (node as HTMLAnchorElement).href)).toEqual([
'http://localhost/#button',
'http://localhost/#input',
]);
});

it('if a custom href is provided, should use it instead of generating internal link', () => {
const components = [
{
visibleName: 'External example',
name: 'External example',
href: 'http://example.com/',
},
{
visibleName: 'Input',
name: 'Input',
slug: 'input',
},
];

const { getAllByRole } = render(
<Provider>
<ComponentsList items={components} />
</Provider>
);

expect(Array.from(getAllByRole('link')).map(node => (node as HTMLAnchorElement).href)).toEqual([
'http://example.com/',
'http://localhost/#input',
]);
});

it('should set an id parameter on link when useHashId is activated', () => {
const components = [
{
visibleName: 'Button',
name: 'Button',
slug: 'button',
},
{
visibleName: 'Input',
name: 'Input',
slug: 'input',
},
];

const { getAllByRole } = render(
<Provider>
<ComponentsList items={components} useRouterLinks hashPath={['Components']} useHashId />
</Provider>
);

expect(Array.from(getAllByRole('link')).map(node => (node as HTMLAnchorElement).href)).toEqual([
'http://localhost/#/Components?id=button',
'http://localhost/#/Components?id=input',
]);
});

it('should set a sub route on link when useHashId is deactivated', () => {
const components = [
{
visibleName: 'Button',
name: 'Button',
slug: 'button',
},
{
visibleName: 'Input',
name: 'Input',
slug: 'input',
},
];

const { getAllByRole } = render(
<Provider>
<ComponentsList
items={components}
useRouterLinks
hashPath={['Components']}
useHashId={false}
/>
</Provider>
);

expect(Array.from(getAllByRole('link')).map(node => (node as HTMLAnchorElement).href)).toEqual([
'http://localhost/#/Components/Button',
'http://localhost/#/Components/Input',
]);
});

it('should not render any links when the list is empty', () => {
const { queryAllByRole } = render(
<Provider>
@@ -147,12 +38,7 @@ it('should ignore items without visibleName', () => {

const { getAllByRole } = render(
<Provider>
<ComponentsList
items={components}
useRouterLinks
hashPath={['Components']}
useHashId={false}
/>
<ComponentsList items={components} />
</Provider>
);

@@ -167,24 +53,21 @@ it('should show content of items that are open and not what is closed', () => {
visibleName: 'Button',
name: 'Button',
slug: 'button',
href: '#buttton',
content: <div data-testid="content">Content for Button</div>,
},
{
visibleName: 'Input',
name: 'Input',
slug: 'input',
href: '#input',
content: <div data-testid="content">Content for Input</div>,
},
];

const { getAllByTestId, getByText } = render(
<Provider>
<ComponentsList
items={components}
useRouterLinks
hashPath={['Components']}
useHashId={false}
/>
<ComponentsList items={components} />
</Provider>
);

@@ -201,25 +84,22 @@ it('should show content of initialOpen items even if they are not active', () =>
visibleName: 'Button',
name: 'Button',
slug: 'button',
href: '#button',
content: <div data-testid="content">Content for Button</div>,
},
{
visibleName: 'Input',
name: 'Input',
slug: 'input',
href: '#input',
content: <div data-testid="content">Content for Input</div>,
initialOpen: true,
},
];

const { getAllByTestId, getByText } = render(
<Provider>
<ComponentsList
items={components}
useRouterLinks
hashPath={['Components']}
useHashId={false}
/>
<ComponentsList items={components} />
</Provider>
);

@@ -236,13 +116,15 @@ it('should show content of forcedOpen items even if they are initially collapsed
visibleName: 'Button',
name: 'Button',
slug: 'button',
href: '#button',
content: <div data-testid="content">Content for Button</div>,
initialOpen: true,
},
{
visibleName: 'Input',
name: 'Input',
slug: 'input',
href: '#input',
content: <div data-testid="content">Content for Input</div>,
initialOpen: true,
forcedOpen: true,
@@ -251,12 +133,7 @@ it('should show content of forcedOpen items even if they are initially collapsed

const { getAllByTestId, getByText } = render(
<Provider>
<ComponentsList
items={components}
useRouterLinks
hashPath={['Components']}
useHashId={false}
/>
<ComponentsList items={components} />
</Provider>
);

@@ -1,49 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import ComponentsListRenderer from 'rsg-components/ComponentsList/ComponentsListRenderer';
import getUrl from '../../utils/getUrl';
import * as Rsg from '../../../typings';

interface ComponentsListProps {
items: Rsg.TOCItem[];
hashPath?: string[];
useRouterLinks?: boolean;
useHashId?: boolean;
}

const ComponentsList: React.FunctionComponent<ComponentsListProps> = ({
items,
useRouterLinks = false,
useHashId,
hashPath,
}) => {
const mappedItems = items
.map(item => {
const href = item.href
? item.href
: getUrl({
name: item.name,
slug: item.slug,
anchor: !useRouterLinks,
hashPath: useRouterLinks ? hashPath : false,
id: useRouterLinks ? useHashId : false,
});
const ComponentsList: React.FunctionComponent<ComponentsListProps> = ({ items }) => {
const visibleItems = items.filter(item => item.visibleName);

return {
...item,
href,
};
})
.filter(item => item.visibleName);

return mappedItems.length > 0 ? <ComponentsListRenderer items={mappedItems} /> : null;
return visibleItems.length > 0 ? <ComponentsListRenderer items={visibleItems} /> : null;
};

ComponentsList.propTypes = {
items: PropTypes.array.isRequired,
hashPath: PropTypes.array,
useRouterLinks: PropTypes.bool,
useHashId: PropTypes.bool,
};

export default ComponentsList;
@@ -84,6 +84,7 @@ const ComponentsListSectionRenderer: React.FunctionComponent<Rsg.TOCItem & JssIn
href={href}
onClick={() => setOpen(!open)}
target={shouldOpenInNewTab ? '_blank' : undefined}
data-testid="rsg-toc-link"
>
{visibleName}
</Link>
@@ -24,6 +24,7 @@ const component = {
name: 'Foo',
visibleName: 'Foo',
slug: 'foo',
href: '#foo',
pathLine: 'foo/bar.js',
props: {
description: 'Bar',
@@ -53,7 +53,7 @@ export default class ReactComponent extends Component<ReactComponentProps, React
config: { pagePerSection },
} = this.context;
const { component, depth, usageMode, exampleMode } = this.props;
const { name, visibleName, slug = '-', filepath, pathLine } = component;
const { name, visibleName, slug = '-', filepath, pathLine, href } = component;
const { description = '', examples = [], tags = {} } = component.props || {};
if (!name) {
return null;
@@ -78,6 +78,7 @@ export default class ReactComponent extends Component<ReactComponentProps, React
...component,
isolated: displayMode !== DisplayModes.all,
}}
href={href}
depth={depth}
>
{visibleName}
@@ -100,7 +100,7 @@ test('should not render section in isolation mode by default', () => {
});

test('should render section in isolation mode', () => {
const { getByLabelText } = render(
const { queryByLabelText } = render(
<Provider
value={{
...context,
@@ -118,5 +118,5 @@ test('should render section in isolation mode', () => {
/>
</Provider>
);
expect(getByLabelText(/show all components/i)).toBeInTheDocument();
expect(queryByLabelText(/open isolated/i)).toBeNull();
});
@@ -8,7 +8,13 @@ describe('SectionHeading', () => {

test('should forward slot properties to the toolbar', () => {
const actual = shallow(
<SectionHeading id="section" slotName="slot" slotProps={{ foo: 1, bar: 'baz' }} depth={2}>
<SectionHeading
id="section"
slotName="slot"
href="/#section"
slotProps={{ foo: 1, bar: 'baz' }}
depth={2}
>
A Section
</SectionHeading>
);
@@ -51,20 +57,4 @@ describe('SectionHeading', () => {

expect(actual.find('h6')).toHaveLength(1);
});

test('the href have id=section query parameter ', () => {
const actual = shallow(
<SectionHeading
id="section"
pagePerSection
slotName="slot"
slotProps={{ foo: 1, bar: 'baz' }}
depth={2}
>
A Section
</SectionHeading>
);

expect(actual.prop('href')).toEqual('/?id=section');
});
});
@@ -2,14 +2,14 @@ import React from 'react';
import PropTypes from 'prop-types';
import Slot from 'rsg-components/Slot';
import SectionHeadingRenderer from 'rsg-components/SectionHeading/SectionHeadingRenderer';
import getUrl from '../../utils/getUrl';

interface SectionHeadingProps {
children?: React.ReactNode;
id: string;
slotName: string;
slotProps: object;
depth: number;
href?: string;
deprecated?: boolean;
pagePerSection?: boolean;
}
@@ -19,13 +19,9 @@ const SectionHeading: React.FunctionComponent<SectionHeadingProps> = ({
slotProps,
children,
id,
pagePerSection,
href,
...rest
}) => {
const href = pagePerSection
? getUrl({ slug: id, id: rest.depth !== 1, takeHash: true })
: getUrl({ slug: id, anchor: true });

return (
<SectionHeadingRenderer
toolbar={<Slot name={slotName} props={slotProps} />}

0 comments on commit 9b6b6f6

Please sign in to comment.
You can’t perform that action at this time.