Storybook saving values of properties with the same name - reactjs

If I am at the docs page and then go to another component that has the same name on the properties it will cause the value of the control input of that property to the keep that same value.
What's even odder is that storybook isnt even using that value, the component is still rendered with the "real" value.
This same bug is causing some controls to just be "set object", "set string" etc.
If I go to the canvas page and back, or if click the "reset controls" button it will restore to default and show objects and strings as they should.
Anyone encountered this and figured out a solution?
I am suspecting it has something to do with using Typescript, and some of the documentations being automatically generated somehow, is it possible to turn this off?
Here is some example code of a story:
import Component from "##/components/Component";
import { Meta, Story } from "#storybook/react";
const meta: Meta = {
title: "Components/Component",
component: Component,
};
export default meta;
const Template: Story = (args) => (
<div style={{ maxWidth: "500px" }}>
<Component
header=""
items={[]}
{...args}
/>
</div>
);
export const Story = Template.bind({});
Story.args = {
header: "Header",
list: [
{
name: "Test 1",
},
{
name: "Test 2",
},
],
};
Story.argTypes = {
list: {
description: "List of items",
table: {
type: {
summary: "Array",
},
},
},
};

I figured it out.
I had several components all under the same title: "XXX/YYY" instead of "XXX/YYY/ComponentName".

Related

Next JS - how to give object a unique id?

I am trying to give my object a unique id by using Math.random, but I am getting the error below. If I change the Math.random to a integer like 4, the error goes away but I need the id to be unique.
Unhandled Runtime Error
Error: Text content does not match server-rendered HTML.
See more info here: https://nextjs.org/docs/messages/react-hydration-error
const data = [
{
id: Math.random(),
sentence: 'hello there',
},
{
id: Math.random(),
sentence: 'bye!',
},
]
export default function Index(props) {
return (
<div>
<h1>{data[0].id}</h1>
<h1>{data[0].sentence}</h1>
<h1>{data[1].id}</h1>
<h1>{data[1].sentence}</h1>
</div>
)
}
As explained in my comment and one of the answers, the problem is happening because Next.js pre-renders pages, therefore, the random number generated by Math.random() when pre-rendering the page on the server doesn't match the random number generated client-side when hydration occurs.
I'm not quite sure what you're trying to achieve by setting random ids to what seems to be "dummy data" (You could do it manually with constant values that will match both server and client-side) but I understand that this might be a simplified example.
You have a couple of options, typically you'd want to move any random generation code/logic inside a useEffect hook so it executes on the client-side only.
Another solution would be to move your "dummy data" and the rendering of this data to a separate component, let's call it DummyComponent:
const data = [
{
id: Math.random(),
sentence: 'hello there',
},
{
id: Math.random(),
sentence: 'bye!',
},
]
const DummyComponent = () => (
<>
<h1>{data[0].id}</h1>
<h1>{data[0].sentence</h1>
<h1>{data[1].id}</h1>
<h1>{data[1].sentence}</h1>
</>
)
export default DummyComponent
And import it dynamically on your page disabling ssr:
import dynamic from 'next/dynamic'
const DummyComponent = dynamic(() => import('../components/DummyComponent'), {
ssr: false,
})
export default function Index(props) {
return (
<div>
<DummyComponent />
</div>
)
}
Use the uuid npm package to generate unique id's.
import { v4 } from "uuid";
const data = [
{
id: v4(),
sentence: 'hello there',
},
{
id: v4(),
sentence: 'bye!',
},
]
First, the page is rendered on the server, then returned to the client to rehydrate, two times initializing data would cause different ID values. This is called hydration mismatch, which is solved by useId in React 18
But using NextJS, you could solve this problem by initializing data on server to keep it consistent
export default function Index(props) {
return (
<div>
<h1>{props.data[0].id}</h1>
<h1>{props.data[0].sentence}</h1>
<h1>{props.data[1].id}</h1>
<h1>{props.data[1].sentence}</h1>
</div>
);
}
export async function getServerSideProps(context) {
return {
props: {
data: [
{
id: Math.random(),
sentence: 'hello there',
},
{
id: Math.random(),
sentence: 'bye!z',
},
],
}, // will be passed to the page component as props
};
}
Stackblitz demo
References
getServerSideProps

Fluent-UI's dropdown and combobox both not working

I have a React app with Fluent-UI 8 set up using npm install #fluentui/react according to the documents from Microsoft.
When I try their combobox or dropdown components, the dropdown list doesn't appear when clicked on it. I use their examples from the docs, which compiles without errors. But none of their examples work out of the box, and no other information is provided.
The problem is that the dropdown list does not appear when clicked on. Not in Edge, not in Firefox. When I check the elements on the page, I do not see the html elements with the list items, although I can cycle through them with the arrow keys. The list appears from the side when the window is tablet format, and setting ResponsiveMode did nothing. Whith a normal screen however, nothing is displaying, and no onchange events are fired.
This is my code for the dropdown:
import { IStackTokens, ResponsiveMode, Stack } from '#fluentui/react';
import { Dropdown, DropdownMenuItemType, IDropdownOption, IDropdownStyles } from '#fluentui/react/lib/Dropdown';
const dropdownStyles: Partial<IDropdownStyles> = { dropdown: { width: 300 } };
const DropdownControlledMultiExampleOptions = [
{ key: 'fruitsHeader', text: 'Spooler status', itemType: DropdownMenuItemType.Header },
{ key: 'apple', text: 'Apple' },
{ key: 'banana', text: 'Banana' },
{ key: 'grape', text: 'Grape' },
{ key: 'broccoli', text: 'Broccoli' },
{ key: 'carrot', text: 'Carrot' },
{ key: 'lettuce', text: 'Lettuce' },
];
export const DropdownList: React.FunctionComponent = () => {
const stackTokens: IStackTokens = { childrenGap: 20 };
return (
<Stack tokens={stackTokens}>
<Dropdown
placeholder="Select an option"
label="Disabled responsive"
options={DropdownControlledMultiExampleOptions}
styles={dropdownStyles}
responsiveMode={ResponsiveMode.unknown}
/>
<Dropdown
placeholder="Select an option"
label="Responsive with panel"
options={DropdownControlledMultiExampleOptions}
styles={dropdownStyles}
/>
</Stack>
);
};
Which I load in my app.tsx
function App() {
return (
<div className="App">
<DropdownList/>
</div>
);
}
Does anyone have an idea how I can get this to work? Or what is causing this?
EDIT and possible solution: It seems that removing the <React.Strict> tags in index.tsx does the job. Don't know why, but then the Fluid-UI controls work fine.

AntD Tree: need help! can't pass react element as icon OR title for antd tree

I'm using the AntD tree and I have a react element that I want to pass as either an icon or a title because it has custom styling. Due to it being IP I can't share too much code, but my question is:
how can I pass a react element (see below i.e. generic name) as either a title or icon and have antD tree render it?
i.e. this is what I want to pass as a prop to the icon or title
import React from 'react';
const genericName = (props) => {
// code uses props to get some infor for Color
// cant share code due to proprietary reasons
// but it is not needed for this question
const colorHTML = getColor(Color);
return (
<div>
<div className={`colors from`}>${colorHTML}</div>
{pin}
</div>
);
};
export default genericName;
in my console you can see node.icon is a typeof react.element. I want to target that and just pass the prop into antD tree as either title or icon
i.e.
return (
<Tree
icon={node.icon}
/>
)
I've searched and similar answers were given before antD forbid the use of children and strictly allows treeData. All examples I see only use strings in titles/icons, but since antD documentation is very limited, I need to know if my use case is possible. Right now, for the life of me I can't understand why it doesn't populate.
Thank you in advance.
It should definitely work to put a JSX component as title within treeData. Take a look at this snippet, I added a Icon here in one of the titles:
import React from 'react'
import { RightCircleOutlined } from '#ant-design/icons'
type Props = {}
import { Tree } from 'antd';
import type { DataNode, TreeProps } from 'antd/es/tree';
const treeData: DataNode[] = [
{
title: <span>{<RightCircleOutlined />} parent</span>, //icon added here
key: '0-0',
children: [
{
title: 'parent 1-0',
key: '0-0-0',
disabled: true,
children: [
{
title: 'leaf',
key: '0-0-0-0',
disableCheckbox: true,
},
{
title: 'leaf',
key: '0-0-0-1',
},
],
},
{
title: 'parent 1-1',
key: '0-0-1',
children: [{ title: <span style={{ color: '#1890ff' }}>sss</span>, key: '0-0-1-0' }],
},
],
},
];
const Demo: React.FC = () => {
const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
console.log('selected', selectedKeys, info);
};
const onCheck: TreeProps['onCheck'] = (checkedKeys, info) => {
console.log('onCheck', checkedKeys, info);
};
return (
<Tree
checkable
defaultExpandedKeys={['0-0-0', '0-0-1']}
defaultSelectedKeys={['0-0-0', '0-0-1']}
defaultCheckedKeys={['0-0-0', '0-0-1']}
onSelect={onSelect}
onCheck={onCheck}
treeData={treeData}
/>
);
};
export default Demo;

using react-draft-wysiwyg converted to html

I am using react WYSIWYG for the first time in a custom email template. i need to draft template messages that will be sent as email body. from WYSIWYG editor, i can achive this. during the extraction of html from draft-js, i am unable to return jsx or html that will be rendered as body when the email is sent. before i send the email itself, i first tried rendering the value extracted from the editor, but istead, it renders stringified html, when i try using draft to markdown, this work but html formatting is lost, which is also what am not looking for. below is my code
import React, { useState } from "react";
import { Editor } from "react-draft-wysiwyg";
import { EditorState, convertToRaw } from "draft-js";
import "../../node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
import "./editor.css";
import draftToHtml from "draftjs-to-html";
import draftToMarkdown from 'draftjs-to-markdown';
const EditorBook = () => {
const [editorState, setEditorState] = useState(EditorState.createEmpty());
const text = draftToHtml(convertToRaw(editorState.getCurrentContent()))
return (
<div>
<Editor
editorState={editorState}
editorClassName="editor-class"
onEditorStateChange={setEditorState}
placeholder="enter text reminders ..."
mention={{
separator: " ",
trigger: "#",
suggestions: [
{ text: "APPLE", value: "apple", url: "apple" },
{ text: "BANANA", value: "banana", url: "banana" },
{ text: "CHERRY", value: "cherry", url: "cherry" },
{ text: "DURIAN", value: "durian", url: "durian" },
{ text: "EGGFRUIT", value: "eggfruit", url: "eggfruit" },
{ text: "FIG", value: "fig", url: "fig" },
{ text: "GRAPEFRUIT", value: "grapefruit", url: "grapefruit" },
{ text: "HONEYDEW", value: 'honeydew', url: "honeydew" },
],
}}
/>
<button
onClick={() =>
console.log(
draftToHtml(convertToRaw(editorState.getCurrentContent()))
)
}
>
console.log me
</button>
<div>
{text}
</div>
</div>
);
};
export default EditorBook;
when console loged, this is what appears to the console:
<p>here is sample text</p>
now this same text, is what is displayed to the frontend "as a string" yet i just want the text only to be displayed like so:
const text = draftToHtml(convertToRaw(editorState.getCurrentContent()))
when i do this in the react JSX,
<div>
{text}
</div>
i get this in the browser:
here is sample text
when i use the "draftToMarkdown" i get what i want, but formating is lost like this:
const honey = draftToMarkdown(convertToRaw(editorState.getCurrentContent()))
when console logged
<p>this is a sample text</p>
<p>hello every one. (this statement should be on the second line)</p>
result on the browser:
this is a sample text hello every one. (this statement should be on the second line)
I understand the the is an inline block element but i want it in a way that when the keyboard 'Enter' is press, and some text followed, it should appear as a newline in the browser. how can i achieve this ?

StencilJS passing in array of objects from React

I have a stencil component that takes an array of objects to display. I am trying to pass that array in from my react app, and have been following this example to do that. If i log the component with the array passed in, i can see that it appears to be formed correctly.
The actual component I built to create the reference to handle the array is where my problem is, and I just can't figure out where I made the mistake, as there is an issue with the example. My component inside my react app, which returns the stencil component is as follows
const ActionBar: React.FC<{ pageActions: pageActionsObj }> = ({ pageActions }) => {
const elementRef = useRef(null);
useEffect(() => {
(elementRef.current).pageActionList = pageActions;
}, [pageActions]);
return <pw-actionbar ref={elementRef}></pw-actionbar>;
};
and I try to use it as a regular component as such
<ActionBar pageActions={pageActionsObj}/>
Where the array that im passing as the prop is
export const pageActionsObj = [
{
name: "Users",
page: "partner",
icon: "pw-i-filled-multiple-users",
onpage: false
},
{
name: "Billing",
page: "billing",
icon: "pw-i-filled-billing",
onpage: false
},
{
name: "Helpdesk",
page: "help-desk",
icon: "pw-i-filled-help",
onpage: false
},
{
name: "My Profile",
page: "profile",
icon: "pw-i-filled-user",
onpage: true
},
{
name: "Sign Out",
page: "sign-out",
icon: "pw-i-filled-sign-out",
onpage: false
},
];
I very strongly believe that the way the component is set up, paired with the way I am passing in the array as a prop is causing the issue. I have been stuck for hours. What am i missing?

Resources