@aptre/flex-layout 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +194 -151
  2. package/dist/index.mjs +16 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,41 +2,37 @@
2
2
 
3
3
  [![GitHub](https://img.shields.io/github/license/Caplin/FlexLayout)](https://github.com/caplin/FlexLayout/blob/master/LICENSE)
4
4
 
5
- FlexLayout is a layout manager that arranges React components in multiple tab sets, tabs can be resized and moved.
5
+ FlexLayout is a layout manager supporting multiple TabSets with draggable+resizable tabs.
6
6
 
7
7
  ![FlexLayout Demo Screenshot](Screenshot_light.png?raw=true "FlexLayout Demo Screenshot")
8
8
 
9
- **This is a maintenance fork of react-flexlayout. Check out the original project at the link above.**
9
+ **This is a feature-fork of [FlexLayout](https://github.com/caplin/FlexLayout) by Caplin.** The original project hasn't been updated in some time, so this fork includes bug fixes, performance improvements, and new features like `OptimizedLayout`.
10
10
 
11
- To install this fork: `yarn add @aptre/flex-layout` and use `@aptre/flex-layout` in place of `flexlayout-react`.
12
-
13
- [Run the Demo](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/demo/index.html)
14
-
15
- Try it now using [JSFiddle](https://jsfiddle.net/fvd9btea/)
16
-
17
- [API Doc](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/typedoc/index.html)
11
+ To install: `yarn add @aptre/flex-layout`
18
12
 
19
13
  FlexLayout's only dependency is React.
20
14
 
21
15
  Features:
22
- * splitters
23
- * tabs
24
- * tab dragging and ordering
25
- * tab set dragging (move all the tabs in a tab set in one operation)
26
- * dock to tab set or edge of frame
27
- * maximize tab set (double click tab set header or use icon)
28
- * tab overflow (show menu when tabs overflow, scroll tabs using mouse wheel)
29
- * border tab sets
30
- * popout tabs into new browser windows
31
- * submodels, allow layouts inside layouts
32
- * tab renaming (double click tab text to rename)
33
- * theming - light, underline, gray, round and dark
34
- * works on mobile devices (iPad, Android)
35
- * add tabs using drag, add to active tab set, add to tab set by id
36
- * tab and tab set attributes: enableTabStrip, enableDock, enableDrop...
37
- * customizable tabs and tab set rendering
38
- * component state is preserved when tabs are moved
39
- * typescript type declarations
16
+
17
+ - splitters
18
+ - tabs
19
+ - tab dragging and ordering
20
+ - tab set dragging (move all the tabs in a tab set in one operation)
21
+ - dock to tab set or edge of frame
22
+ - maximize tab set (double click tab set header or use icon)
23
+ - tab overflow (show menu when tabs overflow, scroll tabs using mouse wheel)
24
+ - border tab sets
25
+ - popout tabs into new browser windows
26
+ - submodels, allow layouts inside layouts
27
+ - tab renaming (double click tab text to rename)
28
+ - theming - light, underline, gray, round and dark
29
+ - works on mobile devices (iPad, Android)
30
+ - add tabs using drag, add to active tab set, add to tab set by id
31
+ - tab and tab set attributes: enableTabStrip, enableDock, enableDrop...
32
+ - customizable tabs and tab set rendering
33
+ - component state is preserved when tabs are moved
34
+ - typescript type declarations
35
+ - **OptimizedLayout** - renders tab content outside FlexLayout's DOM for better performance
40
36
 
41
37
  ## Demo
42
38
 
@@ -50,19 +46,18 @@ yarn test:browser
50
46
 
51
47
  Your browser will open to show + all the tests with vitest Browser Mode.
52
48
 
53
-
54
49
  ## Installation
55
50
 
56
51
  FlexLayout is in the npm repository. install using:
57
52
 
58
53
  ```
59
- npm install flexlayout-react
54
+ npm install @aptre/flex-layout
60
55
  ```
61
56
 
62
57
  Import FlexLayout in your modules:
63
58
 
64
59
  ```
65
- import {Layout, Model} from 'flexlayout-react';
60
+ import {Layout, Model} from '@aptre/flex-layout';
66
61
  ```
67
62
 
68
63
  Include the light, underline, gray or dark theme by either:
@@ -70,27 +65,25 @@ Include the light, underline, gray or dark theme by either:
70
65
  Adding an additional import:
71
66
 
72
67
  ```
73
- import 'flexlayout-react/style/light.css';
68
+ import '@aptre/flex-layout/style/light.css';
74
69
  ```
75
70
 
76
71
  or by adding the css to your html:
77
72
 
78
73
  ```
79
- <link rel="stylesheet" href="node_modules/flexlayout-react/style/light.css" />
74
+ <link rel="stylesheet" href="node_modules/@aptre/flex-layout/style/light.css" />
80
75
  ```
81
76
 
82
77
  ## Usage
83
78
 
84
79
  The `<Layout>` component renders the tab sets and splitters, it takes the following props:
85
80
 
86
-
87
81
  #### Required props:
88
82
 
89
-
90
- | Prop | Description |
91
- | --------------- | ----------------- |
92
- | model | the layout model |
93
- | factory | a factory function for creating React components |
83
+ | Prop | Description |
84
+ | ------- | ------------------------------------------------ |
85
+ | model | the layout model |
86
+ | factory | a factory function for creating React components |
94
87
 
95
88
  Additional [optional props](#optional-layout-props)
96
89
 
@@ -118,8 +111,8 @@ var json = {
118
111
  type: "tab",
119
112
  name: "One",
120
113
  component: "button",
121
- }
122
- ]
114
+ },
115
+ ],
123
116
  },
124
117
  {
125
118
  type: "tabset",
@@ -129,11 +122,11 @@ var json = {
129
122
  type: "tab",
130
123
  name: "Two",
131
124
  component: "button",
132
- }
133
- ]
134
- }
135
- ]
136
- }
125
+ },
126
+ ],
127
+ },
128
+ ],
129
+ },
137
130
  };
138
131
  ```
139
132
 
@@ -143,63 +136,141 @@ var json = {
143
136
  const model = Model.fromJson(json);
144
137
 
145
138
  function App() {
139
+ const factory = (node) => {
140
+ var component = node.getComponent();
146
141
 
147
- const factory = (node) => {
148
- var component = node.getComponent();
149
-
150
- if (component === "button") {
151
- return <button>{node.getName()}</button>;
152
- }
153
- }
142
+ if (component === "button") {
143
+ return <button>{node.getName()}</button>;
144
+ }
145
+ };
154
146
 
155
- return (
156
- <Layout
157
- model={model}
158
- factory={factory} />
159
- );
147
+ return <Layout model={model} factory={factory} />;
160
148
  }
161
- ```
149
+ ```
162
150
 
163
151
  The above code would render two tab sets horizontally each containing a single tab that hosts a button component. The tabs could be moved and resized by dragging and dropping. Additional grids could be added to the layout by sending actions to the model.
164
152
 
165
- Try it now using [JSFiddle](https://jsfiddle.net/fvd9btea/)
153
+ ## OptimizedLayout
154
+
155
+ `OptimizedLayout` is a wrapper around `Layout` that renders tab content outside of FlexLayout's DOM structure for better performance. This is particularly useful for complex tab content that shouldn't re-render when the layout model changes.
156
+
157
+ ### Key Benefits
158
+
159
+ 1. **No re-renders on layout changes** - Tab components are NOT re-rendered when the Model changes
160
+ 2. **State preservation** - Tab state (scroll position, form inputs, etc.) is preserved across layout mutations
161
+ 3. **CSS-only updates** - Only CSS properties change when layout changes, avoiding React re-renders
166
162
 
167
- A simple Typescript example can be found here:
163
+ ### How It Works
168
164
 
169
- https://github.com/nealus/FlexLayout_cra_example
165
+ 1. `OptimizedLayout` renders `Layout` with lightweight `TabRef` placeholders instead of actual tab content
166
+ 2. `TabRef` components listen to resize/visibility events from `TabNode`s
167
+ 3. A sibling `TabContainer` renders the actual tab content with absolute positioning
168
+ 4. During drag operations, `TabContainer` uses `pointer-events: none` to prevent interfering with FlexLayout's drag overlay
169
+
170
+ ### Example Usage
171
+
172
+ ```tsx
173
+ import { Model, OptimizedLayout } from "@aptre/flex-layout";
174
+ import "@aptre/flex-layout/style/light.css";
175
+
176
+ const json = {
177
+ global: {},
178
+ borders: [],
179
+ layout: {
180
+ type: "row",
181
+ weight: 100,
182
+ children: [
183
+ {
184
+ type: "tabset",
185
+ weight: 50,
186
+ children: [{ type: "tab", name: "Editor", component: "editor" }],
187
+ },
188
+ {
189
+ type: "tabset",
190
+ weight: 50,
191
+ children: [{ type: "tab", name: "Preview", component: "preview" }],
192
+ },
193
+ ],
194
+ },
195
+ };
196
+
197
+ const model = Model.fromJson(json);
198
+
199
+ function App() {
200
+ // renderTab receives a TabNode and returns the content for that tab
201
+ const renderTab = (node) => {
202
+ const component = node.getComponent();
203
+
204
+ if (component === "editor") {
205
+ return <Editor />;
206
+ }
207
+ if (component === "preview") {
208
+ return <Preview />;
209
+ }
210
+ return <div>Unknown component: {component}</div>;
211
+ };
212
+
213
+ return (
214
+ <div style={{ position: "relative", width: "100%", height: "100vh" }}>
215
+ <OptimizedLayout model={model} renderTab={renderTab} />
216
+ </div>
217
+ );
218
+ }
219
+ ```
220
+
221
+ ### Props
222
+
223
+ `OptimizedLayout` accepts all the same props as `Layout`, except:
224
+
225
+ - **`renderTab`** (required) - Replaces `factory`. A function that receives a `TabNode` and returns a React element to render as the tab content.
226
+
227
+ All other `Layout` props (`model`, `onModelChange`, `classNameMapper`, etc.) work the same way.
228
+
229
+ ### When to Use OptimizedLayout
230
+
231
+ Use `OptimizedLayout` when:
232
+
233
+ - Your tab content is expensive to render
234
+ - You need to preserve internal component state across layout changes
235
+ - You have many tabs and want to minimize re-renders
236
+
237
+ Use the standard `Layout` when:
238
+
239
+ - You need tab content to re-render when the model changes
240
+ - Your tab content is simple and lightweight
241
+ - You need the factory pattern for lazy loading components
242
+
243
+ ## Model JSON Structure
170
244
 
171
245
  The model json contains 4 top level elements:
172
246
 
173
- * global - (optional) where global options are defined
174
- * layout - where the main row/tabset/tabs layout hierarchy is defined
175
- * borders - (optional) where up to 4 borders are defined ("top", "bottom", "left", "right").
176
- * popouts - (optional) where the popout windows are defined
247
+ - global - (optional) where global options are defined
248
+ - layout - where the main row/tabset/tabs layout hierarchy is defined
249
+ - borders - (optional) where up to 4 borders are defined ("top", "bottom", "left", "right").
250
+ - popouts - (optional) where the popout windows are defined
177
251
 
178
252
  The layout element is built up using 3 types of 'node':
179
253
 
180
- * row - rows contains a list of tabsets and child rows, the top level 'row' will render horizontally (unless the global attribute rootOrientationVertical is set)
181
- , child 'rows' will render in the opposite orientation to their parent row.
254
+ - row - rows contains a list of tabsets and child rows, the top level 'row' will render horizontally (unless the global attribute rootOrientationVertical is set)
255
+ , child 'rows' will render in the opposite orientation to their parent row.
182
256
 
183
- * tabset - tabsets contain a list of tabs and the index of the selected tab
257
+ - tabset - tabsets contain a list of tabs and the index of the selected tab
184
258
 
185
- * tab - tabs specify the name of the component that they should host (that will be loaded via the factory) and the text of the actual tab.
259
+ - tab - tabs specify the name of the component that they should host (that will be loaded via the factory) and the text of the actual tab.
186
260
 
187
261
  The layout structure is defined with rows within rows that contain tabsets that themselves contain tabs.
188
262
 
189
263
  The optional borders element is made up of border nodes
190
264
 
191
- * border - borders contain a list of tabs and the index of the selected tab, they can only be used in the borders
192
- top level element.
265
+ - border - borders contain a list of tabs and the index of the selected tab, they can only be used in the borders
266
+ top level element.
193
267
 
194
- The tree structure for the JSON model is well defined as Typescript interfaces, see [JSON Model](#json-model-definition)
268
+ The tree structure for the JSON model is well defined as Typescript interfaces, see [JSON Model](#json-model-definition)
195
269
 
196
270
  Each type of node has a defined set of requires/optional attributes.
197
271
 
198
272
  Weights on rows and tabsets specify the relative weight of these nodes within the parent row, the actual values do not matter just their relative values (ie two tabsets of weights 30,70 would render the same if they had weights of 3,7).
199
273
 
200
- NOTE: the easiest way to create your initial layout JSON is to use the [demo](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/demo/index.html) app, modify one of the
201
- existing layouts by dragging/dropping and adding nodes then press the 'Show Layout JSON in console' button to print the JSON to the browser developer console.
202
-
203
274
  By changing global or node attributes you can change the layout appearance and functionality, for example:
204
275
 
205
276
  Setting tabSetEnableTabStrip:false in the global options would change the layout into a multi-splitter (without
@@ -213,29 +284,28 @@ tabs or drag and drop).
213
284
 
214
285
  Once the model json has been loaded all changes to the model are applied through actions.
215
286
 
216
-
217
287
  You apply actions using the `Model.doAction()` method.
218
288
 
219
289
  This method takes a single argument, created by one of the action
220
- generators (typically accessed as `FlexLayout.Actions.<actionName>`):
290
+ generators (typically accessed as `FlexLayout.Actions.<actionName>`).
221
291
 
222
- [Actions doc](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/typedoc/classes/Actions.html)
292
+ See [Actions.ts](src/model/Actions.ts) for available actions.
223
293
 
224
294
  ### Examples
225
295
 
226
296
  ```js
227
- model.doAction(FlexLayout.Actions.updateModelAttributes({
228
- splitterSize:40
229
- }));
297
+ model.doAction(
298
+ FlexLayout.Actions.updateModelAttributes({
299
+ splitterSize: 40,
300
+ }),
301
+ );
230
302
  ```
231
303
 
232
304
  The above example would increase the size of the splitters, this could be used to make
233
305
  adjusting the layout easier on a small device.
234
306
 
235
307
  ```js
236
- model.doAction(FlexLayout.Actions.addNode(
237
- {type:"tab", component:"grid", name:"a grid", id:"5"},
238
- "1", FlexLayout.DockLocation.CENTER, 0));
308
+ model.doAction(FlexLayout.Actions.addNode({ type: "tab", component: "grid", name: "a grid", id: "5" }, "1", FlexLayout.DockLocation.CENTER, 0));
239
309
  ```
240
310
 
241
311
  This example adds a new grid component to the center of tabset with id "1" and at the 0'th tab position (use value -1 to add to the end of the tabs).
@@ -249,59 +319,30 @@ implementing the `onAction` callback property of the `Layout`.
249
319
 
250
320
  ## Optional Layout Props
251
321
 
252
- There are many optional properties that can be applied to the layout:
253
-
254
- [Layout Properties doc](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/typedoc/interfaces/ILayoutProps.html)
255
-
322
+ There are many optional properties that can be applied to the layout. See [ILayoutProps in Layout.tsx](src/view/Layout.tsx) for the full interface.
256
323
 
257
324
  ## JSON Model Definition
258
325
 
259
- The JSON model is well defined as a set of TypeScript interfaces, see the doc for details of all the attributes allowed:
260
-
261
- ## Model Config Attributes
262
-
263
- [Model Attributes doc](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/typedoc/interfaces/IJsonModel.html)
264
-
265
- ## Global Config Attributes
266
-
267
- [Global Attributes doc](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/typedoc/interfaces/IGlobalAttributes.html)
268
-
269
- ## Row Config Attributes
270
-
271
- [Row Attributes doc](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/typedoc/interfaces/IJsonRowNode.html)
272
-
273
- ## Tab Set Config Attributes
274
-
275
- [Tab set Attributes doc](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/typedoc/interfaces/IJsonTabSetNode.html)
276
-
277
- Note: tab sets will be dynamically created as tabs are moved, and deleted when all their tabs are removed (unless enableDeleteWhenEmpty is false).
278
-
279
- ## Tab Config attributes
280
-
281
- [Tab Attributes doc](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/typedoc/interfaces/IJsonTabNode.html)
282
-
283
- ## Border Config attributes
284
-
285
- [Border Attributes doc](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/typedoc/interfaces/IJsonBorderNode.html)
286
-
287
-
288
-
326
+ The JSON model is well defined as a set of TypeScript interfaces. See [IJsonModel.ts](src/model/IJsonModel.ts) for all available attributes:
289
327
 
328
+ - `IJsonModel` - Top-level model structure
329
+ - `IGlobalAttributes` - Global config attributes
330
+ - `IJsonRowNode` - Row config attributes
331
+ - `IJsonTabSetNode` - Tab set config attributes (note: tab sets are dynamically created as tabs are moved, and deleted when empty unless `enableDeleteWhenEmpty` is false)
332
+ - `IJsonTabNode` - Tab config attributes
333
+ - `IJsonBorderNode` - Border config attributes
290
334
 
291
335
  ## Layout Component Methods to Create New Tabs
292
336
 
293
- There are methods on the Layout Component for adding tabs:
294
-
295
- [Layout Methods doc](https://rawgit.com/caplin/FlexLayout/demos/demos/v0.8/typedoc/classes/Layout.html)
337
+ There are methods on the Layout Component for adding tabs. See [Layout.tsx](src/view/Layout.tsx) for available methods.
296
338
 
297
339
  Example:
298
340
 
299
341
  ```
300
342
  layoutRef.current.addTabToTabSet("NAVIGATION", {type:"tab", component:"grid", name:"a grid"});
301
343
  ```
302
- This would add a new grid component to the tab set with id "NAVIGATION" (where layoutRef is a ref to the Layout element, see https://reactjs.org/docs/refs-and-the-dom.html ).
303
-
304
344
 
345
+ This would add a new grid component to the tab set with id "NAVIGATION" (where layoutRef is a ref to the Layout element, see https://reactjs.org/docs/refs-and-the-dom.html ).
305
346
 
306
347
  ## Tab Node Events
307
348
 
@@ -309,6 +350,7 @@ You can handle events on nodes by adding a listener, this would typically be don
309
350
  when the component is mounted in a useEffect method:
310
351
 
311
352
  Example:
353
+
312
354
  ```
313
355
  function MyComponent({node}) {
314
356
 
@@ -322,12 +364,12 @@ Example:
322
364
 
323
365
  ```
324
366
 
325
- | Event | parameters | Description |
326
- | ------------- |:-------------:| -----|
327
- | resize | {rect} | called when tab is resized during layout, called before it is rendered with the new size|
328
- | close | none | called when a tab is closed |
329
- | visibility | {visible} | called when the visibility of a tab changes |
330
- | save | none | called before a tabnode is serialized to json, use to save node config by adding data to the object returned by node.getConfig()|
367
+ | Event | parameters | Description |
368
+ | ---------- | :--------: | -------------------------------------------------------------------------------------------------------------------------------- |
369
+ | resize | {rect} | called when tab is resized during layout, called before it is rendered with the new size |
370
+ | close | none | called when a tab is closed |
371
+ | visibility | {visible} | called when the visibility of a tab changes |
372
+ | save | none | called before a tabnode is serialized to json, use to save node config by adding data to the object returned by node.getConfig() |
331
373
 
332
374
  ## Popout Windows
333
375
 
@@ -356,31 +398,32 @@ Note: libraries may support popout windows by allowing you to specify the docume
356
398
  for example see the getDocument() callback in agGrid at https://www.ag-grid.com/javascript-grid-callbacks/
357
399
 
358
400
  ### Limitations of Popouts
359
- * FlexLayout uses React Portals to draw the popout window content,
360
- this means all the code runs in the main Window's JS context, so effectively the popout windows are just extensions of the area on which the main window can render panels.
361
-
362
- * Your code must use the popout window/document in popout windows when adding event listeners (e.g popoutDocument.addEventListener(...)).
363
-
364
- * Timers throttle when main window is in the background
365
- you could implement a webworker timer replacement if needed (which will not throttle)
366
- * Many third party controls will use the global document for some event listeners,
367
- these will not work correctly without modification
368
- * Some third party controls will suspend when the global document is hidden
369
- you can use the tab overlay attribute to 'gray out' these tabs when the main window is hidden
370
- * Resize observers may be throttled (or stay attached to the main window), so you may need to use some other way to resize the component when in a popout (see aggrid component in demo).
371
- * Popouts will not size and position correctly when the browser is zoomed (ie set to 50% zoom)
372
- * Popouts cannot reload in maximized or minimized states
373
- * by default flexlayout will maintain react state when moving tabs between windows, but you can use the
374
- enableWindowReMount tab attribute to force the component to re-mount.
401
+
402
+ - FlexLayout uses React Portals to draw the popout window content,
403
+ this means all the code runs in the main Window's JS context, so effectively the popout windows are just extensions of the area on which the main window can render panels.
404
+
405
+ - Your code must use the popout window/document in popout windows when adding event listeners (e.g popoutDocument.addEventListener(...)).
406
+
407
+ - Timers throttle when main window is in the background
408
+ you could implement a webworker timer replacement if needed (which will not throttle)
409
+ - Many third party controls will use the global document for some event listeners,
410
+ these will not work correctly without modification
411
+ - Some third party controls will suspend when the global document is hidden
412
+ you can use the tab overlay attribute to 'gray out' these tabs when the main window is hidden
413
+ - Resize observers may be throttled (or stay attached to the main window), so you may need to use some other way to resize the component when in a popout (see aggrid component in demo).
414
+ - Popouts will not size and position correctly when the browser is zoomed (ie set to 50% zoom)
415
+ - Popouts cannot reload in maximized or minimized states
416
+ - by default flexlayout will maintain react state when moving tabs between windows, but you can use the
417
+ enableWindowReMount tab attribute to force the component to re-mount.
375
418
 
376
419
  See this article about using React portals in this way: https://dev.to/noriste/the-challenges-of-rendering-an-openlayers-map-in-a-popup-through-react-2elh
377
420
 
378
421
  ## Alternative Layout Managers
379
422
 
380
- | Name | Repository |
381
- | ------------- |:-------------|
382
- | rc-dock | https://github.com/ticlo/rc-dock |
383
- | Dockview | https://dockview.dev/ |
384
- | lumino | https://github.com/jupyterlab/lumino |
423
+ | Name | Repository |
424
+ | ------------- | :--------------------------------------------- |
425
+ | rc-dock | https://github.com/ticlo/rc-dock |
426
+ | Dockview | https://dockview.dev/ |
427
+ | lumino | https://github.com/jupyterlab/lumino |
385
428
  | golden-layout | https://github.com/golden-layout/golden-layout |
386
- | react-mosaic | https://github.com/nomcopter/react-mosaic |
429
+ | react-mosaic | https://github.com/nomcopter/react-mosaic |
package/dist/index.mjs CHANGED
@@ -5979,7 +5979,8 @@ function TabContainer({
5979
5979
  tabs,
5980
5980
  renderTab,
5981
5981
  isDragging,
5982
- classNameMapper
5982
+ classNameMapper,
5983
+ model
5983
5984
  }) {
5984
5985
  const getClassName = useCallback(
5985
5986
  (defaultClassName) => {
@@ -5987,6 +5988,17 @@ function TabContainer({
5987
5988
  },
5988
5989
  [classNameMapper]
5989
5990
  );
5991
+ const handlePointerDown = useCallback(
5992
+ (node) => {
5993
+ const parent = node.getParent();
5994
+ if (parent instanceof TabSetNode) {
5995
+ if (!parent.isActive()) {
5996
+ model.doAction(Actions.setActiveTabset(parent.getId(), Model.MAIN_WINDOW_ID));
5997
+ }
5998
+ }
5999
+ },
6000
+ [model]
6001
+ );
5990
6002
  return /* @__PURE__ */ React20.createElement(
5991
6003
  "div",
5992
6004
  {
@@ -6025,7 +6037,8 @@ function TabContainer({
6025
6037
  overflow: "auto",
6026
6038
  // Tab panels receive pointer events when visible and not dragging
6027
6039
  pointerEvents: visible && !isDragging ? "auto" : "none"
6028
- }
6040
+ },
6041
+ onPointerDown: () => handlePointerDown(node)
6029
6042
  },
6030
6043
  renderTab(node)
6031
6044
  );
@@ -6121,7 +6134,7 @@ function OptimizedLayout({ model, renderTab, classNameMapper, onDragStateChange,
6121
6134
  },
6122
6135
  [handleTabMount, handleRectChange, handleVisibilityChange]
6123
6136
  );
6124
- return /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Layout, { model, factory, classNameMapper, onDragStateChange: handleDragStateChange, onModelChange: handleModelChange, ...layoutProps }), /* @__PURE__ */ React20.createElement(TabContainer, { tabs, renderTab, isDragging, classNameMapper }));
6137
+ return /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(Layout, { model, factory, classNameMapper, onDragStateChange: handleDragStateChange, onModelChange: handleModelChange, ...layoutProps }), /* @__PURE__ */ React20.createElement(TabContainer, { tabs, renderTab, isDragging, classNameMapper, model }));
6125
6138
  }
6126
6139
 
6127
6140
  // src/model/walk.ts
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@aptre/flex-layout",
3
3
  "author": "Caplin Systems Ltd",
4
4
  "description": "A multi-tab docking layout manager",
5
- "version": "0.5.2",
5
+ "version": "0.5.3",
6
6
  "license": "ISC",
7
7
  "repository": {
8
8
  "type": "git",