@itwin/appui-react 5.9.1 → 5.10.0

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Change Log - @itwin/appui-react
2
2
 
3
+ ## 5.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - bdfb8fe: Updated `ToolbarComposer` component to highlight group items that contain an active toolbar item.
8
+
9
+ ### Patch Changes
10
+
11
+ - @itwin/components-react@5.10.0
12
+ - @itwin/core-react@5.10.0
13
+ - @itwin/imodel-components-react@5.10.0
14
+
3
15
  ## 5.9.1
4
16
 
5
17
  ### Patch Changes
@@ -1,11 +1,11 @@
1
1
  import type { BeEvent } from "@itwin/core-bentley";
2
- type ActiveToolIdSynchedItem<T> = {
2
+ interface Item {
3
3
  id: string;
4
4
  isActive?: boolean;
5
- } | {
6
- id: string;
5
+ }
6
+ type ActiveToolIdSynchedItem<T> = Item | (Item & {
7
7
  items: T[];
8
- };
8
+ });
9
9
  interface ActiveToolIdSynchedHost {
10
10
  activeToolId: string;
11
11
  onToolActivatedEvent: BeEvent<(args: {
@@ -20,6 +20,6 @@ interface ActiveToolIdSynchedHost {
20
20
  * @returns Up to date itemsToSynch.
21
21
  * @internal
22
22
  */
23
- export declare function useActiveToolIdSynchedItems<T extends ActiveToolIdSynchedItem<T>>(itemsToSynch: readonly T[], syncHost: ActiveToolIdSynchedHost): T[];
23
+ export declare function useActiveToolIdSynchedItems<T extends ActiveToolIdSynchedItem<T>>(itemsToSynch: T[], syncHost: ActiveToolIdSynchedHost): T[];
24
24
  export {};
25
25
  //# sourceMappingURL=useActiveToolIdSynchedItems.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useActiveToolIdSynchedItems.d.ts","sourceRoot":"","sources":["../../../src/appui-react/toolbar/useActiveToolIdSynchedItems.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,KAAK,uBAAuB,CAAC,CAAC,IAC1B;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAClC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,EAAE,CAAA;CAAE,CAAC;AAE/B,UAAU,uBAAuB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC,CAAC;CACnE;AAiDD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,CAAC,SAAS,uBAAuB,CAAC,CAAC,CAAC,EACpC,YAAY,EAAE,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,uBAAuB,GAAG,CAAC,EAAE,CAapE"}
1
+ {"version":3,"file":"useActiveToolIdSynchedItems.d.ts","sourceRoot":"","sources":["../../../src/appui-react/toolbar/useActiveToolIdSynchedItems.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAGnD,UAAU,IAAI;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,KAAK,uBAAuB,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,GAAG;IAAE,KAAK,EAAE,CAAC,EAAE,CAAA;CAAE,CAAC,CAAC;AAEjE,UAAU,uBAAuB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC,CAAC;CACnE;AAgCD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,CAAC,SAAS,uBAAuB,CAAC,CAAC,CAAC,EACpC,YAAY,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,uBAAuB,GAAG,CAAC,EAAE,CAW3D"}
@@ -3,41 +3,29 @@
3
3
  * See LICENSE.md in the project root for license terms and full copyright notice.
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import * as React from "react";
6
- /**
7
- * Recursively checks if the item with the current id of "toolId" is
8
- * the only active tool.
9
- * @param items list of items to validate
10
- * @param toolId toolId to check
11
- * @returns true if any item "isActive" must change.
12
- */
13
- function mustRefresh(items, toolId) {
14
- return items.some((item) => {
15
- if ("items" in item) {
16
- return mustRefresh(item.items, toolId);
6
+ import { produce } from "immer";
7
+ function updateActiveItems(items, toolId) {
8
+ return produce(items, (draft) => {
9
+ // Iterative DFS with ancestor backtracking.
10
+ const stack = draft.map((item) => [item, []]);
11
+ while (stack.length > 0) {
12
+ const [current, ancestors] = stack.pop();
13
+ const isActive = current.id === toolId;
14
+ current.isActive = isActive;
15
+ if ("items" in current) {
16
+ for (const child of current.items) {
17
+ stack.push([child, [...ancestors, current]]);
18
+ }
19
+ }
20
+ if (!isActive)
21
+ continue;
22
+ // Mark ancestors of active item as active.
23
+ for (const ancestor of ancestors) {
24
+ ancestor.isActive = true;
25
+ }
17
26
  }
18
- return ((item.isActive && item.id !== toolId) ||
19
- (!item.isActive && item.id === toolId));
20
27
  });
21
28
  }
22
- /**
23
- * Recursively updates the isActive for the tools and only activate
24
- * the one with the id equal to toolId.
25
- * @param items list of items to update
26
- * @param toolId toolId to check
27
- * @returns updated list of items
28
- */
29
- function refreshItems(items, toolId) {
30
- return items.map((item) => "items" in item
31
- ? {
32
- ...item,
33
- isActive: item.id === toolId,
34
- items: refreshItems(item.items, toolId),
35
- }
36
- : {
37
- ...item,
38
- isActive: item.id === toolId,
39
- });
40
- }
41
29
  /**
42
30
  * Synch the provided items to only show the item with id === activeToolId to be
43
31
  * active, as determined by the UiFramework.frontstages.activeToolId.
@@ -47,11 +35,11 @@ function refreshItems(items, toolId) {
47
35
  * @internal
48
36
  */
49
37
  export function useActiveToolIdSynchedItems(itemsToSynch, syncHost) {
50
- const [items, setItems] = React.useState(() => refreshItems(itemsToSynch, syncHost.activeToolId));
38
+ const [items, setItems] = React.useState(() => updateActiveItems(itemsToSynch, syncHost.activeToolId));
51
39
  React.useEffect(() => {
52
- setItems(refreshItems(itemsToSynch, syncHost.activeToolId));
40
+ setItems(updateActiveItems(itemsToSynch, syncHost.activeToolId));
53
41
  return syncHost.onToolActivatedEvent.addListener(({ toolId }) => {
54
- setItems((current) => mustRefresh(current, toolId) ? refreshItems(current, toolId) : current);
42
+ setItems((current) => updateActiveItems(current, toolId));
55
43
  });
56
44
  }, [itemsToSynch, syncHost.activeToolId, syncHost.onToolActivatedEvent]);
57
45
  return items;
@@ -1 +1 @@
1
- {"version":3,"file":"useActiveToolIdSynchedItems.js","sourceRoot":"","sources":["../../../src/appui-react/toolbar/useActiveToolIdSynchedItems.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAChG,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAY/B;;;;;;GAMG;AACH,SAAS,WAAW,CAClB,KAAmB,EACnB,MAAc;IAEd,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QACzB,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;YACpB,OAAO,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,CACL,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC;YACrC,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC,CACvC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,SAAS,YAAY,CACnB,KAAmB,EACnB,MAAc;IAEd,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACxB,OAAO,IAAI,IAAI;QACb,CAAC,CAAC;YACE,GAAG,IAAI;YACP,QAAQ,EAAE,IAAI,CAAC,EAAE,KAAK,MAAM;YAC5B,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC;SACxC;QACH,CAAC,CAAC;YACE,GAAG,IAAI;YACP,QAAQ,EAAE,IAAI,CAAC,EAAE,KAAK,MAAM;SAC7B,CACN,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CAEzC,YAA0B,EAAE,QAAiC;IAC7D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAM,GAAG,EAAE,CACjD,YAAY,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CAClD,CAAC;IACF,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,QAAQ,CAAC,YAAY,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;QAC5D,OAAO,QAAQ,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;YAC9D,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE,CACnB,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CACvE,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC;IACzE,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\nimport * as React from \"react\";\nimport type { BeEvent } from \"@itwin/core-bentley\";\n\ntype ActiveToolIdSynchedItem<T> =\n | { id: string; isActive?: boolean }\n | { id: string; items: T[] };\n\ninterface ActiveToolIdSynchedHost {\n activeToolId: string;\n onToolActivatedEvent: BeEvent<(args: { toolId: string }) => void>;\n}\n\n/**\n * Recursively checks if the item with the current id of \"toolId\" is\n * the only active tool.\n * @param items list of items to validate\n * @param toolId toolId to check\n * @returns true if any item \"isActive\" must change.\n */\nfunction mustRefresh<T extends ActiveToolIdSynchedItem<T>>(\n items: readonly T[],\n toolId: string\n): boolean {\n return items.some((item) => {\n if (\"items\" in item) {\n return mustRefresh(item.items, toolId);\n }\n return (\n (item.isActive && item.id !== toolId) ||\n (!item.isActive && item.id === toolId)\n );\n });\n}\n\n/**\n * Recursively updates the isActive for the tools and only activate\n * the one with the id equal to toolId.\n * @param items list of items to update\n * @param toolId toolId to check\n * @returns updated list of items\n */\nfunction refreshItems<T extends ActiveToolIdSynchedItem<T>>(\n items: readonly T[],\n toolId: string\n): T[] {\n return items.map((item) =>\n \"items\" in item\n ? {\n ...item,\n isActive: item.id === toolId,\n items: refreshItems(item.items, toolId),\n }\n : {\n ...item,\n isActive: item.id === toolId,\n }\n );\n}\n\n/**\n * Synch the provided items to only show the item with id === activeToolId to be\n * active, as determined by the UiFramework.frontstages.activeToolId.\n * @param itemsToSynch List of items to keep in synch.\n * @param syncHost Source of information to synch to (UiFramework.frontstages)\n * @returns Up to date itemsToSynch.\n * @internal\n */\nexport function useActiveToolIdSynchedItems<\n T extends ActiveToolIdSynchedItem<T>\n>(itemsToSynch: readonly T[], syncHost: ActiveToolIdSynchedHost): T[] {\n const [items, setItems] = React.useState<T[]>(() =>\n refreshItems(itemsToSynch, syncHost.activeToolId)\n );\n React.useEffect(() => {\n setItems(refreshItems(itemsToSynch, syncHost.activeToolId));\n return syncHost.onToolActivatedEvent.addListener(({ toolId }) => {\n setItems((current) =>\n mustRefresh(current, toolId) ? refreshItems(current, toolId) : current\n );\n });\n }, [itemsToSynch, syncHost.activeToolId, syncHost.onToolActivatedEvent]);\n return items;\n}\n"]}
1
+ {"version":3,"file":"useActiveToolIdSynchedItems.js","sourceRoot":"","sources":["../../../src/appui-react/toolbar/useActiveToolIdSynchedItems.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAChG,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAchC,SAAS,iBAAiB,CACxB,KAAU,EACV,MAAc;IAEd,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;QAC9B,4CAA4C;QAC5C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAkB,CAAU,CAAC,CAAC;QAEvE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;YAE1C,MAAM,QAAQ,GAAG,OAAO,CAAC,EAAE,KAAK,MAAM,CAAC;YACvC,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;YAE5B,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;gBACvB,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;oBAClC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;YAED,IAAI,CAAC,QAAQ;gBAAE,SAAS;YAExB,2CAA2C;YAC3C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CAEzC,YAAiB,EAAE,QAAiC;IACpD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAM,GAAG,EAAE,CACjD,iBAAiB,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CACvD,CAAC;IACF,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,QAAQ,CAAC,iBAAiB,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;QACjE,OAAO,QAAQ,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;YAC9D,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,YAAY,EAAE,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC;IACzE,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Bentley Systems, Incorporated. All rights reserved.\n * See LICENSE.md in the project root for license terms and full copyright notice.\n *--------------------------------------------------------------------------------------------*/\nimport * as React from \"react\";\nimport type { BeEvent } from \"@itwin/core-bentley\";\nimport { produce } from \"immer\";\n\ninterface Item {\n id: string;\n isActive?: boolean;\n}\n\ntype ActiveToolIdSynchedItem<T> = Item | (Item & { items: T[] });\n\ninterface ActiveToolIdSynchedHost {\n activeToolId: string;\n onToolActivatedEvent: BeEvent<(args: { toolId: string }) => void>;\n}\n\nfunction updateActiveItems<T extends ActiveToolIdSynchedItem<T>>(\n items: T[],\n toolId: string\n) {\n return produce(items, (draft) => {\n // Iterative DFS with ancestor backtracking.\n const stack = draft.map((item) => [item, [] as typeof draft] as const);\n\n while (stack.length > 0) {\n const [current, ancestors] = stack.pop()!;\n\n const isActive = current.id === toolId;\n current.isActive = isActive;\n\n if (\"items\" in current) {\n for (const child of current.items) {\n stack.push([child, [...ancestors, current]]);\n }\n }\n\n if (!isActive) continue;\n\n // Mark ancestors of active item as active.\n for (const ancestor of ancestors) {\n ancestor.isActive = true;\n }\n }\n });\n}\n\n/**\n * Synch the provided items to only show the item with id === activeToolId to be\n * active, as determined by the UiFramework.frontstages.activeToolId.\n * @param itemsToSynch List of items to keep in synch.\n * @param syncHost Source of information to synch to (UiFramework.frontstages)\n * @returns Up to date itemsToSynch.\n * @internal\n */\nexport function useActiveToolIdSynchedItems<\n T extends ActiveToolIdSynchedItem<T>\n>(itemsToSynch: T[], syncHost: ActiveToolIdSynchedHost): T[] {\n const [items, setItems] = React.useState<T[]>(() =>\n updateActiveItems(itemsToSynch, syncHost.activeToolId)\n );\n React.useEffect(() => {\n setItems(updateActiveItems(itemsToSynch, syncHost.activeToolId));\n return syncHost.onToolActivatedEvent.addListener(({ toolId }) => {\n setItems((current) => updateActiveItems(current, toolId));\n });\n }, [itemsToSynch, syncHost.activeToolId, syncHost.onToolActivatedEvent]);\n return items;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itwin/appui-react",
3
- "version": "5.9.1",
3
+ "version": "5.10.0",
4
4
  "description": "A react component library for AppUI framework",
5
5
  "type": "module",
6
6
  "types": "./lib/appui-react.d.ts",
@@ -45,9 +45,9 @@
45
45
  "react-dom": "^18.0.0",
46
46
  "react-redux": "^7.2.2 || ^8.0.0 || ^9.0.0",
47
47
  "redux": "^4.1.0 || ^5.0.0",
48
- "@itwin/components-react": "5.9.1",
49
- "@itwin/core-react": "5.9.1",
50
- "@itwin/imodel-components-react": "5.9.1"
48
+ "@itwin/components-react": "5.10.0",
49
+ "@itwin/core-react": "5.10.0",
50
+ "@itwin/imodel-components-react": "5.10.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@itwin/appui-abstract": "rc",
@@ -91,9 +91,9 @@
91
91
  "typescript": "~5.6.2",
92
92
  "upath": "^2.0.1",
93
93
  "vitest": "^3.0.6",
94
- "@itwin/imodel-components-react": "5.9.1",
95
- "@itwin/core-react": "5.9.1",
96
- "@itwin/components-react": "5.9.1"
94
+ "@itwin/components-react": "5.10.0",
95
+ "@itwin/core-react": "5.10.0",
96
+ "@itwin/imodel-components-react": "5.10.0"
97
97
  },
98
98
  "dependencies": {
99
99
  "@itwin/itwinui-icons-react": "^2.8.0",