Skip to content

Commit 728a0c9

Browse files
committed
v0.9.1
1 parent ae8ad5d commit 728a0c9

40 files changed

Lines changed: 1696 additions & 1559 deletions

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.9.1 - 2026-05-01
2+
* **Changed:** Float panels can now move outside the bounds of the main layout.
3+
* **Added:** New Layout prop `constrainFloatPanels`, setting this to true will constrain floating panels to the main layout.
4+
* **Fixed:** [#520](https://github.com/caplin/FlexLayout/issues/520) Actions.addNode causing duplicate lifecycle flow in web components
5+
* **Updated:** Dev Dependencies.
6+
17
## 0.9.0 - 2026-04-25
28

39
### Features

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ onRenderTabSet = (node: (TabSetNode | BorderNode), renderValues: ITabSetRenderVa
265265
title="Add"
266266
className="flexlayout__tab_toolbar_button"
267267
onClick={() => {
268-
model.doAction(Actions.addNode({
268+
model.doAction(Actions.addTab({
269269
component: "placeholder",
270270
name: "Added " + nextAddIndex.current++
271271
}, node.getId(), DockLocation.CENTER, -1, true));
@@ -291,14 +291,14 @@ Apply actions using the `model.doAction()` method. This method takes a single ar
291291
### Example
292292

293293
```js
294-
model.doAction(FlexLayout.Actions.addNode(
294+
model.doAction(FlexLayout.Actions.addTab(
295295
{type:"tab", component:"grid", name:"a grid", id:"5"},
296296
"1", FlexLayout.DockLocation.CENTER, 0));
297297
```
298298

299299
This example adds a new grid component to the center of the tabset with ID "1" at the first position (0). Use `-1` to add to the end of the tabs.
300300

301-
Note: You can retrieve the ID of a node (e.g., the node returned by the `addNode` action) using `node.getId()`. If an ID wasn't assigned when the node was created, one will be generated for you in the form `#<uuid>` (e.g., `#0c459064-8dee-444e-8636-eb9ab910fb27`).
301+
Note: You can retrieve the ID of a node (e.g., the node returned by the `addTab` action) using `node.getId()`. If an ID wasn't assigned when the node was created, one will be generated for you in the form `#<uuid>` (e.g., `#0c459064-8dee-444e-8636-eb9ab910fb27`).
302302

303303
Note: You can intercept actions resulting from GUI changes before they are applied by implementing the `onAction` callback property of the `Layout`.
304304

@@ -323,7 +323,7 @@ The JSON model is defined as a set of TypeScript interfaces. See the documentati
323323

324324
Note: Tabsets are dynamically created as tabs are moved and deleted when their last tab is removed (unless `enableDeleteWhenEmpty` is set to `false`).
325325

326-
[Tab Attributes Documentation](https://caplin.github.io/FlexLayout/demos/v0.9/typedoc/interfaces/IJsonTabNode.html)
326+
[Tab Attributes Documentation](https://caplin.github.io/FlexLayout/demos/v0.9/typedoc/interfaces/ITabAttributes.html)
327327

328328
[Border Attributes Documentation](https://caplin.github.io/FlexLayout/demos/v0.9/typedoc/interfaces/IJsonBorderNode.html)
329329

@@ -369,7 +369,7 @@ function MyComponent({ node }) {
369369

370370
## Popout Windows
371371

372-
Tabs can be rendered into external browser windows (useful for multi-monitor setups) by using the `enablePopout` attribute. When enabled, a popout icon appears in the tab header.
372+
Tabs can be rendered into external browser windows (useful for multi-monitor setups) by using the `enablePopout` and `enablePopoutIcon` attributes. When enabled, a popout icon appears in the tab header.
373373

374374
Popout windows require an additional HTML page, `popout.html`, hosted at the same location as the main page (you can copy this from the demo app). The `popout.html` acts as the host for the popped-out tab, and the main page's styles are copied into it at runtime.
375375

demo/App.tsx

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,26 @@ function App() {
4646
const latestModel = React.useRef<Model | null>(model);
4747
const latestLayoutFile = React.useRef<string | null>(layoutFile);
4848

49-
latestModel.current = model;
50-
latestLayoutFile.current = layoutFile;
49+
React.useEffect(() => {
50+
latestModel.current = model;
51+
latestLayoutFile.current = layoutFile;
52+
});
53+
54+
React.useEffect(() => {
55+
// save layout when unloading page
56+
window.onbeforeunload = (event: Event) => {
57+
save();
58+
};
59+
60+
const url = new URL(window.location.href);
61+
const params = new URLSearchParams(url.search);
62+
const layout = params.get('layout') || "default";
63+
64+
loadLayout(layout, false);
65+
66+
// use to generate json typescript interfaces
67+
// Model.toTypescriptInterfaces();
68+
}, []);
5169

5270
const save = () => {
5371
const jsonStr = JSON.stringify(latestModel.current!.toJson(), null, "\t");
@@ -97,22 +115,6 @@ function App() {
97115
}
98116
}
99117

100-
React.useEffect(() => {
101-
// save layout when unloading page
102-
window.onbeforeunload = (event: Event) => {
103-
save();
104-
};
105-
106-
const url = new URL(window.location.href);
107-
const params = new URLSearchParams(url.search);
108-
const layout = params.get('layout') || "default";
109-
110-
loadLayout(layout, false);
111-
112-
// use to generate json typescript interfaces
113-
// Model.toTypescriptInterfaces();
114-
}, []);
115-
116118
// const allowDrop = (dragNode: (TabNode | TabSetNode), dropInfo: DropInfo) => {
117119
// let dropNode = dropInfo.node;
118120

@@ -318,15 +320,15 @@ function App() {
318320
*/
319321
return (<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
320322
<div title="Header rendered in factory method"
321-
style={{
322-
display: "flex",
323-
alignItems: "center",
324-
justifyContent: "center",
325-
color: "var(--color-tab-unselected)",
326-
backgroundColor: "var(--color-tabset-background)",
327-
marginBottom: 5,
328-
fontWeight: 500,
329-
}}>User Defined Header</div>
323+
style={{
324+
display: "flex",
325+
alignItems: "center",
326+
justifyContent: "center",
327+
color: "var(--color-tab-unselected)",
328+
backgroundColor: "var(--color-tabset-background)",
329+
marginBottom: 5,
330+
fontWeight: 500,
331+
}}>User Defined Header</div>
330332
<TabLayout tabNode={node} />
331333
</div>);
332334
}
@@ -604,19 +606,19 @@ function App() {
604606
</select>
605607
<button key="reloadbutton" className="toolbar_control" onClick={onReloadFromFile} style={{ marginLeft: 5 }}>Reload</button>
606608
<div style={{ flexGrow: 1 }}></div>
607-
<span style={{ fontSize: "14px" }}>Realtime resize</span>
609+
<span style={{ marginLeft: 5 }}>Realtime resize</span>
608610
<input
609611
name="realtimeResize"
610612
type="checkbox"
611613
checked={realtimeResize}
612614
onChange={onRealtimeResize} />
613-
<span style={{ marginLeft: 5, fontSize: "14px" }}>Show layout</span>
615+
<span style={{ marginLeft: 5 }}>Show layout</span>
614616
<input
615617
name="show layout"
616618
type="checkbox"
617619
checked={showLayout}
618620
onChange={onShowLayout} />
619-
<span style={{ marginLeft: 5, fontSize: "14px" }}>Attributes</span>
621+
<span style={{ marginLeft: 5 }}>Attributes</span>
620622
<input
621623
name="attrs"
622624
type="checkbox"

demo/chart.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ const BarChart = () => {
2929
const options = {
3030
responsive: true,
3131
maintainAspectRatio: false,
32+
animation: {
33+
duration: 0
34+
},
3235
plugins: {
3336
legend: {
3437
position: 'top' as const,

demo/index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
<script type="module" src="/App.tsx"></script>
1010
</body>
1111

12-
<!-- <body style="overflow:auto;">
13-
<div style="height:1300px"></div>
14-
<div style="position: relative; height:500px;">
12+
<!-- <body>
13+
<div style="height:300px"></div>
14+
<div style="position: relative; height:100vh;">
1515
<div id="container"></div>
1616
</div>
1717
<script type="module" src="/App.tsx"></script>

demo/public/layouts/default.layout

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@
8484
"type": "tabset",
8585
"id": "#018c109c-20ab-4458-84c8-1817d2e7d81b",
8686
"weight": 33,
87-
"enableDeleteWhenEmpty": false,
88-
"enableClose": false,
8987
"children": [
9088
{
9189
"type": "tab",

demo/styles.css

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
html,
22
body {
3-
height: 100%;
43
margin: 0;
54
padding: 0;
6-
overflow: hidden;
75
font-size: medium;
86
font-family: system-ui, -apple-system, Arial, sans-serif;
97
scrollbar-width: thin;
@@ -21,6 +19,7 @@ body {
2119
display: flex;
2220
align-items: center;
2321
flex-wrap: wrap;
22+
font-size:14px;
2423
}
2524

2625
.toolbar_control {
@@ -41,7 +40,7 @@ body {
4140
bottom: 10px;
4241
position: absolute;
4342
display: flex;
44-
overflow: hidden;
43+
/* overflow: hidden; */
4544
background-color: white;
4645
}
4746

eslint.config.mjs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,34 @@ import js from "@eslint/js";
33
import globals from "globals";
44
import tseslint from "typescript-eslint";
55
import pluginReact from "eslint-plugin-react";
6+
// 1. Import the hooks plugin
7+
import pluginReactHooks from "eslint-plugin-react-hooks";
68

79
export default defineConfig([
810
{ files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"], plugins: { js }, extends: ["js/recommended"] },
911
{ files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"], languageOptions: { globals: globals.browser } },
10-
tseslint.configs.recommended, // This applies the recommended TypeScript rules
12+
tseslint.configs.recommended,
1113
pluginReact.configs.flat.recommended,
14+
15+
// 2. Add the Hooks configuration
1216
{
13-
files: ["**/*.{ts,tsx}"], // Apply only to TypeScript and TSX files
17+
plugins: {
18+
'react-hooks': pluginReactHooks,
19+
},
20+
rules: {
21+
...pluginReactHooks.configs.recommended.rules,
22+
},
23+
},
24+
25+
{
26+
files: ["**/*.{ts,tsx}"],
1427
rules: {
1528
'@typescript-eslint/no-explicit-any': 'off',
1629
"no-unused-vars": "off",
1730
"@typescript-eslint/no-unused-vars": "off",
1831
"react/react-in-jsx-scope": "off",
19-
// "react/display-name":"off"
32+
// You can also manually adjust hook rules here if needed:
33+
// "react-hooks/exhaustive-deps": "warn"
2034
},
2135
},
2236
{
@@ -26,4 +40,4 @@ export default defineConfig([
2640
},
2741
},
2842
},
29-
]);
43+
]);

package.json

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "flexlayout-react",
3-
"version": "0.9.0",
3+
"version": "0.9.1",
44
"description": "A multi-tab docking layout manager",
55
"author": "Caplin Systems Ltd",
66
"repository": {
@@ -66,33 +66,34 @@
6666
"@emotion/styled": "^11.14.1",
6767
"@eslint/js": "^10.0.1",
6868
"@mui/material": "^9.0.0",
69-
"@mui/x-data-grid": "^9.0.1",
69+
"@mui/x-data-grid": "^9.0.3",
7070
"@playwright/test": "^1.59.1",
71-
"@types/node": "^25.5.2",
71+
"@types/node": "^25.6.0",
7272
"@types/prismjs": "^1.26.6",
7373
"@types/react": "^19.2.14",
7474
"@types/react-dom": "^19.2.3",
7575
"@vitejs/plugin-react": "^6.0.1",
7676
"ag-grid-community": "^35.2.1",
7777
"ag-grid-react": "^35.2.1",
7878
"chart.js": "^4.5.1",
79-
"eslint": "^10.2.0",
79+
"eslint": "^10.2.1",
8080
"eslint-plugin-react": "^7.37.5",
81-
"globals": "^17.4.0",
82-
"ol": "^10.8.0",
83-
"prettier": "^3.8.1",
81+
"eslint-plugin-react-hooks": "^7.1.1",
82+
"globals": "^17.5.0",
83+
"ol": "^10.9.0",
84+
"prettier": "^3.8.3",
8485
"prismjs": "^1.30.0",
8586
"react": "^19.2.5",
8687
"react-chartjs-2": "^5.3.1",
8788
"react-dom": "^19.2.5",
8889
"react-scripts": "5.0.1",
8990
"rimraf": "^6.1.3",
9091
"sass": "^1.99.0",
91-
"styled-components": "^6.4.0",
92-
"typedoc": "^0.28.18",
93-
"typescript": "^6.0.2",
94-
"typescript-eslint": "^8.58.1",
95-
"vite": "^8.0.8",
96-
"vitest": "^4.1.4"
92+
"styled-components": "^6.4.1",
93+
"typedoc": "^0.28.19",
94+
"typescript": "^6.0.3",
95+
"typescript-eslint": "^8.59.1",
96+
"vite": "^8.0.10",
97+
"vitest": "^4.1.5"
9798
}
9899
}

0 commit comments

Comments
 (0)