con*_*exo 21 javascript storybook
我有一个输入 Web 组件,它有一个非常简单的 API - 它有 aget state()和set state(model). 该 Web 组件还处理label用于输入的 ,因此简单的model如下所示:
{
"value": "Foobar",
"required": true,
"disabled": false,
"label": {
"text": "Label for input",
"toolTip": "Tooltip for the input's label",
"position": "east"
}
}
Run Code Online (Sandbox Code Playgroud)
现在为了描述argTypes故事,我尝试了以下方法:
export default {
title: `Components/Input/text-input`,
argTypes: {
value: { control: 'text' },
disabled: { control: 'boolean' },
required: { control: 'boolean' },
label: {
text: { control: 'text' },
toolTip: { control: 'text' },
position: { control: 'select', options: ['north', 'south', 'east', 'west'] },
},
},
};
Run Code Online (Sandbox Code Playgroud)
它在 Storybook 中的呈现如下:
正如您所看到的,我没有对该label方面进行适当的控制,例如 的下拉菜单label.position。事实上,即使我argTypes.label根本不定义,我也会得到完全相同的结果。
当然,我可以在我的state结构上做出妥协,让所有label属性都成为扁平 state属性,例如labelText、labelPosition、 和labelToolTip。但据我了解,Storybook 并不意味着以这种方式影响设计决策。
这似乎是一个非常基本的要求,我很惊讶我在文档中找不到任何相关内容。
问题:那么如何在不改变模型结构的情况下实现这一目标呢?
注意:我使用的是 Storybook HTML v6.3.8。
编辑:
到目前为止,我已尝试解决当前的限制:
我使用一个TemplateFactory函数来替换奇数Template.bind({})只是为了创建一个新实例。我们的每个组件都支持通过 setter 设置组件状态el.state。
import { ArgsParser } from '../helper/ArgsParser.js';
export function TemplateFactory(tagName) {
return (args) => {
const el = document.createElement(tagName);
el.state = ArgsParser.expand(args);
return el;
};
}
Run Code Online (Sandbox Code Playgroud)
// ArgsParser
export class ArgsParser {
static flat = (args) => {
const parsedArgs = {};
for (const [key, value] of Object.entries(args)) {
if (['string', 'boolean', 'number'].includes(typeof value)) {
parsedArgs[key] = value;
} else {
for (const innerKey in value) parsedArgs[`${key}.${innerKey}`] = value[innerKey];
}
}
return parsedArgs;
};
static expand(args) {
const parsedArgs = {};
for (const [key, value] of Object.entries(args)) {
const parsedKeys = key.split('.');
if (parsedKeys.length === 1) {
parsedArgs[key] = value;
} else {
const [parentKey, prop] = parsedKeys;
parsedArgs[parentKey] = parsedArgs[parentKey] ?? {};
parsedArgs[parentKey][prop] = value[prop];
}
}
return parsedArgs;
}
}
Run Code Online (Sandbox Code Playgroud)
// custom-text.stories.js
import { TemplateFactory } from '../helper/TemplateFactory.js';
const TAG_NAME = 'custom-text';
export default {
title: `Components/Input/${TAG_NAME}`,
argTypes: {
value: { control: 'text' },
disabled: { control: 'boolean' },
required: { control: 'boolean' },
['label.text']: { control: 'text' },
['label.toolTip']: { control: 'text' },
['label.position']: {
control: { type: 'select', options: ['north', 'south', 'east', 'west'] },
},
},
};
export const EmptyEnabled = TemplateFactory(TAG_NAME);
EmptyEnabled.args = ArgsParser.flat({
value: '',
disabled: false,
label: {
text: 'Empty and Labeled',
toolTip: 'A beautiful tooltip',
position: 'north',
},
});
/* assigns
{
"value": "",
"disabled": false,
"label.text": "Empty and Labeled",
"label.toolTip": "A beautiful tooltip",
"label.position": "north"
}
*/
Run Code Online (Sandbox Code Playgroud)
这导致:
如果我现在修改 3 个标签属性的控件,则不会影响组件。而且,初始状态下的标签也消失了。
如果我分配扩展模型:
export const EmptyEnabled = TemplateFactory(TAG_NAME);
EmptyEnabled.args = {
value: '',
disabled: false,
label: {
text: 'Empty and Labeled',
position: 'north',
},
};
Run Code Online (Sandbox Code Playgroud)
然后我得到这个:
但是当我尝试使用单选按钮时,label.position它不会影响组件,但是(仅在选择两次之后)它会导致 JSON 突然显示undefined为position:
label.text如果我编辑和/或,也会发生同样的情况label.toolTip:
这是我在 Angular 项目中的方法:
type InputPropOverrides = {
'arg1.label': string,
};
export default {
title: 'Components/MyComponent',
component: MyComponent,
decorators: [
moduleMetadata({
imports: [MyModule],
}),
],
argTypes: {
arg1: { ... },
'arg1.label': {
control: {
type: 'text',
},
},
},
} as Meta;
const Template: Story<MyComponent & InputPropOverrides> = (args: MyComponent & InputPropOverrides) => {
const updatedArgs = args;
updatedArgs.menuItem.label = args['arg1.label'];
return { props: updatedArgs };
};
Run Code Online (Sandbox Code Playgroud)
这将呈现一个标有文本字段的额外控件arg1.label。当我将数据输入该字段时,故事将重新呈现,标签字段将被该文本替换。
我可以通过添加额外的 argType 并将该 arg 的值传递回真实的 arg 来手动自定义任何参数的属性。