From 2605743895413130d28ced91a44d197ba8458618 Mon Sep 17 00:00:00 2001 From: powerdragonfire Date: Mon, 15 Sep 2025 17:47:17 +0100 Subject: [PATCH 1/2] Initialised fork --- CHANGELOG.md | 448 +------------------------------------------------ package.json | 77 +++++---- vite.config.ts | 6 +- 3 files changed, 53 insertions(+), 478 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dadcff4..a2efae1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,447 +1,5 @@ -## 0.8.17 - 2025-05-03 +## Change Log: -* **Fixed:** Issues with tab redraw and scroll when page is scrolled down (corrects fix for [#488]) +## 1.0.0 -## 0.8.16 - 2025-04-30 - -* **Fixed:** [#488](https://github.com/caplin/FlexLayout/issues/488) Wrong tab position on scroll - -## 0.8.15 - 2025-04-25 - -* **Added:** Option to tabset customization to allow the creation of a control to the left of the tabs (see the 'New Features' layout in the demo for an example). -* **Changed:** Only re-render tabs when they are visible. - -## 0.8.14 - 2025-04-18 - -* **Removed:** UMD builds. -* **Changed:** Package type is now 'module'. -* **Changed:** Demo build now uses Vite. -* **Added:** Icons are now exported. -* **Added:** Error boundary now has a retry button. - -## 0.8.13 - 2025-04-15 (deprecated) - -Published with missing types in module exports - -## 0.8.12 - 2025-04-15 - -* **Updated:** Dependencies. -* **Fixed:** Initial tab flash. -* **Disabled:** Popout of MUI tabs in demo (because Emotion generated styles in production cannot be copied to the popout window). -* **Converted:** Cypress tests to Playwright. -* **Updated:** Demo app to use React hooks. - -## 0.8.11 - 2025-04-09 (deprecated) - -Published with additional files by mistake. - -## 0.8.10 - 2025-04-09 - -* **Fixed:** [#481](https://github.com/caplin/FlexLayout/issues/481) Numpad Enter doesn't confirm rename. -* **Workaround:** Addressed a `` issue in React 19 ([https://github.com/facebook/react/issues/29585](https://github.com/facebook/react/issues/29585)) causing tabs to re-mount when moved. - -## 0.8.9 - 2025-04-04 - -* **Fixed:** [#480](https://github.com/caplin/FlexLayout/issues/480) `Actions.selectTab` is called when closing a Tab. -* **Added:** `isVisible()` method to `TabNode`. - -## 0.8.8 - 2025-03-22 - -* **Enabled:** Escape key to close the overflow menu. -* **Prevented:** Initial reposition flash when there are hidden tabs. -* **Removed:** Roboto font from the demo. - -## 0.8.7 - 2025-03-17 - -* **Improved:** Tab scrolling into the visible area. -* **Added:** Sections about tab and tabset customization to the README. - -## 0.8.6 - 2025-03-15 - -* **Restructured:** SCSS files to remove the use of the deprecated `@import` rule. -* **Added:** `combined.css` containing all themes. -* **Updated:** Demo to use `combined.css` for simple theme switching using class names. -* **Added:** Option in the demo to show the layout structure. - -## 0.8.5 - 2025-03-08 - -* **Changed:** The mini scrollbar now only shows when tabs are hovered over. - -## 0.8.4 - 2025-03-03 - -* **Added:** Attribute `'enableTabScrollbar'` to `TabSet` and `Border` nodes. Enabling this attribute will show a mini 'scrollbar' for the tabs to indicate the scroll position. See the Demo app's default layout for an example. - -## 0.8.3 - 2025-02-21 - -* **Prevented:** Sticky buttons from scrolling when there are no tabs. -* **Fixed:** Border `'show'` attribute. -* **Removed:** Code to adjust popout positions when loading. - -## 0.8.2 - 2025-02-15 - -* **Updated:** Dependencies. -* **Enabled:** Use with React 19. -* **Removed:** Strict mode from the demo due to a bug in React 19 ([https://github.com/facebook/react/issues/29585](https://github.com/facebook/react/issues/29585)) causing tabs to re-mount when moved. -* **Used:** CodeSandbox in `README.md` since React 19 doesn't create UMD versions needed by JSFiddle. - -## 0.8.1 - 2024-09-24 - -* **Fixed:** `enableDrag` on tab and tabset nodes. -* **Fixed:** Calculation for min/max tabset height from min/max tab height. -* **Modified:** Stylesheet code in the demo to reduce flash. - -## 0.8.0 - 2024-09-12 - -**New Features:** - -* Wrap tabs option. -* Improved popouts, no longer keep a placeholder tab. -* Drag from the overflow menu. -* Improved splitter resizing. -* Now uses HTML drag and drop to allow cross-window dragging. -* Rendering now uses flexbox rather than absolute positions, which should make styling easier. -* Rounded theme. -* Updated dependencies. - -**Breaking Changes:** - -* The `addTabWithDragAndDrop` signature has changed and must now be called from a drag start handler. -* The `moveTabWithDragAndDrop` signature has changed and must now be called from a drag start handler. -* Removed `addTabWithDragAndDropIndirect`. -* Removed `onTabDrag` (custom internal drag). -* Removed the `font` prop; use CSS variables `--font-size` and `--font-family` instead. -* Removed the `titleFactory` and `iconFactory` props; use `onRenderTab` instead. -* Removed the tabset header option. -* Removed attributes: `for insets`, `tabset header`, `row/tabset width and height`, `legacymenu`, etc. -* Several CSS changes reflect the use of flexbox. - -## 0.7.15 - 2023-11-14 - -* **Added:** Arrow icon to edge indicators. - -## 0.7.14 - 2023-11-10 - -* **Added:** Attribute `tabsetClassName` to tab nodes. This will add the class name to the parent tabset when there is a single stretched tab. Updated the mosaic layout in the demo to use this to color headers. - -## 0.7.13 - 2023-10-22 - -* **New attribute on tabset:** `enableSingleTabStretch` will stretch a single tab to take up all the remaining space and change the style to look like a header. Combined with `enableDrop`, this can be used to create a Mosaic-style layout (headed panels without tabs). See the new Mosaic Style layout in the Demo. -* The layout methods `addTabToTabSet` and `addTabToActiveTabSet` now return the added `TabNode`. -* **Fixed:** [#352](https://github.com/caplin/FlexLayout/issues/352) - `Layout.getDomRect` returning null. - -## 0.7.12 - -* `Action.setActiveTabset` can now take `undefined` to unset the active tabset. -* **Added:** Tab attribute `contentClassName` to add a class to the tab content. - -## 0.7.11 - -* **Added:** `ITabSetRenderValues.overflowPosition` to allow the overflow button position to be specified. If left undefined, the 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; the default is `true`. -* **Added:** Additional class names to edge indicators. - -## 0.7.10 - -* **Fixed:** [#399](https://github.com/caplin/FlexLayout/issues/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) but before any other buttons. -* **Enabled:** Sticky buttons in border tabsets. - -## 0.7.9 - -* **Fixed:** Drag issue found when used in a devtool extension. -* **Fixed:** Double render in popout when in strict mode. - -## 0.7.8 - -* **Fixed:** Popout size of tab with individual border size. -* **Hid:** Edge handles when disabled. -* **Updated:** Version of Cypress. - -## 0.7.7 - -* **Fixed:** [#379](https://github.com/caplin/FlexLayout/issues/379) - `uuid` could only be generated in secure contexts. - -## 0.7.6 - -* **Removed:** Dependency on the `uuid` package. -* **Added:** `action` argument to the `onModelChange` callback. - -## 0.7.5 - -* **Fixed:** [#340](https://github.com/caplin/FlexLayout/issues/340) - Error dragging a tabset into an empty tabset. - -## 0.7.4 - -* **Fixed:** Popout windows when using ``. -* **Output now targets:** ES6. - -## 0.7.3 - -* **Fixed:** Right edge marker location when border `enableAutoHide`. -* Dragging out a selected border tab will now leave the border unselected. - -## 0.7.2 - -* **New Layout JSON tabs:** Added to the demo. -* **Added:** `--color-icon` CSS rootOrientationVertical. - -## 0.7.1 - -* **Fixed:** [#310](https://github.com/caplin/FlexLayout/issues/310) - Added new layout method: `moveTabWithDragAndDrop(node)` to allow tab dragging to be started from custom code. - -## 0.7.0 - -* **Updated:** Dependencies, in particular, changed React peer dependency to React 18. -* **Made changes for:** React 18. - -## 0.6.10 - -* **Fixed:** [#312](https://github.com/caplin/FlexLayout/issues/312), Chrome warning for wheel event listener. - -## 0.6.9 - -* **Fixed:** [#308](https://github.com/caplin/FlexLayout/issues/308), Allow dragging within a maximized tabset. - -## 0.6.8 - -* **Added:** `onTabSetPlaceHolder` prop to render the tabset area when there are no tabs. - -## 0.6.7 - -* **Added:** More CSS variables, Underline theme, and updated dependencies. - -## 0.6.6 - -* **Fixed:** [#296](https://github.com/caplin/FlexLayout/issues/296). - -## 0.6.5 - -* **Fixed:** [#289](https://github.com/caplin/FlexLayout/issues/289), Allow setting attributes to undefined value. - -## 0.6.4 - -* Code tidy. -* Updated dependencies. - -## 0.6.3 - -* **Changed:** To using named rather than default import/exports. This will require changing top-level imports: - ```javascript - // from: - import FlexLayout from 'flexlayout-react'; - // to: - import * as FlexLayout from 'flexlayout-react'; - ``` -* **Added:** Typedoc link to README. - -## 0.6.2 - -* **Extended:** `icons` prop to allow the use of functions to set icons. -* **Added:** `onShowOverflowMenu` callback for handling the display of the tab overflow menu. - -## 0.6.1 - -* **Used:** Portal for the drag rectangle to preserve React context in `onRenderTab`. - -## 0.6.0 - -* **Changed:** Icons to use SVG images, which will now scale with the font size. -* **Improved:** Element spacing, removed most margin/padding spacers. -* The overflow menu and drag rectangle will now show the tab icon and content as rendered in the tab. -* **Added:** `altName` attribute to `TabNode`. This will be used as the name in the overflow menu if there is no `name` attribute (e.g., the tab has just an icon). -* **Changed:** The drag outline colors from red/green to light blue/green. -* **Removed:** `closeIcon` prop from `Layout`; use the `icons` property instead. -* **Changed:** `onRenderDragRect` callback to take a `ReactElement` rather than a string. The content now contains the tab button as rendered. - -## 0.5.21 - -* **Fixed:** Copying stylesheet links for popout windows when `cssRules` throw an exception. -* **Added:** Option `enableUseVisibility` to allow the use of `visibility: hidden` rather than `display: none` for hiding elements. - -## 0.5.20 - -* **Added:** Cypress Tests. -* **Fixed:** Bug with tab icon not showing. - -## 0.5.19 - -* **Added:** `onRenderFloatingTabPlaceholder` callback prop for rendering the floating tab placeholder. -* **Changed:** Style sheets to use CSS custom properties (variables) for several values. -* **Fixed:** Selected index in a single empty tabset. -* **Added:** `onContextMenu` callback prop for handling context menus on tabs and tabsets. -* **Added:** `onAuxMouseClick` callback prop for handling mouse clicks on tabs and tabsets with alt, meta, shift keys, and also handles center mouse clicks. - -## 0.5.18 - -* **Added:** `onRenderDragRect` callback prop for rendering the drag rectangles. -* **New border attribute:** `enableAutoHide`, to hide the border if it has zero tabs. - -## 0.5.17 - -* **New global option:** `splitterExtra`, to allow splitters to have extended hit test areas. This makes it easier to use narrow splitters. -* **Added new TabNode attributes:** `borderWidth` and `borderHeight`. These allow for individual border sizes for certain tabs. -* **Fixed:** [#263](https://github.com/caplin/FlexLayout/issues/263) - Border splitters not taking the minimum size of the center into account. -* **Improved:** Algorithm for finding the drop location. -* **Additional parameter:** `cursor`, for `onTabDrag`. - -## 0.5.16 - -* **Added:** 'New Features' layout to the demo. -* **New tab attribute:** `helpText`, to show a tooltip over tabs. -* **New model action:** `deleteTabset`, to delete a tabset and all its child tabs. -* **New tabset attribute:** `enableClose`, to close the tabset. - -## 0.5.15 - -* **Added new Layout prop:** `onTabDrag` that allows tab dragging to be intercepted. -* **Added example of `onTabDrag`:** In the demo app, the example shows a list where tabs can be dragged into, moved in the list, and dragged back out into the layout. -* Node IDs that are not assigned a value are now auto-generated using a UUID rather than a rolling number (e.g., previous ID: #3, new ID: #0c459064-8dee-444e-8636-eb9ab910fb27). -* **Made:** The `toJson` method of the node public. - -## 0.5.14 - -* **Fixed:** An issue with copying styles for a floating window when using a CSS-in-JS solution. -* **Fixed:** [#227](https://github.com/caplin/FlexLayout/issues/227) - Edge rects are not moved if the window is resized while dragging. - -## 0.5.13 - -* **Added prop:** `realtimeResize` to make tabs resize as their splitters are dragged. - **Warning:** This can cause resizing to become choppy when tabs are slow to draw. - -## 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 a different set of buttons to be applied to headed `TabSets`. - -## 0.5.11 - -* **Added:** `StickyButtons` to `onRenderTabSet` render values to allow for the implementation of a Chrome-style + button. -* **Added:** Example of the + button to the default layout in the demo app. - -## 0.5.10 - -* Adjusted the selected tab when tabs are popped out to an external window. - -## 0.5.9 - -* `TitleFactory` can now return an object with `titleContent` and `name` (name is used for the tab overflow menu). -* Corrected the position of `rootOrientationVertical` in the TypeScript JSON model. - -## 0.5.8 - -* **Fixed:** [#172](https://github.com/caplin/FlexLayout/issues/172) - Added global `rootOrientationVertical` attribute to allow vertical layout for the root 'row'. -* **Added:** Missing exports for the TypeScript JSON model. -* **Moved:** CRA example to a separate repo. - -## 0.5.7 - -* **Added:** TypeScript typings for the model JSON. -* **Fixed:** Drag rectangle showing as a dot before the first position was found (when dragging into the layout). -* **Fixed:** [#191](https://github.com/caplin/FlexLayout/issues/191) - Global Attributes for class names not working. -* **Fixed:** [#212](https://github.com/caplin/FlexLayout/issues/212) - TypeScript issue with `ILayoutState`. - -## 0.5.6 - -* **Added:** External drag and drop into the layout; see the new `onExternalDrag` prop. -* **Updated:** Demo to accept dragged links, HTML, and text. -* Tab scrolling direction changed to match VSCode. -* Improved positioning of a single tab when the overflow menu is shown. -* Some small changes to theme colors. - -## 0.5.5 - -* **Fixed:** [#170](https://github.com/caplin/FlexLayout/issues/170) - Closing the last tab of a maximized tabset crashes the layout. - -## 0.5.4 - -* **Fixed:** Issue running with React 17.0.1. -* Window title now updates when a tab is renamed. - -## 0.5.3 - -* **Changed:** Class name strings to enum values. -* **Replaced:** TSLint with ESLint. -* **Added:** Create-React-App (CRA) example. -* **New theme:** 'light' (lighter and without box shadows, gradients). -* **Renamed:** Existing 'light' theme to 'gray'. - -## 0.5.2 - -* **Fixed:** Issues caused by double touch/mouse events in iOS. -* **Prevented:** iOS scroll during drag in the demo app. -* **Added:** Extra option to `onRenderTab` to allow the name of the item in the overflow menu to be set. -* **New option:** `closeType` for tabs. -* The maximized tabset now sets others to `display: none` rather than using `z-index`. -* **Disabled:** Maximize if only one tabset. -* Splitters will now default to 8px on desktop and 12px on mobile (so they can be tapped more easily). -* Close element is enlarged on mobile. - -## 0.5.1 - -* Various small fixes. - -## 0.5.0 - -* Overflowing tabs now scroll to keep the selected tab in view. They can also be manually scrolled using the mouse wheel. -* Now works on scrolling pages. -* **NOTE:** Several CSS classes with names starting with `flexlayout__tabset_header...` have been renamed to `flexlayout__tabset_tabbar...`. - -## 0.4.9 - -* Keep the selected tab in the tabset/border when another tab is moved out. - -## 0.4.8 - -* **Added:** Minimum size attributes on tabset and border. -* **Added:** Extra CSS classes on elements for border and splitter styling. - -## 0.4.7 - -* **Added:** `font` property. -* Font now defaults to `medium`. -* Tabs now auto-adjust to the current font. -* **Added:** `fontSize` dropdown to the demo. -* **Modified:** CSS for the above font size changes and to remove some fixed sizes. -* **Added:** New attributes to control the auto-selection of tabs. - -## 0.4.6 - -* **Added:** `icons` prop to allow default icons to be replaced. -* **Added:** `tabLocation` attribute to tabsets to allow top and bottom tab placement. -* **Modified:** CSS; the default font is now 14px. - -## 0.4.5 - -* **Fixed:** Use of global objects for use when server-side rendering. -* **Added:** Error boundary around tab contents to prevent tab rendering exceptions from crashing the app. - -## 0.4.4 - -* **Changed:** All components except `Layout` to use React Hooks. -* Popouts now wait for stylesheets to load. -* **Fixed:** Problem rendering popouts in Safari. - -## 0.4.3 - -* **Fixed:** `addTabWithDragAndDrop` not working since 0.4.0. - -## 0.4.2 - -* Use Sass to generate light and dark themes. - -## 0.4.1 - -* Copy styles into popout tabs. - -## 0.4.0 - -* **Added:** Ability to pop out tabs into new browser windows. Press the 'reload from file' button in the demo app to load new layouts with the `popout` attribute. - -## 0.3.11 - -* **Added:** Overflow menu to border tabs. -* **Fixed:** Issues running on IE11. - -## 0.3.10 - -* **Removed:** Deprecated React lifecycle methods. Will now work in React strict mode without warnings (for example, in apps created with Create React App). \ No newline at end of file +- Initialised Fork \ No newline at end of file diff --git a/package.json b/package.json index f0def5c2..1c8e26f6 100755 --- a/package.json +++ b/package.json @@ -1,29 +1,7 @@ { - "name": "flexlayout-react", - "version": "0.8.17", - "description": "A multi-tab docking layout manager", - "author": "Caplin Systems Ltd", - "repository": { - "type": "git", - "url": "git+https://github.com/caplin/FlexLayout.git" - }, - "license": "ISC", - "type": "module", - "main": "./dist/index.js", - "module": "./dist/index.js", - "types": "./types/index.d.ts", - "exports": { - ".": { - "import": "./dist/index.js", - "types": "./types/index.d.ts" - }, - "./style/*": "./style/*" - }, - "files": [ - "dist/", - "types/", - "style/" - ], + "name": "flexycakes", + "version": "1.0.0", + "description": "Community fork of caplin/FlexLayout (ISC). Not affiliated.", "keywords": [ "react", "layout", @@ -43,6 +21,40 @@ "docking library", "docking layout" ], + "homepage": "https://github.com/powerdragonfire/flex-core#readme", + "bugs": { + "url": "https://github.com/powerdragonfire/flex-core/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/powerdragonfire/flex-core.git" + }, + "license": "ISC", + "author": "powerdragonfire", + "maintainers": [ + { + "name": "powerdragonfire", + "email": "flex.core.git@gmail.com" + } + ], + "type": "module", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./types/index.d.ts" + }, + "./style/*": "./style/*" + }, + "main": "./dist/index.js", + "types": "./types/index.d.ts", + "directories": { + "test": "tests" + }, + "files": [ + "dist/", + "types/", + "style/" + ], "scripts": { "dev": "vite", "preview": "vite preview", @@ -57,13 +69,6 @@ "doc": "typedoc --out typedoc --exclude \"**/demo/**/*.tsx\" --excludeInternal --disableSources --excludePrivate --excludeProtected --readme none ./src", "css": "sass style:style" }, - "eslintConfig": { - "extends": "react-app" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, "devDependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", @@ -97,5 +102,13 @@ "typescript-eslint": "^8.30.1", "vite": "^6.3.0", "vitest": "^3.1.1" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "module": "./dist/index.js", + "eslintConfig": { + "extends": "react-app" } } diff --git a/vite.config.ts b/vite.config.ts index 85732e75..f532a286 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,7 +5,11 @@ import pkg from './package.json'; export default defineConfig({ root: './demo/', base: './', // use relative paths - plugins: [react()], + plugins: [react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }),], build: { outDir: 'dist', rollupOptions: { From 6d6ca188fddee4be4c88ef49ff20c6c01131007c Mon Sep 17 00:00:00 2001 From: powerdragonfire Date: Mon, 22 Sep 2025 16:17:07 +0100 Subject: [PATCH 2/2] v0.9.0: Add pin/unpin feature for side and bottom panels --- CHANGELOG.md | 453 ++++++++++++++++++++++++++++++++- package.json | 79 +++--- pnpm-lock.yaml | 3 +- pnpm-workspace.yaml | 5 + src/I18nLabel.ts | 2 + src/model/IJsonModel.ts | 510 +++++++++++++++++++------------------- src/model/TabNode.ts | 8 +- src/view/BorderTab.tsx | 33 ++- src/view/BorderTabSet.tsx | 43 +++- src/view/Icons.tsx | 18 ++ src/view/Layout.tsx | 8 +- src/view/Tab.tsx | 5 + vite.config.ts | 6 +- 13 files changed, 856 insertions(+), 317 deletions(-) create mode 100644 pnpm-workspace.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index a2efae1e..1d7303e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,452 @@ -## Change Log: +## 0.9.0 = 2025-09-22 -## 1.0.0 +* **Added:** Pin/unpin feature for side (left/right) and bottom panels. Users can now keep panels permanently visible ("pinned") or allow them to collapse automatically ("unpinned"), similar to behavior in modern IDEs and dashboard layouts. +* **Enhanced:** Improved layout flexibility by allowing users to control panel visibility behavior, helping to streamline workflows and reduce visual clutter in complex layouts. -- Initialised Fork \ No newline at end of file +## 0.8.17 - 2025-05-03 + +* **Fixed:** Issues with tab redraw and scroll when page is scrolled down (corrects fix for [#488]) + +## 0.8.16 - 2025-04-30 + +* **Fixed:** [#488](https://github.com/caplin/FlexLayout/issues/488) Wrong tab position on scroll + +## 0.8.15 - 2025-04-25 + +* **Added:** Option to tabset customization to allow the creation of a control to the left of the tabs (see the 'New Features' layout in the demo for an example). +* **Changed:** Only re-render tabs when they are visible. + +## 0.8.14 - 2025-04-18 + +* **Removed:** UMD builds. +* **Changed:** Package type is now 'module'. +* **Changed:** Demo build now uses Vite. +* **Added:** Icons are now exported. +* **Added:** Error boundary now has a retry button. + +## 0.8.13 - 2025-04-15 (deprecated) + +Published with missing types in module exports + +## 0.8.12 - 2025-04-15 + +* **Updated:** Dependencies. +* **Fixed:** Initial tab flash. +* **Disabled:** Popout of MUI tabs in demo (because Emotion generated styles in production cannot be copied to the popout window). +* **Converted:** Cypress tests to Playwright. +* **Updated:** Demo app to use React hooks. + +## 0.8.11 - 2025-04-09 (deprecated) + +Published with additional files by mistake. + +## 0.8.10 - 2025-04-09 + +* **Fixed:** [#481](https://github.com/caplin/FlexLayout/issues/481) Numpad Enter doesn't confirm rename. +* **Workaround:** Addressed a `` issue in React 19 ([https://github.com/facebook/react/issues/29585](https://github.com/facebook/react/issues/29585)) causing tabs to re-mount when moved. + +## 0.8.9 - 2025-04-04 + +* **Fixed:** [#480](https://github.com/caplin/FlexLayout/issues/480) `Actions.selectTab` is called when closing a Tab. +* **Added:** `isVisible()` method to `TabNode`. + +## 0.8.8 - 2025-03-22 + +* **Enabled:** Escape key to close the overflow menu. +* **Prevented:** Initial reposition flash when there are hidden tabs. +* **Removed:** Roboto font from the demo. + +## 0.8.7 - 2025-03-17 + +* **Improved:** Tab scrolling into the visible area. +* **Added:** Sections about tab and tabset customization to the README. + +## 0.8.6 - 2025-03-15 + +* **Restructured:** SCSS files to remove the use of the deprecated `@import` rule. +* **Added:** `combined.css` containing all themes. +* **Updated:** Demo to use `combined.css` for simple theme switching using class names. +* **Added:** Option in the demo to show the layout structure. + +## 0.8.5 - 2025-03-08 + +* **Changed:** The mini scrollbar now only shows when tabs are hovered over. + +## 0.8.4 - 2025-03-03 + +* **Added:** Attribute `'enableTabScrollbar'` to `TabSet` and `Border` nodes. Enabling this attribute will show a mini 'scrollbar' for the tabs to indicate the scroll position. See the Demo app's default layout for an example. + +## 0.8.3 - 2025-02-21 + +* **Prevented:** Sticky buttons from scrolling when there are no tabs. +* **Fixed:** Border `'show'` attribute. +* **Removed:** Code to adjust popout positions when loading. + +## 0.8.2 - 2025-02-15 + +* **Updated:** Dependencies. +* **Enabled:** Use with React 19. +* **Removed:** Strict mode from the demo due to a bug in React 19 ([https://github.com/facebook/react/issues/29585](https://github.com/facebook/react/issues/29585)) causing tabs to re-mount when moved. +* **Used:** CodeSandbox in `README.md` since React 19 doesn't create UMD versions needed by JSFiddle. + +## 0.8.1 - 2024-09-24 + +* **Fixed:** `enableDrag` on tab and tabset nodes. +* **Fixed:** Calculation for min/max tabset height from min/max tab height. +* **Modified:** Stylesheet code in the demo to reduce flash. + +## 0.8.0 - 2024-09-12 + +**New Features:** + +* Wrap tabs option. +* Improved popouts, no longer keep a placeholder tab. +* Drag from the overflow menu. +* Improved splitter resizing. +* Now uses HTML drag and drop to allow cross-window dragging. +* Rendering now uses flexbox rather than absolute positions, which should make styling easier. +* Rounded theme. +* Updated dependencies. + +**Breaking Changes:** + +* The `addTabWithDragAndDrop` signature has changed and must now be called from a drag start handler. +* The `moveTabWithDragAndDrop` signature has changed and must now be called from a drag start handler. +* Removed `addTabWithDragAndDropIndirect`. +* Removed `onTabDrag` (custom internal drag). +* Removed the `font` prop; use CSS variables `--font-size` and `--font-family` instead. +* Removed the `titleFactory` and `iconFactory` props; use `onRenderTab` instead. +* Removed the tabset header option. +* Removed attributes: `for insets`, `tabset header`, `row/tabset width and height`, `legacymenu`, etc. +* Several CSS changes reflect the use of flexbox. + +## 0.7.15 - 2023-11-14 + +* **Added:** Arrow icon to edge indicators. + +## 0.7.14 - 2023-11-10 + +* **Added:** Attribute `tabsetClassName` to tab nodes. This will add the class name to the parent tabset when there is a single stretched tab. Updated the mosaic layout in the demo to use this to color headers. + +## 0.7.13 - 2023-10-22 + +* **New attribute on tabset:** `enableSingleTabStretch` will stretch a single tab to take up all the remaining space and change the style to look like a header. Combined with `enableDrop`, this can be used to create a Mosaic-style layout (headed panels without tabs). See the new Mosaic Style layout in the Demo. +* The layout methods `addTabToTabSet` and `addTabToActiveTabSet` now return the added `TabNode`. +* **Fixed:** [#352](https://github.com/caplin/FlexLayout/issues/352) - `Layout.getDomRect` returning null. + +## 0.7.12 + +* `Action.setActiveTabset` can now take `undefined` to unset the active tabset. +* **Added:** Tab attribute `contentClassName` to add a class to the tab content. + +## 0.7.11 + +* **Added:** `ITabSetRenderValues.overflowPosition` to allow the overflow button position to be specified. If left undefined, the 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; the default is `true`. +* **Added:** Additional class names to edge indicators. + +## 0.7.10 + +* **Fixed:** [#399](https://github.com/caplin/FlexLayout/issues/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) but before any other buttons. +* **Enabled:** Sticky buttons in border tabsets. + +## 0.7.9 + +* **Fixed:** Drag issue found when used in a devtool extension. +* **Fixed:** Double render in popout when in strict mode. + +## 0.7.8 + +* **Fixed:** Popout size of tab with individual border size. +* **Hid:** Edge handles when disabled. +* **Updated:** Version of Cypress. + +## 0.7.7 + +* **Fixed:** [#379](https://github.com/caplin/FlexLayout/issues/379) - `uuid` could only be generated in secure contexts. + +## 0.7.6 + +* **Removed:** Dependency on the `uuid` package. +* **Added:** `action` argument to the `onModelChange` callback. + +## 0.7.5 + +* **Fixed:** [#340](https://github.com/caplin/FlexLayout/issues/340) - Error dragging a tabset into an empty tabset. + +## 0.7.4 + +* **Fixed:** Popout windows when using ``. +* **Output now targets:** ES6. + +## 0.7.3 + +* **Fixed:** Right edge marker location when border `enableAutoHide`. +* Dragging out a selected border tab will now leave the border unselected. + +## 0.7.2 + +* **New Layout JSON tabs:** Added to the demo. +* **Added:** `--color-icon` CSS rootOrientationVertical. + +## 0.7.1 + +* **Fixed:** [#310](https://github.com/caplin/FlexLayout/issues/310) - Added new layout method: `moveTabWithDragAndDrop(node)` to allow tab dragging to be started from custom code. + +## 0.7.0 + +* **Updated:** Dependencies, in particular, changed React peer dependency to React 18. +* **Made changes for:** React 18. + +## 0.6.10 + +* **Fixed:** [#312](https://github.com/caplin/FlexLayout/issues/312), Chrome warning for wheel event listener. + +## 0.6.9 + +* **Fixed:** [#308](https://github.com/caplin/FlexLayout/issues/308), Allow dragging within a maximized tabset. + +## 0.6.8 + +* **Added:** `onTabSetPlaceHolder` prop to render the tabset area when there are no tabs. + +## 0.6.7 + +* **Added:** More CSS variables, Underline theme, and updated dependencies. + +## 0.6.6 + +* **Fixed:** [#296](https://github.com/caplin/FlexLayout/issues/296). + +## 0.6.5 + +* **Fixed:** [#289](https://github.com/caplin/FlexLayout/issues/289), Allow setting attributes to undefined value. + +## 0.6.4 + +* Code tidy. +* Updated dependencies. + +## 0.6.3 + +* **Changed:** To using named rather than default import/exports. This will require changing top-level imports: + ```javascript + // from: + import FlexLayout from 'flexlayout-react'; + // to: + import * as FlexLayout from 'flexlayout-react'; + ``` +* **Added:** Typedoc link to README. + +## 0.6.2 + +* **Extended:** `icons` prop to allow the use of functions to set icons. +* **Added:** `onShowOverflowMenu` callback for handling the display of the tab overflow menu. + +## 0.6.1 + +* **Used:** Portal for the drag rectangle to preserve React context in `onRenderTab`. + +## 0.6.0 + +* **Changed:** Icons to use SVG images, which will now scale with the font size. +* **Improved:** Element spacing, removed most margin/padding spacers. +* The overflow menu and drag rectangle will now show the tab icon and content as rendered in the tab. +* **Added:** `altName` attribute to `TabNode`. This will be used as the name in the overflow menu if there is no `name` attribute (e.g., the tab has just an icon). +* **Changed:** The drag outline colors from red/green to light blue/green. +* **Removed:** `closeIcon` prop from `Layout`; use the `icons` property instead. +* **Changed:** `onRenderDragRect` callback to take a `ReactElement` rather than a string. The content now contains the tab button as rendered. + +## 0.5.21 + +* **Fixed:** Copying stylesheet links for popout windows when `cssRules` throw an exception. +* **Added:** Option `enableUseVisibility` to allow the use of `visibility: hidden` rather than `display: none` for hiding elements. + +## 0.5.20 + +* **Added:** Cypress Tests. +* **Fixed:** Bug with tab icon not showing. + +## 0.5.19 + +* **Added:** `onRenderFloatingTabPlaceholder` callback prop for rendering the floating tab placeholder. +* **Changed:** Style sheets to use CSS custom properties (variables) for several values. +* **Fixed:** Selected index in a single empty tabset. +* **Added:** `onContextMenu` callback prop for handling context menus on tabs and tabsets. +* **Added:** `onAuxMouseClick` callback prop for handling mouse clicks on tabs and tabsets with alt, meta, shift keys, and also handles center mouse clicks. + +## 0.5.18 + +* **Added:** `onRenderDragRect` callback prop for rendering the drag rectangles. +* **New border attribute:** `enableAutoHide`, to hide the border if it has zero tabs. + +## 0.5.17 + +* **New global option:** `splitterExtra`, to allow splitters to have extended hit test areas. This makes it easier to use narrow splitters. +* **Added new TabNode attributes:** `borderWidth` and `borderHeight`. These allow for individual border sizes for certain tabs. +* **Fixed:** [#263](https://github.com/caplin/FlexLayout/issues/263) - Border splitters not taking the minimum size of the center into account. +* **Improved:** Algorithm for finding the drop location. +* **Additional parameter:** `cursor`, for `onTabDrag`. + +## 0.5.16 + +* **Added:** 'New Features' layout to the demo. +* **New tab attribute:** `helpText`, to show a tooltip over tabs. +* **New model action:** `deleteTabset`, to delete a tabset and all its child tabs. +* **New tabset attribute:** `enableClose`, to close the tabset. + +## 0.5.15 + +* **Added new Layout prop:** `onTabDrag` that allows tab dragging to be intercepted. +* **Added example of `onTabDrag`:** In the demo app, the example shows a list where tabs can be dragged into, moved in the list, and dragged back out into the layout. +* Node IDs that are not assigned a value are now auto-generated using a UUID rather than a rolling number (e.g., previous ID: #3, new ID: #0c459064-8dee-444e-8636-eb9ab910fb27). +* **Made:** The `toJson` method of the node public. + +## 0.5.14 + +* **Fixed:** An issue with copying styles for a floating window when using a CSS-in-JS solution. +* **Fixed:** [#227](https://github.com/caplin/FlexLayout/issues/227) - Edge rects are not moved if the window is resized while dragging. + +## 0.5.13 + +* **Added prop:** `realtimeResize` to make tabs resize as their splitters are dragged. + **Warning:** This can cause resizing to become choppy when tabs are slow to draw. + +## 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 a different set of buttons to be applied to headed `TabSets`. + +## 0.5.11 + +* **Added:** `StickyButtons` to `onRenderTabSet` render values to allow for the implementation of a Chrome-style + button. +* **Added:** Example of the + button to the default layout in the demo app. + +## 0.5.10 + +* Adjusted the selected tab when tabs are popped out to an external window. + +## 0.5.9 + +* `TitleFactory` can now return an object with `titleContent` and `name` (name is used for the tab overflow menu). +* Corrected the position of `rootOrientationVertical` in the TypeScript JSON model. + +## 0.5.8 + +* **Fixed:** [#172](https://github.com/caplin/FlexLayout/issues/172) - Added global `rootOrientationVertical` attribute to allow vertical layout for the root 'row'. +* **Added:** Missing exports for the TypeScript JSON model. +* **Moved:** CRA example to a separate repo. + +## 0.5.7 + +* **Added:** TypeScript typings for the model JSON. +* **Fixed:** Drag rectangle showing as a dot before the first position was found (when dragging into the layout). +* **Fixed:** [#191](https://github.com/caplin/FlexLayout/issues/191) - Global Attributes for class names not working. +* **Fixed:** [#212](https://github.com/caplin/FlexLayout/issues/212) - TypeScript issue with `ILayoutState`. + +## 0.5.6 + +* **Added:** External drag and drop into the layout; see the new `onExternalDrag` prop. +* **Updated:** Demo to accept dragged links, HTML, and text. +* Tab scrolling direction changed to match VSCode. +* Improved positioning of a single tab when the overflow menu is shown. +* Some small changes to theme colors. + +## 0.5.5 + +* **Fixed:** [#170](https://github.com/caplin/FlexLayout/issues/170) - Closing the last tab of a maximized tabset crashes the layout. + +## 0.5.4 + +* **Fixed:** Issue running with React 17.0.1. +* Window title now updates when a tab is renamed. + +## 0.5.3 + +* **Changed:** Class name strings to enum values. +* **Replaced:** TSLint with ESLint. +* **Added:** Create-React-App (CRA) example. +* **New theme:** 'light' (lighter and without box shadows, gradients). +* **Renamed:** Existing 'light' theme to 'gray'. + +## 0.5.2 + +* **Fixed:** Issues caused by double touch/mouse events in iOS. +* **Prevented:** iOS scroll during drag in the demo app. +* **Added:** Extra option to `onRenderTab` to allow the name of the item in the overflow menu to be set. +* **New option:** `closeType` for tabs. +* The maximized tabset now sets others to `display: none` rather than using `z-index`. +* **Disabled:** Maximize if only one tabset. +* Splitters will now default to 8px on desktop and 12px on mobile (so they can be tapped more easily). +* Close element is enlarged on mobile. + +## 0.5.1 + +* Various small fixes. + +## 0.5.0 + +* Overflowing tabs now scroll to keep the selected tab in view. They can also be manually scrolled using the mouse wheel. +* Now works on scrolling pages. +* **NOTE:** Several CSS classes with names starting with `flexlayout__tabset_header...` have been renamed to `flexlayout__tabset_tabbar...`. + +## 0.4.9 + +* Keep the selected tab in the tabset/border when another tab is moved out. + +## 0.4.8 + +* **Added:** Minimum size attributes on tabset and border. +* **Added:** Extra CSS classes on elements for border and splitter styling. + +## 0.4.7 + +* **Added:** `font` property. +* Font now defaults to `medium`. +* Tabs now auto-adjust to the current font. +* **Added:** `fontSize` dropdown to the demo. +* **Modified:** CSS for the above font size changes and to remove some fixed sizes. +* **Added:** New attributes to control the auto-selection of tabs. + +## 0.4.6 + +* **Added:** `icons` prop to allow default icons to be replaced. +* **Added:** `tabLocation` attribute to tabsets to allow top and bottom tab placement. +* **Modified:** CSS; the default font is now 14px. + +## 0.4.5 + +* **Fixed:** Use of global objects for use when server-side rendering. +* **Added:** Error boundary around tab contents to prevent tab rendering exceptions from crashing the app. + +## 0.4.4 + +* **Changed:** All components except `Layout` to use React Hooks. +* Popouts now wait for stylesheets to load. +* **Fixed:** Problem rendering popouts in Safari. + +## 0.4.3 + +* **Fixed:** `addTabWithDragAndDrop` not working since 0.4.0. + +## 0.4.2 + +* Use Sass to generate light and dark themes. + +## 0.4.1 + +* Copy styles into popout tabs. + +## 0.4.0 + +* **Added:** Ability to pop out tabs into new browser windows. Press the 'reload from file' button in the demo app to load new layouts with the `popout` attribute. + +## 0.3.11 + +* **Added:** Overflow menu to border tabs. +* **Fixed:** Issues running on IE11. + +## 0.3.10 + +* **Removed:** Deprecated React lifecycle methods. Will now work in React strict mode without warnings (for example, in apps created with Create React App). \ No newline at end of file diff --git a/package.json b/package.json index 1c8e26f6..db718f20 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,29 @@ { - "name": "flexycakes", - "version": "1.0.0", - "description": "Community fork of caplin/FlexLayout (ISC). Not affiliated.", + "name": "flexlayout-react", + "version": "0.9.0", + "description": "A multi-tab docking layout manager", + "author": "Caplin Systems Ltd", + "repository": { + "type": "git", + "url": "git+https://github.com/caplin/FlexLayout.git" + }, + "license": "ISC", + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./types/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./types/index.d.ts" + }, + "./style/*": "./style/*" + }, + "files": [ + "dist/", + "types/", + "style/" + ], "keywords": [ "react", "layout", @@ -21,40 +43,6 @@ "docking library", "docking layout" ], - "homepage": "https://github.com/powerdragonfire/flex-core#readme", - "bugs": { - "url": "https://github.com/powerdragonfire/flex-core/issues" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/powerdragonfire/flex-core.git" - }, - "license": "ISC", - "author": "powerdragonfire", - "maintainers": [ - { - "name": "powerdragonfire", - "email": "flex.core.git@gmail.com" - } - ], - "type": "module", - "exports": { - ".": { - "import": "./dist/index.js", - "types": "./types/index.d.ts" - }, - "./style/*": "./style/*" - }, - "main": "./dist/index.js", - "types": "./types/index.d.ts", - "directories": { - "test": "tests" - }, - "files": [ - "dist/", - "types/", - "style/" - ], "scripts": { "dev": "vite", "preview": "vite preview", @@ -69,6 +57,13 @@ "doc": "typedoc --out typedoc --exclude \"**/demo/**/*.tsx\" --excludeInternal --disableSources --excludePrivate --excludeProtected --readme none ./src", "css": "sass style:style" }, + "eslintConfig": { + "extends": "react-app" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, "devDependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", @@ -93,7 +88,7 @@ "react": "^19.1.0", "react-chartjs-2": "^5.3.0", "react-dom": "^19.1.0", - "react-scripts": "5.0.1", + "react-scripts": "^5.0.1", "rimraf": "^6.0.1", "sass": "^1.86.3", "styled-components": "^6.1.17", @@ -102,13 +97,5 @@ "typescript-eslint": "^8.30.1", "vite": "^6.3.0", "vitest": "^3.1.1" - }, - "peerDependencies": { - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, - "module": "./dist/index.js", - "eslintConfig": { - "extends": "react-app" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 41f06c7b..310f5849 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,7 +78,7 @@ importers: specifier: ^19.1.0 version: 19.1.0(react@19.1.0) react-scripts: - specifier: 5.0.1 + specifier: ^5.0.1 version: 5.0.1(@babel/plugin-syntax-flow@7.26.0(@babel/core@7.26.10))(@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.10))(@types/babel__core@7.20.5)(eslint@9.24.0(jiti@1.21.7))(react@19.1.0)(sass@1.86.3)(type-fest@0.21.3)(typescript@5.8.3) rimraf: specifier: ^6.0.1 @@ -5772,6 +5772,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..dee48d65 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,5 @@ +onlyBuiltDependencies: + - '@parcel/watcher' + - core-js + - core-js-pure + - esbuild diff --git a/src/I18nLabel.ts b/src/I18nLabel.ts index c79e22b0..94fc1d22 100644 --- a/src/I18nLabel.ts +++ b/src/I18nLabel.ts @@ -7,6 +7,8 @@ export enum I18nLabel { Maximize = "Maximize tab set", Restore = "Restore tab set", Popout_Tab = "Popout selected tab", + Pin_Tab = "Pin tab", + Unpin_Tab = "Unpin tab", Overflow_Menu_Tooltip = "Hidden tabs", Error_rendering_component = "Error rendering component", Error_rendering_component_retry = "Retry", diff --git a/src/model/IJsonModel.ts b/src/model/IJsonModel.ts index 9545c4b6..c5508d34 100755 --- a/src/model/IJsonModel.ts +++ b/src/model/IJsonModel.ts @@ -6,19 +6,19 @@ export interface IJsonModel { global?: IGlobalAttributes; borders?: IJsonBorderNode[]; layout: IJsonRowNode; // top level 'row' is horizontal, rows inside rows take opposite orientation to parent row (ie can act as columns) - popouts?: Record; + popouts?: Record; } export interface IJsonRect { - x: number; - y: number; - width: number; - height: number; + x: number; + y: number; + width: number; + height: number; } export interface IJsonPopout { layout: IJsonRowNode; - rect: IJsonRect ; + rect: IJsonRect; } export interface IJsonBorderNode extends IBorderAttributes { @@ -31,234 +31,234 @@ export interface IJsonRowNode extends IRowAttributes { } export interface IJsonTabSetNode extends ITabSetAttributes { - /** Marks this as the active tab set, read from initial json but - * must subseqently be set on the model (only one tab set can be active)*/ - active?: boolean; - /** Marks this tab set as being maximized, read from initial json but - * must subseqently be set on the model (only one tab set can be maximized) */ - maximized?: boolean; + /** Marks this as the active tab set, read from initial json but + * must subseqently be set on the model (only one tab set can be active)*/ + active?: boolean; + /** Marks this tab set as being maximized, read from initial json but + * must subseqently be set on the model (only one tab set can be maximized) */ + maximized?: boolean; children: IJsonTabNode[]; } -export interface IJsonTabNode extends ITabAttributes { -} +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface IJsonTabNode extends ITabAttributes {} //---------------------------------------------------------------------------------------------------------- // below this line is autogenerated from attributes in code via Model static method toTypescriptInterfaces() //---------------------------------------------------------------------------------------------------------- export interface IGlobalAttributes { - /** + /** Value for BorderNode attribute autoSelectTabWhenClosed if not overridden whether to select new/moved tabs in border when the border is currently closed Default: false */ - borderAutoSelectTabWhenClosed?: boolean; + borderAutoSelectTabWhenClosed?: boolean; - /** + /** Value for BorderNode attribute autoSelectTabWhenOpen if not overridden whether to select new/moved tabs in border when the border is already open Default: true */ - borderAutoSelectTabWhenOpen?: boolean; + borderAutoSelectTabWhenOpen?: boolean; - /** + /** Value for BorderNode attribute className if not overridden class applied to tab button Default: undefined */ - borderClassName?: string; + borderClassName?: string; - /** + /** Value for BorderNode attribute enableAutoHide if not overridden hide border if it has zero tabs Default: false */ - borderEnableAutoHide?: boolean; + borderEnableAutoHide?: boolean; - /** + /** Value for BorderNode attribute enableDrop if not overridden whether tabs can be dropped into this border Default: true */ - borderEnableDrop?: boolean; + borderEnableDrop?: boolean; - /** + /** Value for BorderNode attribute enableTabScrollbar if not overridden whether to show a mini scrollbar for the tabs Default: false */ - borderEnableTabScrollbar?: boolean; + borderEnableTabScrollbar?: boolean; - /** + /** Value for BorderNode attribute maxSize if not overridden the maximum size of the tab area Default: 99999 */ - borderMaxSize?: number; + borderMaxSize?: number; - /** + /** Value for BorderNode attribute minSize if not overridden the minimum size of the tab area Default: 0 */ - borderMinSize?: number; + borderMinSize?: number; - /** + /** Value for BorderNode attribute size if not overridden size of the tab area when selected Default: 200 */ - borderSize?: number; + borderSize?: number; - /** + /** enable docking to the edges of the layout, this will show the edge indicators Default: true */ - enableEdgeDock?: boolean; + enableEdgeDock?: boolean; - /** + /** boolean indicating if tab icons should rotate with the text in the left and right borders Default: true */ - enableRotateBorderIcons?: boolean; + enableRotateBorderIcons?: boolean; - /** + /** the top level 'row' will layout horizontally by default, set this option true to make it layout vertically Default: false */ - rootOrientationVertical?: boolean; + rootOrientationVertical?: boolean; - /** + /** enable a small centralized handle on all splitters Default: false */ - splitterEnableHandle?: boolean; + splitterEnableHandle?: boolean; - /** + /** additional width in pixels of the splitter hit test area Default: 0 */ - splitterExtra?: number; + splitterExtra?: number; - /** + /** width in pixels of all splitters between tabsets/borders Default: 8 */ - splitterSize?: number; + splitterSize?: number; - /** + /** Value for TabNode attribute borderHeight if not overridden height when added to border, -1 will use border size Default: -1 */ - tabBorderHeight?: number; + tabBorderHeight?: number; - /** + /** Value for TabNode attribute borderWidth if not overridden width when added to border, -1 will use border size Default: -1 */ - tabBorderWidth?: number; + tabBorderWidth?: number; - /** + /** Value for TabNode attribute className if not overridden class applied to tab button Default: undefined */ - tabClassName?: string; + tabClassName?: string; - /** + /** Value for TabNode attribute closeType if not overridden see values in ICloseType Default: 1 */ - tabCloseType?: ICloseType; + tabCloseType?: ICloseType; - /** + /** Value for TabNode attribute contentClassName if not overridden class applied to tab content Default: undefined */ - tabContentClassName?: string; + tabContentClassName?: string; - /** + /** Default: 0.3 */ - tabDragSpeed?: number; + tabDragSpeed?: number; - /** + /** Value for TabNode attribute enableClose if not overridden allow user to close tab via close button Default: true */ - tabEnableClose?: boolean; + tabEnableClose?: boolean; - /** + /** Value for TabNode attribute enableDrag if not overridden allow user to drag tab to new location Default: true */ - tabEnableDrag?: boolean; + tabEnableDrag?: boolean; - /** + /** Value for TabNode attribute enablePopout if not overridden enable popout (in popout capable browser) Default: false */ - tabEnablePopout?: boolean; + tabEnablePopout?: boolean; - /** + /** Value for TabNode attribute enablePopoutIcon if not overridden whether to show the popout icon in the tabset header if this tab enables popouts Default: true */ - tabEnablePopoutIcon?: boolean; + tabEnablePopoutIcon?: boolean; - /** + /** Value for TabNode attribute enablePopoutOverlay if not overridden if this tab will not work correctly in a popout window when the main window is backgrounded (inactive) @@ -266,702 +266,704 @@ export interface IGlobalAttributes { Default: false */ - tabEnablePopoutOverlay?: boolean; + tabEnablePopoutOverlay?: boolean; - /** + /** Value for TabNode attribute enableRename if not overridden allow user to rename tabs by double clicking Default: true */ - tabEnableRename?: boolean; + tabEnableRename?: boolean; - /** + /** Value for TabNode attribute enableRenderOnDemand if not overridden whether to avoid rendering component until tab is visible Default: true */ - tabEnableRenderOnDemand?: boolean; + tabEnableRenderOnDemand?: boolean; - /** + /** Value for TabNode attribute icon if not overridden the tab icon Default: undefined */ - tabIcon?: string; + tabIcon?: string; - /** + /** Value for TabNode attribute maxHeight if not overridden the max height of this tab Default: 99999 */ - tabMaxHeight?: number; + tabMaxHeight?: number; - /** + /** Value for TabNode attribute maxWidth if not overridden the max width of this tab Default: 99999 */ - tabMaxWidth?: number; + tabMaxWidth?: number; - /** + /** Value for TabNode attribute minHeight if not overridden the min height of this tab Default: 0 */ - tabMinHeight?: number; + tabMinHeight?: number; - /** + /** Value for TabNode attribute minWidth if not overridden the min width of this tab Default: 0 */ - tabMinWidth?: number; + tabMinWidth?: number; - /** + /** Value for TabSetNode attribute autoSelectTab if not overridden whether to select new/moved tabs in tabset Default: true */ - tabSetAutoSelectTab?: boolean; + tabSetAutoSelectTab?: boolean; - /** + /** Value for TabSetNode attribute classNameTabStrip if not overridden a class name to apply to the tab strip Default: undefined */ - tabSetClassNameTabStrip?: string; + tabSetClassNameTabStrip?: string; - /** + /** Value for TabSetNode attribute enableActiveIcon if not overridden whether the active icon (*) should be displayed when the tabset is active Default: false */ - tabSetEnableActiveIcon?: boolean; + tabSetEnableActiveIcon?: boolean; - /** + /** Value for TabSetNode attribute enableClose if not overridden allow user to close tabset via a close button Default: false */ - tabSetEnableClose?: boolean; + tabSetEnableClose?: boolean; - /** + /** Value for TabSetNode attribute enableDeleteWhenEmpty if not overridden whether to delete this tabset when is has no tabs Default: true */ - tabSetEnableDeleteWhenEmpty?: boolean; + tabSetEnableDeleteWhenEmpty?: boolean; - /** + /** Value for TabSetNode attribute enableDivide if not overridden allow user to drag tabs to region of this tabset, splitting into new tabset Default: true */ - tabSetEnableDivide?: boolean; + tabSetEnableDivide?: boolean; - /** + /** Value for TabSetNode attribute enableDrag if not overridden allow user to drag tabs out this tabset Default: true */ - tabSetEnableDrag?: boolean; + tabSetEnableDrag?: boolean; - /** + /** Value for TabSetNode attribute enableDrop if not overridden allow user to drag tabs into this tabset Default: true */ - tabSetEnableDrop?: boolean; + tabSetEnableDrop?: boolean; - /** + /** Value for TabSetNode attribute enableMaximize if not overridden allow user to maximize tabset to fill view via maximize button Default: true */ - tabSetEnableMaximize?: boolean; + tabSetEnableMaximize?: boolean; - /** + /** Value for TabSetNode attribute enableSingleTabStretch if not overridden if the tabset has only a single tab then stretch the single tab to fill area and display in a header style Default: false */ - tabSetEnableSingleTabStretch?: boolean; + tabSetEnableSingleTabStretch?: boolean; - /** + /** Value for TabSetNode attribute enableTabScrollbar if not overridden whether to show a mini scrollbar for the tabs Default: false */ - tabSetEnableTabScrollbar?: boolean; + tabSetEnableTabScrollbar?: boolean; - /** + /** Value for TabSetNode attribute enableTabStrip if not overridden enable tab strip and allow multiple tabs in this tabset Default: true */ - tabSetEnableTabStrip?: boolean; + tabSetEnableTabStrip?: boolean; - /** + /** Value for TabSetNode attribute enableTabWrap if not overridden wrap tabs onto multiple lines Default: false */ - tabSetEnableTabWrap?: boolean; + tabSetEnableTabWrap?: boolean; - /** + /** Value for TabSetNode attribute maxHeight if not overridden maximum height (in px) for this tabset Default: 99999 */ - tabSetMaxHeight?: number; + tabSetMaxHeight?: number; - /** + /** Value for TabSetNode attribute maxWidth if not overridden maximum width (in px) for this tabset Default: 99999 */ - tabSetMaxWidth?: number; + tabSetMaxWidth?: number; - /** + /** Value for TabSetNode attribute minHeight if not overridden minimum height (in px) for this tabset Default: 0 */ - tabSetMinHeight?: number; + tabSetMinHeight?: number; - /** + /** Value for TabSetNode attribute minWidth if not overridden minimum width (in px) for this tabset Default: 0 */ - tabSetMinWidth?: number; + tabSetMinWidth?: number; - /** + /** Value for TabSetNode attribute tabLocation if not overridden the location of the tabs either top or bottom Default: "top" */ - tabSetTabLocation?: ITabLocation; - + tabSetTabLocation?: ITabLocation; } export interface IRowAttributes { - /** + /** the unique id of the row, if left undefined a uuid will be assigned Default: undefined */ - id?: string; + id?: string; - /** + /** Fixed value: "row" */ - type?: string; + type?: string; - /** + /** relative weight for sizing of this row in parent row Default: 100 */ - weight?: number; - + weight?: number; } export interface ITabSetAttributes { - /** + /** whether to select new/moved tabs in tabset Default: inherited from Global attribute tabSetAutoSelectTab (default true) */ - autoSelectTab?: boolean; + autoSelectTab?: boolean; - /** + /** a class name to apply to the tab strip Default: inherited from Global attribute tabSetClassNameTabStrip (default undefined) */ - classNameTabStrip?: string; + classNameTabStrip?: string; - /** + /** a place to hold json config used in your own code Default: undefined */ - config?: any; + config?: any; - /** + /** whether the active icon (*) should be displayed when the tabset is active Default: inherited from Global attribute tabSetEnableActiveIcon (default false) */ - enableActiveIcon?: boolean; + enableActiveIcon?: boolean; - /** + /** allow user to close tabset via a close button Default: inherited from Global attribute tabSetEnableClose (default false) */ - enableClose?: boolean; + enableClose?: boolean; - /** + /** whether to delete this tabset when is has no tabs Default: inherited from Global attribute tabSetEnableDeleteWhenEmpty (default true) */ - enableDeleteWhenEmpty?: boolean; + enableDeleteWhenEmpty?: boolean; - /** + /** allow user to drag tabs to region of this tabset, splitting into new tabset Default: inherited from Global attribute tabSetEnableDivide (default true) */ - enableDivide?: boolean; + enableDivide?: boolean; - /** + /** allow user to drag tabs out this tabset Default: inherited from Global attribute tabSetEnableDrag (default true) */ - enableDrag?: boolean; + enableDrag?: boolean; - /** + /** allow user to drag tabs into this tabset Default: inherited from Global attribute tabSetEnableDrop (default true) */ - enableDrop?: boolean; + enableDrop?: boolean; - /** + /** allow user to maximize tabset to fill view via maximize button Default: inherited from Global attribute tabSetEnableMaximize (default true) */ - enableMaximize?: boolean; + enableMaximize?: boolean; - /** + /** if the tabset has only a single tab then stretch the single tab to fill area and display in a header style Default: inherited from Global attribute tabSetEnableSingleTabStretch (default false) */ - enableSingleTabStretch?: boolean; + enableSingleTabStretch?: boolean; - /** + /** whether to show a mini scrollbar for the tabs Default: inherited from Global attribute tabSetEnableTabScrollbar (default false) */ - enableTabScrollbar?: boolean; + enableTabScrollbar?: boolean; - /** + /** enable tab strip and allow multiple tabs in this tabset Default: inherited from Global attribute tabSetEnableTabStrip (default true) */ - enableTabStrip?: boolean; + enableTabStrip?: boolean; - /** + /** wrap tabs onto multiple lines Default: inherited from Global attribute tabSetEnableTabWrap (default false) */ - enableTabWrap?: boolean; + enableTabWrap?: boolean; - /** + /** the unique id of the tab set, if left undefined a uuid will be assigned Default: undefined */ - id?: string; + id?: string; - /** + /** maximum height (in px) for this tabset Default: inherited from Global attribute tabSetMaxHeight (default 99999) */ - maxHeight?: number; + maxHeight?: number; - /** + /** maximum width (in px) for this tabset Default: inherited from Global attribute tabSetMaxWidth (default 99999) */ - maxWidth?: number; + maxWidth?: number; - /** + /** minimum height (in px) for this tabset Default: inherited from Global attribute tabSetMinHeight (default 0) */ - minHeight?: number; + minHeight?: number; - /** + /** minimum width (in px) for this tabset Default: inherited from Global attribute tabSetMinWidth (default 0) */ - minWidth?: number; + minWidth?: number; - /** + /** Default: undefined */ - name?: string; + name?: string; - /** + /** index of selected/visible tab in tabset Default: 0 */ - selected?: number; + selected?: number; - /** + /** the location of the tabs either top or bottom Default: inherited from Global attribute tabSetTabLocation (default "top") */ - tabLocation?: ITabLocation; + tabLocation?: ITabLocation; - /** + /** Fixed value: "tabset" */ - type?: string; + type?: string; - /** + /** relative weight for sizing of this tabset in parent row Default: 100 */ - weight?: number; - + weight?: number; } export interface ITabAttributes { - /** + /** if there is no name specifed then this value will be used in the overflow menu Default: undefined */ - altName?: string; + altName?: string; - /** + /** height when added to border, -1 will use border size Default: inherited from Global attribute tabBorderHeight (default -1) */ - borderHeight?: number; + borderHeight?: number; - /** + /** width when added to border, -1 will use border size Default: inherited from Global attribute tabBorderWidth (default -1) */ - borderWidth?: number; + borderWidth?: number; - /** + /** class applied to tab button Default: inherited from Global attribute tabClassName (default undefined) */ - className?: string; + className?: string; - /** + /** see values in ICloseType Default: inherited from Global attribute tabCloseType (default 1) */ - closeType?: ICloseType; + closeType?: ICloseType; - /** + /** string identifying which component to run (for factory) Default: undefined */ - component?: string; + component?: string; - /** + /** a place to hold json config for the hosted component Default: undefined */ - config?: any; + config?: any; - /** + /** class applied to tab content Default: inherited from Global attribute tabContentClassName (default undefined) */ - contentClassName?: string; + contentClassName?: string; - /** + /** allow user to close tab via close button Default: inherited from Global attribute tabEnableClose (default true) */ - enableClose?: boolean; + enableClose?: boolean; - /** + /** allow user to drag tab to new location Default: inherited from Global attribute tabEnableDrag (default true) */ - enableDrag?: boolean; + enableDrag?: boolean; - /** + /** enable popout (in popout capable browser) Default: inherited from Global attribute tabEnablePopout (default false) */ - enablePopout?: boolean; + enablePopout?: boolean; - /** + /** whether to show the popout icon in the tabset header if this tab enables popouts Default: inherited from Global attribute tabEnablePopoutIcon (default true) */ - enablePopoutIcon?: boolean; + enablePopoutIcon?: boolean; - /** + /** if this tab will not work correctly in a popout window when the main window is backgrounded (inactive) then enabling this option will gray out this tab Default: inherited from Global attribute tabEnablePopoutOverlay (default false) */ - enablePopoutOverlay?: boolean; + enablePopoutOverlay?: boolean; - /** + /** allow user to rename tabs by double clicking Default: inherited from Global attribute tabEnableRename (default true) */ - enableRename?: boolean; + enableRename?: boolean; - /** + /** whether to avoid rendering component until tab is visible Default: inherited from Global attribute tabEnableRenderOnDemand (default true) */ - enableRenderOnDemand?: boolean; + enableRenderOnDemand?: boolean; - /** + /** if enabled the tab will re-mount when popped out/in Default: false */ - enableWindowReMount?: boolean; + enableWindowReMount?: boolean; + + /** + whether the tab remains open when clicking elsewhere - /** + Default: true + */ + pinned?: boolean; + + /** An optional help text for the tab to be displayed upon tab hover. Default: undefined */ - helpText?: string; + helpText?: string; - /** + /** the tab icon Default: inherited from Global attribute tabIcon (default undefined) */ - icon?: string; + icon?: string; - /** + /** the unique id of the tab, if left undefined a uuid will be assigned Default: undefined */ - id?: string; + id?: string; - /** + /** the max height of this tab Default: inherited from Global attribute tabMaxHeight (default 99999) */ - maxHeight?: number; + maxHeight?: number; - /** + /** the max width of this tab Default: inherited from Global attribute tabMaxWidth (default 99999) */ - maxWidth?: number; + maxWidth?: number; - /** + /** the min height of this tab Default: inherited from Global attribute tabMinHeight (default 0) */ - minHeight?: number; + minHeight?: number; - /** + /** the min width of this tab Default: inherited from Global attribute tabMinWidth (default 0) */ - minWidth?: number; + minWidth?: number; - /** + /** name of tab to be displayed in the tab button Default: "[Unnamed Tab]" */ - name?: string; + name?: string; - /** + /** class applied to parent tabset when this is the only tab and it is stretched to fill the tabset Default: undefined */ - tabsetClassName?: string; + tabsetClassName?: string; - /** + /** Fixed value: "tab" */ - type?: string; - + type?: string; } export interface IBorderAttributes { - /** + /** whether to select new/moved tabs in border when the border is currently closed Default: inherited from Global attribute borderAutoSelectTabWhenClosed (default false) */ - autoSelectTabWhenClosed?: boolean; + autoSelectTabWhenClosed?: boolean; - /** + /** whether to select new/moved tabs in border when the border is already open Default: inherited from Global attribute borderAutoSelectTabWhenOpen (default true) */ - autoSelectTabWhenOpen?: boolean; + autoSelectTabWhenOpen?: boolean; - /** + /** class applied to tab button Default: inherited from Global attribute borderClassName (default undefined) */ - className?: string; + className?: string; - /** + /** a place to hold json config used in your own code Default: undefined */ - config?: any; + config?: any; - /** + /** hide border if it has zero tabs Default: inherited from Global attribute borderEnableAutoHide (default false) */ - enableAutoHide?: boolean; + enableAutoHide?: boolean; - /** + /** whether tabs can be dropped into this border Default: inherited from Global attribute borderEnableDrop (default true) */ - enableDrop?: boolean; + enableDrop?: boolean; - /** + /** whether to show a mini scrollbar for the tabs Default: inherited from Global attribute borderEnableTabScrollbar (default false) */ - enableTabScrollbar?: boolean; + enableTabScrollbar?: boolean; - /** + /** the maximum size of the tab area Default: inherited from Global attribute borderMaxSize (default 99999) */ - maxSize?: number; + maxSize?: number; - /** + /** the minimum size of the tab area Default: inherited from Global attribute borderMinSize (default 0) */ - minSize?: number; + minSize?: number; - /** + /** index of selected/visible tab in border; -1 means no tab selected Default: -1 */ - selected?: number; + selected?: number; - /** + /** show/hide this border Default: true */ - show?: boolean; + show?: boolean; - /** + /** size of the tab area when selected Default: inherited from Global attribute borderSize (default 200) */ - size?: number; + size?: number; - /** + /** Fixed value: "border" */ - type?: string; - -} \ No newline at end of file + type?: string; +} diff --git a/src/model/TabNode.ts b/src/model/TabNode.ts index c9d38450..fe9fe48a 100755 --- a/src/model/TabNode.ts +++ b/src/model/TabNode.ts @@ -158,6 +158,10 @@ export class TabNode extends Node implements IDraggable { return this.getAttr("enableRenderOnDemand") as boolean; } + isPinned() { + return this.getAttr("pinned") as boolean; + } + getMinWidth() { return this.getAttr("minWidth") as number; } @@ -364,7 +368,9 @@ export class TabNode extends Node implements IDraggable { attributeDefinitions.add("enableWindowReMount", false).setType(Attribute.BOOLEAN).setDescription( `if enabled the tab will re-mount when popped out/in` ); - + attributeDefinitions.add("pinned", true).setType(Attribute.BOOLEAN).setDescription( + `whether the tab remains open when clicking elsewhere` + ); attributeDefinitions.addInherited("enableClose", "tabEnableClose").setType(Attribute.BOOLEAN).setDescription( `allow user to close tab via close button` ); diff --git a/src/view/BorderTab.tsx b/src/view/BorderTab.tsx index 02dceaa4..8bc31c33 100644 --- a/src/view/BorderTab.tsx +++ b/src/view/BorderTab.tsx @@ -17,6 +17,8 @@ export function BorderTab(props: IBorderTabProps) { const { layout, border, show } = props; const selfRef = React.useRef(null); const timer = React.useRef(undefined); + const selectedNode = border.getSelectedNode(); + const pinned = selectedNode?.isPinned(); React.useLayoutEffect(() => { const contentRect = layout.getBoundingClientRect(selfRef.current!); @@ -55,20 +57,47 @@ export function BorderTab(props: IBorderTabProps) { style.display = show ? "flex" : "none"; + if (show && pinned === false) { + style.position = "absolute"; + style.zIndex = 999; + style.pointerEvents = "none"; + style.backgroundColor = "transparent"; + const headerRect = border.getTabHeaderRect(); + if (border.getLocation() === DockLocation.LEFT) { + style.left = headerRect.width; + style.top = 0; + style.bottom = 0; + } else if (border.getLocation() === DockLocation.RIGHT) { + style.right = headerRect.width; + style.top = 0; + style.bottom = 0; + } else if (border.getLocation() === DockLocation.TOP) { + style.top = headerRect.height; + style.left = 0; + style.right = 0; + } else { // DockLocation.BOTTOM + style.bottom = headerRect.height; + style.left = 0; + style.right = 0; + } + } + const className = layout.getClassName(CLASSES.FLEXLAYOUT__BORDER_TAB_CONTENTS); + const splitter = show && pinned !== false ? : null; + if (border.getLocation() === DockLocation.LEFT || border.getLocation() === DockLocation.TOP) { return ( <>
- {show && } + {splitter} ); } else { return ( <> - {show && } + {splitter}
diff --git a/src/view/BorderTabSet.tsx b/src/view/BorderTabSet.tsx index ed6056b1..98ba3567 100755 --- a/src/view/BorderTabSet.tsx +++ b/src/view/BorderTabSet.tsx @@ -178,9 +178,46 @@ export const BorderTabSet = (props: IBorderTabSetProps) => { } const selectedIndex = border.getSelected(); - if (selectedIndex !== -1) { - const selectedTabNode = border.getChildren()[selectedIndex] as TabNode; - if (selectedTabNode !== undefined && layout.isSupportsPopout() && selectedTabNode.isEnablePopout()) { + const selectedTabNode = selectedIndex !== -1 ? (border.getChildren()[selectedIndex] as TabNode) : undefined; + const isPinned = selectedTabNode?.isPinned(); + + React.useEffect(() => { + if (selectedTabNode && !isPinned) { + const onBodyPointerDown = (e: PointerEvent) => { + const layoutRect = layout.getDomRect(); + const x = e.clientX - layoutRect.x; + const y = e.clientY - layoutRect.y; + if (!border.getTabHeaderRect().contains(x, y) && !border.getContentRect().contains(x, y)) { + layout.doAction(Actions.selectTab(selectedTabNode.getId())); + } + }; + document.addEventListener("pointerdown", onBodyPointerDown); + return () => document.removeEventListener("pointerdown", onBodyPointerDown); + } + }, [selectedTabNode, isPinned, border, layout]); + + if (selectedTabNode !== undefined) { + const pinTitle = selectedTabNode.isPinned() ? layout.i18nName(I18nLabel.Unpin_Tab) : layout.i18nName(I18nLabel.Pin_Tab); + const pinIcon = selectedTabNode.isPinned() + ? ((typeof icons.unpin === "function") ? icons.unpin(selectedTabNode) : icons.unpin) + : ((typeof icons.pin === "function") ? icons.pin(selectedTabNode) : icons.pin); + const onPinClick = (event: React.MouseEvent) => { + layout.doAction(Actions.updateNodeAttributes(selectedTabNode.getId(), { pinned: !selectedTabNode.isPinned() })); + event.stopPropagation(); + }; + buttons.push( + + ); + + if (layout.isSupportsPopout() && selectedTabNode.isEnablePopout()) { const popoutTitle = layout.i18nName(I18nLabel.Popout_Tab); buttons.push(