@storybook/addon-links
Version:
Link stories together to build demos and prototypes with your UI components
99 lines (88 loc) • 2.21 kB
JavaScript
import global from 'global';
import qs from 'qs';
import { addons, makeDecorator } from '@storybook/addons';
import { STORY_CHANGED, SELECT_STORY } from '@storybook/core-events';
import { toId } from '@storybook/csf';
import { PARAM_KEY } from './constants';
const {
document,
HTMLElement
} = global;
export const navigate = params => addons.getChannel().emit(SELECT_STORY, params);
export const hrefTo = (title, name) => {
return new Promise(resolve => {
const {
location
} = document;
const query = qs.parse(location.search, {
ignoreQueryPrefix: true
});
const existingId = [].concat(query.id)[0];
const titleToLink = title || existingId.split('--', 2)[0];
const id = toId(titleToLink, name);
const url = `${location.origin + location.pathname}?${qs.stringify(Object.assign({}, query, {
id
}), {
encode: false
})}`;
resolve(url);
});
};
const valueOrCall = args => value => typeof value === 'function' ? value(...args) : value;
export const linkTo = (idOrTitle, nameInput) => (...args) => {
const resolver = valueOrCall(args);
const title = resolver(idOrTitle);
const name = resolver(nameInput);
if (title !== null && title !== void 0 && title.match(/--/) && !name) {
navigate({
storyId: title
});
} else {
navigate({
kind: title,
story: name
});
}
};
const linksListener = e => {
const {
target
} = e;
if (!(target instanceof HTMLElement)) {
return;
}
const element = target;
const {
sbKind: kind,
sbStory: story
} = element.dataset;
if (kind || story) {
e.preventDefault();
navigate({
kind,
story
});
}
};
let hasListener = false;
const on = () => {
if (!hasListener) {
hasListener = true;
document.addEventListener('click', linksListener);
}
};
const off = () => {
if (hasListener) {
hasListener = false;
document.removeEventListener('click', linksListener);
}
};
export const withLinks = makeDecorator({
name: 'withLinks',
parameterName: PARAM_KEY,
wrapper: (getStory, context) => {
on();
addons.getChannel().once(STORY_CHANGED, off);
return getStory(context);
}
});