I build a headless tab manager js framework

Wing Lo
3 min readSep 11, 2022

--

Recently, I wrote an tab manager framework that you can assemble yourself with any UI framework, and the result is as follows

Project url

meogic-tab-manager

A brief description of how to use

The following is an example using vue only

How to define data model

After npm install @meogic/tab-manager-vue — save, create the data model for example:

export class UserTabNode extends TabNode<Component> {
static getType(): string {
return 'user-tab';
}
private __user: User;
static clone(node: UserTabNode): UserTabNode {
const tabNode = new UserTabNode(node.__user, node.__active, node.__key)
return tabNode;
}


constructor(user:User, active?: boolean, key?: NodeKey) {
super(user.name, active, key);
this.__user = user
}

//region getters
getUser(): User {
const self = this.getLatest()
return self.__user
}
//endregion

//region mutations
setUser(value: User): this {
const self = this.getWritable()
self.__user = value
return this
}
//endregion

decorate(tabManager: TabManager, config: TabManagerConfig): Component {
return h(
UserDetail,
this.exportJSON()
);
}
static importJSON<T>(serializedNode: SerializedUserTabNode): UserTabNode {
const node = $createUserTabNode(serializedNode.user, serializedNode.active);
return node;
}

exportJSON(): SerializedUserTabNode {
return {
name: this.getName(),
active: this.getActive(),
user: this.getUser(),
type: 'tab',
version: 1,
};
}
}

export function $createUserTabNode(user: User, active?: boolean) {
return new UserTabNode(user, active)
}

UserTabNode

The function named $createUserTabNode, starting with $, identifies that it can only be used in the update callback function

How to define the page structure

Once the data model has been created, the next step is to build the page

<TabManagerComposer :initial-config="config" @error="onError">
<TabManagerRootElement/>
<TabGroupBarPlugin/>
<Decorators/>
<TabGroupResizablePlugin/>
<TabGroupDraggablePlugin/>
</TabManagerComposer>
  • Here TabManagerRootElement is the root DOM object of your entire tab manager
  • TabManagerComposer is the context of the tabManager object for the whole subcomponent
  • The purpose of the config here is not only to specify the name of the css class to be used for the corresponding theme, and the registered Node class, but also to set the initialization state, such as
function prepared() {
const root = $getRoot();
const window = $createWindowNode()
const tabGroupNode = $createResizableTabGroupNode()
tabGroupNode.setActive(true)
tabGroupNode.setPercent(33.33)
const tabGroupBar = $createTabGroupBarNode()
tabGroupNode.append(tabGroupBar)
const tabGroupNode2 = $createResizableTabGroupNode()
tabGroupNode2.setPercent(33.33)
const tabGroupBar2 = $createTabGroupBarNode()
tabGroupNode2.append(tabGroupBar2)
const tabGroupNode3 = $createResizableTabGroupNode()
tabGroupNode3.setPercent(33.33)
const tabGroupBar3 = $createTabGroupBarNode()
tabGroupNode3.append(tabGroupBar3)
root.append(
window.append(
tabGroupNode,
tabGroupNode2,
tabGroupNode3
)
)
}
const config = {
tabManagerState: prepared,
namespace: 'Playground',
nodes: [...PlaygroundNodes],
tabNodes: [UserTabNode],
tabGroupNodes: [ResizableTabGroupNode],
theme
}

App.vue

Simple interaction

You can see that the UserTabNode defined above is not used here, that is because adding a tab requires a series of actions to be triggered

tabManager.update(() => {  
const tabGroupNode = $getNodeByKey(tabGroupNodeKey)
if(!$isTabGroupNode(tabGroupNode)){
return
}
const userTabNode = $createUserTabNode(user)
tabGroupNode.append(userTabNode)
$updateTabGroupBarNode(tabGroupNode)
$activeTabNode(userTabNode)
})

TabManagerOpenPlugin

For example, when we click on an item in the user list page and need to open it in Tab
1. find the tabGroupNode that is currently active
2. append the corresponding userTabNode to the tabGroupNode.
3. update the tabGroupBar corresponding to this tabGroupNode with $updateTabGroupBarNode to add the corresponding tab header
4. Finally, use $activeTabNode to activate the currently added tabNode and hide the other tabNodes

Local trial

The above basically demonstrates how to define the data model, how to define the page structure, and the simple interaction, you may still feel a bit confused, it’s okay, there are already examples in the project code.

git clone git@github.com:meogic-tech/meogic-tab-manager.git
npm i --force
npm run dev

Then you can see it on localhost

At last

Due to time and energy constraints, I only provide the vue example and tool library, if you like this project and are willing to contribute code, you are welcome to PR.
Finally, if this project is helpful to you, please give me a star, thank you!

--

--