storybookjs / addon-knobs

Storybook addon prop editor component
MIT License
12 stars 17 forks source link

Knobs array of objects does not work with a function property #26

Open kaitmore opened 6 years ago

kaitmore commented 6 years ago

Support request summary

I have a story that uses the object knob with an array of objects. These objects have an "onSort" property:

const columns = [
  {
    title: "Name",
    dataIndex: "name",
    key: "name",
    width: "50%",
    onSort: () => console.log("onSort was called")
  },  ...
]

storiesOf("Table", module).add("simple Table", () => {
  return (
    <Table columns={object("columns", columns)} data={object("data", data)} />
  );
});

This is valid javascript, but serializing it strips out the function property because it's not valid JSON: image

Is there a workaround for this?

Steps to reproduce

Please specify which version of Storybook and optionally any affected addons that you're running

KendraTang commented 6 years ago

@kaitmore May I ask why you closed this issue? I'm encountering this issue, too. Wondering if there's a workaround for this :/

kaitmore commented 6 years ago

@KendraTang Unfortunately I haven't found a workaround. I closed it because I realized this is just how serializing JSON works - It's not really storybook's fault. 🤷‍♀️ If you call JSON.stringify() on that object in the console, it will strip out the function key/val pair.

I'd still be interested to hear about workarounds though, or if storybook has plans to support this sort of use case in the future.

ganorberg commented 5 years ago

@kaitmore I'm not sure if this solution makes sense for Storybook to implement, but I wanted to throw out an option for allowing functions to survive JSON.stringify and JSON.parse in case it might be helpful to you.

You can customize their replacer and reviver functions like so:

/**
* @description Used as JSON.stringify parameter to stringify functions. 
* @param {String} key - If replacer finds object or array, this represents each key
* @param {Any} value - If replacer finds object or array, this represents each value
* @return {Any} Replaces old value. If falsy, removes old value.
*/
function replacer(key, value) {
  if (value instanceof Function) return value.toString();
  return value;
}

/**
* @description Used as JSON.parse parameter to convert a function string to a function
* @param {String} key - If reviver finds object or array, this represents each key
* @param {Any} value - If reviver finds object or array, this represents each value
* @return {Any} - Revives original value or function
*/
function reviver(key, value) {
  return key === 'myFunctionName' ? new Function('return ' + value)() : value;
}

Usage:

const json = JSON.stringify(object, replacer);
JSON.parse(json, reviver);

Of course, we'd want to set up the reviver in such a way that it dynamically uses your function names instead of hard-coding them into the reviver. Otherwise, you'd have to set up a separate reviver for each function.

Hope this helps!

shilman commented 4 years ago

Hi gang, We’ve just released addon-controls in 6.0-beta!

Controls are portable, auto-generated knobs that are intended to replace addon-knobs long term.

Please upgrade and try them out today. Thanks for your help and support getting this stable for release!

shilman commented 4 years ago

For anybody who is interested in Controls but don't know where to start, I've created a quick & dirty step-by-step walkthrough to go from a fresh CRA project to a working demo. Check it out:

=> Storybook Controls w/ CRA & TypeScript

There are also some "knobs to controls" migration docs in the Controls README:

=> How do I migrate from addon-knobs?