Skip to content

Commit aaf0471

Browse files
chrisdopuchsapegin
authored andcommitted
Fix: Allow isolated components with duplicate names (fixes styleguidist#1454)
If you have more than one component with the same name, the isolated mode will incorrectly show all of the components of the same name (instead of just the one you clicked on). This fix solves the issue by prepending the existing hash path from the page the user came from. By prepending this hash path, Styleguidist correctly scopes the isolated example to just the desired component.
1 parent c171330 commit aaf0471

File tree

6 files changed

+50
-14
lines changed

6 files changed

+50
-14
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import React from 'react';
2+
3+
/**
4+
* Simple text label.
5+
*/
6+
export default function Label() {
7+
return <span>I am a duplicate Label component!</span>;
8+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Should use the `fantasy` font inherited from `body`:
2+
3+
```jsx
4+
<Label />
5+
```
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './Label';

examples/sections/styleguide.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ module.exports = {
5252
exampleMode: 'expand', // 'hide' | 'collapse' | 'expand'
5353
usageMode: 'expand', // 'hide' | 'collapse' | 'expand'
5454
},
55+
{
56+
name: 'Labels',
57+
components: () => ['./src/components/MyLabel/Label.js'],
58+
exampleMode: 'expand', // 'hide' | 'collapse' | 'expand'
59+
usageMode: 'expand', // 'hide' | 'collapse' | 'expand'
60+
},
5561
{
5662
name: 'Others',
5763
components: () => ['./src/components/RandomButton/RandomButton.js'],

src/client/utils/__tests__/getUrl.spec.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,37 +31,37 @@ describe('getUrl', () => {
3131

3232
it('should return an isolated URL', () => {
3333
const result = getUrl({ name, slug, isolated: true }, loc);
34-
expect(result).toBe('/styleguide/#!/FooBar');
34+
expect(result).toBe('/styleguide/#!/Components/FooBar');
3535
});
3636

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

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

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

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

5757
it('should return a nochrome URL', () => {
5858
const result = getUrl({ name, slug, nochrome: true }, loc);
59-
expect(result).toBe('/styleguide/?nochrome#!/FooBar');
59+
expect(result).toBe('/styleguide/?nochrome#!/Components/FooBar');
6060
});
6161

6262
it('should return an absolute nochrome URL', () => {
6363
const result = getUrl({ name, slug, nochrome: true, absolute: true }, loc);
64-
expect(result).toBe('http://example.com/styleguide/?nochrome#!/FooBar');
64+
expect(result).toBe('http://example.com/styleguide/?nochrome#!/Components/FooBar');
6565
});
6666

6767
it('should return a route path', () => {

src/client/utils/getUrl.js

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,14 @@
1313
*/
1414
export default function getUrl(
1515
{ name, slug, example, anchor, isolated, nochrome, absolute, hashPath, id, takeHash } = {},
16-
{ origin, pathname, hash } = window.location
16+
{ origin, pathname, hash = '' } = window.location
1717
) {
1818
let url = pathname;
1919

20+
const currentHash = hash.indexOf('?') > -1 ? hash.substring(0, hash.indexOf('?')) : hash;
21+
2022
if (takeHash) {
21-
if (hash.indexOf('?') > -1) {
22-
url += hash.substring(0, hash.indexOf('?'));
23-
} else {
24-
url += hash;
25-
}
23+
url += currentHash;
2624
}
2725

2826
if (nochrome) {
@@ -34,7 +32,7 @@ export default function getUrl(
3432
if (anchor) {
3533
url += `#${slug}`;
3634
} else if (isolated || nochrome) {
37-
url += `#!/${encodedName}`;
35+
url += buildIsolatedOrNoChromeFragment({ currentHash, encodedName });
3836
}
3937

4038
if (hashPath) {
@@ -59,3 +57,21 @@ export default function getUrl(
5957

6058
return url;
6159
}
60+
61+
/**
62+
* Gets the URL fragment for an isolated or nochrome link.
63+
*
64+
* @param {string} $.currentHash The current hash fragment of the page
65+
* @param {string} $.encodedName The URL encoded name of the component
66+
* @return {string}
67+
*/
68+
function buildIsolatedOrNoChromeFragment({ currentHash, encodedName }) {
69+
const stripFragment = /^#\/?/;
70+
const stripTrailingSlash = /\/$/;
71+
const currentHashPath =
72+
// skip if we are already using `#!/`
73+
currentHash && !currentHash.includes('#!/')
74+
? currentHash.replace(stripFragment, '').replace(stripTrailingSlash, '') + '/'
75+
: '';
76+
return `#!/${currentHashPath}${encodedName}`;
77+
}

0 commit comments

Comments
 (0)