@itwin/map-layers 4.0.0-dev.41 → 4.0.0-dev.47

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 (193) hide show
  1. package/CHANGELOG.md +864 -864
  2. package/README.md +32 -32
  3. package/lib/cjs/MapLayerPreferences.d.ts +88 -88
  4. package/lib/cjs/MapLayerPreferences.js +311 -311
  5. package/lib/cjs/MapLayerPreferences.js.map +1 -1
  6. package/lib/cjs/map-layers.d.ts +6 -6
  7. package/lib/cjs/map-layers.js +22 -22
  8. package/lib/cjs/mapLayers.d.ts +26 -44
  9. package/lib/cjs/mapLayers.d.ts.map +1 -1
  10. package/lib/cjs/mapLayers.js +33 -61
  11. package/lib/cjs/mapLayers.js.map +1 -1
  12. package/lib/cjs/ui/FeatureInfoUiItemsProvider.d.ts +16 -11
  13. package/lib/cjs/ui/FeatureInfoUiItemsProvider.d.ts.map +1 -1
  14. package/lib/cjs/ui/FeatureInfoUiItemsProvider.js +46 -51
  15. package/lib/cjs/ui/FeatureInfoUiItemsProvider.js.map +1 -1
  16. package/lib/cjs/ui/Interfaces.d.ts +50 -50
  17. package/lib/cjs/ui/Interfaces.js +2 -2
  18. package/lib/cjs/ui/Interfaces.js.map +1 -1
  19. package/lib/cjs/ui/MapFeatureInfoTool.d.ts +13 -13
  20. package/lib/cjs/ui/MapFeatureInfoTool.js +50 -50
  21. package/lib/cjs/ui/MapFeatureInfoTool.js.map +1 -1
  22. package/lib/cjs/ui/MapLayersUiItemsProvider.d.ts +8 -8
  23. package/lib/cjs/ui/MapLayersUiItemsProvider.d.ts.map +1 -1
  24. package/lib/cjs/ui/MapLayersUiItemsProvider.js +35 -38
  25. package/lib/cjs/ui/MapLayersUiItemsProvider.js.map +1 -1
  26. package/lib/cjs/ui/widget/AttachLayerPopupButton.d.ts +13 -14
  27. package/lib/cjs/ui/widget/AttachLayerPopupButton.d.ts.map +1 -1
  28. package/lib/cjs/ui/widget/AttachLayerPopupButton.js +335 -335
  29. package/lib/cjs/ui/widget/BasemapPanel.d.ts +7 -8
  30. package/lib/cjs/ui/widget/BasemapPanel.d.ts.map +1 -1
  31. package/lib/cjs/ui/widget/BasemapPanel.js +156 -156
  32. package/lib/cjs/ui/widget/BasemapPanel.js.map +1 -1
  33. package/lib/cjs/ui/widget/BasemapPanel.scss +87 -87
  34. package/lib/cjs/ui/widget/ConfirmMessageDialog.d.ts +20 -21
  35. package/lib/cjs/ui/widget/ConfirmMessageDialog.d.ts.map +1 -1
  36. package/lib/cjs/ui/widget/ConfirmMessageDialog.js +22 -22
  37. package/lib/cjs/ui/widget/ConfirmMessageDialog.js.map +1 -1
  38. package/lib/cjs/ui/widget/FeatureInfoDataProvider.d.ts +40 -40
  39. package/lib/cjs/ui/widget/FeatureInfoDataProvider.js +138 -138
  40. package/lib/cjs/ui/widget/FeatureInfoDataProvider.js.map +1 -1
  41. package/lib/cjs/ui/widget/FeatureInfoWidget.d.ts +6 -7
  42. package/lib/cjs/ui/widget/FeatureInfoWidget.d.ts.map +1 -1
  43. package/lib/cjs/ui/widget/FeatureInfoWidget.js +65 -65
  44. package/lib/cjs/ui/widget/FeatureInfoWidget.js.map +1 -1
  45. package/lib/cjs/ui/widget/MapLayerDroppable.d.ts +18 -19
  46. package/lib/cjs/ui/widget/MapLayerDroppable.d.ts.map +1 -1
  47. package/lib/cjs/ui/widget/MapLayerDroppable.js +85 -85
  48. package/lib/cjs/ui/widget/MapLayerDroppable.js.map +1 -1
  49. package/lib/cjs/ui/widget/MapLayerManager.d.ts +26 -26
  50. package/lib/cjs/ui/widget/MapLayerManager.js +401 -401
  51. package/lib/cjs/ui/widget/MapLayerManager.js.map +1 -1
  52. package/lib/cjs/ui/widget/MapLayerManager.scss +409 -409
  53. package/lib/cjs/ui/widget/MapLayerSettingsMenu.d.ts +11 -12
  54. package/lib/cjs/ui/widget/MapLayerSettingsMenu.d.ts.map +1 -1
  55. package/lib/cjs/ui/widget/MapLayerSettingsMenu.js +82 -82
  56. package/lib/cjs/ui/widget/MapLayerSettingsMenu.js.map +1 -1
  57. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.d.ts +6 -7
  58. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.d.ts.map +1 -1
  59. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.js +65 -65
  60. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.js.map +1 -1
  61. package/lib/cjs/ui/widget/MapLayerSettingsPopupButton.scss +20 -20
  62. package/lib/cjs/ui/widget/MapLayersWidget.d.ts +10 -11
  63. package/lib/cjs/ui/widget/MapLayersWidget.d.ts.map +1 -1
  64. package/lib/cjs/ui/widget/MapLayersWidget.js +31 -31
  65. package/lib/cjs/ui/widget/MapLayersWidget.js.map +1 -1
  66. package/lib/cjs/ui/widget/MapManagerSettings.d.ts +2 -3
  67. package/lib/cjs/ui/widget/MapManagerSettings.d.ts.map +1 -1
  68. package/lib/cjs/ui/widget/MapManagerSettings.js +200 -200
  69. package/lib/cjs/ui/widget/MapManagerSettings.js.map +1 -1
  70. package/lib/cjs/ui/widget/MapManagerSettings.scss +29 -29
  71. package/lib/cjs/ui/widget/MapUrlDialog.d.ts +22 -23
  72. package/lib/cjs/ui/widget/MapUrlDialog.d.ts.map +1 -1
  73. package/lib/cjs/ui/widget/MapUrlDialog.js +530 -530
  74. package/lib/cjs/ui/widget/MapUrlDialog.js.map +1 -1
  75. package/lib/cjs/ui/widget/MapUrlDialog.scss +99 -100
  76. package/lib/cjs/ui/widget/SelectMapFormat.d.ts +17 -18
  77. package/lib/cjs/ui/widget/SelectMapFormat.d.ts.map +1 -1
  78. package/lib/cjs/ui/widget/SelectMapFormat.js +54 -54
  79. package/lib/cjs/ui/widget/SelectMapFormat.js.map +1 -1
  80. package/lib/cjs/ui/widget/SubLayersDataProvider.d.ts +18 -20
  81. package/lib/cjs/ui/widget/SubLayersDataProvider.d.ts.map +1 -1
  82. package/lib/cjs/ui/widget/SubLayersDataProvider.js +74 -75
  83. package/lib/cjs/ui/widget/SubLayersDataProvider.js.map +1 -1
  84. package/lib/cjs/ui/widget/SubLayersPopupButton.d.ts +9 -10
  85. package/lib/cjs/ui/widget/SubLayersPopupButton.d.ts.map +1 -1
  86. package/lib/cjs/ui/widget/SubLayersPopupButton.js +40 -40
  87. package/lib/cjs/ui/widget/SubLayersPopupButton.js.map +1 -1
  88. package/lib/cjs/ui/widget/SubLayersTree.d.ts +14 -15
  89. package/lib/cjs/ui/widget/SubLayersTree.d.ts.map +1 -1
  90. package/lib/cjs/ui/widget/SubLayersTree.js +413 -413
  91. package/lib/cjs/ui/widget/SubLayersTree.js.map +1 -1
  92. package/lib/cjs/ui/widget/SubLayersTree.scss +69 -69
  93. package/lib/cjs/ui/widget/TransparencyPopupButton.d.ts +13 -14
  94. package/lib/cjs/ui/widget/TransparencyPopupButton.d.ts.map +1 -1
  95. package/lib/cjs/ui/widget/TransparencyPopupButton.js +47 -47
  96. package/lib/cjs/ui/widget/TransparencyPopupButton.js.map +1 -1
  97. package/lib/cjs/ui/widget/TransparencyPopupButton.scss +35 -36
  98. package/lib/esm/MapLayerPreferences.d.ts +88 -88
  99. package/lib/esm/MapLayerPreferences.js +307 -307
  100. package/lib/esm/MapLayerPreferences.js.map +1 -1
  101. package/lib/esm/map-layers.d.ts +6 -6
  102. package/lib/esm/map-layers.js +10 -10
  103. package/lib/esm/mapLayers.d.ts +26 -44
  104. package/lib/esm/mapLayers.d.ts.map +1 -1
  105. package/lib/esm/mapLayers.js +29 -57
  106. package/lib/esm/mapLayers.js.map +1 -1
  107. package/lib/esm/ui/FeatureInfoUiItemsProvider.d.ts +16 -11
  108. package/lib/esm/ui/FeatureInfoUiItemsProvider.d.ts.map +1 -1
  109. package/lib/esm/ui/FeatureInfoUiItemsProvider.js +42 -47
  110. package/lib/esm/ui/FeatureInfoUiItemsProvider.js.map +1 -1
  111. package/lib/esm/ui/Interfaces.d.ts +50 -50
  112. package/lib/esm/ui/Interfaces.js +1 -1
  113. package/lib/esm/ui/Interfaces.js.map +1 -1
  114. package/lib/esm/ui/MapFeatureInfoTool.d.ts +13 -13
  115. package/lib/esm/ui/MapFeatureInfoTool.js +45 -45
  116. package/lib/esm/ui/MapFeatureInfoTool.js.map +1 -1
  117. package/lib/esm/ui/MapLayersUiItemsProvider.d.ts +8 -8
  118. package/lib/esm/ui/MapLayersUiItemsProvider.d.ts.map +1 -1
  119. package/lib/esm/ui/MapLayersUiItemsProvider.js +31 -34
  120. package/lib/esm/ui/MapLayersUiItemsProvider.js.map +1 -1
  121. package/lib/esm/ui/widget/AttachLayerPopupButton.d.ts +13 -14
  122. package/lib/esm/ui/widget/AttachLayerPopupButton.d.ts.map +1 -1
  123. package/lib/esm/ui/widget/AttachLayerPopupButton.js +331 -331
  124. package/lib/esm/ui/widget/BasemapPanel.d.ts +7 -8
  125. package/lib/esm/ui/widget/BasemapPanel.d.ts.map +1 -1
  126. package/lib/esm/ui/widget/BasemapPanel.js +152 -152
  127. package/lib/esm/ui/widget/BasemapPanel.js.map +1 -1
  128. package/lib/esm/ui/widget/BasemapPanel.scss +87 -87
  129. package/lib/esm/ui/widget/ConfirmMessageDialog.d.ts +20 -21
  130. package/lib/esm/ui/widget/ConfirmMessageDialog.d.ts.map +1 -1
  131. package/lib/esm/ui/widget/ConfirmMessageDialog.js +18 -18
  132. package/lib/esm/ui/widget/ConfirmMessageDialog.js.map +1 -1
  133. package/lib/esm/ui/widget/FeatureInfoDataProvider.d.ts +40 -40
  134. package/lib/esm/ui/widget/FeatureInfoDataProvider.js +134 -134
  135. package/lib/esm/ui/widget/FeatureInfoDataProvider.js.map +1 -1
  136. package/lib/esm/ui/widget/FeatureInfoWidget.d.ts +6 -7
  137. package/lib/esm/ui/widget/FeatureInfoWidget.d.ts.map +1 -1
  138. package/lib/esm/ui/widget/FeatureInfoWidget.js +61 -61
  139. package/lib/esm/ui/widget/FeatureInfoWidget.js.map +1 -1
  140. package/lib/esm/ui/widget/MapLayerDroppable.d.ts +18 -19
  141. package/lib/esm/ui/widget/MapLayerDroppable.d.ts.map +1 -1
  142. package/lib/esm/ui/widget/MapLayerDroppable.js +81 -81
  143. package/lib/esm/ui/widget/MapLayerDroppable.js.map +1 -1
  144. package/lib/esm/ui/widget/MapLayerManager.d.ts +26 -26
  145. package/lib/esm/ui/widget/MapLayerManager.js +396 -396
  146. package/lib/esm/ui/widget/MapLayerManager.js.map +1 -1
  147. package/lib/esm/ui/widget/MapLayerManager.scss +409 -409
  148. package/lib/esm/ui/widget/MapLayerSettingsMenu.d.ts +11 -12
  149. package/lib/esm/ui/widget/MapLayerSettingsMenu.d.ts.map +1 -1
  150. package/lib/esm/ui/widget/MapLayerSettingsMenu.js +78 -78
  151. package/lib/esm/ui/widget/MapLayerSettingsMenu.js.map +1 -1
  152. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.d.ts +6 -7
  153. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.d.ts.map +1 -1
  154. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.js +61 -61
  155. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.js.map +1 -1
  156. package/lib/esm/ui/widget/MapLayerSettingsPopupButton.scss +20 -20
  157. package/lib/esm/ui/widget/MapLayersWidget.d.ts +10 -11
  158. package/lib/esm/ui/widget/MapLayersWidget.d.ts.map +1 -1
  159. package/lib/esm/ui/widget/MapLayersWidget.js +27 -27
  160. package/lib/esm/ui/widget/MapLayersWidget.js.map +1 -1
  161. package/lib/esm/ui/widget/MapManagerSettings.d.ts +2 -3
  162. package/lib/esm/ui/widget/MapManagerSettings.d.ts.map +1 -1
  163. package/lib/esm/ui/widget/MapManagerSettings.js +196 -196
  164. package/lib/esm/ui/widget/MapManagerSettings.js.map +1 -1
  165. package/lib/esm/ui/widget/MapManagerSettings.scss +29 -29
  166. package/lib/esm/ui/widget/MapUrlDialog.d.ts +22 -23
  167. package/lib/esm/ui/widget/MapUrlDialog.d.ts.map +1 -1
  168. package/lib/esm/ui/widget/MapUrlDialog.js +526 -526
  169. package/lib/esm/ui/widget/MapUrlDialog.js.map +1 -1
  170. package/lib/esm/ui/widget/MapUrlDialog.scss +99 -100
  171. package/lib/esm/ui/widget/SelectMapFormat.d.ts +17 -18
  172. package/lib/esm/ui/widget/SelectMapFormat.d.ts.map +1 -1
  173. package/lib/esm/ui/widget/SelectMapFormat.js +50 -50
  174. package/lib/esm/ui/widget/SelectMapFormat.js.map +1 -1
  175. package/lib/esm/ui/widget/SubLayersDataProvider.d.ts +18 -20
  176. package/lib/esm/ui/widget/SubLayersDataProvider.d.ts.map +1 -1
  177. package/lib/esm/ui/widget/SubLayersDataProvider.js +70 -71
  178. package/lib/esm/ui/widget/SubLayersDataProvider.js.map +1 -1
  179. package/lib/esm/ui/widget/SubLayersPopupButton.d.ts +9 -10
  180. package/lib/esm/ui/widget/SubLayersPopupButton.d.ts.map +1 -1
  181. package/lib/esm/ui/widget/SubLayersPopupButton.js +36 -36
  182. package/lib/esm/ui/widget/SubLayersPopupButton.js.map +1 -1
  183. package/lib/esm/ui/widget/SubLayersTree.d.ts +14 -15
  184. package/lib/esm/ui/widget/SubLayersTree.d.ts.map +1 -1
  185. package/lib/esm/ui/widget/SubLayersTree.js +408 -408
  186. package/lib/esm/ui/widget/SubLayersTree.js.map +1 -1
  187. package/lib/esm/ui/widget/SubLayersTree.scss +69 -69
  188. package/lib/esm/ui/widget/TransparencyPopupButton.d.ts +13 -14
  189. package/lib/esm/ui/widget/TransparencyPopupButton.d.ts.map +1 -1
  190. package/lib/esm/ui/widget/TransparencyPopupButton.js +43 -43
  191. package/lib/esm/ui/widget/TransparencyPopupButton.js.map +1 -1
  192. package/lib/esm/ui/widget/TransparencyPopupButton.scss +35 -36
  193. package/package.json +31 -37
@@ -1,336 +1,336 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AttachLayerPopupButton = exports.AttachLayerButtonType = void 0;
4
- /*---------------------------------------------------------------------------------------------
5
- * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
6
- * See LICENSE.md in the project root for license terms and full copyright notice.
7
- *--------------------------------------------------------------------------------------------*/
8
- const React = require("react");
9
- const core_frontend_1 = require("@itwin/core-frontend");
10
- const appui_abstract_1 = require("@itwin/appui-abstract");
11
- const UiCore = require("@itwin/core-react");
12
- const appui_react_1 = require("@itwin/appui-react");
13
- const MapLayerManager_1 = require("./MapLayerManager");
14
- const MapUrlDialog_1 = require("./MapUrlDialog");
15
- const ConfirmMessageDialog_1 = require("./ConfirmMessageDialog");
16
- const itwinui_react_1 = require("@itwin/itwinui-react");
17
- const MapLayerPreferences_1 = require("../../MapLayerPreferences");
18
- const mapLayers_1 = require("../../mapLayers");
19
- // cSpell:ignore droppable Sublayer
20
- var LayerAction;
21
- (function (LayerAction) {
22
- LayerAction[LayerAction["Attached"] = 0] = "Attached";
23
- LayerAction[LayerAction["Edited"] = 1] = "Edited";
24
- })(LayerAction || (LayerAction = {}));
25
- // eslint-disable-next-line @typescript-eslint/naming-convention
26
- function AttachLayerPanel({ isOverlay, onLayerAttached, onHandleOutsideClick }) {
27
- const [layerNameToAdd, setLayerNameToAdd] = React.useState();
28
- const [sourceFilterString, setSourceFilterString] = React.useState();
29
- const { placeholderLabel, addCustomLayerLabel, addCustomLayerToolTip, loadingMapSources, removeLayerDefButtonTitle, editLayerDefButtonTitle, removeLayerDefDialogTitle } = React.useMemo(() => {
30
- return {
31
- placeholderLabel: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.SearchPlaceholder"),
32
- addCustomLayerLabel: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.Custom"),
33
- addCustomLayerToolTip: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.AttachCustomLayer"),
34
- loadingMapSources: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.LoadingMapSources"),
35
- removeLayerDefButtonTitle: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefButtonTitle"),
36
- editLayerDefButtonTitle: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.EditLayerDefButtonTitle"),
37
- removeLayerDefDialogTitle: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefDialogTitle"),
38
- };
39
- }, []);
40
- const [loading, setLoading] = React.useState(false);
41
- const [layerNameUnderCursor, setLayerNameUnderCursor] = React.useState();
42
- const resumeOutsideClick = React.useCallback(() => {
43
- if (onHandleOutsideClick) {
44
- onHandleOutsideClick(true);
45
- }
46
- }, [onHandleOutsideClick]);
47
- // 'isMounted' is used to prevent any async operation once the hook has been
48
- // unloaded. Otherwise we get a 'Can't perform a React state update on an unmounted component.' warning in the console.
49
- const isMounted = React.useRef(false);
50
- React.useEffect(() => {
51
- isMounted.current = true;
52
- return () => {
53
- isMounted.current = false;
54
- // We close any open dialogs that we might have opened
55
- // This was added because the modal dialog remained remained displayed after the session expired.
56
- appui_react_1.UiFramework.dialogs.modal.close();
57
- };
58
- }, []);
59
- const handleFilterTextChanged = React.useCallback((event) => {
60
- setSourceFilterString(event.target.value);
61
- }, []);
62
- const { loadingSources, sources, activeViewport, backgroundLayers, overlayLayers, mapLayerOptions } = (0, MapLayerManager_1.useSourceMapContext)();
63
- const mapTypesOptions = mapLayerOptions?.mapTypeOptions;
64
- const iTwinId = activeViewport?.iModel?.iTwinId;
65
- const iModelId = activeViewport?.iModel?.iModelId;
66
- const styleContainsLayer = React.useCallback((name) => {
67
- if (backgroundLayers) {
68
- if (-1 !== backgroundLayers.findIndex((layer) => layer.name === name))
69
- return true;
70
- }
71
- if (overlayLayers) {
72
- if (-1 !== overlayLayers.findIndex((layer) => layer.name === name))
73
- return true;
74
- }
75
- return false;
76
- }, [backgroundLayers, overlayLayers]);
77
- const handleModalUrlDialogOk = React.useCallback((action) => {
78
- if (LayerAction.Attached === action) {
79
- // close popup and refresh UI
80
- onLayerAttached();
81
- }
82
- resumeOutsideClick();
83
- }, [onLayerAttached, resumeOutsideClick]);
84
- const handleModalUrlDialogCancel = React.useCallback(() => {
85
- // close popup and refresh UI
86
- setLoading(false);
87
- appui_react_1.UiFramework.dialogs.modal.close();
88
- resumeOutsideClick();
89
- }, [resumeOutsideClick]);
90
- React.useEffect(() => {
91
- async function attemptToAddLayer(layerName) {
92
- if (layerName && activeViewport) {
93
- // if the layer is not in the style add it now.
94
- if (undefined === backgroundLayers?.find((layer) => layerName === layer.name) && undefined === overlayLayers?.find((layer) => layerName === layer.name)) {
95
- const mapLayerSettings = sources?.find((source) => source.name === layerName);
96
- if (mapLayerSettings === undefined) {
97
- return;
98
- }
99
- try {
100
- if (isMounted.current) {
101
- setLoading(true);
102
- }
103
- const { status, subLayers } = await mapLayerSettings.validateSource();
104
- if (status === core_frontend_1.MapLayerSourceStatus.Valid || status === core_frontend_1.MapLayerSourceStatus.RequireAuth) {
105
- if (status === core_frontend_1.MapLayerSourceStatus.Valid) {
106
- const settings = mapLayerSettings.toLayerSettings(subLayers);
107
- if (settings) {
108
- activeViewport.displayStyle.attachMapLayer({ settings, isOverlay });
109
- activeViewport.invalidateRenderPlan();
110
- const msg = core_frontend_1.IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerAttached", { sourceName: settings.name, sourceUrl: settings.url });
111
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Info, msg));
112
- }
113
- if (isMounted.current) {
114
- setLoading(false);
115
- }
116
- if (onLayerAttached) {
117
- onLayerAttached();
118
- }
119
- }
120
- else if (status === core_frontend_1.MapLayerSourceStatus.RequireAuth && isMounted.current) {
121
- appui_react_1.UiFramework.dialogs.modal.open(React.createElement(MapUrlDialog_1.MapUrlDialog, { activeViewport: activeViewport, isOverlay: isOverlay, layerRequiringCredentials: mapLayerSettings.toJSON(), onOkResult: () => handleModalUrlDialogOk(LayerAction.Attached), onCancelResult: handleModalUrlDialogCancel, mapTypesOptions: mapTypesOptions }));
122
- if (onHandleOutsideClick) {
123
- onHandleOutsideClick(false);
124
- }
125
- }
126
- }
127
- else {
128
- const msg = core_frontend_1.IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerValidationFailed", { sourceUrl: mapLayerSettings.url });
129
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
130
- if (isMounted.current) {
131
- setLoading(false);
132
- }
133
- }
134
- }
135
- catch (err) {
136
- if (isMounted.current) {
137
- setLoading(false);
138
- }
139
- const msg = core_frontend_1.IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error: err, sourceUrl: mapLayerSettings.url });
140
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
141
- }
142
- }
143
- }
144
- return;
145
- }
146
- if (layerNameToAdd) {
147
- attemptToAddLayer(layerNameToAdd); // eslint-disable-line @typescript-eslint/no-floating-promises
148
- if (isMounted.current) {
149
- setLayerNameToAdd(undefined);
150
- }
151
- }
152
- }, [setLayerNameToAdd, layerNameToAdd, activeViewport, sources, backgroundLayers, isOverlay, overlayLayers, onLayerAttached, handleModalUrlDialogOk, mapTypesOptions, handleModalUrlDialogCancel, onHandleOutsideClick]);
153
- const options = React.useMemo(() => sources?.filter((source) => !styleContainsLayer(source.name)), [sources, styleContainsLayer]);
154
- const filteredOptions = React.useMemo(() => {
155
- if (undefined === sourceFilterString || 0 === sourceFilterString.length) {
156
- return options;
157
- }
158
- else {
159
- return options?.filter((option) => option.name.toLowerCase().includes(sourceFilterString?.toLowerCase()));
160
- }
161
- }, [options, sourceFilterString]);
162
- const handleAddNewMapSource = React.useCallback(() => {
163
- appui_react_1.UiFramework.dialogs.modal.open(React.createElement(MapUrlDialog_1.MapUrlDialog, { activeViewport: activeViewport, isOverlay: isOverlay, onOkResult: () => handleModalUrlDialogOk(LayerAction.Attached), onCancelResult: handleModalUrlDialogCancel, mapTypesOptions: mapTypesOptions }));
164
- if (onHandleOutsideClick) {
165
- onHandleOutsideClick(false);
166
- }
167
- return;
168
- }, [activeViewport, handleModalUrlDialogCancel, handleModalUrlDialogOk, isOverlay, mapTypesOptions, onHandleOutsideClick]);
169
- const handleAttach = React.useCallback((mapName) => {
170
- setLayerNameToAdd(mapName);
171
- }, []);
172
- const handleKeypressOnSourceList = React.useCallback((event) => {
173
- const key = event.key;
174
- if (key === "Enter") {
175
- event.preventDefault();
176
- const mapName = event.currentTarget?.dataset?.value;
177
- if (mapName && mapName.length) {
178
- handleAttach(mapName);
179
- }
180
- }
181
- }, [handleAttach]);
182
- const onListboxValueChange = React.useCallback((mapName) => {
183
- setLayerNameToAdd(mapName);
184
- }, []);
185
- const handleNoConfirmation = React.useCallback((_layerName) => {
186
- appui_react_1.UiFramework.dialogs.modal.close();
187
- resumeOutsideClick();
188
- }, [resumeOutsideClick]);
189
- const handleYesConfirmation = React.useCallback(async (source) => {
190
- const layerName = source.name;
191
- if (!!iTwinId) {
192
- try {
193
- await MapLayerPreferences_1.MapLayerPreferences.deleteByName(source, iTwinId, iModelId);
194
- const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefSuccess", { layerName });
195
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Info, msg));
196
- }
197
- catch (err) {
198
- const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefError", { layerName });
199
- core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
200
- }
201
- }
202
- appui_react_1.UiFramework.dialogs.modal.close();
203
- resumeOutsideClick();
204
- }, [iTwinId, iModelId, resumeOutsideClick]);
205
- /*
206
- Handle Remove layer button clicked
207
- */
208
- const onItemRemoveButtonClicked = React.useCallback((source, event) => {
209
- event.stopPropagation(); // We don't want the owning ListBox to react on mouse click.
210
- const layerName = source.name;
211
- const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefDialogMessage", { layerName });
212
- appui_react_1.UiFramework.dialogs.modal.open(React.createElement(ConfirmMessageDialog_1.ConfirmMessageDialog, { className: "map-sources-delete-confirmation", title: removeLayerDefDialogTitle, message: msg, maxWidth: 400, onClose: () => handleNoConfirmation(layerName), onEscape: () => handleNoConfirmation(layerName), onYesResult: async () => handleYesConfirmation(source), onNoResult: () => handleNoConfirmation(layerName) }));
213
- if (onHandleOutsideClick) {
214
- onHandleOutsideClick(false);
215
- }
216
- }, [handleNoConfirmation, handleYesConfirmation, onHandleOutsideClick, removeLayerDefDialogTitle]);
217
- /*
218
- Handle Edit layer button clicked
219
- */
220
- const onItemEditButtonClicked = React.useCallback((event) => {
221
- event.stopPropagation(); // We don't want the owning ListBox to react on mouse click.
222
- const targetLayerName = event?.currentTarget?.parentNode?.dataset?.value;
223
- const matchingSource = sources.find((layerSource) => layerSource.name === targetLayerName);
224
- // we expect a single layer source matching this name
225
- if (matchingSource === undefined) {
226
- return;
227
- }
228
- appui_react_1.UiFramework.dialogs.modal.open(React.createElement(MapUrlDialog_1.MapUrlDialog, { activeViewport: activeViewport, isOverlay: isOverlay, mapLayerSourceToEdit: matchingSource, onOkResult: () => handleModalUrlDialogOk(LayerAction.Edited), onCancelResult: handleModalUrlDialogCancel, mapTypesOptions: mapTypesOptions }));
229
- if (onHandleOutsideClick) {
230
- onHandleOutsideClick(false);
231
- }
232
- }, [activeViewport, handleModalUrlDialogCancel, handleModalUrlDialogOk, isOverlay, mapTypesOptions, onHandleOutsideClick, sources]);
233
- return (React.createElement("div", { className: "map-manager-header" },
234
- (loading || loadingSources) && React.createElement(UiCore.LoadingSpinner, { message: loadingMapSources }),
235
- React.createElement("div", { className: "map-manager-source-listbox-header" },
236
- React.createElement(itwinui_react_1.Input, { type: "text", className: "map-manager-source-list-filter", placeholder: placeholderLabel, value: sourceFilterString, onChange: handleFilterTextChanged, size: "small" }),
237
- React.createElement(itwinui_react_1.Button, { className: "map-manager-add-source-button", title: addCustomLayerToolTip, onClick: handleAddNewMapSource }, addCustomLayerLabel)),
238
- React.createElement("div", { className: "map-manager-sources" },
239
- React.createElement(UiCore.Listbox, { id: "map-sources", selectedValue: layerNameToAdd, className: "map-manager-source-list", onKeyPress: handleKeypressOnSourceList, onListboxValueChange: onListboxValueChange }, filteredOptions?.map((source) => React.createElement(UiCore.ListboxItem, { key: source.name, className: "map-source-list-entry", value: source.name, onMouseEnter: () => setLayerNameUnderCursor(source.name), onMouseLeave: () => setLayerNameUnderCursor(undefined) },
240
- React.createElement("span", { className: "map-source-list-entry-name", title: source.name }, source.name),
241
- // otherwise list feels cluttered.
242
- (!!iTwinId && layerNameUnderCursor && layerNameUnderCursor === source.name) &&
243
- React.createElement(React.Fragment, null,
244
- React.createElement(itwinui_react_1.Button, { size: "small", styleType: "borderless", className: "map-source-list-entry-button", title: editLayerDefButtonTitle, onClick: onItemEditButtonClicked },
245
- React.createElement(UiCore.Icon, { iconSpec: "icon-edit" })),
246
- React.createElement(itwinui_react_1.Button, { size: "small", styleType: "borderless", className: "map-source-list-entry-button", title: removeLayerDefButtonTitle, onClick: (event) => { onItemRemoveButtonClicked(source, event); } },
247
- React.createElement(UiCore.Icon, { iconSpec: "icon-delete" })))))))));
248
- }
249
- /** @internal */
250
- var AttachLayerButtonType;
251
- (function (AttachLayerButtonType) {
252
- AttachLayerButtonType[AttachLayerButtonType["Primary"] = 0] = "Primary";
253
- AttachLayerButtonType[AttachLayerButtonType["Blue"] = 1] = "Blue";
254
- AttachLayerButtonType[AttachLayerButtonType["Icon"] = 2] = "Icon";
255
- })(AttachLayerButtonType = exports.AttachLayerButtonType || (exports.AttachLayerButtonType = {}));
256
- /** @internal */
257
- // eslint-disable-next-line @typescript-eslint/naming-convention
258
- function AttachLayerPopupButton(props) {
259
- const { showAttachLayerLabel, hideAttachLayerLabel, addCustomLayerButtonLabel } = React.useMemo(() => {
260
- return {
261
- showAttachLayerLabel: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AttachLayerPopup.Attach"),
262
- hideAttachLayerLabel: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AttachLayerPopup.Close"),
263
- addCustomLayerButtonLabel: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.AddCustomLayerButtonLabel"),
264
- };
265
- }, []);
266
- const [handleOutsideClick, setHandleOutsideClick] = React.useState(true);
267
- const [popupOpen, setPopupOpen] = React.useState(false);
268
- const buttonRef = React.useRef(null);
269
- const panelRef = React.useRef(null);
270
- // 'isMounted' is used to prevent any async operation once the hook has been
271
- // unloaded. Otherwise we get a 'Can't perform a React state update on an unmounted component.' warning in the console.
272
- const isMounted = React.useRef(false);
273
- React.useEffect(() => {
274
- isMounted.current = true;
275
- return () => {
276
- isMounted.current = false;
277
- };
278
- }, []);
279
- const togglePopup = React.useCallback(() => {
280
- setPopupOpen(!popupOpen);
281
- }, [popupOpen]);
282
- const handleClosePopup = React.useCallback(() => {
283
- setPopupOpen(false);
284
- }, []);
285
- const onHandleOutsideClick = React.useCallback((event) => {
286
- if (!handleOutsideClick) {
287
- return;
288
- }
289
- // If clicking on button that open panel - don't trigger outside click processing
290
- if (buttonRef?.current && buttonRef?.current.contains(event.target)) {
291
- return;
292
- }
293
- // If clicking the panel, this is not an outside clicked
294
- if (panelRef.current && panelRef?.current.contains(event.target)) {
295
- return;
296
- }
297
- // If we reach this point, we got an outside clicked, no close the popup
298
- setPopupOpen(false);
299
- }, [handleOutsideClick]);
300
- const { refreshFromStyle } = (0, MapLayerManager_1.useSourceMapContext)();
301
- const handleLayerAttached = React.useCallback(() => {
302
- if (!isMounted.current) {
303
- return;
304
- }
305
- setPopupOpen(false);
306
- refreshFromStyle();
307
- }, [refreshFromStyle]);
308
- function renderButton() {
309
- let button;
310
- if (props.buttonType === undefined || props.buttonType === AttachLayerButtonType.Icon) {
311
- button = (React.createElement(itwinui_react_1.Button, { disabled: props.disabled, size: "small", styleType: "borderless", ref: buttonRef, className: "map-manager-attach-layer-button", title: popupOpen ? hideAttachLayerLabel : showAttachLayerLabel, onClick: togglePopup },
312
- React.createElement(UiCore.WebFontIcon, { iconName: "icon-add" })));
313
- }
314
- else {
315
- const determineStyleType = () => {
316
- switch (props.buttonType) {
317
- case AttachLayerButtonType.Blue:
318
- return "high-visibility";
319
- case AttachLayerButtonType.Primary:
320
- default:
321
- return "cta";
322
- }
323
- };
324
- const styleType = determineStyleType();
325
- button = (React.createElement(itwinui_react_1.Button, { disabled: props.disabled, ref: buttonRef, styleType: styleType, title: popupOpen ? hideAttachLayerLabel : showAttachLayerLabel, onClick: togglePopup }, addCustomLayerButtonLabel));
326
- }
327
- return button;
328
- }
329
- return (React.createElement(React.Fragment, null,
330
- renderButton(),
331
- React.createElement(UiCore.Popup, { isOpen: popupOpen, position: appui_abstract_1.RelativePosition.BottomRight, onClose: handleClosePopup, onOutsideClick: onHandleOutsideClick, target: buttonRef.current, closeOnEnter: false, closeOnContextMenu: false },
332
- React.createElement("div", { ref: panelRef, className: "map-sources-popup-panel" },
333
- React.createElement(AttachLayerPanel, { isOverlay: props.isOverlay, onLayerAttached: handleLayerAttached, onHandleOutsideClick: setHandleOutsideClick })))));
334
- }
335
- exports.AttachLayerPopupButton = AttachLayerPopupButton;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AttachLayerPopupButton = exports.AttachLayerButtonType = void 0;
4
+ /*---------------------------------------------------------------------------------------------
5
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
6
+ * See LICENSE.md in the project root for license terms and full copyright notice.
7
+ *--------------------------------------------------------------------------------------------*/
8
+ const React = require("react");
9
+ const core_frontend_1 = require("@itwin/core-frontend");
10
+ const appui_abstract_1 = require("@itwin/appui-abstract");
11
+ const UiCore = require("@itwin/core-react");
12
+ const appui_react_1 = require("@itwin/appui-react");
13
+ const MapLayerManager_1 = require("./MapLayerManager");
14
+ const MapUrlDialog_1 = require("./MapUrlDialog");
15
+ const ConfirmMessageDialog_1 = require("./ConfirmMessageDialog");
16
+ const itwinui_react_1 = require("@itwin/itwinui-react");
17
+ const MapLayerPreferences_1 = require("../../MapLayerPreferences");
18
+ const mapLayers_1 = require("../../mapLayers");
19
+ // cSpell:ignore droppable Sublayer
20
+ var LayerAction;
21
+ (function (LayerAction) {
22
+ LayerAction[LayerAction["Attached"] = 0] = "Attached";
23
+ LayerAction[LayerAction["Edited"] = 1] = "Edited";
24
+ })(LayerAction || (LayerAction = {}));
25
+ // eslint-disable-next-line @typescript-eslint/naming-convention
26
+ function AttachLayerPanel({ isOverlay, onLayerAttached, onHandleOutsideClick }) {
27
+ const [layerNameToAdd, setLayerNameToAdd] = React.useState();
28
+ const [sourceFilterString, setSourceFilterString] = React.useState();
29
+ const { placeholderLabel, addCustomLayerLabel, addCustomLayerToolTip, loadingMapSources, removeLayerDefButtonTitle, editLayerDefButtonTitle, removeLayerDefDialogTitle } = React.useMemo(() => {
30
+ return {
31
+ placeholderLabel: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.SearchPlaceholder"),
32
+ addCustomLayerLabel: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.Custom"),
33
+ addCustomLayerToolTip: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.AttachCustomLayer"),
34
+ loadingMapSources: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.LoadingMapSources"),
35
+ removeLayerDefButtonTitle: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefButtonTitle"),
36
+ editLayerDefButtonTitle: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.EditLayerDefButtonTitle"),
37
+ removeLayerDefDialogTitle: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefDialogTitle"),
38
+ };
39
+ }, []);
40
+ const [loading, setLoading] = React.useState(false);
41
+ const [layerNameUnderCursor, setLayerNameUnderCursor] = React.useState();
42
+ const resumeOutsideClick = React.useCallback(() => {
43
+ if (onHandleOutsideClick) {
44
+ onHandleOutsideClick(true);
45
+ }
46
+ }, [onHandleOutsideClick]);
47
+ // 'isMounted' is used to prevent any async operation once the hook has been
48
+ // unloaded. Otherwise we get a 'Can't perform a React state update on an unmounted component.' warning in the console.
49
+ const isMounted = React.useRef(false);
50
+ React.useEffect(() => {
51
+ isMounted.current = true;
52
+ return () => {
53
+ isMounted.current = false;
54
+ // We close any open dialogs that we might have opened
55
+ // This was added because the modal dialog remained remained displayed after the session expired.
56
+ appui_react_1.UiFramework.dialogs.modal.close();
57
+ };
58
+ }, []);
59
+ const handleFilterTextChanged = React.useCallback((event) => {
60
+ setSourceFilterString(event.target.value);
61
+ }, []);
62
+ const { loadingSources, sources, activeViewport, backgroundLayers, overlayLayers, mapLayerOptions } = (0, MapLayerManager_1.useSourceMapContext)();
63
+ const mapTypesOptions = mapLayerOptions?.mapTypeOptions;
64
+ const iTwinId = activeViewport?.iModel?.iTwinId;
65
+ const iModelId = activeViewport?.iModel?.iModelId;
66
+ const styleContainsLayer = React.useCallback((name) => {
67
+ if (backgroundLayers) {
68
+ if (-1 !== backgroundLayers.findIndex((layer) => layer.name === name))
69
+ return true;
70
+ }
71
+ if (overlayLayers) {
72
+ if (-1 !== overlayLayers.findIndex((layer) => layer.name === name))
73
+ return true;
74
+ }
75
+ return false;
76
+ }, [backgroundLayers, overlayLayers]);
77
+ const handleModalUrlDialogOk = React.useCallback((action) => {
78
+ if (LayerAction.Attached === action) {
79
+ // close popup and refresh UI
80
+ onLayerAttached();
81
+ }
82
+ resumeOutsideClick();
83
+ }, [onLayerAttached, resumeOutsideClick]);
84
+ const handleModalUrlDialogCancel = React.useCallback(() => {
85
+ // close popup and refresh UI
86
+ setLoading(false);
87
+ appui_react_1.UiFramework.dialogs.modal.close();
88
+ resumeOutsideClick();
89
+ }, [resumeOutsideClick]);
90
+ React.useEffect(() => {
91
+ async function attemptToAddLayer(layerName) {
92
+ if (layerName && activeViewport) {
93
+ // if the layer is not in the style add it now.
94
+ if (undefined === backgroundLayers?.find((layer) => layerName === layer.name) && undefined === overlayLayers?.find((layer) => layerName === layer.name)) {
95
+ const mapLayerSettings = sources?.find((source) => source.name === layerName);
96
+ if (mapLayerSettings === undefined) {
97
+ return;
98
+ }
99
+ try {
100
+ if (isMounted.current) {
101
+ setLoading(true);
102
+ }
103
+ const { status, subLayers } = await mapLayerSettings.validateSource();
104
+ if (status === core_frontend_1.MapLayerSourceStatus.Valid || status === core_frontend_1.MapLayerSourceStatus.RequireAuth) {
105
+ if (status === core_frontend_1.MapLayerSourceStatus.Valid) {
106
+ const settings = mapLayerSettings.toLayerSettings(subLayers);
107
+ if (settings) {
108
+ activeViewport.displayStyle.attachMapLayer({ settings, isOverlay });
109
+ activeViewport.invalidateRenderPlan();
110
+ const msg = core_frontend_1.IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerAttached", { sourceName: settings.name, sourceUrl: settings.url });
111
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Info, msg));
112
+ }
113
+ if (isMounted.current) {
114
+ setLoading(false);
115
+ }
116
+ if (onLayerAttached) {
117
+ onLayerAttached();
118
+ }
119
+ }
120
+ else if (status === core_frontend_1.MapLayerSourceStatus.RequireAuth && isMounted.current) {
121
+ appui_react_1.UiFramework.dialogs.modal.open(React.createElement(MapUrlDialog_1.MapUrlDialog, { activeViewport: activeViewport, isOverlay: isOverlay, layerRequiringCredentials: mapLayerSettings.toJSON(), onOkResult: () => handleModalUrlDialogOk(LayerAction.Attached), onCancelResult: handleModalUrlDialogCancel, mapTypesOptions: mapTypesOptions }));
122
+ if (onHandleOutsideClick) {
123
+ onHandleOutsideClick(false);
124
+ }
125
+ }
126
+ }
127
+ else {
128
+ const msg = core_frontend_1.IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerValidationFailed", { sourceUrl: mapLayerSettings.url });
129
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
130
+ if (isMounted.current) {
131
+ setLoading(false);
132
+ }
133
+ }
134
+ }
135
+ catch (err) {
136
+ if (isMounted.current) {
137
+ setLoading(false);
138
+ }
139
+ const msg = core_frontend_1.IModelApp.localization.getLocalizedString("mapLayers:Messages.MapLayerAttachError", { error: err, sourceUrl: mapLayerSettings.url });
140
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
141
+ }
142
+ }
143
+ }
144
+ return;
145
+ }
146
+ if (layerNameToAdd) {
147
+ attemptToAddLayer(layerNameToAdd); // eslint-disable-line @typescript-eslint/no-floating-promises
148
+ if (isMounted.current) {
149
+ setLayerNameToAdd(undefined);
150
+ }
151
+ }
152
+ }, [setLayerNameToAdd, layerNameToAdd, activeViewport, sources, backgroundLayers, isOverlay, overlayLayers, onLayerAttached, handleModalUrlDialogOk, mapTypesOptions, handleModalUrlDialogCancel, onHandleOutsideClick]);
153
+ const options = React.useMemo(() => sources?.filter((source) => !styleContainsLayer(source.name)), [sources, styleContainsLayer]);
154
+ const filteredOptions = React.useMemo(() => {
155
+ if (undefined === sourceFilterString || 0 === sourceFilterString.length) {
156
+ return options;
157
+ }
158
+ else {
159
+ return options?.filter((option) => option.name.toLowerCase().includes(sourceFilterString?.toLowerCase()));
160
+ }
161
+ }, [options, sourceFilterString]);
162
+ const handleAddNewMapSource = React.useCallback(() => {
163
+ appui_react_1.UiFramework.dialogs.modal.open(React.createElement(MapUrlDialog_1.MapUrlDialog, { activeViewport: activeViewport, isOverlay: isOverlay, onOkResult: () => handleModalUrlDialogOk(LayerAction.Attached), onCancelResult: handleModalUrlDialogCancel, mapTypesOptions: mapTypesOptions }));
164
+ if (onHandleOutsideClick) {
165
+ onHandleOutsideClick(false);
166
+ }
167
+ return;
168
+ }, [activeViewport, handleModalUrlDialogCancel, handleModalUrlDialogOk, isOverlay, mapTypesOptions, onHandleOutsideClick]);
169
+ const handleAttach = React.useCallback((mapName) => {
170
+ setLayerNameToAdd(mapName);
171
+ }, []);
172
+ const handleKeypressOnSourceList = React.useCallback((event) => {
173
+ const key = event.key;
174
+ if (key === "Enter") {
175
+ event.preventDefault();
176
+ const mapName = event.currentTarget?.dataset?.value;
177
+ if (mapName && mapName.length) {
178
+ handleAttach(mapName);
179
+ }
180
+ }
181
+ }, [handleAttach]);
182
+ const onListboxValueChange = React.useCallback((mapName) => {
183
+ setLayerNameToAdd(mapName);
184
+ }, []);
185
+ const handleNoConfirmation = React.useCallback((_layerName) => {
186
+ appui_react_1.UiFramework.dialogs.modal.close();
187
+ resumeOutsideClick();
188
+ }, [resumeOutsideClick]);
189
+ const handleYesConfirmation = React.useCallback(async (source) => {
190
+ const layerName = source.name;
191
+ if (!!iTwinId) {
192
+ try {
193
+ await MapLayerPreferences_1.MapLayerPreferences.deleteByName(source, iTwinId, iModelId);
194
+ const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefSuccess", { layerName });
195
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Info, msg));
196
+ }
197
+ catch (err) {
198
+ const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefError", { layerName });
199
+ core_frontend_1.IModelApp.notifications.outputMessage(new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Error, msg));
200
+ }
201
+ }
202
+ appui_react_1.UiFramework.dialogs.modal.close();
203
+ resumeOutsideClick();
204
+ }, [iTwinId, iModelId, resumeOutsideClick]);
205
+ /*
206
+ Handle Remove layer button clicked
207
+ */
208
+ const onItemRemoveButtonClicked = React.useCallback((source, event) => {
209
+ event.stopPropagation(); // We don't want the owning ListBox to react on mouse click.
210
+ const layerName = source.name;
211
+ const msg = mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.RemoveLayerDefDialogMessage", { layerName });
212
+ appui_react_1.UiFramework.dialogs.modal.open(React.createElement(ConfirmMessageDialog_1.ConfirmMessageDialog, { className: "map-sources-delete-confirmation", title: removeLayerDefDialogTitle, message: msg, maxWidth: 400, onClose: () => handleNoConfirmation(layerName), onEscape: () => handleNoConfirmation(layerName), onYesResult: async () => handleYesConfirmation(source), onNoResult: () => handleNoConfirmation(layerName) }));
213
+ if (onHandleOutsideClick) {
214
+ onHandleOutsideClick(false);
215
+ }
216
+ }, [handleNoConfirmation, handleYesConfirmation, onHandleOutsideClick, removeLayerDefDialogTitle]);
217
+ /*
218
+ Handle Edit layer button clicked
219
+ */
220
+ const onItemEditButtonClicked = React.useCallback((event) => {
221
+ event.stopPropagation(); // We don't want the owning ListBox to react on mouse click.
222
+ const targetLayerName = event?.currentTarget?.parentNode?.dataset?.value;
223
+ const matchingSource = sources.find((layerSource) => layerSource.name === targetLayerName);
224
+ // we expect a single layer source matching this name
225
+ if (matchingSource === undefined) {
226
+ return;
227
+ }
228
+ appui_react_1.UiFramework.dialogs.modal.open(React.createElement(MapUrlDialog_1.MapUrlDialog, { activeViewport: activeViewport, isOverlay: isOverlay, mapLayerSourceToEdit: matchingSource, onOkResult: () => handleModalUrlDialogOk(LayerAction.Edited), onCancelResult: handleModalUrlDialogCancel, mapTypesOptions: mapTypesOptions }));
229
+ if (onHandleOutsideClick) {
230
+ onHandleOutsideClick(false);
231
+ }
232
+ }, [activeViewport, handleModalUrlDialogCancel, handleModalUrlDialogOk, isOverlay, mapTypesOptions, onHandleOutsideClick, sources]);
233
+ return (React.createElement("div", { className: "map-manager-header" },
234
+ (loading || loadingSources) && React.createElement(UiCore.LoadingSpinner, { message: loadingMapSources }),
235
+ React.createElement("div", { className: "map-manager-source-listbox-header" },
236
+ React.createElement(itwinui_react_1.Input, { type: "text", className: "map-manager-source-list-filter", placeholder: placeholderLabel, value: sourceFilterString, onChange: handleFilterTextChanged, size: "small" }),
237
+ React.createElement(itwinui_react_1.Button, { className: "map-manager-add-source-button", title: addCustomLayerToolTip, onClick: handleAddNewMapSource }, addCustomLayerLabel)),
238
+ React.createElement("div", { className: "map-manager-sources" },
239
+ React.createElement(UiCore.Listbox, { id: "map-sources", selectedValue: layerNameToAdd, className: "map-manager-source-list", onKeyPress: handleKeypressOnSourceList, onListboxValueChange: onListboxValueChange }, filteredOptions?.map((source) => React.createElement(UiCore.ListboxItem, { key: source.name, className: "map-source-list-entry", value: source.name, onMouseEnter: () => setLayerNameUnderCursor(source.name), onMouseLeave: () => setLayerNameUnderCursor(undefined) },
240
+ React.createElement("span", { className: "map-source-list-entry-name", title: source.name }, source.name),
241
+ // otherwise list feels cluttered.
242
+ (!!iTwinId && layerNameUnderCursor && layerNameUnderCursor === source.name) &&
243
+ React.createElement(React.Fragment, null,
244
+ React.createElement(itwinui_react_1.Button, { size: "small", styleType: "borderless", className: "map-source-list-entry-button", title: editLayerDefButtonTitle, onClick: onItemEditButtonClicked },
245
+ React.createElement(UiCore.Icon, { iconSpec: "icon-edit" })),
246
+ React.createElement(itwinui_react_1.Button, { size: "small", styleType: "borderless", className: "map-source-list-entry-button", title: removeLayerDefButtonTitle, onClick: (event) => { onItemRemoveButtonClicked(source, event); } },
247
+ React.createElement(UiCore.Icon, { iconSpec: "icon-delete" })))))))));
248
+ }
249
+ /** @internal */
250
+ var AttachLayerButtonType;
251
+ (function (AttachLayerButtonType) {
252
+ AttachLayerButtonType[AttachLayerButtonType["Primary"] = 0] = "Primary";
253
+ AttachLayerButtonType[AttachLayerButtonType["Blue"] = 1] = "Blue";
254
+ AttachLayerButtonType[AttachLayerButtonType["Icon"] = 2] = "Icon";
255
+ })(AttachLayerButtonType = exports.AttachLayerButtonType || (exports.AttachLayerButtonType = {}));
256
+ /** @internal */
257
+ // eslint-disable-next-line @typescript-eslint/naming-convention
258
+ function AttachLayerPopupButton(props) {
259
+ const { showAttachLayerLabel, hideAttachLayerLabel, addCustomLayerButtonLabel } = React.useMemo(() => {
260
+ return {
261
+ showAttachLayerLabel: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AttachLayerPopup.Attach"),
262
+ hideAttachLayerLabel: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:AttachLayerPopup.Close"),
263
+ addCustomLayerButtonLabel: mapLayers_1.MapLayersUI.localization.getLocalizedString("mapLayers:CustomAttach.AddCustomLayerButtonLabel"),
264
+ };
265
+ }, []);
266
+ const [handleOutsideClick, setHandleOutsideClick] = React.useState(true);
267
+ const [popupOpen, setPopupOpen] = React.useState(false);
268
+ const buttonRef = React.useRef(null);
269
+ const panelRef = React.useRef(null);
270
+ // 'isMounted' is used to prevent any async operation once the hook has been
271
+ // unloaded. Otherwise we get a 'Can't perform a React state update on an unmounted component.' warning in the console.
272
+ const isMounted = React.useRef(false);
273
+ React.useEffect(() => {
274
+ isMounted.current = true;
275
+ return () => {
276
+ isMounted.current = false;
277
+ };
278
+ }, []);
279
+ const togglePopup = React.useCallback(() => {
280
+ setPopupOpen(!popupOpen);
281
+ }, [popupOpen]);
282
+ const handleClosePopup = React.useCallback(() => {
283
+ setPopupOpen(false);
284
+ }, []);
285
+ const onHandleOutsideClick = React.useCallback((event) => {
286
+ if (!handleOutsideClick) {
287
+ return;
288
+ }
289
+ // If clicking on button that open panel - don't trigger outside click processing
290
+ if (buttonRef?.current && buttonRef?.current.contains(event.target)) {
291
+ return;
292
+ }
293
+ // If clicking the panel, this is not an outside clicked
294
+ if (panelRef.current && panelRef?.current.contains(event.target)) {
295
+ return;
296
+ }
297
+ // If we reach this point, we got an outside clicked, no close the popup
298
+ setPopupOpen(false);
299
+ }, [handleOutsideClick]);
300
+ const { refreshFromStyle } = (0, MapLayerManager_1.useSourceMapContext)();
301
+ const handleLayerAttached = React.useCallback(() => {
302
+ if (!isMounted.current) {
303
+ return;
304
+ }
305
+ setPopupOpen(false);
306
+ refreshFromStyle();
307
+ }, [refreshFromStyle]);
308
+ function renderButton() {
309
+ let button;
310
+ if (props.buttonType === undefined || props.buttonType === AttachLayerButtonType.Icon) {
311
+ button = (React.createElement(itwinui_react_1.Button, { disabled: props.disabled, size: "small", styleType: "borderless", ref: buttonRef, className: "map-manager-attach-layer-button", title: popupOpen ? hideAttachLayerLabel : showAttachLayerLabel, onClick: togglePopup },
312
+ React.createElement(UiCore.WebFontIcon, { iconName: "icon-add" })));
313
+ }
314
+ else {
315
+ const determineStyleType = () => {
316
+ switch (props.buttonType) {
317
+ case AttachLayerButtonType.Blue:
318
+ return "high-visibility";
319
+ case AttachLayerButtonType.Primary:
320
+ default:
321
+ return "cta";
322
+ }
323
+ };
324
+ const styleType = determineStyleType();
325
+ button = (React.createElement(itwinui_react_1.Button, { disabled: props.disabled, ref: buttonRef, styleType: styleType, title: popupOpen ? hideAttachLayerLabel : showAttachLayerLabel, onClick: togglePopup }, addCustomLayerButtonLabel));
326
+ }
327
+ return button;
328
+ }
329
+ return (React.createElement(React.Fragment, null,
330
+ renderButton(),
331
+ React.createElement(UiCore.Popup, { isOpen: popupOpen, position: appui_abstract_1.RelativePosition.BottomRight, onClose: handleClosePopup, onOutsideClick: onHandleOutsideClick, target: buttonRef.current, closeOnEnter: false, closeOnContextMenu: false },
332
+ React.createElement("div", { ref: panelRef, className: "map-sources-popup-panel" },
333
+ React.createElement(AttachLayerPanel, { isOverlay: props.isOverlay, onLayerAttached: handleLayerAttached, onHandleOutsideClick: setHandleOutsideClick })))));
334
+ }
335
+ exports.AttachLayerPopupButton = AttachLayerPopupButton;
336
336
  //# sourceMappingURL=AttachLayerPopupButton.js.map