Skip to content

Commit

Permalink
Added config to tabset, border & onCreateTabSet callback to model & f…
Browse files Browse the repository at this point in the history
…ixed tabset header ref buttons
  • Loading branch information
nealus committed Jun 15, 2021
1 parent 40bb65e commit 3b8eb07
Show file tree
Hide file tree
Showing 15 changed files with 249 additions and 180 deletions.
7 changes: 7 additions & 0 deletions ChangeLog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
0.5.12
New callback on Model to allow TabSet attributes to be set when a tab is moved in such a way
that it creates a new TabSet.
Added config attributes to TabSet and Border
Added headerButtons to ITabSetRenderValues, to allow different set of buttons to be applied to headed
TabSets.

0.5.11
Added StickyButtons to onRenderTabSet render values to allow for implementation of Chrome style + button
Added example of + button to default layout in demo app
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ Note: tabsets can be dynamically created as tabs are moved and deleted when all
| width | null | preferred pixel width |
| height | null | preferred pixel height |
| name | null | named tabsets will show a header bar above the tabs |
| config | null | a place to hold json config used in your own code |
| selected | 0 | index of selected/visible tab in tabset |
| maximized | false | whether tabset is currently maximized to fill view |
| id | auto generated | |
Expand Down Expand Up @@ -442,6 +443,7 @@ Inherited defaults will take their value from the associated global attributes (
| minSize | *inherited* | |
| selected | -1 | index of selected/visible tab in border; -1 means no tab unselected / border closed |
| id | auto generated | border_ + border name e.g. border_left |
| config | null | a place to hold json config used in your own code |
| show | true | show/hide this border |
| children | *required* | a list of tab nodes |
| barSize | *inherited* | size of this border's bar in pixels; if left as 0 then the value will be calculated from the current fontSize |
Expand Down
10 changes: 9 additions & 1 deletion examples/demo/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class App extends React.Component<any, { layoutFile: string | null, model: FlexL
componentDidMount() {
this.loadLayout("default", false);
document.body.addEventListener("touchmove", this.preventIOSScrollingWhenDragging, { passive: false });

// use to generate json typescript interfaces
// Model.toTypescriptInterfaces();
}

save() {
Expand Down Expand Up @@ -61,6 +64,11 @@ class App extends React.Component<any, { layoutFile: string | null, model: FlexL
load = (jsonText: string) => {
let json = JSON.parse(jsonText);
let model = FlexLayout.Model.fromJson(json);
// model.setOnCreateTabSet((tabNode?: TabNode) => {
// console.log("onCreateTabSet " + tabNode);
// // return { type: "tabset", name: "Header Text" };
// return { type: "tabset" };
// });

// you can control where nodes can be dropped
//model.setOnAllowDrop(this.allowDrop);
Expand Down Expand Up @@ -297,7 +305,7 @@ class App extends React.Component<any, { layoutFile: string | null, model: FlexL
alt="Add"
key="Add button"
title="Add Tab (using onRenderTabSet callback, see Demo)"
style={{ marginLeft: 5 }}
style={{ marginLeft: 5, width:24, height:24 }}
onClick={() => this.onAddFromTabSetButton(node)}
/>);
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "flexlayout-react",
"version": "0.5.11",
"version": "0.5.12",
"description": "A multi-tab docking layout manager",
"main": "lib/index.js",
"types": "./declarations/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/AttributeDefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class AttributeDefinitions {
const lines = [];
const sorted = this.attributes.sort((a,b)=> a.name.localeCompare(b.name));
// const sorted = this.attributes;
lines.push("interface I" + name + "Attributes {");
lines.push("export interface I" + name + "Attributes {");
for (let i = 0; i < sorted.length; i++) {
const c = sorted[i];
let type = c.type;
Expand Down
12 changes: 12 additions & 0 deletions src/model/BorderNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class BorderNode extends Node implements IDropTarget {

attributeDefinitions.add("selected", -1).setType(Attribute.NUMBER);
attributeDefinitions.add("show", true).setType(Attribute.BOOLEAN);
attributeDefinitions.add("config", undefined).setType("any");

attributeDefinitions.addInherited("barSize", "borderBarSize").setType(Attribute.NUMBER);
attributeDefinitions.addInherited("enableDrop", "borderEnableDrop").setType(Attribute.BOOLEAN);
Expand Down Expand Up @@ -148,6 +149,17 @@ class BorderNode extends Node implements IDropTarget {
return this._location.getOrientation();
}

/**
* Returns the config attribute that can be used to store node specific data that
* WILL be saved to the json. The config attribute should be changed via the action Actions.updateNodeAttributes rather
* than directly, for example:
* this.state.model.doAction(
* FlexLayout.Actions.updateNodeAttributes(node.getId(), {config:myConfigObject}));
*/
getConfig() {
return this._attributes.config;
}

isMaximized() {
return false;
}
Expand Down
188 changes: 95 additions & 93 deletions src/model/IJsonModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,101 +30,103 @@ export interface IJsonTabNode extends ITabAttributes {
//----------------------------------------------------------------------------------------------------------
// below this line is autogenerated from attributes in code via Model static method toTypescriptInterfaces()
//----------------------------------------------------------------------------------------------------------
interface IGlobalAttributes {
borderAutoSelectTabWhenClosed?: boolean; // default: false
borderAutoSelectTabWhenOpen?: boolean; // default: true
borderBarSize?: number; // default: 0
borderClassName?: string;
borderEnableDrop?: boolean; // default: true
borderMinSize?: number; // default: 0
borderSize?: number; // default: 200
enableEdgeDock?: boolean; // default: true
marginInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0}
splitterSize?: number; // default: -1
tabClassName?: string;
tabCloseType?: ICloseType; // default: 1
tabDragSpeed?: number; // default: 0.3
tabEnableClose?: boolean; // default: true
tabEnableDrag?: boolean; // default: true
tabEnableFloat?: boolean; // default: false
tabEnableRename?: boolean; // default: true
tabEnableRenderOnDemand?: boolean; // default: true
tabIcon?: string;
tabSetAutoSelectTab?: boolean; // default: true
tabSetBorderInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0}
tabSetClassNameHeader?: string;
tabSetClassNameTabStrip?: string;
tabSetEnableDeleteWhenEmpty?: boolean; // default: true
tabSetEnableDivide?: boolean; // default: true
tabSetEnableDrag?: boolean; // default: true
tabSetEnableDrop?: boolean; // default: true
tabSetEnableMaximize?: boolean; // default: true
tabSetEnableTabStrip?: boolean; // default: true
tabSetHeaderHeight?: number; // default: 0
tabSetMarginInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0}
tabSetMinHeight?: number; // default: 0
tabSetMinWidth?: number; // default: 0
tabSetTabLocation?: ITabLocation; // default: "top"
tabSetTabStripHeight?: number; // default: 0
rootOrientationVertical?: boolean; // default: false
export interface IGlobalAttributes {
borderAutoSelectTabWhenClosed?: boolean; // default: false
borderAutoSelectTabWhenOpen?: boolean; // default: true
borderBarSize?: number; // default: 0
borderClassName?: string;
borderEnableDrop?: boolean; // default: true
borderMinSize?: number; // default: 0
borderSize?: number; // default: 200
enableEdgeDock?: boolean; // default: true
marginInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0}
rootOrientationVertical?: boolean; // default: false
splitterSize?: number; // default: -1
tabClassName?: string;
tabCloseType?: ICloseType; // default: 1
tabDragSpeed?: number; // default: 0.3
tabEnableClose?: boolean; // default: true
tabEnableDrag?: boolean; // default: true
tabEnableFloat?: boolean; // default: false
tabEnableRename?: boolean; // default: true
tabEnableRenderOnDemand?: boolean; // default: true
tabIcon?: string;
tabSetAutoSelectTab?: boolean; // default: true
tabSetBorderInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0}
tabSetClassNameHeader?: string;
tabSetClassNameTabStrip?: string;
tabSetEnableDeleteWhenEmpty?: boolean; // default: true
tabSetEnableDivide?: boolean; // default: true
tabSetEnableDrag?: boolean; // default: true
tabSetEnableDrop?: boolean; // default: true
tabSetEnableMaximize?: boolean; // default: true
tabSetEnableTabStrip?: boolean; // default: true
tabSetHeaderHeight?: number; // default: 0
tabSetMarginInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0}
tabSetMinHeight?: number; // default: 0
tabSetMinWidth?: number; // default: 0
tabSetTabLocation?: ITabLocation; // default: "top"
tabSetTabStripHeight?: number; // default: 0
}
interface IRowAttributes {
height?: number;
id?: string;
type: "row";
weight?: number; // default: 100
width?: number;
export interface IRowAttributes {
height?: number;
id?: string;
type: "row";
weight?: number; // default: 100
width?: number;
}
interface ITabSetAttributes {
autoSelectTab?: boolean; // default: true - inherited from global tabSetAutoSelectTab
borderInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0} - inherited from global tabSetBorderInsets
classNameHeader?: string; // - inherited from global tabSetClassNameHeader
classNameTabStrip?: string; // - inherited from global tabSetClassNameTabStrip
enableDeleteWhenEmpty?: boolean; // default: true - inherited from global tabSetEnableDeleteWhenEmpty
enableDivide?: boolean; // default: true - inherited from global tabSetEnableDivide
enableDrag?: boolean; // default: true - inherited from global tabSetEnableDrag
enableDrop?: boolean; // default: true - inherited from global tabSetEnableDrop
enableMaximize?: boolean; // default: true - inherited from global tabSetEnableMaximize
enableTabStrip?: boolean; // default: true - inherited from global tabSetEnableTabStrip
headerHeight?: number; // default: 0 - inherited from global tabSetHeaderHeight
height?: number;
id?: string;
marginInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0} - inherited from global tabSetMarginInsets
minHeight?: number; // default: 0 - inherited from global tabSetMinHeight
minWidth?: number; // default: 0 - inherited from global tabSetMinWidth
name?: string;
selected?: number; // default: 0
tabLocation?: ITabLocation; // default: "top" - inherited from global tabSetTabLocation
tabStripHeight?: number; // default: 0 - inherited from global tabSetTabStripHeight
type: "tabset";
weight?: number; // default: 100
width?: number;
export interface ITabSetAttributes {
autoSelectTab?: boolean; // default: true - inherited from global tabSetAutoSelectTab
borderInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0} - inherited from global tabSetBorderInsets
classNameHeader?: string; // - inherited from global tabSetClassNameHeader
classNameTabStrip?: string; // - inherited from global tabSetClassNameTabStrip
config?: any;
enableDeleteWhenEmpty?: boolean; // default: true - inherited from global tabSetEnableDeleteWhenEmpty
enableDivide?: boolean; // default: true - inherited from global tabSetEnableDivide
enableDrag?: boolean; // default: true - inherited from global tabSetEnableDrag
enableDrop?: boolean; // default: true - inherited from global tabSetEnableDrop
enableMaximize?: boolean; // default: true - inherited from global tabSetEnableMaximize
enableTabStrip?: boolean; // default: true - inherited from global tabSetEnableTabStrip
headerHeight?: number; // default: 0 - inherited from global tabSetHeaderHeight
height?: number;
id?: string;
marginInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0} - inherited from global tabSetMarginInsets
minHeight?: number; // default: 0 - inherited from global tabSetMinHeight
minWidth?: number; // default: 0 - inherited from global tabSetMinWidth
name?: string;
selected?: number; // default: 0
tabLocation?: ITabLocation; // default: "top" - inherited from global tabSetTabLocation
tabStripHeight?: number; // default: 0 - inherited from global tabSetTabStripHeight
type: "tabset";
weight?: number; // default: 100
width?: number;
}
interface ITabAttributes {
className?: string; // - inherited from global tabClassName
closeType?: ICloseType; // default: 1 - inherited from global tabCloseType
component?: string;
config?: any;
enableClose?: boolean; // default: true - inherited from global tabEnableClose
enableDrag?: boolean; // default: true - inherited from global tabEnableDrag
enableFloat?: boolean; // default: false - inherited from global tabEnableFloat
enableRename?: boolean; // default: true - inherited from global tabEnableRename
enableRenderOnDemand?: boolean; // default: true - inherited from global tabEnableRenderOnDemand
floating?: boolean; // default: false
icon?: string; // - inherited from global tabIcon
id?: string;
name?: string; // default: "[Unnamed Tab]"
type?: string; // default: "tab"
export interface ITabAttributes {
className?: string; // - inherited from global tabClassName
closeType?: ICloseType; // default: 1 - inherited from global tabCloseType
component?: string;
config?: any;
enableClose?: boolean; // default: true - inherited from global tabEnableClose
enableDrag?: boolean; // default: true - inherited from global tabEnableDrag
enableFloat?: boolean; // default: false - inherited from global tabEnableFloat
enableRename?: boolean; // default: true - inherited from global tabEnableRename
enableRenderOnDemand?: boolean; // default: true - inherited from global tabEnableRenderOnDemand
floating?: boolean; // default: false
icon?: string; // - inherited from global tabIcon
id?: string;
name?: string; // default: "[Unnamed Tab]"
type?: string; // default: "tab"
}
interface IBorderAttributes {
autoSelectTabWhenClosed?: boolean; // default: false - inherited from global borderAutoSelectTabWhenClosed
autoSelectTabWhenOpen?: boolean; // default: true - inherited from global borderAutoSelectTabWhenOpen
barSize?: number; // default: 0 - inherited from global borderBarSize
className?: string; // - inherited from global borderClassName
enableDrop?: boolean; // default: true - inherited from global borderEnableDrop
minSize?: number; // default: 0 - inherited from global borderMinSize
selected?: number; // default: -1
show?: boolean; // default: true
size?: number; // default: 200 - inherited from global borderSize
type: "border";
export interface IBorderAttributes {
autoSelectTabWhenClosed?: boolean; // default: false - inherited from global borderAutoSelectTabWhenClosed
autoSelectTabWhenOpen?: boolean; // default: true - inherited from global borderAutoSelectTabWhenOpen
barSize?: number; // default: 0 - inherited from global borderBarSize
className?: string; // - inherited from global borderClassName
config?: any;
enableDrop?: boolean; // default: true - inherited from global borderEnableDrop
minSize?: number; // default: 0 - inherited from global borderMinSize
selected?: number; // default: -1
show?: boolean; // default: true
size?: number; // default: 200 - inherited from global borderSize
type: "border";
}
20 changes: 18 additions & 2 deletions src/model/Model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Node from "./Node";
import RowNode from "./RowNode";
import TabNode from "./TabNode";
import TabSetNode from "./TabSetNode";
import {ITabSetAttributes} from "./IJsonModel";
import { adjustSelectedIndexAfterDock, adjustSelectedIndexAfterFloat } from "./Utils";

/** @hidden @internal */
Expand Down Expand Up @@ -121,6 +122,8 @@ class Model {
private _borderRects: { inner: Rect; outer: Rect } = { inner: Rect.empty(), outer: Rect.empty() };
/** @hidden @internal */
private _pointerFine: boolean;
/** @hidden @internal */
private _onCreateTabSet? : (tabNode?: TabNode) => ITabSetAttributes;

/**
* 'private' constructor. Use the static method Model.fromJson(json) to create a model
Expand Down Expand Up @@ -483,6 +486,21 @@ class Model {
return this._onAllowDrop;
}

/**
* set callback called when a new TabSet is created.
* The tabNode can be undefined if it's the auto created first tabset in the root row (when the last
* tab is deleted, the root tabset can be recreated)
* @param onCreateTabSet
*/
setOnCreateTabSet(onCreateTabSet: (tabNode?: TabNode) => ITabSetAttributes) {
this._onCreateTabSet = onCreateTabSet;
}

/** @hidden @internal */
_getOnCreateTabSet() {
return this._onCreateTabSet;
}

static toTypescriptInterfaces() {
console.log(Model._attributeDefinitions.toTypescriptInterface("Global", undefined));
console.log(RowNode.getAttributeDefinitions().toTypescriptInterface("Row", Model._attributeDefinitions));
Expand All @@ -496,7 +514,5 @@ class Model {
}
}

// use to generate json typescript interfaces
// Model.toTypescriptInterfaces();

export default Model;
11 changes: 7 additions & 4 deletions src/model/RowNode.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TabNode } from "..";
import Attribute from "../Attribute";
import AttributeDefinitions from "../AttributeDefinitions";
import DockLocation from "../DockLocation";
Expand Down Expand Up @@ -365,7 +366,7 @@ class RowNode extends Node implements IDropTarget {
} else if (child instanceof TabSetNode && child.getChildren().length === 0) {
if (child.isEnableDeleteWhenEmpty()) {
this._removeChild(child);
if ( child === this._model.getMaximizedTabset()) {
if (child === this._model.getMaximizedTabset()) {
this._model._setMaximizedTabset(undefined);
}
} else {
Expand All @@ -378,7 +379,8 @@ class RowNode extends Node implements IDropTarget {

// add tabset into empty root
if (this === this._model.getRoot() && this._children.length === 0) {
const child = new TabSetNode(this._model, { type: "tabset" });
const callback = this._model._getOnCreateTabSet();
const child = new TabSetNode(this._model, callback ? callback() : {});
this._model._setActiveTabset(child);
this._addChild(child);
}
Expand Down Expand Up @@ -453,7 +455,8 @@ class RowNode extends Node implements IDropTarget {
if (dragNode instanceof TabSetNode) {
tabSet = dragNode;
} else {
tabSet = new TabSetNode(this._model, {});
const callback = this._model._getOnCreateTabSet();
tabSet = new TabSetNode(this._model, callback ? callback(dragNode as TabNode) : {});
tabSet._addChild(dragNode);
}
let size = this._children.reduce((sum, child) => {
Expand All @@ -467,7 +470,7 @@ class RowNode extends Node implements IDropTarget {
tabSet._setWeight(size / 3);

const horz = !this._model.isRootOrientationVertical();

if (horz && dockLocation === DockLocation.LEFT || !horz && dockLocation === DockLocation.TOP) {
this._addChild(tabSet, 0);
} else if (horz && dockLocation === DockLocation.RIGHT || !horz && dockLocation === DockLocation.BOTTOM) {
Expand Down
Loading

0 comments on commit 3b8eb07

Please sign in to comment.