@openmrs/esm-extensions 8.0.1-pre.3439 → 8.0.1-pre.3457

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.
@@ -1,3 +1,3 @@
1
- [0] Successfully compiled: 11 files with swc (101.32ms)
1
+ [0] Successfully compiled: 11 files with swc (169.01ms)
2
2
  [0] swc --strip-leading-paths src -d dist exited with code 0
3
3
  [1] tsc --project tsconfig.build.json exited with code 0
@@ -1,5 +1,5 @@
1
1
  /** @module @category Extension */
2
- import { type AssignedExtension, type ExtensionRegistration, type ExtensionInternalStore } from './store';
2
+ import { type AssignedExtension, type ExtensionInternalStore, type ExtensionRegistration, type ExtensionSlotCustomState } from './store';
3
3
  /**
4
4
  * Given an extension ID, which is a string uniquely identifying
5
5
  * an instance of an extension within an extension slot, this
@@ -63,9 +63,18 @@ export declare function getAssignedExtensions(slotName: string): Array<AssignedE
63
63
  *
64
64
  * @param moduleName The name of the module that contains the extension slot
65
65
  * @param slotName The extension slot name that is actually used
66
+ * @param state Optional custom state for the slot, which will be stored in the extension store.
66
67
  * @internal
67
68
  */
68
- export declare const registerExtensionSlot: (moduleName: string, slotName: string) => void;
69
+ export declare const registerExtensionSlot: (moduleName: string, slotName: string, state?: ExtensionSlotCustomState) => void;
70
+ /**
71
+ * Used by extension slots to update the copy of the state for the extension slot
72
+ *
73
+ * @param slotName The name of the slot with state to update
74
+ * @param state A copy of the new state
75
+ * @param partial Whether this should be applied as a partial
76
+ */
77
+ export declare function updateExtensionSlotState(slotName: string, state: ExtensionSlotCustomState, partial?: boolean): void;
69
78
  /**
70
79
  * @internal
71
80
  * Just for testing.
@@ -6,14 +6,14 @@
6
6
  * - assigned (computed from attached and configured)
7
7
  * - connected (computed from assigned using connectivity and online / offline)
8
8
  */ import { sessionStore, userHasAccess } from "@openmrs/esm-api";
9
- import { getExtensionConfigFromStore, getExtensionsConfigStore, getExtensionSlotConfig, getExtensionConfigFromExtensionSlotStore, getExtensionSlotConfigFromStore, getExtensionSlotsConfigStore } from "@openmrs/esm-config";
9
+ import { getExtensionConfigFromExtensionSlotStore, getExtensionConfigFromStore, getExtensionSlotConfig, getExtensionSlotConfigFromStore, getExtensionSlotsConfigStore, getExtensionsConfigStore } from "@openmrs/esm-config";
10
10
  import { evaluateAsBoolean } from "@openmrs/esm-expression-evaluator";
11
11
  import { featureFlagsStore } from "@openmrs/esm-feature-flags";
12
12
  import { subscribeConnectivityChanged } from "@openmrs/esm-globals";
13
13
  import { isOnline as isOnlineFn } from "@openmrs/esm-utils";
14
14
  import { isEqual, merge } from "lodash-es";
15
15
  import { checkStatusFor } from "./helpers.js";
16
- import { getExtensionStore, getExtensionInternalStore, updateInternalExtensionStore } from "./store.js";
16
+ import { getExtensionInternalStore, getExtensionStore, updateInternalExtensionStore } from "./store.js";
17
17
  const extensionInternalStore = getExtensionInternalStore();
18
18
  const extensionStore = getExtensionStore();
19
19
  const slotsConfigStore = getExtensionSlotsConfigStore();
@@ -57,12 +57,13 @@ function updateOutputStoreToCurrent() {
57
57
  }
58
58
  updateOutputStoreToCurrent();
59
59
  subscribeConnectivityChanged(updateOutputStoreToCurrent);
60
- function createNewExtensionSlotInfo(slotName, moduleName) {
60
+ function createNewExtensionSlotInfo(slotName, moduleName, state) {
61
61
  return {
62
62
  moduleName,
63
63
  name: slotName,
64
64
  attachedIds: [],
65
- config: null
65
+ config: null,
66
+ state
66
67
  };
67
68
  }
68
69
  /**
@@ -220,6 +221,14 @@ function getAssignedExtensionsFromSlotData(slotName, internalState, config, exte
220
221
  const attachedIds = internalState.slots[slotName].attachedIds;
221
222
  const assignedIds = calculateAssignedIds(config, attachedIds);
222
223
  const extensions = [];
224
+ // Create context once for all extensions in this slot
225
+ const slotState = internalState.slots[slotName]?.state;
226
+ const expressionContext = slotState && typeof slotState === 'object' ? {
227
+ session,
228
+ ...slotState
229
+ } : {
230
+ session
231
+ };
223
232
  for (let id of assignedIds){
224
233
  const { config: rawExtensionConfig } = getExtensionConfigFromStore(extensionConfigStoreState, slotName, id);
225
234
  const rawExtensionSlotExtensionConfig = getExtensionConfigFromExtensionSlotStore(config, slotName, id);
@@ -237,16 +246,14 @@ function getAssignedExtensionsFromSlotData(slotName, internalState, config, exte
237
246
  continue;
238
247
  }
239
248
  }
240
- const displayConditionExpression = extensionConfig?.['Display conditions']?.expression ?? null;
241
- if (displayConditionExpression !== null) {
249
+ const displayConditionExpression = extensionConfig?.['Display conditions']?.expression || extension.displayExpression;
250
+ if (displayConditionExpression !== undefined && typeof displayConditionExpression === 'string' && displayConditionExpression.trim().length > 0) {
242
251
  try {
243
- if (!evaluateAsBoolean(displayConditionExpression, {
244
- session
245
- })) {
252
+ if (!evaluateAsBoolean(displayConditionExpression, expressionContext)) {
246
253
  continue;
247
254
  }
248
255
  } catch (e) {
249
- console.error(`Error while evaluating expression ${displayConditionExpression}`, e);
256
+ console.error(`Error while evaluating expression '${displayConditionExpression}' for extension ${name} in slot ${slotName}`, e);
250
257
  continue;
251
258
  }
252
259
  }
@@ -310,38 +317,63 @@ function calculateAssignedIds(config, attachedIds) {
310
317
  *
311
318
  * @param moduleName The name of the module that contains the extension slot
312
319
  * @param slotName The extension slot name that is actually used
320
+ * @param state Optional custom state for the slot, which will be stored in the extension store.
313
321
  * @internal
314
- */ export const registerExtensionSlot = (moduleName, slotName)=>extensionInternalStore.setState((state)=>{
315
- const existingModuleName = state.slots[slotName]?.moduleName;
322
+ */ export const registerExtensionSlot = (moduleName, slotName, state)=>extensionInternalStore.setState((currentState)=>{
323
+ const existingModuleName = currentState.slots[slotName]?.moduleName;
316
324
  if (existingModuleName && existingModuleName != moduleName) {
317
325
  console.warn(`An extension slot with the name '${slotName}' already exists. Refusing to register the same slot name twice (in "registerExtensionSlot"). The existing one is from module ${existingModuleName}.`);
318
- return state;
326
+ return currentState;
319
327
  }
320
328
  if (existingModuleName && existingModuleName == moduleName) {
321
329
  // Re-rendering an existing slot
322
- return state;
330
+ return currentState;
323
331
  }
324
- if (state.slots[slotName]) {
332
+ if (currentState.slots[slotName]) {
325
333
  return {
326
- ...state,
334
+ ...currentState,
327
335
  slots: {
328
- ...state.slots,
336
+ ...currentState.slots,
329
337
  [slotName]: {
330
- ...state.slots[slotName],
331
- moduleName
338
+ ...currentState.slots[slotName],
339
+ moduleName,
340
+ state
332
341
  }
333
342
  }
334
343
  };
335
344
  }
336
- const slot = createNewExtensionSlotInfo(slotName, moduleName);
345
+ const slot = createNewExtensionSlotInfo(slotName, moduleName, state);
337
346
  return {
338
- ...state,
347
+ ...currentState,
339
348
  slots: {
340
- ...state.slots,
341
- [slotName]: slot
349
+ ...currentState.slots,
350
+ [slotName]: {
351
+ ...slot
352
+ }
342
353
  }
343
354
  };
344
355
  });
356
+ /**
357
+ * Used by extension slots to update the copy of the state for the extension slot
358
+ *
359
+ * @param slotName The name of the slot with state to update
360
+ * @param state A copy of the new state
361
+ * @param partial Whether this should be applied as a partial
362
+ */ export function updateExtensionSlotState(slotName, state, partial = false) {
363
+ extensionInternalStore.setState((currentState)=>{
364
+ const newState = partial ? merge(currentState.slots[slotName].state, state) : state;
365
+ return {
366
+ ...currentState,
367
+ slots: {
368
+ ...currentState.slots,
369
+ [slotName]: {
370
+ ...currentState.slots[slotName],
371
+ state: newState
372
+ }
373
+ }
374
+ };
375
+ });
376
+ }
345
377
  /**
346
378
  * @internal
347
379
  * Just for testing.
@@ -1,10 +1,12 @@
1
1
  import { type ComponentConfig } from './types';
2
+ import { type ExtensionSlotState } from './store';
2
3
  type LeftNavMode = 'normal' | 'collapsed' | 'hidden';
3
4
  export interface LeftNavStore {
4
5
  slotName: string | null;
5
6
  basePath: string;
6
7
  mode: LeftNavMode;
7
8
  componentContext?: ComponentConfig;
9
+ state?: ExtensionSlotState;
8
10
  }
9
11
  /** @internal */
10
12
  export declare const leftNavStore: import("zustand").StoreApi<LeftNavStore>;
@@ -18,13 +20,14 @@ export interface SetLeftNavParams {
18
20
  */
19
21
  mode?: LeftNavMode;
20
22
  componentContext?: ComponentConfig;
23
+ state?: ExtensionSlotState;
21
24
  }
22
25
  /**
23
26
  * Sets the current left nav context. Must be paired with {@link unsetLeftNav}.
24
27
  *
25
28
  * @deprecated Please use {@link useLeftNav} instead. This function will be made internal in a future release.
26
29
  */
27
- export declare function setLeftNav({ name, basePath, mode, componentContext }: SetLeftNavParams): void;
30
+ export declare function setLeftNav({ name, basePath, mode, componentContext, state }: SetLeftNavParams): void;
28
31
  /**
29
32
  * Unsets the left nav context if the current context is for the supplied name.
30
33
  *
package/dist/left-nav.js CHANGED
@@ -8,12 +8,13 @@ import { createGlobalStore } from "@openmrs/esm-state";
8
8
  * Sets the current left nav context. Must be paired with {@link unsetLeftNav}.
9
9
  *
10
10
  * @deprecated Please use {@link useLeftNav} instead. This function will be made internal in a future release.
11
- */ export function setLeftNav({ name, basePath, mode, componentContext }) {
11
+ */ export function setLeftNav({ name, basePath, mode, componentContext, state }) {
12
12
  leftNavStore.setState({
13
13
  slotName: name,
14
14
  basePath,
15
15
  mode: mode ?? 'normal',
16
- componentContext
16
+ componentContext,
17
+ state
17
18
  });
18
19
  }
19
20
  /**
package/dist/store.d.ts CHANGED
@@ -13,6 +13,7 @@ export interface ExtensionRegistration {
13
13
  readonly offline?: boolean;
14
14
  readonly privileges?: string | Array<string>;
15
15
  readonly featureFlag?: string;
16
+ readonly displayExpression?: string;
16
17
  }
17
18
  export interface ExtensionInfo extends ExtensionRegistration {
18
19
  /**
@@ -31,6 +32,7 @@ export interface ExtensionInternalStore {
31
32
  /** Extensions indexed by name */
32
33
  extensions: Record<string, ExtensionInfo>;
33
34
  }
35
+ export type ExtensionSlotCustomState = Record<string | symbol | number, unknown> | undefined | null;
34
36
  export interface ExtensionSlotInfo {
35
37
  /**
36
38
  * The module in which the extension slot exists. Undefined if the slot
@@ -48,6 +50,7 @@ export interface ExtensionSlotInfo {
48
50
  attachedIds: Array<string>;
49
51
  /** The configuration provided for this slot. `null` if not yet loaded. */
50
52
  config: Omit<ExtensionSlotConfig, 'configuration'> | null;
53
+ state?: ExtensionSlotCustomState;
51
54
  }
52
55
  export interface ExtensionStore {
53
56
  slots: Record<string, ExtensionSlotState>;
@@ -55,6 +58,7 @@ export interface ExtensionStore {
55
58
  export interface ExtensionSlotState {
56
59
  moduleName?: string;
57
60
  assignedExtensions: Array<AssignedExtension>;
61
+ state?: ExtensionSlotCustomState;
58
62
  }
59
63
  export interface AssignedExtension {
60
64
  readonly id: string;
package/dist/store.js CHANGED
@@ -15,6 +15,7 @@ const extensionInternalStore = createGlobalStore('extensionsInternal', {
15
15
  extensions: {}
16
16
  });
17
17
  /** @internal */ export function updateInternalExtensionStore(updater) {
18
+ // This is a function that updates the internal extension store.
18
19
  const state = extensionInternalStore.getState();
19
20
  const newState = updater(state);
20
21
  if (newState !== state) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-extensions",
3
- "version": "8.0.1-pre.3439",
3
+ "version": "8.0.1-pre.3457",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Coordinates extensions and extension points in the OpenMRS Frontend",
6
6
  "type": "module",
@@ -64,12 +64,12 @@
64
64
  "single-spa": "6.x"
65
65
  },
66
66
  "devDependencies": {
67
- "@openmrs/esm-api": "8.0.1-pre.3439",
68
- "@openmrs/esm-config": "8.0.1-pre.3439",
69
- "@openmrs/esm-expression-evaluator": "8.0.1-pre.3439",
70
- "@openmrs/esm-feature-flags": "8.0.1-pre.3439",
71
- "@openmrs/esm-state": "8.0.1-pre.3439",
72
- "@openmrs/esm-utils": "8.0.1-pre.3439",
67
+ "@openmrs/esm-api": "8.0.1-pre.3457",
68
+ "@openmrs/esm-config": "8.0.1-pre.3457",
69
+ "@openmrs/esm-expression-evaluator": "8.0.1-pre.3457",
70
+ "@openmrs/esm-feature-flags": "8.0.1-pre.3457",
71
+ "@openmrs/esm-state": "8.0.1-pre.3457",
72
+ "@openmrs/esm-utils": "8.0.1-pre.3457",
73
73
  "@swc/cli": "^0.7.7",
74
74
  "@swc/core": "^1.11.29",
75
75
  "concurrently": "^9.1.2",
package/src/extensions.ts CHANGED
@@ -10,15 +10,15 @@
10
10
 
11
11
  import { type Session, type SessionStore, sessionStore, userHasAccess } from '@openmrs/esm-api';
12
12
  import {
13
- type ExtensionsConfigStore,
14
13
  type ExtensionSlotConfig,
15
14
  type ExtensionSlotsConfigStore,
15
+ type ExtensionsConfigStore,
16
+ getExtensionConfigFromExtensionSlotStore,
16
17
  getExtensionConfigFromStore,
17
- getExtensionsConfigStore,
18
18
  getExtensionSlotConfig,
19
- getExtensionConfigFromExtensionSlotStore,
20
19
  getExtensionSlotConfigFromStore,
21
20
  getExtensionSlotsConfigStore,
21
+ getExtensionsConfigStore,
22
22
  } from '@openmrs/esm-config';
23
23
  import { evaluateAsBoolean } from '@openmrs/esm-expression-evaluator';
24
24
  import { type FeatureFlagsStore, featureFlagsStore } from '@openmrs/esm-feature-flags';
@@ -28,12 +28,13 @@ import { isEqual, merge } from 'lodash-es';
28
28
  import { checkStatusFor } from './helpers';
29
29
  import {
30
30
  type AssignedExtension,
31
+ type ExtensionInternalStore,
31
32
  type ExtensionRegistration,
33
+ type ExtensionSlotCustomState,
32
34
  type ExtensionSlotInfo,
33
- type ExtensionInternalStore,
34
35
  type ExtensionSlotState,
35
- getExtensionStore,
36
36
  getExtensionInternalStore,
37
+ getExtensionStore,
37
38
  updateInternalExtensionStore,
38
39
  } from './store';
39
40
 
@@ -139,12 +140,17 @@ function updateOutputStoreToCurrent() {
139
140
  updateOutputStoreToCurrent();
140
141
  subscribeConnectivityChanged(updateOutputStoreToCurrent);
141
142
 
142
- function createNewExtensionSlotInfo(slotName: string, moduleName?: string): ExtensionSlotInfo {
143
+ function createNewExtensionSlotInfo(
144
+ slotName: string,
145
+ moduleName?: string,
146
+ state?: ExtensionSlotCustomState,
147
+ ): ExtensionSlotInfo {
143
148
  return {
144
149
  moduleName,
145
150
  name: slotName,
146
151
  attachedIds: [],
147
152
  config: null,
153
+ state,
148
154
  };
149
155
  }
150
156
 
@@ -333,6 +339,10 @@ function getAssignedExtensionsFromSlotData(
333
339
  const assignedIds = calculateAssignedIds(config, attachedIds);
334
340
  const extensions: Array<AssignedExtension> = [];
335
341
 
342
+ // Create context once for all extensions in this slot
343
+ const slotState = internalState.slots[slotName]?.state;
344
+ const expressionContext = slotState && typeof slotState === 'object' ? { session, ...slotState } : { session };
345
+
336
346
  for (let id of assignedIds) {
337
347
  const { config: rawExtensionConfig } = getExtensionConfigFromStore(extensionConfigStoreState, slotName, id);
338
348
  const rawExtensionSlotExtensionConfig = getExtensionConfigFromExtensionSlotStore(config, slotName, id);
@@ -357,15 +367,23 @@ function getAssignedExtensionsFromSlotData(
357
367
  }
358
368
  }
359
369
 
360
- const displayConditionExpression = extensionConfig?.['Display conditions']?.expression ?? null;
361
- if (displayConditionExpression !== null) {
370
+ const displayConditionExpression =
371
+ extensionConfig?.['Display conditions']?.expression || extension.displayExpression;
372
+
373
+ if (
374
+ displayConditionExpression !== undefined &&
375
+ typeof displayConditionExpression === 'string' &&
376
+ displayConditionExpression.trim().length > 0
377
+ ) {
362
378
  try {
363
- if (!evaluateAsBoolean(displayConditionExpression, { session })) {
379
+ if (!evaluateAsBoolean(displayConditionExpression, expressionContext)) {
364
380
  continue;
365
381
  }
366
382
  } catch (e) {
367
- console.error(`Error while evaluating expression ${displayConditionExpression}`, e);
368
- // if the expression has an error, we do not display the extension
383
+ console.error(
384
+ `Error while evaluating expression '${displayConditionExpression}' for extension ${name} in slot ${slotName}`,
385
+ e,
386
+ );
369
387
  continue;
370
388
  }
371
389
  }
@@ -449,43 +467,77 @@ function calculateAssignedIds(config: ExtensionSlotConfig, attachedIds: Array<st
449
467
  *
450
468
  * @param moduleName The name of the module that contains the extension slot
451
469
  * @param slotName The extension slot name that is actually used
470
+ * @param state Optional custom state for the slot, which will be stored in the extension store.
452
471
  * @internal
453
472
  */
454
- export const registerExtensionSlot: (moduleName: string, slotName: string) => void = (moduleName, slotName) =>
455
- extensionInternalStore.setState((state) => {
456
- const existingModuleName = state.slots[slotName]?.moduleName;
473
+ export const registerExtensionSlot: (moduleName: string, slotName: string, state?: ExtensionSlotCustomState) => void = (
474
+ moduleName,
475
+ slotName,
476
+ state,
477
+ ) =>
478
+ extensionInternalStore.setState((currentState) => {
479
+ const existingModuleName = currentState.slots[slotName]?.moduleName;
457
480
  if (existingModuleName && existingModuleName != moduleName) {
458
481
  console.warn(
459
482
  `An extension slot with the name '${slotName}' already exists. Refusing to register the same slot name twice (in "registerExtensionSlot"). The existing one is from module ${existingModuleName}.`,
460
483
  );
461
- return state;
484
+ return currentState;
462
485
  }
486
+
463
487
  if (existingModuleName && existingModuleName == moduleName) {
464
488
  // Re-rendering an existing slot
465
- return state;
489
+ return currentState;
466
490
  }
467
- if (state.slots[slotName]) {
491
+
492
+ if (currentState.slots[slotName]) {
468
493
  return {
469
- ...state,
494
+ ...currentState,
470
495
  slots: {
471
- ...state.slots,
496
+ ...currentState.slots,
472
497
  [slotName]: {
473
- ...state.slots[slotName],
498
+ ...currentState.slots[slotName],
474
499
  moduleName,
500
+ state,
475
501
  },
476
502
  },
477
503
  };
478
504
  }
479
- const slot = createNewExtensionSlotInfo(slotName, moduleName);
505
+
506
+ const slot = createNewExtensionSlotInfo(slotName, moduleName, state);
480
507
  return {
481
- ...state,
508
+ ...currentState,
482
509
  slots: {
483
- ...state.slots,
484
- [slotName]: slot,
510
+ ...currentState.slots,
511
+ [slotName]: {
512
+ ...slot,
513
+ },
485
514
  },
486
515
  };
487
516
  });
488
517
 
518
+ /**
519
+ * Used by extension slots to update the copy of the state for the extension slot
520
+ *
521
+ * @param slotName The name of the slot with state to update
522
+ * @param state A copy of the new state
523
+ * @param partial Whether this should be applied as a partial
524
+ */
525
+ export function updateExtensionSlotState(slotName: string, state: ExtensionSlotCustomState, partial: boolean = false) {
526
+ extensionInternalStore.setState((currentState) => {
527
+ const newState = partial ? merge(currentState.slots[slotName].state, state) : state;
528
+ return {
529
+ ...currentState,
530
+ slots: {
531
+ ...currentState.slots,
532
+ [slotName]: {
533
+ ...currentState.slots[slotName],
534
+ state: newState,
535
+ },
536
+ },
537
+ };
538
+ });
539
+ }
540
+
489
541
  /**
490
542
  * @internal
491
543
  * Just for testing.
package/src/left-nav.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type {} from '@openmrs/esm-globals';
2
2
  import { createGlobalStore } from '@openmrs/esm-state';
3
3
  import { type ComponentConfig } from './types';
4
+ import { type ExtensionSlotState } from './store';
4
5
 
5
6
  type LeftNavMode = 'normal' | 'collapsed' | 'hidden';
6
7
  export interface LeftNavStore {
@@ -8,6 +9,7 @@ export interface LeftNavStore {
8
9
  basePath: string;
9
10
  mode: LeftNavMode;
10
11
  componentContext?: ComponentConfig;
12
+ state?: ExtensionSlotState;
11
13
  }
12
14
 
13
15
  /** @internal */
@@ -27,6 +29,7 @@ export interface SetLeftNavParams {
27
29
  */
28
30
  mode?: LeftNavMode;
29
31
  componentContext?: ComponentConfig;
32
+ state?: ExtensionSlotState;
30
33
  }
31
34
 
32
35
  /**
@@ -34,8 +37,8 @@ export interface SetLeftNavParams {
34
37
  *
35
38
  * @deprecated Please use {@link useLeftNav} instead. This function will be made internal in a future release.
36
39
  */
37
- export function setLeftNav({ name, basePath, mode, componentContext }: SetLeftNavParams) {
38
- leftNavStore.setState({ slotName: name, basePath, mode: mode ?? 'normal', componentContext });
40
+ export function setLeftNav({ name, basePath, mode, componentContext, state }: SetLeftNavParams) {
41
+ leftNavStore.setState({ slotName: name, basePath, mode: mode ?? 'normal', componentContext, state });
39
42
  }
40
43
 
41
44
  /**
package/src/store.ts CHANGED
@@ -19,6 +19,7 @@ export interface ExtensionRegistration {
19
19
  readonly offline?: boolean;
20
20
  readonly privileges?: string | Array<string>;
21
21
  readonly featureFlag?: string;
22
+ readonly displayExpression?: string;
22
23
  }
23
24
 
24
25
  export interface ExtensionInfo extends ExtensionRegistration {
@@ -41,6 +42,8 @@ export interface ExtensionInternalStore {
41
42
  extensions: Record<string, ExtensionInfo>;
42
43
  }
43
44
 
45
+ export type ExtensionSlotCustomState = Record<string | symbol | number, unknown> | undefined | null;
46
+
44
47
  export interface ExtensionSlotInfo {
45
48
  /**
46
49
  * The module in which the extension slot exists. Undefined if the slot
@@ -58,6 +61,7 @@ export interface ExtensionSlotInfo {
58
61
  attachedIds: Array<string>;
59
62
  /** The configuration provided for this slot. `null` if not yet loaded. */
60
63
  config: Omit<ExtensionSlotConfig, 'configuration'> | null;
64
+ state?: ExtensionSlotCustomState;
61
65
  }
62
66
 
63
67
  export interface ExtensionStore {
@@ -67,6 +71,7 @@ export interface ExtensionStore {
67
71
  export interface ExtensionSlotState {
68
72
  moduleName?: string;
69
73
  assignedExtensions: Array<AssignedExtension>;
74
+ state?: ExtensionSlotCustomState;
70
75
  }
71
76
 
72
77
  export interface AssignedExtension {
@@ -110,6 +115,7 @@ export const getExtensionInternalStore = () =>
110
115
 
111
116
  /** @internal */
112
117
  export function updateInternalExtensionStore(updater: (state: ExtensionInternalStore) => ExtensionInternalStore) {
118
+ // This is a function that updates the internal extension store.
113
119
  const state = extensionInternalStore.getState();
114
120
  const newState = updater(state);
115
121