Skip to content

Commit

Permalink
Isolation mode for CSF stories
Browse files Browse the repository at this point in the history
  • Loading branch information
sapegin committed May 5, 2021
1 parent 599b755 commit 2c9eade
Show file tree
Hide file tree
Showing 12 changed files with 42 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/client/rsg-components/Context/Context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface StyleGuideContextContents {
config: Rsg.ProcessedStyleguidistConfig;
slots: Record<string, (SlotObject | React.FunctionComponent<any>)[]>;
displayMode: string;
targetIndex?: number;
targetIndex?: number | string;
}

export function useStyleGuideContext(): StyleGuideContextContents {
Expand Down
4 changes: 2 additions & 2 deletions src/client/rsg-components/Playground/PlaygroundRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const styles = ({ space, color, borderRadius }: Rsg.Theme) => ({
});

interface PlaygroundRendererProps extends JssInjectedProps {
exampleIndex: number;
exampleIndex: number | string;
componentName: string;
padded: boolean;
preview: React.ReactNode;
Expand Down Expand Up @@ -79,7 +79,7 @@ export const PlaygroundRenderer: React.FunctionComponent<PlaygroundRendererProps

PlaygroundRenderer.propTypes = {
classes: PropTypes.objectOf(PropTypes.string.isRequired).isRequired,
exampleIndex: PropTypes.number.isRequired,
exampleIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
componentName: PropTypes.string.isRequired,
padded: PropTypes.bool.isRequired,
preview: PropTypes.node.isRequired,
Expand Down
16 changes: 15 additions & 1 deletion src/client/rsg-components/ReactComponent/ReactComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default function ReactComponent(props: ReactComponentProps) {
const { component, depth, usageMode, exampleMode } = props;
const { name: componentName, visibleName, slug = '-', filepath, pathLine, href } = component;
const { description = '', content, tags = {} } = component.props || {};
const { __examples: examples = [] } = content || {};
const { __examples: examples = [], __namedExamples: namedExamples = {} } = content || {};

if (!componentName) {
return null;
Expand All @@ -50,6 +50,7 @@ export default function ReactComponent(props: ReactComponentProps) {
};

function getExamples() {
// Isolated mode: fenced code block example
if (typeof targetIndex === 'number' && examples[targetIndex] && content) {
const example = examples[targetIndex];
return (
Expand All @@ -61,6 +62,19 @@ export default function ReactComponent(props: ReactComponentProps) {
);
}

// Isolated mode: named story imported from a CSF file
if (typeof targetIndex === 'string' && namedExamples[targetIndex] && content) {
const example = namedExamples[targetIndex];
return (
<MdxWrapper componentName={componentName} exampleMode={exampleMode} {...content}>
<MdxCode index={targetIndex} className="language-jsx">
{example}
</MdxCode>
</MdxWrapper>
);
}

// Static code
if (content) {
return <Examples content={content} componentName={componentName} exampleMode={exampleMode} />;
}
Expand Down
4 changes: 2 additions & 2 deletions src/client/rsg-components/StyleGuide/StyleGuide.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export interface StyleGuideProps {
welcomeScreen?: boolean;
patterns?: string[];
displayMode?: string;
targetIndex?: number;
targetIndex?: number | string;
allSections?: Rsg.Section[];
pagePerSection?: boolean;
}
Expand All @@ -61,7 +61,7 @@ export default class StyleGuide extends Component<StyleGuideProps, StyleGuideSta
welcomeScreen: PropTypes.bool,
patterns: PropTypes.array,
displayMode: PropTypes.string,
targetIndex: PropTypes.number,
targetIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
allSections: PropTypes.array.isRequired,
pagePerSection: PropTypes.bool,
};
Expand Down
5 changes: 3 additions & 2 deletions src/client/rsg-components/mdx/public/Story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export default function Story({ id, name, ...modifiers }: Props) {
);
}

const code = namedExamples?.[getLocalExampleNameById(id)];
const key = getLocalExampleNameById(id);
const code = namedExamples?.[key];
if (!code) {
return (
<Para>
Expand All @@ -70,7 +71,7 @@ export default function Story({ id, name, ...modifiers }: Props) {
exampleMode={exampleMode}
documentScope={documentScope}
exampleScope={exampleScope}
modifiers={modifiers}
modifiers={{ ...modifiers, index: key }}
/>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/client/rsg-components/slots/IsolateButton.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ it('should renderer a link to isolated mode', () => {
});

it('should renderer a link to example isolated mode', () => {
const actual = shallow(<IsolateButton name="Pizza" href="/#pizza" example={3} />);
const actual = shallow(<IsolateButton name="Pizza" href="/#pizza" exampleIndex={3} />);

expect(actual).toMatchSnapshot();
});
Expand Down
4 changes: 2 additions & 2 deletions src/client/rsg-components/slots/IsolateButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import getUrl from '../../utils/getUrl';

export interface IsolateButtonProps {
name: string;
exampleIndex?: number;
exampleIndex?: number | string;
isolated?: boolean;
href: string;
}
Expand Down Expand Up @@ -35,7 +35,7 @@ const IsolateButton = ({ name, exampleIndex, isolated, href }: IsolateButtonProp

IsolateButton.propTypes = {
name: PropTypes.string.isRequired,
exampleIndex: PropTypes.number,
exampleIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
isolated: PropTypes.bool,
};

Expand Down
8 changes: 4 additions & 4 deletions src/client/utils/__tests__/getUrl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,22 @@ describe('getUrl', () => {
});

it('should return an isolated example URL', () => {
const result = getUrl({ name, slug, example: 3, isolated: true }, loc);
const result = getUrl({ name, slug, exampleIndex: 3, isolated: true }, loc);
expect(result).toBe('/styleguide/#!/Components/FooBar/3');
});

it('should return an isolated example for a HashedURL', () => {
const result = getUrl({ name, slug, example: 0, isolated: true }, locHashedURL);
const result = getUrl({ name, slug, exampleIndex: 0, isolated: true }, locHashedURL);
expect(result).toBe('/styleguide/#!/FooBar/0');
});

it('should return an isolated example=0 URL', () => {
const result = getUrl({ name, slug, example: 0, isolated: true }, loc);
const result = getUrl({ name, slug, exampleIndex: 0, isolated: true }, loc);
expect(result).toBe('/styleguide/#!/Components/FooBar/0');
});

it('should return an absolute isolated example URL', () => {
const result = getUrl({ name, slug, example: 3, isolated: true, absolute: true }, loc);
const result = getUrl({ name, slug, exampleIndex: 3, isolated: true, absolute: true }, loc);
expect(result).toBe('http://example.com/styleguide/#!/Components/FooBar/3');
});

Expand Down
6 changes: 3 additions & 3 deletions src/client/utils/getInfoFromHash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ export default function getInfoFromHash(
isolate?: boolean;
hashArray?: string[];
targetName?: string;
targetIndex?: number;
targetIndex?: number | string;
} {
const shouldIsolate = hasInHash(hash, '#!/');
if (shouldIsolate || hasInHash(hash, '#/')) {
const hashArray = getHashAsArray(hash, shouldIsolate ? '#!/' : '#/');
const targetHash = hashArray[hashArray.length - 1];
return {
isolate: shouldIsolate,
hashArray: hashArray.filter(item => !hasDigitsOnly(item)),
hashArray: hashArray.filter((item) => !hasDigitsOnly(item)),
targetName: hashArray[0],
targetIndex: hasDigitsOnly(targetHash) ? parseInt(targetHash, 10) : undefined,
targetIndex: hasDigitsOnly(targetHash) ? parseInt(targetHash, 10) : targetHash,
};
}
return {};
Expand Down
6 changes: 3 additions & 3 deletions src/client/utils/getRouteData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function getRouteData(
sections: Rsg.Section[],
hash: string,
pagePerSection = false
): { sections: Rsg.Section[]; displayMode: string; targetIndex?: number } {
): { sections: Rsg.Section[]; displayMode: string; targetIndex?: number | string } {
// Parse URL hash to check if the components list must be filtered
const infoFromHash = getInfoFromHash(hash);

Expand Down Expand Up @@ -101,8 +101,8 @@ export default function getRouteData(
}

// If a single component or section is filtered and a fenced block index
// is specified hide all other examples
if (typeof targetIndex === 'number') {
// or story name is specified hide all other examples
if (typeof targetIndex !== 'undefined') {
displayMode = DisplayModes.example;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/client/utils/getUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ interface GetUrlOptions {
/**
* Example index inside the Mdx document
*/
exampleIndex: number;
exampleIndex: number | string;
anchor: boolean;
/**
* Isolated mode
Expand Down
7 changes: 5 additions & 2 deletions src/typings/RsgExample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import { ComponentType } from 'react';

export interface Modifiers {
/** Example index inside the Mdx document, added automatically */
index: number;
/**
* Example index inside the Mdx document: either number or the name of the
* exported CSF story, added automatically
*/
index: number | string;
/** Render static highlighted code instead of a dynamic preview with a code editor */
static?: boolean;
/** Renders an example code but hides the code editor */
Expand Down

0 comments on commit 2c9eade

Please sign in to comment.