react-tabs
Version:
An accessible and easy tab component for ReactJS
111 lines (99 loc) • 3.26 kB
JavaScript
import { deepForEach } from './childrenDeepMap';
import { isTab, isTabList, isTabPanel } from './elementTypes';
export function childrenPropType(props, propName, componentName) {
let error;
let tabsCount = 0;
let panelsCount = 0;
let tabListFound = false;
const listTabs = [];
const children = props[propName];
deepForEach(children, child => {
if (isTabList(child)) {
if (
child.props &&
child.props.children &&
typeof child.props.children === 'object'
) {
deepForEach(child.props.children, listChild =>
listTabs.push(listChild),
);
}
if (tabListFound) {
error = new Error(
"Found multiple 'TabList' components inside 'Tabs'. Only one is allowed.",
);
}
tabListFound = true;
}
if (isTab(child)) {
if (!tabListFound || listTabs.indexOf(child) === -1) {
error = new Error(
"Found a 'Tab' component outside of the 'TabList' component. 'Tab' components " +
"have to be inside the 'TabList' component.",
);
}
tabsCount++;
} else if (isTabPanel(child)) {
panelsCount++;
}
});
if (!error && tabsCount !== panelsCount) {
error = new Error(
`There should be an equal number of 'Tab' and 'TabPanel' in \`${componentName}\`. ` +
`Received ${tabsCount} 'Tab' and ${panelsCount} 'TabPanel'.`,
);
}
return error;
}
export function onSelectPropType(
props,
propName,
componentName,
location,
propFullName,
) {
const prop = props[propName];
const name = propFullName || propName;
let error = null;
if (prop && typeof prop !== 'function') {
error = new Error(
`Invalid ${location} \`${name}\` of type \`${typeof prop}\` supplied ` +
`to \`${componentName}\`, expected \`function\`.`,
);
} else if (props.selectedIndex != null && prop == null) {
error = new Error(
`The ${location} \`${name}\` is marked as required in \`${componentName}\`, but ` +
`its value is \`undefined\` or \`null\`.\n` +
`\`onSelect\` is required when \`selectedIndex\` is also set. Not doing so will ` +
`make the tabs not do anything, as \`selectedIndex\` indicates that you want to ` +
`handle the selected tab yourself.\n` +
`If you only want to set the inital tab replace \`selectedIndex\` with \`defaultIndex\`.`,
);
}
return error;
}
export function selectedIndexPropType(
props,
propName,
componentName,
location,
propFullName,
) {
const prop = props[propName];
const name = propFullName || propName;
let error = null;
if (prop != null && typeof prop !== 'number') {
error = new Error(
`Invalid ${location} \`${name}\` of type \`${typeof prop}\` supplied to ` +
`\`${componentName}\`, expected \`number\`.`,
);
} else if (props.defaultIndex != null && prop != null) {
return new Error(
`The ${location} \`${name}\` cannot be used together with \`defaultIndex\` ` +
`in \`${componentName}\`.\n` +
`Either remove \`${name}\` to let \`${componentName}\` handle the selected ` +
`tab internally or remove \`defaultIndex\` to handle it yourself.`,
);
}
return error;
}