How to implement tabs with multiple editors? #383
Replies: 3 comments
-
I am still working on this.. |
Beta Was this translation helpful? Give feedback.
-
I'm not sure if understanding your problem but why not just do: <Drawer />
<Tabs>
<Tab>
<Editor>
<Frame>
...
</Frame>
</Editor>
</Tab>
<Tab>
<Editor>
<Frame>
...
</Frame>
</Editor>
</Tab>
</Tabs> |
Beta Was this translation helpful? Give feedback.
-
I once implemented a working Tabs component. The most important thing is to always render the tabs to the Dom and only make them After that it's a bit of We scrapped the component because we replaced tabs with other Ui, but I have found some old code. Sadly it relies on some other internal components, but I hope it helps. export const TabsContainer: UserComponent<TabsContainerProps> = ({
children,
color,
appearance,
className,
style,
defaultSelectedIndex,
}) => {
const {
id: tabsContainerId,
connectors: { connect },
} = useNode();
const { actions, query } = useEditor();
const [selectedIndex, setSelectedIndex] = React.useState(
defaultSelectedIndex
);
// because of the automatically added invisible fragment we need to get the children's children
const tabs = (React.Children.toArray(children)[0] as ReactElement).props
.children;
return (
<div
style={style}
className={classNames(
'ts-tabs',
'my-2',
getColorClassName('tabs', color ?? 'primary'),
getAppearanceClassName('tabs', appearance),
className
)}
ref={connect}
>
<div className="scroll-container">
<ul className="nav nav-tabs">
{tabs.map(
(tab: ReactElement<Pick<Node, 'id'> & TabProps>, index: number) => {
const tabId = tab.props.id;
return (
<TabHeader
key={`tab-header-${tabId}`}
isActive={selectedIndex === index}
tabId={tabId}
onClick={() => {
setSelectedIndex(index);
}}
/>
);
}
)}
{query.getOptions().enabled && (
<li
className="nav-item"
onClick={() => {
const newNode = query.createNode(
<Element canvas is={Tab} {...Tab.defaultProps}></Element>
);
actions.add(newNode, tabsContainerId);
// TODO uncomment as soon as available (after craftjs update)
// actions.selectNode(newNode.id)
}}
>
<span className="nav-link">
<Icon icon={faPlus} />
</span>
</li>
)}
</ul>
</div>
<div className="tab-content">{tabs[selectedIndex]}</div>
</div>
);
};
TabsContainer.defaultProps = {
defaultSelectedIndex: 0,
color: 'primary',
appearance: 'outline',
}; And the code for the tab: export interface TabProps extends WithColor, WithAppearance, WithStyling {
icon?: IconLookup;
title?: string;
}
export interface TabHeaderProps {
isActive: boolean;
onClick: () => void;
tabId: string;
}
export const TabHeader: FunctionComponent<TabHeaderProps> = ({
onClick,
isActive,
tabId,
}) => {
const { connectors, props } = useEditor((_state, query) => ({
props: query.node(tabId).get().data.props,
}));
const content = props.icon ? (
<span className={classNames('nav-link', { active: isActive })}>
<Icon icon={findIconDefinition(props.icon)} />{' '}
<ControlledContentEditable nodeId={tabId} propName="title" />
</span>
) : (
<span className={classNames('nav-link', { active: isActive })}>
<ControlledContentEditable nodeId={tabId} propName="title" />
</span>
);
return (
<li
className={classNames('nav-item', { active: isActive })}
ref={(ref) => {
connectors.select(ref, tabId);
}}
onClick={onClick}
>
{content}
</li>
);
};
export const Tab: UserComponent<TabProps> = ({
children,
style,
className,
}) => {
const {
connectors: { connect },
} = useNode();
return (
<div ref={connect} className={classNames(className, 'p-2')} style={style}>
<CanvasContainer>{children}</CanvasContainer>
</div>
);
};
Tab.defaultProps = {
title: 'New Tab',
}; The code enables you to have a TabsContainer. You can drag Tabs into the TabsContainer and then drag Components into the Tab And on CreateNode of the TabContainer we create to empty tabs: <Element canvas is={TabsContainer} {...props}>
<Element canvas is={Tab} title="Tab A" />
<Element canvas is={Tab} title="Tab B" />
</Element> |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi.
I am trying to create multiple tabs, where each tab content is a CraftJS editor. Here's a nerfed version of the app:
If I wrapped
Frame
withEditor
as the parent, the drawer cannot render the layers anymore. So how can I change the tab without the same nodes being rendered in the other tab? Is there a way to move the state outsideEditor
to make it a controlled component like text field?PS: I did consider serializing to move out the state. But I think that would slow down the code.
Beta Was this translation helpful? Give feedback.
All reactions