diff --git a/ChangeLog.txt b/ChangeLog.txt index 3487c8d9..3e63f96b 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,10 @@ +0.7.11 +Added ITabSetRenderValues.overflowPosition to allow overflow button position to be +specified, if left undefined, position will be after sticky buttons as before. +New model attribute enableRotateBorderIcons, this allows the tab icons in the left and +right borders to rotate with the text or not, default is true. +Added additional class names to edge indicators + 0.7.10 Fix for #399 - the overflow button in a tabset is now placed after any sticky buttons (additional buttons that stick to the last tab of a tabset) diff --git a/README.md b/README.md index 93d54c5f..0aa5ba23 100755 --- a/README.md +++ b/README.md @@ -348,6 +348,7 @@ Attributes allowed in the 'global' element | splitterExtra | 0 | additional width in pixels of the splitter hit test area | | legacyOverflowMenu | false | use the legacy text only overflow menu | | enableEdgeDock | true | | +| enableRotateBorderIcons | true | boolean indicating if tab icons should rotate with the text in the left and right borders | | tabEnableClose | true | allow user to close all tabs via close button | | tabCloseType | 1 | see values in ICloseType | | tabEnableDrag | true | allow user to drag all tabs to new location | @@ -446,7 +447,7 @@ Note: tabsets can be dynamically created as tabs are moved and deleted when all | 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 | -| active | false | whether tabset is currently active; this attribute can only be used in the initial configuration, to change the active tabset you should use the `setActiveTabset` action on the model | +| active | false | whether tabset is currently active; this attribute can only be used in the initial configuration, to change the active tabset you should use the `setActiveTabset` action on the model | | maximized | false | whether tabset is currently maximized to fill view | | enableClose | false | allow user to close tabset via a close button | | id | auto generated | | diff --git a/examples/demo/App.tsx b/examples/demo/App.tsx index 1bb1eab2..cee2d9a5 100755 --- a/examples/demo/App.tsx +++ b/examples/demo/App.tsx @@ -412,6 +412,9 @@ class App extends React.Component this.onAddFromTabSetButton(node)} />); + + // put overflow button before + button (default is after) + // renderValues.overflowPosition=0 } } } diff --git a/examples/demo/layouts/default.layout b/examples/demo/layouts/default.layout index 06590a31..13fd8781 100755 --- a/examples/demo/layouts/default.layout +++ b/examples/demo/layouts/default.layout @@ -3,7 +3,8 @@ "tabEnableFloat": true, "tabSetMinHeight":100, "tabSetMinWidth":100, - "borderMinSize":100 + "borderMinSize":100, + "enableRotateBorderIcons":true }, "layout": { "type": "row", diff --git a/package.json b/package.json index 075615e4..b84007dd 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flexlayout-react", - "version": "0.7.10", + "version": "0.7.11", "description": "A multi-tab docking layout manager", "main": "lib/index.js", "types": "./declarations/index.d.ts", diff --git a/src/Types.ts b/src/Types.ts index 9a6ecf47..0d56a8ef 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -26,7 +26,12 @@ export enum CLASSES { FLEXLAYOUT__BORDER_TOOLBAR_BUTTON_FLOAT = "flexlayout__border_toolbar_button-float", FLEXLAYOUT__DRAG_RECT = "flexlayout__drag_rect", + FLEXLAYOUT__EDGE_RECT = "flexlayout__edge_rect", + FLEXLAYOUT__EDGE_RECT_TOP = "flexlayout__edge_rect_top", + FLEXLAYOUT__EDGE_RECT_LEFT = "flexlayout__edge_rect_left", + FLEXLAYOUT__EDGE_RECT_BOTTOM = "flexlayout__edge_rect_bottom", + FLEXLAYOUT__EDGE_RECT_RIGHT = "flexlayout__edge_rect_right", FLEXLAYOUT__ERROR_BOUNDARY_CONTAINER = "flexlayout__error_boundary_container", FLEXLAYOUT__ERROR_BOUNDARY_CONTENT = "flexlayout__error_boundary_content", diff --git a/src/model/IJsonModel.ts b/src/model/IJsonModel.ts index ced5a7e0..a32eed8c 100755 --- a/src/model/IJsonModel.ts +++ b/src/model/IJsonModel.ts @@ -41,6 +41,7 @@ export interface IGlobalAttributes { borderSize?: number; // default: 200 enableEdgeDock?: boolean; // default: true enableUseVisibility?: boolean; // default: false + enableRotateBorderIcons?: boolean; // default: true legacyOverflowMenu?: boolean; // default: false marginInsets?: IInsets; // default: {"top":0,"right":0,"bottom":0,"left":0} rootOrientationVertical?: boolean; // default: false @@ -108,6 +109,10 @@ export interface ITabSetAttributes { type: "tabset"; weight?: number; // default: 100 width?: number; + + // special attributes are read from initial json but must subseqently be set on the model + maximized?: boolean; // default false + active?:boolean; // default false } export interface ITabAttributes { altName?: string; diff --git a/src/model/Model.ts b/src/model/Model.ts index 1ef3237a..032c9ba7 100755 --- a/src/model/Model.ts +++ b/src/model/Model.ts @@ -52,15 +52,16 @@ export class Model { const attributeDefinitions = new AttributeDefinitions(); attributeDefinitions.add("legacyOverflowMenu", false).setType(Attribute.BOOLEAN); - - // splitter - attributeDefinitions.add("splitterSize", -1).setType(Attribute.NUMBER); - attributeDefinitions.add("splitterExtra", 0).setType(Attribute.NUMBER); attributeDefinitions.add("enableEdgeDock", true).setType(Attribute.BOOLEAN); attributeDefinitions.add("rootOrientationVertical", false).setType(Attribute.BOOLEAN); attributeDefinitions.add("marginInsets", { top: 0, right: 0, bottom: 0, left: 0 }) .setType("IInsets"); attributeDefinitions.add("enableUseVisibility", false).setType(Attribute.BOOLEAN); + attributeDefinitions.add("enableRotateBorderIcons", true).setType(Attribute.BOOLEAN); + + // splitter + attributeDefinitions.add("splitterSize", -1).setType(Attribute.NUMBER); + attributeDefinitions.add("splitterExtra", 0).setType(Attribute.NUMBER); // tab attributeDefinitions.add("tabEnableClose", true).setType(Attribute.BOOLEAN); @@ -207,6 +208,10 @@ export class Model { return this._attributes.enableUseVisibility as boolean; } + isEnableRotateBorderIcons() { + return this._attributes.enableRotateBorderIcons as boolean; + } + /** * Gets the * @returns {BorderSet|*} diff --git a/src/view/BorderButton.tsx b/src/view/BorderButton.tsx index b805675d..1ab13343 100755 --- a/src/view/BorderButton.tsx +++ b/src/view/BorderButton.tsx @@ -137,7 +137,16 @@ export const BorderButton = (props: IBorderButtonProps) => { classNames += " " + node.getClassName(); } - const renderState = getRenderStateEx(layout, node, iconFactory, titleFactory); + let iconAngle = 0; + if (node.getModel().isEnableRotateBorderIcons() === false) { + if (border === "left") { + iconAngle = 90; + } else if (border === "right") { + iconAngle = -90; + } + } + + const renderState = getRenderStateEx(layout, node, iconFactory, titleFactory, iconAngle); let content = renderState.content ? (
diff --git a/src/view/BorderTabSet.tsx b/src/view/BorderTabSet.tsx index f199fbf1..60e25f26 100755 --- a/src/view/BorderTabSet.tsx +++ b/src/view/BorderTabSet.tsx @@ -3,7 +3,7 @@ import { DockLocation } from "../DockLocation"; import { BorderNode } from "../model/BorderNode"; import { TabNode } from "../model/TabNode"; import { BorderButton } from "./BorderButton"; -import { IIcons, ILayoutCallbacks, ITitleObject } from "./Layout"; +import { IIcons, ILayoutCallbacks, ITabSetRenderValues, ITitleObject } from "./Layout"; import { showPopup } from "../PopupMenu"; import { Actions } from "../model/Actions"; import { I18nLabel } from "../I18nLabel"; @@ -117,9 +117,30 @@ export const BorderTabSet = (props: IBorderTabSetProps) => { // allow customization of tabset right/bottom buttons let buttons: any[] = []; let stickyButtons: any[] = []; - const renderState = { headerContent: undefined, buttons, stickyButtons: stickyButtons, headerButtons: [] }; + const renderState : ITabSetRenderValues= { headerContent: undefined, buttons, stickyButtons: stickyButtons, headerButtons: [], overflowPosition: undefined }; layout.customizeTabSet(border, renderState); buttons = renderState.buttons; + + if (renderState.overflowPosition === undefined) { + renderState.overflowPosition = stickyButtons.length; + } + + if (stickyButtons.length > 0) { + if (tabsTruncated) { + buttons = [...stickyButtons, ...buttons]; + } else { + tabs.push(
{ e.preventDefault() }} + className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_STICKY_BUTTONS_CONTAINER)} + > + {stickyButtons} +
); + } + } if (hiddenTabs.length > 0) { const overflowTitle = layout.i18nName(I18nLabel.Overflow_Menu_Tooltip); @@ -132,7 +153,7 @@ export const BorderTabSet = (props: IBorderTabSetProps) => {
{hiddenTabs.length}
); } - buttons.unshift( + buttons.splice(Math.min(renderState.overflowPosition, buttons.length), 0, ); } - - if (stickyButtons.length > 0) { - if (tabsTruncated) { - buttons = [...stickyButtons, ...buttons]; - } else { - tabs.push(
{ e.preventDefault() }} - className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_STICKY_BUTTONS_CONTAINER)} - > - {stickyButtons} -
); - } - } const selectedIndex = border.getSelected(); if (selectedIndex !== -1) { diff --git a/src/view/Layout.tsx b/src/view/Layout.tsx index aab233a2..1bc1012e 100755 --- a/src/view/Layout.tsx +++ b/src/view/Layout.tsx @@ -101,6 +101,9 @@ export interface ITabSetRenderValues { stickyButtons: React.ReactNode[]; buttons: React.ReactNode[]; headerButtons: React.ReactNode[]; + // position to insert overflow button within [...stickyButtons, ...buttons] + // if left undefined position will be after the sticky buttons (if any) + overflowPosition: number | undefined; } export interface ITabRenderValues { @@ -510,10 +513,10 @@ export class Layout extends React.Component { const offset = this.edgeRectLength / 2; const className = this.getClassName(CLASSES.FLEXLAYOUT__EDGE_RECT); const radius = 50; - edges.push(
) - edges.push(
) - edges.push(
) - edges.push(
) + edges.push(
); + edges.push(
); + edges.push(
); + edges.push(
); } // this.layoutTime = (Date.now() - this.start); @@ -596,8 +599,8 @@ export class Layout extends React.Component { if (this.supportsPopout && child.isFloating()) { const rect = this._getScreenRect(child); - const tabBorderWidth= child._getAttr("borderWidth"); - const tabBorderHeight= child._getAttr("borderHeight"); + const tabBorderWidth = child._getAttr("borderWidth"); + const tabBorderHeight = child._getAttr("borderHeight"); if (tabBorderWidth !== -1 && border.getLocation().getOrientation() === Orientation.HORZ) { rect.width = tabBorderWidth; } else if (tabBorderHeight !== -1 && border.getLocation().getOrientation() === Orientation.VERT) { diff --git a/src/view/TabSet.tsx b/src/view/TabSet.tsx index 135f9b6f..259edfef 100755 --- a/src/view/TabSet.tsx +++ b/src/view/TabSet.tsx @@ -4,7 +4,7 @@ import { Actions } from "../model/Actions"; import { TabNode } from "../model/TabNode"; import { TabSetNode } from "../model/TabSetNode"; import { showPopup } from "../PopupMenu"; -import { IIcons, ILayoutCallbacks, ITitleObject } from "./Layout"; +import { IIcons, ILayoutCallbacks, ITabSetRenderValues, ITitleObject } from "./Layout"; import { TabButton } from "./TabButton"; import { useTabOverflow } from "./TabOverflowHook"; import { Orientation } from "../Orientation"; @@ -160,13 +160,34 @@ export const TabSet = (props: ITabSetProps) => { let headerButtons: React.ReactNode[] = []; // allow customization of header contents and buttons - const renderState = { headerContent: node.getName(), stickyButtons, buttons, headerButtons }; + const renderState : ITabSetRenderValues = { headerContent: node.getName(), stickyButtons, buttons, headerButtons, overflowPosition: undefined }; layout.customizeTabSet(node, renderState); const headerContent = renderState.headerContent; stickyButtons = renderState.stickyButtons; buttons = renderState.buttons; headerButtons = renderState.headerButtons; + if (renderState.overflowPosition === undefined) { + renderState.overflowPosition = stickyButtons.length; + } + + if (stickyButtons.length > 0) { + if (tabsTruncated) { + buttons = [...stickyButtons, ...buttons]; + } else { + tabs.push(
{ e.preventDefault() }} + className={cm(CLASSES.FLEXLAYOUT__TAB_TOOLBAR_STICKY_BUTTONS_CONTAINER)} + > + {stickyButtons} +
); + } + } + if (hiddenTabs.length > 0) { const overflowTitle = layout.i18nName(I18nLabel.Overflow_Menu_Tooltip); let overflowContent; @@ -178,7 +199,7 @@ export const TabSet = (props: ITabSetProps) => {
{hiddenTabs.length}
); } - buttons.unshift( + buttons.splice(Math.min(renderState.overflowPosition, buttons.length), 0,