Storybook stories disappear when hot module reloading occurs - storybook

When I edit a component and hot module reloading occurs then all the other stories with the same title disappear. The only one still there is the story for the component that I just edited.
In component1.stories.tsx:
import * as React from 'react';
import Provider from './provider';
import Component1Component from './component1';
export const Component1 = () => {
return(
<Provider>
<Component1Component />
<Provider>
)
}
export default {
title: 'Components',
};
In component2.stories.tsx:
import * as React from 'react';
import Provider from './provider';
import Component2Component from './component2';
export const Component2 = () => {
return(
<Provider>
<Component1Component />
<Provider>
)
}
export default {
title: 'Components',
};
So in the above example if I edit component1.tsx then the story for component2.tsx disapears.
In my package.json
"#storybook/addon-actions": "^5.3.19",
"#storybook/addon-info": "^5.3.19",
"#storybook/addon-knobs": "^5.3.19",
"#storybook/addon-links": "^5.3.19",
"#storybook/addon-storysource": "^5.3.19",
"#storybook/addons": "^5.3.19",
"#storybook/react": "^5.3.19"
"react-storybook-addon-props-combinations": "^1.1.0",

Per this Github issue comment:
https://github.com/storybookjs/storybook/issues/7493#issuecomment-514508328
Stories should not have duplicate titles. Try changing your titles to reflect the names of the different components.
This issue was apparently fixed in this PR:
https://github.com/storybookjs/storybook/pull/7542

Related

How to add a global decorator in Storybook

In ReactJs project you can use .storybook/preview.js file to add global decorators and parameters. How to achieve this same behaviour with #storybook/react-native?
What I need is to wrap all my stories with ThemeProvider but the unique way that I found is to wrap individual stories with .addDecorator().
Edit storybook/index.js, by using addDecorator on it.
Example:
import React from 'react'
import { getStorybookUI, configure, addDecorator } from '#storybook/react-native'
import Decorator from './Decorator'
addDecorator(storyFn => (
<Decorator>
{storyFn()}
</Decorator>
))
// import stories
configure(() => {
require('../stories')
}, module)
const StorybookUI = getStorybookUI({ onDeviceUI: true })
export default StorybookUI;;
Found an updated answer in Storybook's own documentation.
// .storybook/preview.js
import React from 'react';
export const decorators = [
(Story) => (
<div style={{ margin: '3em' }}>
<Story />
</div>
),
];
As of June 2021, using storybook v5.3.25, the above answer does not work. However I have managed to figure out a solution.
Decorators must be added to the storybook/index.js file in the following format:
import { ThemeDecorator } from './storybook/ThemeDecorator';
addDecorator(withKnobs); // inbuilt storybook addon decorator
addDecorator(ThemeDecorator);// custom decorator
configure(() => {
loadStories();
}, module);
in this instance, ThemeDecorator.js is a simple wrapper component that renders your story, it would look something like this:
import React from 'react';
import { Provider } from 'theme-provider';
export const ThemeDecorator = (getStory) => (
<Provider>{getStory()}</Provider>
);
Importantly, the addDecorator function expects a React component (not a wrapper function as other examples claim), that it will render, with its props being a reference to an individual story at runtime.

react-admin with next js

I am creating an app with React using Nextjs.
I'd like to really use react-admin for my BO. I tried test example and with react it works perfectly. Unfortunately, while I am trying to include some code to next js - it doesn't work.
I created /admin/dashboard.tsx file, and added next code (previously tested by myself - working code):
import * as React from 'react';
import PostIcon from '#material-ui/icons/Book';
import UserIcon from '#material-ui/icons/Group';
import { Admin, Resource, ListGuesser } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
import { PostList, PostEdit, PostCreate, PostShow } from './react-admin/posts';
import { UserList } from './react-admin/users';
import Dashboard from './react-admin/Dashboard';
import authProvider from './react-admin/AuthProvider';
const App = () => (
<Admin
dataProvider={jsonServerProvider(
'https://jsonplaceholder.typicode.com'
)}
authProvider={authProvider}
dashboard={Dashboard}
>
<Resource
name="posts"
icon={PostIcon}
list={PostList}
edit={PostEdit}
create={PostCreate}
show={PostShow}
/>
<Resource name="users" icon={UserIcon} list={UserList} />
<Resource name="comments" list={ListGuesser} />
</Admin>
);
export default App;
I have the next error (rendering context):
rendering issue
Maybe someone can suggest me some tutorial about react-admin and Next.Js?
Thanks a lot
This Admin component works only on client side , you need to wrap all of it to a single component and use dynamic import which help you to achieve that
//pages/index.tsx
import dynamic from "next/dynamic"
const ReactAdmin = dynamic(() => import("components/admin/ReactAdmin"), {
ssr: false,
})
const HomePage = () => <ReactAdmin />
export default HomePage
and the component itself
//components/admin/ReactAdmin.tsx
import { Admin } from "react-admin"
import jsonServerProvider from "ra-data-json-server"
const dataProvider = jsonServerProvider("https://jsonplaceholder.typicode.com")
const ReactAdmin = () => {
return <Admin dataProvider={dataProvider} />
}
export default ReactAdmin

Import .stories file into another .stories file with Storybook?

Can you import one .stories file into another .stories with Storybook?
Eg I have
/component1/component1.tsx
/component1/component1.stories.tsx
/component2/component2.tsx
/component2/component2.stories.tsx
I would like to also have a story for all of my components:
In /all-components/all-components.stories.tsx
import * as React from 'react';
import Component1Story from '../component1/component1.stories.tsx';
import Component2Story from '../component2/component2.stories.tsx';
export const Test = () => {
return (
<div>
<Component1Story />
<Component2Story />
</div>
);
};
export default {
title: 'Components',
};
I get this error:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of storyFn.
this should be doable as your stories are just React components. Your problem is happening because you're trying to import the default from your module, which is actually just an object:
export default {
title: 'Components',
};
All stories are named exports, and you should import them with destructuring:
import { Component1Story } from '../component1/component1.stories';
import { Component2Story } from '../component2/component2.stories';
I created an example for you which shows a working scenario here.
p.s. It's interesting to know that starting with Storybook 6 there's a new mechanism to simplify the creation and reuse of stories so stay tuned! It's called Args.

is it possible Customise FullCalendar with css in react?

I just begin with FullCalendar , i'm implementing it in a react project , everything good now but i want to customize the actual calendar , iwant it to respect my customer need.
My question : is it possible to add a classname to the FullCalendar component like this :
( i tried but i can't reach the classname in my css file )
<FullCalendar
className= "FullCalendarMonthClient"
defaultView= "dayGridMonth"
plugins={[dayGridPlugin]}
columnHeaderFormat= {{
weekday: "long"
}}
locale="fr"
events={[
{ title: 'event 1', start: '2019-12-06', end: '2019-12-07' },
{ title: 'event 1', start: '2019-12-06', end: '2019-12-07' }
]}
/>
and after use it to customize my calendar with css. I use on the same page an other calendar , a DayView that why i ask to put a classname in my component so i can style my dayview/monthview without touching the Monthview. Or how can i create my own theme ?
Thanks comunity
You can create a styled wrapper that will overwrite the internal styles.
import FullCalendar from "#fullcalendar/react";
import styled from "#emotion/styled";
export const StyleWrapper = styled.div`
.fc td {
background: red;
}
`
const MyApp = ()=> {
return (
<StyleWrapper>
<FullCalendar/>
</StyleWrapper>
);
}
Indeed, a styled wrapper works. For example, try changing the buttons (next, prev) in the Calendar:
import FullCalendar from "#fullcalendar/react";
import timeGridPlugin from '#fullcalendar/timegrid';
// needed for the style wrapper
import styled from "#emotion/styled";
// add styles as css
export const StyleWrapper = styled.div`
.fc-button.fc-prev-button, .fc-button.fc-next-button, .fc-button.fc-button-primary{
background: red;
background-image: none;
}
`
// component with calendar, surround the calendar with the StyleWrapper
function Schedule({ ...props }) {
return (
<StyleWrapper>
<FullCalendar ... />
</StyleWrapper>
);
}
export default Schedule;
If you happen to be using #fullcalendar/react with #fullcalendar/bootstrap and #fullcalendar/rrule YOU NEED TO CHECK YOUR IMPORTS.
I have having an issue where the rrulePlugin was over-riding my bootstrap theme, It was the way I was importing.
Import in this order solved it for me
import React from 'react';
import {Card, CardBody, CardHeader, Col, Row} from 'reactstrap';
import FullCalendar from '#fullcalendar/react';
import dayGridPlugin from '#fullcalendar/daygrid';
import interactionPlugin from '#fullcalendar/interaction';
import timeGridPlugin from '#fullcalendar/timegrid';
import listPlugin from '#fullcalendar/list';
import rrulePlugin from '#fullcalendar/rrule';
import bootstrapPlugin from '#fullcalendar/bootstrap';
<div>
<CardBody className="p-0">
<FullCalendar
ref={calendarRef}
headerToolbar={false}
plugins={[ // plugins MUST be in this order for mine to work or else I get errors
rrulePlugin,
dayGridPlugin,
bootstrapPlugin,
timeGridPlugin,
interactionPlugin,
listPlugin,
]}
initialView="dayGridMonth"
themeSystem="bootstrap"
dayMaxEvents={2}
height={800}
stickyHeaderDates={false}
editable
selectable
selectMirror
select={info => {
console.log("calendarInfo", info.start.toISOString())
if(info.start < moment().subtract(1, 'day')) {
toast(
<Fragment>
<strong>Select Future date</strong>
</Fragment>
);
} else if(isCompose) {
return (calendarView === "Month View" ? setShowTimeModal(!showTimeModal) : ""),
setAddScheduleStartDate(info.start.toString())
} else {
setAddScheduleStartDate(info.start.toISOString());
setIsOpenScheduleModal(true);
}
}}
views={views}
eventTimeFormat={eventTimeFormat}
eventClick={handleEventClick}
events={calendar}
buttonText={buttonText}
eventDrop={(e) => { return console.log("eventDrop ran======-----======", dispatch(calendarUpdate({start: e.event.start, end: e.event.end, _id: e.event._def.extendedProps._id})))}}
/>
</CardBody>
</div>

JssProvider in Material-UI isn't applying my custom production prefix to CSS

I've built a fairly simple React app based on create-react-app which uses the Material-UI for its interface components. It also depends on one of my own packages which also uses Material-UI (same version) for a couple of shared components.
Things were looking good locally until I ran a production build and deployed it. Some of the styles were behaving oddly, for example the Material-UI grid was much narrower than when running locally.
I did some reading and found a few instances of people discussing colliding class names under my scenario. This took me to some official Material-UI documentation which provides the following example code to use a custom class name prefix:
import JssProvider from 'react-jss/lib/JssProvider';
import { createGenerateClassName } from '#material-ui/core/styles';
const generateClassName = createGenerateClassName({
dangerouslyUseGlobalCSS: true,
productionPrefix: 'c',
});
function App() {
return (
<JssProvider generateClassName={generateClassName}>
...
</JssProvider>
);
}
export default App;
Before applying this fix when inspecting my production app's source code I could see the outermost DIV using the CSS class jss2 jss24.
After applying this fix my production app actually visually renders the same layout as my development version and so would appear to be fixed. However, examining the source shows the outermost DIV to have the class MuiGrid-container-2 MuiGrid-spacing-xs-8-24 which suggests to me something isn't right. I could leave it like this but it does mean I'm running with unoptimised code.
Am I doing something wrong here? Or is there an alternative resolution? I'm using current latest version of #material-ui/core (3.3.2) and the full contents of my App.js are:
import React, { Component } from 'react';
import { Provider } from "react-redux";
import { OidcProvider } from 'redux-oidc';
import JssProvider from 'react-jss/lib/JssProvider';
import Routes from './routes';
import store from './store';
import userManager from './utils/userManager';
import {
CustomUiTheme as Theme,
CustomUiLayout as Layout,
CustomUiSnackbar as Snackbar,
CustomUiModalAlert as Alert
} from 'custom-ui';
import Loading from './components/loading';
import { createGenerateClassName } from '#material-ui/core/styles';
const generateClassName = createGenerateClassName({
dangerouslyUseGlobalCSS: true,
productionPrefix: 'tw',
});
class App extends Component {
render() {
return (
<JssProvider generateClassName={generateClassName}>
<Provider store={store}>
<OidcProvider store={store} userManager={userManager}>
<Theme>
<Loading />
<Layout variant="xmas">
<Alert />
<Routes />
<Snackbar />
</Layout>
</Theme>
</OidcProvider>
</Provider>
</JssProvider>
);
}
}
export default App;

Resources