Is your feature request related to a problem? Please describe
Right now select elements shows wrong options for me in controls when using PropTypes.oneOf combined with Object.keys(something). See image in bottom of the page.
Describe the solution you'd like
I saw that it wasn't easy to get the values from prop-types. I provided a hacky way todo it. I don't think it's possible without this kind of hack. I think this could be integrated into controls. As I understand is that you guys read the file as text to extract prop types? I haven't read your codebase but some really weird things were showing while I tried different things.
import PropTypes from 'prop-types';
const escapeRegExp = string => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const extractOneOf = propType => {
const { error } = console;
const isOwnProperty = Object.prototype.hasOwnProperty.call(console, 'error');
const [prop, component, value] = Array.from({ length: 3 }, () =>
escapeRegExp(`${Math.random()}`),
);
const check = `Warning: Failed ${prop} type: Invalid ${prop} \`${prop}\` of value \`${value}\` supplied to \`${component}\`, expected one of `;
let result;
console.error = (...args) => {
const [message] = args;
if (message.startsWith(check)) {
try {
result = JSON.parse(message.slice(check.length - 1, -1));
} catch (e) {
// Continue
}
}
};
PropTypes.checkPropTypes({ [prop]: propType }, { [prop]: value }, prop, component);
// restore console.error
if (isOwnProperty) {
console.error = error;
} else {
delete console.error;
}
return result;
};
console.log(extractOneOf(MyComponent.propTypes.color));
Are you able to assist to bring the feature to reality?
Yes, see my code above.
Additional context
MyComponent.propTypes = {
color: PropTypes.oneOf(Object.keys(defaultTheme)),
};

We were trying to use a Map to drive the values and were disappointed that we had to create an array for it to work.
@anthonybennett can you provide more details about the problem and your solution?
@shilman Sure thing! Here are some screenshots of what we're getting versus what we expect:
Actual

Expected

And here's some sample code:
index.js
// Libraries.
import PropTypes from 'prop-types';
import React from 'react';
// Constants.
export const DEFAULT_VARIANT = 'primary';
export const VARIANTS_MAP = new Map([
['primary', 'primary-button'],
['secondary', 'secondary-button'],
['outlined', 'outlined-button'],
['plain', 'plain-button'],
]);
// Need Array as Storybook Controls is unable to generate valid controls when Map is used.
export const VARIANTS_ARRAY = ['primary', 'secondary', 'outlined', 'plain'];
// Public.
const Button = (props) => {
const { children, variant } = props;
return (
<button type="button" className={VARIANTS_MAP.get(variant)}>
{children}
</button>
);
};
Button.defaultProps = {
variant: DEFAULT_VARIANT,
};
Button.propTypes = {
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
// variant: PropTypes.oneOf([...VARIANTS_MAP.keys()]), <----- ** Controls don't generate as expected. **
variant: PropTypes.oneOf(Array.from(VARIANTS_MAP.keys())), // <----- ** Controls don't generate as expected. **
// variant: PropTypes.oneOf(VARIANTS_ARRAY), <----- Using this as a workaround.
};
export default Button;
index.stories.js
// Libraries.
import React from 'react';
// Dependencies.
import Button from '.';
// Private.
const Template = (args) => <Button {...args} />;
// Public.
export default {
component: Button,
title: 'Test/Button',
argTypes: {
children: {
control: 'text',
},
},
};
export const Default = Template.bind({});
Default.args = {
children: 'This is an Example.',
};
Most helpful comment
We were trying to use a Map to drive the values and were disappointed that we had to create an array for it to work.