Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

types of csf properties #3

Merged
merged 18 commits into from
Jan 30, 2020
Merged
28 changes: 28 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import startCase from 'lodash/startCase';
import { StoryProperties, StoryProperty, FieldTypes } from './properties';

export * from './properties';

/**
* Remove punctuation and illegal characters from a story ID.
Expand Down Expand Up @@ -82,3 +85,28 @@ export const parseKind = (kind: string, { rootSeparator, groupSeparator }: Separ
groups,
};
};

/**
* csf story definition
*/
export interface CSFStory {
atanasster marked this conversation as resolved.
Show resolved Hide resolved
story?: {
/**
* story name if differnet from the export name
atanasster marked this conversation as resolved.
Show resolved Hide resolved
*/
name?: string;
atanasster marked this conversation as resolved.
Show resolved Hide resolved

/**
* optional collection of properties, which values
* will be passed onto the story function
*/
properties?: StoryProperties;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the naming here "properties" -- other options that have been suggested include: "args", "values", "controls". Properties is quite long and perhaps easily confused with React "props" which they are very similar to but not the same.

Also, have we decided this is a top-level field on the story metadata already?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i can actually go for props - since we already named the enum PropertyTypes so i think we should go consistent on this - properties or props
For the top level, i thought we had already decided :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the word controls a lot too. I was also pondering data or dataTypes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

controls are rather called the property editors in the UI. The definitions here i cant see being called controls.


/**
* optional collection of story parameters
*/
parameters?: {
[key: string]: any;
atanasster marked this conversation as resolved.
Show resolved Hide resolved
};
};
}
atanasster marked this conversation as resolved.
Show resolved Hide resolved
12 changes: 12 additions & 0 deletions src/properties.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { FieldTypes, StoryProperty } from '.';

describe('properties', () => {
it('type FieldTypes.TEXT', () => {
expect(() => {
const prop: StoryProperty = {
type: FieldTypes.TEXT,
};
return prop.type === 'text';
}).toBeTruthy();
});
});
219 changes: 219 additions & 0 deletions src/properties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
/**
atanasster marked this conversation as resolved.
Show resolved Hide resolved
* Property field types
* examples are propvided for the different types:
atanasster marked this conversation as resolved.
Show resolved Hide resolved
*
*/
export enum FieldTypes {
atanasster marked this conversation as resolved.
Show resolved Hide resolved
/**
* userName: {
* type: csf.FieldTypes.TEXT,
* label: 'Name',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer the term 'title' OR 'name'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name is already used to refer to the property name, but title is available and I can rename it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to keep in mind, in knobs-1 its label

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I know, we are not required to make this match that api.

The word "label" stems from the fact we're showing a <label /> but that's an implementation detail. I'd rather make an attempt to remove confusing language, and name things the same if at all possible

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe its me, but title is confusing for me :) Lets get more feedback, but on my end I would rather not change this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't much like "label". I'd much rather this be "name" (which represents a human readable string of any characters) and have some other property for what is currently name. Maybe it's:

["name", "label"] -> ["id", "name"]

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name is the name of the variable that is passed to the story

for example

export const textStory = ({ text }) => text;
  
textStory.story = {
  properties: {
     text: { type: PropertyTypes.TEXT, label: 'Text' }
  }
}

here name is the text variable name. If we rename the label to name:

     text: { type: PropertyTypes.TEXT, name: 'Text}

now would the user expect to receive { Text } as the prop to the story
Anyway for me - we say variable 'name', not variable 'id' and I will keep confusing what to refer to for this.

Copy link

@jonspalmer jonspalmer Jan 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can live with "name" and "label" I guess. The asymmetry with CSFStory feels really confusing to me.

wouldn't it to be better like this:

export const textStory = ({ text }) => text;
  
textStory.story = {
  label: 'Text Story`, 
  properties: {
     text: { type: PropertyTypes.TEXT, label: 'Text' }
  }
}

then we'd say "The story with name 'textStory'"

(on a similar note that we don't have a better name that 'kind' for collections of stories feels super weird)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shilman - last call - name or label?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was an intentional choice that the "kind" (or "component") has a title but the story has a name -- it makes it simpler to talk about these things and not have to qualify them all the time.

With that in mind it's kind of nice that there's another term for the name of a property.

* defaultValue: 'Storyteller',
atanasster marked this conversation as resolved.
Show resolved Hide resolved
* },
*/
TEXT = 'text',

/**
* age: {
* type: csf.FieldTypes.NUMBER,
* label: 'Age',
* defaultValue: 78,
* range: true,
* min: 0,
* max: 90,
* step: 5,
* },
*/
NUMBER = 'number',

/**
* nice: {
* type: csf.FieldTypes.BOOLEAN,
* label: 'Nice',
* defaultValue: true,
* },
*/
BOOLEAN = 'boolean',

/**
* fruit: {
* type: csf.FieldTypes.OPTIONS,
* label: 'Fruit',
* defaultValue: 'apple',
* options: {
* Apple: 'apple',
* Banana: 'banana',
* Cherry: 'cherry',
* },
* },
*/
OPTIONS = 'options',

/**
* birthday: {
* type: csf.FieldTypes.DATE,
* label: 'Birthday',
* defaultValue: new Date(),
* },
*/
DATE = 'date',

/**
* color: {
* type: 'color',
* defaultValue: '#000000',
* },
*/
COLOR = 'color',

/**
* button: {
* type: csf.FieldTypes.BUTTON,
* onClick: () => {
* ... code to modify some variables
* }
* },
*/
BUTTON = 'button',

/**
* otherStyles: {
* type: csf.FieldTypes.OBJECT,
* label: 'Styles',
* defaultValue: {
* border: '2px dashed silver',
* borderRadius: 10,
* padding: 10,
* },
* },
*/
OBJECT = 'object',

/**
* items: {
* type: csf.FieldTypes.ARRAY,
* label: 'Items',
* defaultValue: ['Laptop', 'Book', 'Whiskey'],
* },
*/
ARRAY = 'array',

/**
* images: {
* type: csf.FieldTypes.FILES,
* label: 'Happy Picture',
* accept: 'image/*',
* defaultValue: [
* 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfiARwMCyEWcOFPAAAAP0lEQVQoz8WQMQoAIAwDL/7/z3GwghSp4KDZyiUpBMCYUgd8rehtH16/l3XewgU2KAzapjXBbNFaPS6lDMlKB6OiDv3iAH1OAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE4LTAxLTI4VDEyOjExOjMzLTA3OjAwlAHQBgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOC0wMS0yOFQxMjoxMTozMy0wNzowMOVcaLoAAAAASUVORK5CYII=',
* ],
* },
*/
FILES = 'files',
}

export interface StoryPropertyObject {
type?: FieldTypes;
atanasster marked this conversation as resolved.
Show resolved Hide resolved

/**
* label to display next to the field editor
* by default uses the property name itself
*/

label?: string;

/**
* placehlder for empty properties
* either undefined defautValue
* or user clears the field
*/
placeholder?: string;

/**
* a default value for the property
*/
defaultValue?: any;
atanasster marked this conversation as resolved.
Show resolved Hide resolved

/**
* hide the label from the property editor
*/
hideLabel?: boolean;
/**
* hide the property editor for this property
* will only use the defaultValue
*/

hidden?: boolean;
/**
* allows grouping of the properties
* in a property editor
* for example different editor tabs
*/
groupId?: string;

// FIELD TYPE SPECIFIC
/**
* for button type fields, an onClick handler
*/
onClick?: () => any;
atanasster marked this conversation as resolved.
Show resolved Hide resolved

/**
* for options type fields
*/

display?: 'select' | 'radio' | 'inline-radio' | 'multi-select' | 'check' | 'inline-check';

/**
* for numeric type fields
*/

/**
* if true, will display a range type slider editor
*/
range?: boolean;
atanasster marked this conversation as resolved.
Show resolved Hide resolved

/**
* minimum allowed value for numeric propery
atanasster marked this conversation as resolved.
Show resolved Hide resolved
*/
min?: number;

/**
* maximum allowed value for numeric propery
atanasster marked this conversation as resolved.
Show resolved Hide resolved
*/
max?: number;

/**
* stepper for numeric editor /i nc/dec value
*/

step?: number;
}

/**
* StoryProperty is a either an object of property settings
* or a shortcut can be used:
* properties: {
* text: 'Hello',
* },
*/

export type StoryProperty = StoryPropertyObject | string;
atanasster marked this conversation as resolved.
Show resolved Hide resolved

/**
* StoryProperties are defined in key value pairs
* the name of the property is the key
* and the value is the StoryProperty
*/
export interface StoryProperties {
[name: string]: StoryProperty;
}

export type StoryPropertiesArray = StoryProperty[];
atanasster marked this conversation as resolved.
Show resolved Hide resolved

/**
* StoryValues are passed into the story function
* either the default value or
* if a property editor is installed, can be modified
*/
export interface StoryValues {
[name: string]: any;
}