@genesislcap/foundation-layout 14.92.2-beta.revert-PA-913.1 → 14.92.3-beta.0a7ca6c.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- var _FoundationLayout__boundPreDeletionListener, _FoundationLayout__boundDragListener, _a;
1
+ var _FoundationLayout__boundDragListener, _a;
2
2
  import { __classPrivateFieldGet, __classPrivateFieldSet, __decorate } from "tslib";
3
3
  import { GoldenLayout, LayoutConfig, ResolvedLayoutConfig, } from '@genesis-community/golden-layout';
4
4
  import { Session } from '@genesislcap/foundation-comms';
@@ -6,7 +6,7 @@ import { layoutCacheDocument, UUID } from '@genesislcap/foundation-utils';
6
6
  import { html, attr, observable, when, ref } from '@microsoft/fast-element';
7
7
  import { FoundationElement } from '@microsoft/fast-foundation';
8
8
  import { globalDraggingStyles, glVisualConfig, layoutStyles } from '../styles';
9
- import { DEFAULT_RELOAD_BUFFER, LayoutEmitEvents, LayoutReceiveEvents, componentType, AUTOSAVE_KEY, regionConveter, } from '../utils/';
9
+ import { DEFAULT_RELOAD_BUFFER, LayoutEmitEvents, LayoutReceiveEvents, componentType, AUTOSAVE_KEY, regionConveter, instanceContainer, } from '../utils/';
10
10
  import { getMissingArrayItems } from '../utils/';
11
11
  import { LayoutRegistrationError, LayoutUsageError } from '../utils/error';
12
12
  import { logger } from '../utils/logger';
@@ -88,14 +88,13 @@ export class FoundationLayout extends FoundationElement {
88
88
  */
89
89
  this.lifecycleUpdateToken = undefined;
90
90
  /** @internal */
91
- _FoundationLayout__boundPreDeletionListener.set(this, undefined);
92
- /** @internal */
93
91
  _FoundationLayout__boundDragListener.set(this, undefined);
94
92
  this.onDragStart = this.onDragStart.bind(this);
95
93
  this.onDragStop = this.onDragStop.bind(this);
96
94
  this.cacheAndSaveLayout = this.cacheAndSaveLayout.bind(this);
97
95
  this.onPostItemRemoved = this.onPostItemRemoved.bind(this);
98
96
  this.onPreItemRemoved = this.onPreItemRemoved.bind(this);
97
+ this.onAutosaveRequest = this.onAutosaveRequest.bind(this);
99
98
  }
100
99
  /** @internal */
101
100
  connectedCallback() {
@@ -111,18 +110,24 @@ export class FoundationLayout extends FoundationElement {
111
110
  .catch((e) => console.error('Failed to replace styles:', e));
112
111
  appliedGlobalStyles = true;
113
112
  }
113
+ // golden layout events
114
114
  this.shadowRoot.addEventListener('dragStart', this.onDragStart, true);
115
115
  this.shadowRoot.addEventListener('dragStop', this.onDragStop, true);
116
116
  this.shadowRoot.addEventListener('closeButtonPre', this.onPreItemRemoved, true);
117
117
  this.shadowRoot.addEventListener('closeButtonPressed', this.onPostItemRemoved, true);
118
+ // events.ts events
119
+ this.shadowRoot.addEventListener(LayoutReceiveEvents.autosave, this.onAutosaveRequest, true);
118
120
  this.setupCustomButtons();
119
121
  }
120
122
  /** @internal */
121
123
  disconnectedCallback() {
124
+ // golden layout events
122
125
  this.shadowRoot.removeEventListener('dragStart', this.onDragStart);
123
126
  this.shadowRoot.removeEventListener('dragStop', this.onDragStop);
124
127
  this.shadowRoot.removeEventListener('closeButtonPre', this.onPreItemRemoved);
125
128
  this.shadowRoot.removeEventListener('closeButtonPressed', this.onPostItemRemoved);
129
+ // events.ts events
130
+ this.shadowRoot.addEventListener(LayoutReceiveEvents.autosave, this.onAutosaveRequest);
126
131
  }
127
132
  /** @internal */
128
133
  onDragStart() {
@@ -153,6 +158,10 @@ export class FoundationLayout extends FoundationElement {
153
158
  this.$emit(LayoutEmitEvents.itemResized);
154
159
  this.cacheAndSaveLayout();
155
160
  }
161
+ /** @internal */
162
+ onAutosaveRequest() {
163
+ this.cacheAndSaveLayout();
164
+ }
156
165
  /**
157
166
  * JS API, public
158
167
  */
@@ -194,9 +203,22 @@ export class FoundationLayout extends FoundationElement {
194
203
  /**
195
204
  * @public
196
205
  * Gets a minified string containing the config describing the current layout of the layout object to later restore in {@link FoundationLayout.loadLayout | function}
206
+ * @remarks
207
+ * Includes any state for a contained component exposed by the {@link LayoutComponentWithState} interface.
197
208
  * @returns - latest version of {@link SerialisedLayout} describing the layout
198
209
  */
199
210
  getLayout() {
211
+ const componentCollection = this.getLayoutComponents();
212
+ componentCollection.forEach((items) => {
213
+ if (!items.length)
214
+ return;
215
+ const orderedStates = [...items].map((item) => { var _b; return (_b = item.getCurrentState) === null || _b === void 0 ? void 0 : _b.call(item); });
216
+ const componentInstanceContainer = items[0][instanceContainer];
217
+ componentInstanceContainer.container.setState({
218
+ instance: componentInstanceContainer.instance,
219
+ orderedStates,
220
+ });
221
+ });
200
222
  return { v: '1', c: ResolvedLayoutConfig.minifyConfig(this.layout.saveLayout()) };
201
223
  }
202
224
  /**
@@ -413,6 +435,9 @@ export class FoundationLayout extends FoundationElement {
413
435
  *
414
436
  * This has the effect of allowing us to create multiple instances of the same registered item, and each
415
437
  * created instance is separate allowing it to implement its own serialise and cache of data.
438
+ *
439
+ * As part of creating each instance we attach a reference to the instance container which is used
440
+ * to be able to optionally save state, and any state which has been saved we apply to the component.
416
441
  */
417
442
  const registrationFunction = (() => {
418
443
  // Use appendChild to consume the elements and save them in the master copy
@@ -433,11 +458,25 @@ export class FoundationLayout extends FoundationElement {
433
458
  // the key point is "cloneNode" which makes a copy at this point
434
459
  if (!instances.has(state === null || state === void 0 ? void 0 : state['instance'])) {
435
460
  const instanceCopy = document.createDocumentFragment();
436
- Array.from(masterCopy.children).forEach((e) => instanceCopy.appendChild(e.cloneNode(true)));
461
+ Array.from(masterCopy.children).forEach((e) => {
462
+ instanceCopy.appendChild(e.cloneNode(true));
463
+ });
437
464
  instances.set(state['instance'], [...instanceCopy.children]);
438
465
  }
466
+ // provide each component with a reference to the instance container
467
+ // so they can optionally save and load their own state
468
+ const componentInstanceContainer = {
469
+ container,
470
+ instance: state['instance'],
471
+ };
472
+ const instanceOrderedStates = state['orderedStates'] || [];
439
473
  // get the instance from the map and append it to the container
440
- instances.get(state['instance']).forEach((e) => container.element.appendChild(e));
474
+ instances.get(state['instance']).forEach((component, i) => {
475
+ var _b, _c;
476
+ (_b = component.applyState) === null || _b === void 0 ? void 0 : _b.call(component, (_c = instanceOrderedStates[i]) !== null && _c !== void 0 ? _c : null);
477
+ container.element.appendChild(component);
478
+ component[instanceContainer] = componentInstanceContainer;
479
+ });
441
480
  this.setupLayoutReceiveEvents(container, state);
442
481
  };
443
482
  })();
@@ -552,8 +591,17 @@ export class FoundationLayout extends FoundationElement {
552
591
  });
553
592
  });
554
593
  }
594
+ /**
595
+ * Return an array of each contained items in the layout.
596
+ * @internal
597
+ */
598
+ getLayoutComponents() {
599
+ return [...this.shadowRoot.querySelectorAll('div.lm_content')].map((container) => [
600
+ ...container.children,
601
+ ]);
602
+ }
555
603
  }
556
- _FoundationLayout__boundPreDeletionListener = new WeakMap(), _FoundationLayout__boundDragListener = new WeakMap(), _a = componentType;
604
+ _FoundationLayout__boundDragListener = new WeakMap(), _a = componentType;
557
605
  __decorate([
558
606
  attr({ attribute: 'reload-buffer' })
559
607
  ], FoundationLayout.prototype, "reloadBuffer", void 0);
@@ -3,6 +3,11 @@
3
3
  * @internal
4
4
  */
5
5
  export const componentType = Symbol('component-type');
6
+ /**
7
+ * Used to key a reference to the instance and golden layout container on a layout component.
8
+ * @internal
9
+ */
10
+ export const instanceContainer = Symbol('component-instance');
6
11
  /**
7
12
  * Default time in milliseconds for the layout to buffer calls to reloading
8
13
  * the layout while the declarative API is loading.
@@ -21,8 +21,10 @@ export const LayoutEmitEvents = {
21
21
  * Defines events that the layout system listens for
22
22
  *
23
23
  * 'changeTitle' - emit this from a contained item to update the title of the window that contains it.
24
+ * 'autosave' - emit this from a contained item to hint to the layout system that it should autosave the layout. A contained item should do this if it has just changed some state it would like to persist. See {@link LayoutComponentWithState}.
24
25
  * @public
25
26
  */
26
27
  export const LayoutReceiveEvents = {
27
28
  changeTitle: 'change-title',
29
+ autosave: 'autosave',
28
30
  };
@@ -1,3 +1,3 @@
1
- import { componentType } from './constants';
1
+ import { componentType, instanceContainer } from './constants';
2
2
  /** @internal */
3
3
  export const layoutRegionValue = ['horizontal', 'vertical', 'tabs'];
@@ -527,7 +527,7 @@
527
527
  {
528
528
  "kind": "Method",
529
529
  "canonicalReference": "@genesislcap/foundation-layout!FoundationLayout#getLayout:member(1)",
530
- "docComment": "/**\n * Gets a minified string containing the config describing the current layout of the layout object to later restore in {@link FoundationLayout.loadLayout | function}\n *\n * @returns - latest version of {@link SerialisedLayout} describing the layout\n *\n * @public\n */\n",
530
+ "docComment": "/**\n * Gets a minified string containing the config describing the current layout of the layout object to later restore in {@link FoundationLayout.loadLayout | function}\n *\n * @remarks\n *\n * Includes any state for a contained component exposed by the {@link LayoutComponentWithState} interface.\n *\n * @returns - latest version of {@link SerialisedLayout} describing the layout\n *\n * @public\n */\n",
531
531
  "excerptTokens": [
532
532
  {
533
533
  "kind": "Content",
@@ -1432,6 +1432,110 @@
1432
1432
  "endIndex": 2
1433
1433
  }
1434
1434
  },
1435
+ {
1436
+ "kind": "Interface",
1437
+ "canonicalReference": "@genesislcap/foundation-layout!LayoutComponentWithState:interface",
1438
+ "docComment": "/**\n * Interface to implement on an item which is a component of the layout and you wish to serialise state with. This is saved separately for each instance of the component, which allows you to restore multiple instances of the same component with different state.\n *\n * @remarks\n *\n * When the layout is saved either via the autosave functionality or manually calling {@link FoundationLayout.getLayout}, all contained components will be requested to provide state if they wish.\n *\n * Any state which is provided will be saved as part of the layout config and will be passed back to the component when the layout is reloaded. Before an item is appended onto the layout DOM, the state will be applied to the component via `applyState`. You will likely want to cache this and then use it later in the lifecycle of the component. The state is `null` when the instance is first created.\n *\n * See the written documentation for some error scenarios to consider about when implementing this interface.\n *\n * @typeParam T - the type of the state object you wish to serialise with the component.\n *\n * @example\n * ```\n * type ComponentState = {\n * foo: string;\n * }\n * \\@customElement({ name: 'my-component' })\n * export class MyComponent extends FASTElement implements LayoutComponentWithState<ComponentState> {\n * \\@observable foo: string;\n * private fooCache: ComponentState | null;\n *\n * getCurrentState(): ComponentState {\n * if (!this.foo) return null;\n * return {\n * foo: this.foo;\n * }\n * }\n *\n * applyState(state: ComponentState | null) {\n * this.fooCache = state;\n * }\n *\n * connectedCallback() {\n * // do other required setup\n * if (this.fooCache) {\n * this.foo = this.fooCache.foo;\n * }\n * }\n * }\n * ```\n *\n * @example\n *\n * If you are using the autosave functionality you should inform the layout system when you update the state of a component, otherwise the state will only be updated when the user performs an action such as resizing an item. Use the {@link LayoutReceiveEvents} `autosave` event.\n * ```\n * // Same component as above\n * export class MyComponent extends FASTElement implements LayoutComponentWithState<ComponentState> {\n * // can use xChanged pattern as `foo` was declared observable\n * fooChanged() {\n * this.$emit(LayoutReceiveEvents.autosave);\n * }\n * }\n * ```\n *\n * @public\n */\n",
1439
+ "excerptTokens": [
1440
+ {
1441
+ "kind": "Content",
1442
+ "text": "export interface LayoutComponentWithState<T> "
1443
+ }
1444
+ ],
1445
+ "fileUrlPath": "src/utils/types.ts",
1446
+ "releaseTag": "Public",
1447
+ "typeParameters": [
1448
+ {
1449
+ "typeParameterName": "T",
1450
+ "constraintTokenRange": {
1451
+ "startIndex": 0,
1452
+ "endIndex": 0
1453
+ },
1454
+ "defaultTypeTokenRange": {
1455
+ "startIndex": 0,
1456
+ "endIndex": 0
1457
+ }
1458
+ }
1459
+ ],
1460
+ "name": "LayoutComponentWithState",
1461
+ "preserveMemberOrder": false,
1462
+ "members": [
1463
+ {
1464
+ "kind": "MethodSignature",
1465
+ "canonicalReference": "@genesislcap/foundation-layout!LayoutComponentWithState#applyState:member(1)",
1466
+ "docComment": "/**\n * Handle any state that has been saved previously for this instance of this component. This will be called before the component is appended to the DOM. Due to the lifecycle events not running by this point, it is recommended you cache the state and then apply it in `connectedCallback`.\n */\n",
1467
+ "excerptTokens": [
1468
+ {
1469
+ "kind": "Content",
1470
+ "text": "applyState(state: "
1471
+ },
1472
+ {
1473
+ "kind": "Content",
1474
+ "text": "T | null"
1475
+ },
1476
+ {
1477
+ "kind": "Content",
1478
+ "text": "): "
1479
+ },
1480
+ {
1481
+ "kind": "Content",
1482
+ "text": "void"
1483
+ },
1484
+ {
1485
+ "kind": "Content",
1486
+ "text": ";"
1487
+ }
1488
+ ],
1489
+ "isOptional": false,
1490
+ "returnTypeTokenRange": {
1491
+ "startIndex": 3,
1492
+ "endIndex": 4
1493
+ },
1494
+ "releaseTag": "Public",
1495
+ "overloadIndex": 1,
1496
+ "parameters": [
1497
+ {
1498
+ "parameterName": "state",
1499
+ "parameterTypeTokenRange": {
1500
+ "startIndex": 1,
1501
+ "endIndex": 2
1502
+ },
1503
+ "isOptional": false
1504
+ }
1505
+ ],
1506
+ "name": "applyState"
1507
+ },
1508
+ {
1509
+ "kind": "MethodSignature",
1510
+ "canonicalReference": "@genesislcap/foundation-layout!LayoutComponentWithState#getCurrentState:member(1)",
1511
+ "docComment": "/**\n * Provide the state you wish to save. It is recommended if the component which implements this interface has not fully initialised at the point this is called that you return `null` as the state, following the pattern of `null` being set as the initial state.\n */\n",
1512
+ "excerptTokens": [
1513
+ {
1514
+ "kind": "Content",
1515
+ "text": "getCurrentState(): "
1516
+ },
1517
+ {
1518
+ "kind": "Content",
1519
+ "text": "T"
1520
+ },
1521
+ {
1522
+ "kind": "Content",
1523
+ "text": ";"
1524
+ }
1525
+ ],
1526
+ "isOptional": false,
1527
+ "returnTypeTokenRange": {
1528
+ "startIndex": 1,
1529
+ "endIndex": 2
1530
+ },
1531
+ "releaseTag": "Public",
1532
+ "overloadIndex": 1,
1533
+ "parameters": [],
1534
+ "name": "getCurrentState"
1535
+ }
1536
+ ],
1537
+ "extendsTokenRanges": []
1538
+ },
1435
1539
  {
1436
1540
  "kind": "Variable",
1437
1541
  "canonicalReference": "@genesislcap/foundation-layout!LayoutEmitEvents:var",
@@ -1458,7 +1562,7 @@
1458
1562
  {
1459
1563
  "kind": "Variable",
1460
1564
  "canonicalReference": "@genesislcap/foundation-layout!LayoutReceiveEvents:var",
1461
- "docComment": "/**\n * Defines events that the layout system listens for\n *\n * 'changeTitle' - emit this from a contained item to update the title of the window that contains it.\n *\n * @public\n */\n",
1565
+ "docComment": "/**\n * Defines events that the layout system listens for\n *\n * 'changeTitle' - emit this from a contained item to update the title of the window that contains it. 'autosave' - emit this from a contained item to hint to the layout system that it should autosave the layout. A contained item should do this if it has just changed some state it would like to persist. See {@link LayoutComponentWithState}.\n *\n * @public\n */\n",
1462
1566
  "excerptTokens": [
1463
1567
  {
1464
1568
  "kind": "Content",
@@ -1466,7 +1570,7 @@
1466
1570
  },
1467
1571
  {
1468
1572
  "kind": "Content",
1469
- "text": "{\n readonly changeTitle: \"change-title\";\n}"
1573
+ "text": "{\n readonly changeTitle: \"change-title\";\n readonly autosave: \"autosave\";\n}"
1470
1574
  }
1471
1575
  ],
1472
1576
  "fileUrlPath": "src/utils/events.ts",
@@ -1481,7 +1585,7 @@
1481
1585
  {
1482
1586
  "kind": "TypeAlias",
1483
1587
  "canonicalReference": "@genesislcap/foundation-layout!LayoutReceiveEventsDetail:type",
1484
- "docComment": "/**\n * Defines the shape of the detail that the layout listens works with for events it listens on\n *\n * 'changeTitle' - `title` is the string you want to set. For `mode`: `replace` will set the title to be `title`, `suffix` will append `title` to the end of the existing title.\n *\n * @public\n */\n",
1588
+ "docComment": "/**\n * Defines the shape of the detail that the layout listens works with for events it listens on\n *\n * 'changeTitle' - `title` is the string you want to set. For `mode`: `replace` will set the title to be `title`, `suffix` will append `title` to the end of the existing title. 'autosave' - no other parameters.\n *\n * @public\n */\n",
1485
1589
  "excerptTokens": [
1486
1590
  {
1487
1591
  "kind": "Content",
@@ -1489,7 +1593,7 @@
1489
1593
  },
1490
1594
  {
1491
1595
  "kind": "Content",
1492
- "text": "{\n changeTitle: {\n title: string;\n mode: 'replace' | 'suffix';\n };\n}"
1596
+ "text": "{\n changeTitle: {\n title: string;\n mode: 'replace' | 'suffix';\n };\n autosave: void;\n}"
1493
1597
  },
1494
1598
  {
1495
1599
  "kind": "Content",
@@ -143,6 +143,8 @@ export declare class FoundationLayout extends FoundationElement implements Layou
143
143
  private onPostItemRemoved;
144
144
  /** @internal */
145
145
  private onPostItemResized;
146
+ /** @internal */
147
+ private onAutosaveRequest;
146
148
  /**
147
149
  * JS API, public
148
150
  */
@@ -171,6 +173,8 @@ export declare class FoundationLayout extends FoundationElement implements Layou
171
173
  /**
172
174
  * @public
173
175
  * Gets a minified string containing the config describing the current layout of the layout object to later restore in {@link FoundationLayout.loadLayout | function}
176
+ * @remarks
177
+ * Includes any state for a contained component exposed by the {@link LayoutComponentWithState} interface.
174
178
  * @returns - latest version of {@link SerialisedLayout} describing the layout
175
179
  */
176
180
  getLayout(): SerialisedLayout;
@@ -314,6 +318,11 @@ export declare class FoundationLayout extends FoundationElement implements Layou
314
318
  * @internal
315
319
  */
316
320
  private setupCustomButtons;
321
+ /**
322
+ * Return an array of each contained items in the layout.
323
+ * @internal
324
+ */
325
+ private getLayoutComponents;
317
326
  }
318
327
 
319
328
  /**
@@ -488,6 +497,70 @@ declare interface LayoutComponent {
488
497
  requestLayoutReload(): void;
489
498
  }
490
499
 
500
+ /**
501
+ * Interface to implement on an item which is a component of the layout and you wish to serialise state with. This is saved separately for each instance of the component, which allows you to restore multiple instances of the same component with different state.
502
+ * @typeParam T - the type of the state object you wish to serialise with the component.
503
+ * @remarks
504
+ * When the layout is saved either via the autosave functionality or manually calling {@link FoundationLayout.getLayout}, all contained components will be requested to provide state if they wish.
505
+ *
506
+ * Any state which is provided will be saved as part of the layout config and will be passed back to the component when the layout is reloaded. Before an item is appended onto the layout DOM, the state will be applied to the component via `applyState`. You will likely want to cache this and then use it later in the lifecycle of the component. The state is `null` when the instance is first created.
507
+ *
508
+ * See the written documentation for some error scenarios to consider about when implementing this interface.
509
+ *
510
+ * @example
511
+ * ```
512
+ * type ComponentState = {
513
+ * foo: string;
514
+ * }
515
+ * \@customElement({ name: 'my-component' })
516
+ * export class MyComponent extends FASTElement implements LayoutComponentWithState<ComponentState> {
517
+ * \@observable foo: string;
518
+ * private fooCache: ComponentState | null;
519
+ *
520
+ * getCurrentState(): ComponentState {
521
+ * if (!this.foo) return null;
522
+ * return {
523
+ * foo: this.foo;
524
+ * }
525
+ * }
526
+ *
527
+ * applyState(state: ComponentState | null) {
528
+ * this.fooCache = state;
529
+ * }
530
+ *
531
+ * connectedCallback() {
532
+ * // do other required setup
533
+ * if (this.fooCache) {
534
+ * this.foo = this.fooCache.foo;
535
+ * }
536
+ * }
537
+ * }
538
+ * ```
539
+ *
540
+ * @example
541
+ * If you are using the autosave functionality you should inform the layout system when you update the state of a component, otherwise the state will only be updated when the user performs an action such as resizing an item. Use the {@link LayoutReceiveEvents} `autosave` event.
542
+ * ```
543
+ * // Same component as above
544
+ * export class MyComponent extends FASTElement implements LayoutComponentWithState<ComponentState> {
545
+ * // can use xChanged pattern as `foo` was declared observable
546
+ * fooChanged() {
547
+ * this.$emit(LayoutReceiveEvents.autosave);
548
+ * }
549
+ * }
550
+ * ```
551
+ * @public
552
+ * */
553
+ export declare interface LayoutComponentWithState<T> {
554
+ /**
555
+ * Provide the state you wish to save. It is recommended if the component which implements this interface has not fully initialised at the point this is called that you return `null` as the state, following the pattern of `null` being set as the initial state.
556
+ */
557
+ getCurrentState(): T;
558
+ /**
559
+ * Handle any state that has been saved previously for this instance of this component. This will be called before the component is appended to the DOM. Due to the lifecycle events not running by this point, it is recommended you cache the state and then apply it in `connectedCallback`.
560
+ */
561
+ applyState(state: T | null): void;
562
+ }
563
+
491
564
  /**
492
565
  * Defines events that the layout system emits
493
566
  *
@@ -512,16 +585,19 @@ export declare const LayoutEmitEvents: {
512
585
  * Defines events that the layout system listens for
513
586
  *
514
587
  * 'changeTitle' - emit this from a contained item to update the title of the window that contains it.
588
+ * 'autosave' - emit this from a contained item to hint to the layout system that it should autosave the layout. A contained item should do this if it has just changed some state it would like to persist. See {@link LayoutComponentWithState}.
515
589
  * @public
516
590
  */
517
591
  export declare const LayoutReceiveEvents: {
518
592
  readonly changeTitle: "change-title";
593
+ readonly autosave: "autosave";
519
594
  };
520
595
 
521
596
  /**
522
597
  * Defines the shape of the detail that the layout listens works with for events it listens on
523
598
  *
524
599
  * 'changeTitle' - `title` is the string you want to set. For `mode`: `replace` will set the title to be `title`, `suffix` will append `title` to the end of the existing title.
600
+ * 'autosave' - no other parameters.
525
601
  * @public
526
602
  */
527
603
  export declare type LayoutReceiveEventsDetail = {
@@ -529,6 +605,7 @@ export declare type LayoutReceiveEventsDetail = {
529
605
  title: string;
530
606
  mode: 'replace' | 'suffix';
531
607
  };
608
+ autosave: void;
532
609
  };
533
610
 
534
611
  /**
@@ -17,3 +17,7 @@ getLayout(): SerialisedLayout;
17
17
 
18
18
  - latest version of [SerialisedLayout](./foundation-layout.serialisedlayout.md) describing the layout
19
19
 
20
+ ## Remarks
21
+
22
+ Includes any state for a contained component exposed by the [LayoutComponentWithState](./foundation-layout.layoutcomponentwithstate.md) interface.
23
+
@@ -0,0 +1,24 @@
1
+ <!-- Do not edit this file. It is automatically generated by API Documenter. -->
2
+
3
+ [Home](./index.md) &gt; [@genesislcap/foundation-layout](./foundation-layout.md) &gt; [LayoutComponentWithState](./foundation-layout.layoutcomponentwithstate.md) &gt; [applyState](./foundation-layout.layoutcomponentwithstate.applystate.md)
4
+
5
+ ## LayoutComponentWithState.applyState() method
6
+
7
+ Handle any state that has been saved previously for this instance of this component. This will be called before the component is appended to the DOM. Due to the lifecycle events not running by this point, it is recommended you cache the state and then apply it in `connectedCallback`<!-- -->.
8
+
9
+ **Signature:**
10
+
11
+ ```typescript
12
+ applyState(state: T | null): void;
13
+ ```
14
+
15
+ ## Parameters
16
+
17
+ | Parameter | Type | Description |
18
+ | --- | --- | --- |
19
+ | state | T \| null | |
20
+
21
+ **Returns:**
22
+
23
+ void
24
+
@@ -0,0 +1,17 @@
1
+ <!-- Do not edit this file. It is automatically generated by API Documenter. -->
2
+
3
+ [Home](./index.md) &gt; [@genesislcap/foundation-layout](./foundation-layout.md) &gt; [LayoutComponentWithState](./foundation-layout.layoutcomponentwithstate.md) &gt; [getCurrentState](./foundation-layout.layoutcomponentwithstate.getcurrentstate.md)
4
+
5
+ ## LayoutComponentWithState.getCurrentState() method
6
+
7
+ Provide the state you wish to save. It is recommended if the component which implements this interface has not fully initialised at the point this is called that you return `null` as the state, following the pattern of `null` being set as the initial state.
8
+
9
+ **Signature:**
10
+
11
+ ```typescript
12
+ getCurrentState(): T;
13
+ ```
14
+ **Returns:**
15
+
16
+ T
17
+
@@ -0,0 +1,75 @@
1
+ <!-- Do not edit this file. It is automatically generated by API Documenter. -->
2
+
3
+ [Home](./index.md) &gt; [@genesislcap/foundation-layout](./foundation-layout.md) &gt; [LayoutComponentWithState](./foundation-layout.layoutcomponentwithstate.md)
4
+
5
+ ## LayoutComponentWithState interface
6
+
7
+ Interface to implement on an item which is a component of the layout and you wish to serialise state with. This is saved separately for each instance of the component, which allows you to restore multiple instances of the same component with different state.
8
+
9
+ **Signature:**
10
+
11
+ ```typescript
12
+ export interface LayoutComponentWithState<T>
13
+ ```
14
+
15
+ ## Remarks
16
+
17
+ When the layout is saved either via the autosave functionality or manually calling [FoundationLayout.getLayout()](./foundation-layout.foundationlayout.getlayout.md)<!-- -->, all contained components will be requested to provide state if they wish.
18
+
19
+ Any state which is provided will be saved as part of the layout config and will be passed back to the component when the layout is reloaded. Before an item is appended onto the layout DOM, the state will be applied to the component via `applyState`<!-- -->. You will likely want to cache this and then use it later in the lifecycle of the component. The state is `null` when the instance is first created.
20
+
21
+ See the written documentation for some error scenarios to consider about when implementing this interface.
22
+
23
+ ## Example 1
24
+
25
+
26
+ ```
27
+ type ComponentState = {
28
+ foo: string;
29
+ }
30
+ \@customElement({ name: 'my-component' })
31
+ export class MyComponent extends FASTElement implements LayoutComponentWithState<ComponentState> {
32
+ \@observable foo: string;
33
+ private fooCache: ComponentState | null;
34
+
35
+ getCurrentState(): ComponentState {
36
+ if (!this.foo) return null;
37
+ return {
38
+ foo: this.foo;
39
+ }
40
+ }
41
+
42
+ applyState(state: ComponentState | null) {
43
+ this.fooCache = state;
44
+ }
45
+
46
+ connectedCallback() {
47
+ // do other required setup
48
+ if (this.fooCache) {
49
+ this.foo = this.fooCache.foo;
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ ## Example 2
56
+
57
+ If you are using the autosave functionality you should inform the layout system when you update the state of a component, otherwise the state will only be updated when the user performs an action such as resizing an item. Use the [LayoutReceiveEvents](./foundation-layout.layoutreceiveevents.md) `autosave` event.
58
+
59
+ ```
60
+ // Same component as above
61
+ export class MyComponent extends FASTElement implements LayoutComponentWithState<ComponentState> {
62
+ // can use xChanged pattern as `foo` was declared observable
63
+ fooChanged() {
64
+ this.$emit(LayoutReceiveEvents.autosave);
65
+ }
66
+ }
67
+ ```
68
+
69
+ ## Methods
70
+
71
+ | Method | Description |
72
+ | --- | --- |
73
+ | [applyState(state)](./foundation-layout.layoutcomponentwithstate.applystate.md) | Handle any state that has been saved previously for this instance of this component. This will be called before the component is appended to the DOM. Due to the lifecycle events not running by this point, it is recommended you cache the state and then apply it in <code>connectedCallback</code>. |
74
+ | [getCurrentState()](./foundation-layout.layoutcomponentwithstate.getcurrentstate.md) | Provide the state you wish to save. It is recommended if the component which implements this interface has not fully initialised at the point this is called that you return <code>null</code> as the state, following the pattern of <code>null</code> being set as the initial state. |
75
+
@@ -6,12 +6,13 @@
6
6
 
7
7
  Defines events that the layout system listens for
8
8
 
9
- 'changeTitle' - emit this from a contained item to update the title of the window that contains it.
9
+ 'changeTitle' - emit this from a contained item to update the title of the window that contains it. 'autosave' - emit this from a contained item to hint to the layout system that it should autosave the layout. A contained item should do this if it has just changed some state it would like to persist. See [LayoutComponentWithState](./foundation-layout.layoutcomponentwithstate.md)<!-- -->.
10
10
 
11
11
  **Signature:**
12
12
 
13
13
  ```typescript
14
14
  LayoutReceiveEvents: {
15
15
  readonly changeTitle: "change-title";
16
+ readonly autosave: "autosave";
16
17
  }
17
18
  ```
@@ -6,7 +6,7 @@
6
6
 
7
7
  Defines the shape of the detail that the layout listens works with for events it listens on
8
8
 
9
- 'changeTitle' - `title` is the string you want to set. For `mode`<!-- -->: `replace` will set the title to be `title`<!-- -->, `suffix` will append `title` to the end of the existing title.
9
+ 'changeTitle' - `title` is the string you want to set. For `mode`<!-- -->: `replace` will set the title to be `title`<!-- -->, `suffix` will append `title` to the end of the existing title. 'autosave' - no other parameters.
10
10
 
11
11
  **Signature:**
12
12
 
@@ -16,5 +16,6 @@ export type LayoutReceiveEventsDetail = {
16
16
  title: string;
17
17
  mode: 'replace' | 'suffix';
18
18
  };
19
+ autosave: void;
19
20
  };
20
21
  ```
@@ -18,6 +18,7 @@
18
18
 
19
19
  | Interface | Description |
20
20
  | --- | --- |
21
+ | [LayoutComponentWithState](./foundation-layout.layoutcomponentwithstate.md) | Interface to implement on an item which is a component of the layout and you wish to serialise state with. This is saved separately for each instance of the component, which allows you to restore multiple instances of the same component with different state. |
21
22
  | [RegisteredElementConfig](./foundation-layout.registeredelementconfig.md) | The parameters that can be set on a new item when being added by the [FoundationLayout.addItem()](./foundation-layout.foundationlayout.additem.md) API |
22
23
 
23
24
  ## Variables
@@ -28,7 +29,7 @@
28
29
  | [foundationLayoutComponents](./foundation-layout.foundationlayoutcomponents.md) | Registration object to register the layout with your design system. |
29
30
  | [LAYOUT\_ICONS](./foundation-layout.layout_icons.md) | A collection of SVG icons in base64 format. |
30
31
  | [LayoutEmitEvents](./foundation-layout.layoutemitevents.md) | <p>Defines events that the layout system emits</p><p>'firstLoaded' - emitted when the layout has finished loading the first time using the declarative API after [DEFAULT\_RELOAD\_BUFFER](./foundation-layout.default_reload_buffer.md) ms. <br/> 'itemAdded' - emitted when an item is added to the layout' <br/> 'itemRemoved' - emitted when an item is removed from the layout' <br/> 'itemResized' - emitted when the user drags the divider to resize elements</p> |
31
- | [LayoutReceiveEvents](./foundation-layout.layoutreceiveevents.md) | <p>Defines events that the layout system listens for</p><p>'changeTitle' - emit this from a contained item to update the title of the window that contains it.</p> |
32
+ | [LayoutReceiveEvents](./foundation-layout.layoutreceiveevents.md) | <p>Defines events that the layout system listens for</p><p>'changeTitle' - emit this from a contained item to update the title of the window that contains it. 'autosave' - emit this from a contained item to hint to the layout system that it should autosave the layout. A contained item should do this if it has just changed some state it would like to persist. See [LayoutComponentWithState](./foundation-layout.layoutcomponentwithstate.md)<!-- -->.</p> |
32
33
  | [layoutStyles](./foundation-layout.layoutstyles.md) | <code>ElementStyles</code> which defines the css for [FoundationLayout](./foundation-layout.foundationlayout.md)<!-- -->. |
33
34
  | [layoutTemplate](./foundation-layout.layouttemplate.md) | <code>ViewTemplate</code> which defines the html for [FoundationLayout](./foundation-layout.foundationlayout.md)<!-- -->. |
34
35
 
@@ -37,7 +38,7 @@
37
38
  | Type Alias | Description |
38
39
  | --- | --- |
39
40
  | [CustomButton](./foundation-layout.custombutton.md) | Definition of a custom button which will be added to all layout items. |
40
- | [LayoutReceiveEventsDetail](./foundation-layout.layoutreceiveeventsdetail.md) | <p>Defines the shape of the detail that the layout listens works with for events it listens on</p><p>'changeTitle' - <code>title</code> is the string you want to set. For <code>mode</code>: <code>replace</code> will set the title to be <code>title</code>, <code>suffix</code> will append <code>title</code> to the end of the existing title.</p> |
41
+ | [LayoutReceiveEventsDetail](./foundation-layout.layoutreceiveeventsdetail.md) | <p>Defines the shape of the detail that the layout listens works with for events it listens on</p><p>'changeTitle' - <code>title</code> is the string you want to set. For <code>mode</code>: <code>replace</code> will set the title to be <code>title</code>, <code>suffix</code> will append <code>title</code> to the end of the existing title. 'autosave' - no other parameters.</p> |
41
42
  | [LayoutRegionType](./foundation-layout.layoutregiontype.md) | Union type describing the three different types of region splits. Set on the <code>type</code> attribute on [FoundationLayoutRegion](./foundation-layout.foundationlayoutregion.md)<!-- -->. |
42
43
  | [Placement](./foundation-layout.placement.md) | Where to and how to add the new item(s) into the layout when using the [FoundationLayout.addItem()](./foundation-layout.foundationlayout.additem.md) API. |
43
44
  | [SerialisedLayout](./foundation-layout.serialisedlayout.md) | Versioned layout config objects. <code>v</code> is the version and <code>c</code> contains the layout config. |