@itwin/map-layers 6.0.7 → 6.0.9

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 +1 @@
1
- {"version":3,"file":"MapLayerDroppable.js","sourceRoot":"","sources":["../../../../src/ui/widget/MapLayerDroppable.tsx"],"names":[],"mappings":"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","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 *--------------------------------------------------------------------------------------------*/\n// cSpell:ignore droppable Sublayer Basemap\n\n// the following quiet warning caused by react-beautiful-dnd package\n\nimport \"./MapLayerDroppable.scss\";\nimport * as React from \"react\";\nimport { Draggable, Droppable } from \"react-beautiful-dnd\";\nimport { UiFramework } from \"@itwin/appui-react\";\nimport { assert } from \"@itwin/core-bentley\";\nimport { ImageMapLayerSettings } from \"@itwin/core-common\";\nimport { IModelApp, MapLayerImageryProviderStatus, MapTileTreeScaleRangeVisibility, NotifyMessageDetails, OutputMessagePriority } from \"@itwin/core-frontend\";\nimport { SvgStatusWarning, SvgVisibilityHide, SvgVisibilityShow } from \"@itwin/itwinui-icons-react\";\nimport { Checkbox, IconButton } from \"@itwin/itwinui-react\";\nimport { MapLayersUI } from \"../../mapLayers\";\nimport { AttachLayerButtonType, AttachLayerPopupButton } from \"./AttachLayerPopupButton\";\nimport { MapLayerSettingsMenu } from \"./MapLayerSettingsMenu\";\nimport { MapUrlDialog } from \"./MapUrlDialog\";\nimport { SubLayersPopupButton } from \"./SubLayersPopupButton\";\n\nimport type { DraggableChildrenFn, DroppableProps , DroppableProvided , DroppableStateSnapshot } from \"react-beautiful-dnd\";\nimport type { SubLayerId } from \"@itwin/core-common\";\nimport type { MapLayerIndex, ScreenViewport } from \"@itwin/core-frontend\";\nimport type { MapLayerOptions, StyleMapLayerSettings } from \"../Interfaces\";\nimport type { SourceState } from \"./MapUrlDialog\";\n\n\n/** @internal */\ninterface MapLayerDroppableProps {\n isOverlay: boolean;\n layersList?: StyleMapLayerSettings[];\n mapLayerOptions?: MapLayerOptions;\n getContainerForClone: () => HTMLElement;\n activeViewport: ScreenViewport;\n onMenuItemSelected: (action: string, mapLayerSettings: StyleMapLayerSettings) => void;\n onItemVisibilityToggleClicked: (mapLayerSettings: StyleMapLayerSettings) => void;\n onItemSelected: (isOverlay: boolean, index: number) => void;\n onItemEdited: () => void;\n disabled?: boolean;\n}\n\n// eslint-disable-next-line @typescript-eslint/unbound-method\nconst StrictModeDroppable = ({ children, ...props }: DroppableProps) =>{\n const [enabled, setEnabled] = React.useState(false);\n React.useEffect(() => {\n const animation = requestAnimationFrame(() => setEnabled(true));\n return () => {\n cancelAnimationFrame(animation);\n setEnabled(false);\n };\n }, []);\n if (!enabled) {\n return null;\n }\n return <Droppable {...props}>{children}</Droppable>;\n};\n\nconst changeVisibilityByElementId = (element: Element | null, visible: boolean) => {\n if (element) {\n element.setAttribute(\"style\", `visibility: ${visible ? \"visible\" : \"hidden\"}`);\n }\n};\n\n/** @internal */\nexport function MapLayerDroppable(props: MapLayerDroppableProps) {\n const containsLayer = props.layersList && props.layersList.length > 0;\n const droppableId = props.isOverlay ? \"overlayMapLayers\" : \"backgroundMapLayers\";\n const [toggleVisibility] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.ToggleVisibility\"));\n const [requireAuthTooltip] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.RequireAuthTooltip\"));\n const [noBackgroundMapsSpecifiedLabel] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.NoBackgroundLayers\"));\n const [noUnderlaysSpecifiedLabel] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.NoOverlayLayers\"));\n const [dropLayerLabel] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.DropLayerLabel\"));\n const [outOfRangeTitle] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.layerOutOfRange\"));\n\n const onSubLayerStateChange = (activeLayer: StyleMapLayerSettings, subLayerId: SubLayerId, isSelected: boolean) => {\n const mapLayerStyleIdx = props.activeViewport.displayStyle.findMapLayerIndexByNameAndSource(activeLayer.name, activeLayer.source, activeLayer.isOverlay);\n if (mapLayerStyleIdx !== -1 && activeLayer.subLayers) {\n props.activeViewport.displayStyle.changeMapSubLayerProps({ visible: isSelected }, subLayerId, {\n index: mapLayerStyleIdx,\n isOverlay: activeLayer.isOverlay,\n });\n }\n };\n\n const handleOk = React.useCallback(\n (index: MapLayerIndex, sourceState?: SourceState) => {\n UiFramework.dialogs.modal.close();\n\n const source = sourceState?.source;\n const vp = props?.activeViewport;\n if (vp === undefined || sourceState === undefined || source === undefined) {\n const error = MapLayersUI.localization.getLocalizedString(\"mapLayers:Messages.MapLayerAttachMissingViewOrSource\");\n const msg = MapLayersUI.localization.getLocalizedString(\"mapLayers:Messages.MapLayerAttachError\", { error, sourceName: source?.name ?? \"\" });\n IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Error, msg));\n return;\n }\n\n const validation = sourceState.validation;\n\n // Layer is already attached,\n // This calls invalidateRenderPlan()\n vp.displayStyle.changeMapLayerProps({ subLayers: validation.subLayers }, index);\n vp.displayStyle.changeMapLayerCredentials(index, source.userName, source.password);\n\n // Either initial attach/initialize failed or the layer failed to load at least one tile\n // because of an invalid token; in both cases tile tree needs to be fully reset\n const provider = vp.getMapLayerImageryProvider(index);\n provider?.resetStatus();\n vp.resetMapLayer(index);\n\n props.onItemEdited();\n },\n [props],\n );\n\n const changeSettingsMenuVisibility = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, visible: boolean) => {\n changeVisibilityByElementId(event.currentTarget.querySelector(\"#MapLayerSettingsMenuWrapper\"), visible);\n changeVisibilityByElementId(event.currentTarget.querySelector(\"#MapLayerSettingsSubLayersMenu\"), visible);\n };\n\n const renderItem: DraggableChildrenFn = (dragProvided, _, rubric) => {\n assert(props.layersList !== undefined);\n const activeLayer = props.layersList[rubric.source.index];\n const outOfRange = activeLayer.treeVisibility === MapTileTreeScaleRangeVisibility.Hidden;\n\n return (\n <div\n className=\"map-manager-source-item\"\n data-id={rubric.source.index}\n key={activeLayer.name}\n {...dragProvided.draggableProps}\n ref={dragProvided.innerRef}\n onMouseEnter={(event) => changeSettingsMenuVisibility(event, true)}\n onMouseLeave={(event) => changeSettingsMenuVisibility(event, false)}\n >\n {/* Checkbox */}\n <Checkbox\n data-testid={\"select-item-checkbox\"}\n checked={activeLayer.selected}\n onChange={(event: React.ChangeEvent<HTMLInputElement>) => {\n activeLayer.selected = event.target.checked;\n props.onItemSelected(props.isOverlay, rubric.source.index);\n }}\n ></Checkbox>\n {/* Visibility icon */}\n <IconButton\n disabled={props.disabled}\n size=\"small\"\n styleType=\"borderless\"\n className=\"map-manager-item-visibility\"\n label={toggleVisibility}\n onClick={() => {\n props.onItemVisibilityToggleClicked(activeLayer);\n }}\n >\n {activeLayer.visible ? <SvgVisibilityShow data-testid=\"layer-visibility-icon-show\" /> : <SvgVisibilityHide data-testid=\"layer-visibility-icon-hide\" />}\n </IconButton>\n\n {/* Label */}\n <span\n className={props.disabled || outOfRange ? \"map-manager-item-label-disabled\" : \"map-manager-item-label\"}\n title={outOfRange ? outOfRangeTitle : undefined}\n {...dragProvided.dragHandleProps}\n >\n {activeLayer.name}\n {/* eslint-disable-next-line @itwin/no-internal */}\n {activeLayer.provider?.status === MapLayerImageryProviderStatus.RequireAuth && (\n <IconButton\n disabled={props.disabled}\n size=\"small\"\n styleType=\"borderless\"\n onClick={() => {\n const indexInDisplayStyle = props.activeViewport?.displayStyle.findMapLayerIndexByNameAndSource(\n activeLayer.name,\n activeLayer.source,\n activeLayer.isOverlay,\n );\n if (indexInDisplayStyle !== undefined && indexInDisplayStyle >= 0) {\n const index = { index: indexInDisplayStyle, isOverlay: activeLayer.isOverlay };\n const layer = props.activeViewport.displayStyle.mapLayerAtIndex(index);\n if (layer instanceof ImageMapLayerSettings) {\n UiFramework.dialogs.modal.open(\n <MapUrlDialog\n activeViewport={props.activeViewport}\n signInModeArgs={{ layer }}\n onOkResult={(sourceState?: SourceState) => handleOk(index, sourceState)}\n onCancelResult={() => {\n UiFramework.dialogs.modal.close();\n }}\n mapLayerOptions={props.mapLayerOptions}\n />,\n );\n }\n }\n }}\n label={requireAuthTooltip}\n >\n <SvgStatusWarning />\n </IconButton>\n )}\n </span>\n\n {/* SubLayersPopupButton */}\n <div id=\"MapLayerSettingsSubLayersMenu\" className=\"map-manager-item-sub-layer-container map-manager-hidden\">\n {activeLayer.subLayers && activeLayer.subLayers.length > 1 && (\n <SubLayersPopupButton\n checkboxStyle=\"eye\"\n expandMode=\"rootGroupOnly\"\n subLayers={props.activeViewport ? activeLayer.subLayers : undefined}\n singleVisibleSubLayer={activeLayer.provider?.mutualExclusiveSubLayer}\n onSubLayerStateChange={(subLayerId: SubLayerId, isSelected: boolean) => {\n onSubLayerStateChange(activeLayer, subLayerId, isSelected);\n }}\n />\n )}\n </div>\n {/* eslint-disable-next-line @itwin/no-internal */}\n {activeLayer.provider?.status === MapLayerImageryProviderStatus.RequireAuth && (\n <IconButton\n disabled={props.disabled}\n size=\"small\"\n styleType=\"borderless\"\n onClick={() => {\n const indexInDisplayStyle = props.activeViewport?.displayStyle.findMapLayerIndexByNameAndSource(\n activeLayer.name,\n activeLayer.source,\n activeLayer.isOverlay,\n );\n if (indexInDisplayStyle !== undefined && indexInDisplayStyle >= 0) {\n const index = { index: indexInDisplayStyle, isOverlay: activeLayer.isOverlay };\n const layer = props.activeViewport.displayStyle.mapLayerAtIndex(index);\n if (layer instanceof ImageMapLayerSettings) {\n UiFramework.dialogs.modal.open(\n <MapUrlDialog\n activeViewport={props.activeViewport}\n signInModeArgs={{ layer }}\n onOkResult={(sourceState?: SourceState) => handleOk(index, sourceState)}\n onCancelResult={() => {\n UiFramework.dialogs.modal.close();\n }}\n mapLayerOptions={props.mapLayerOptions}\n />,\n );\n }\n }\n }}\n label={requireAuthTooltip}\n >\n <SvgStatusWarning />\n </IconButton>\n )}\n <div id=\"MapLayerSettingsMenuWrapper\" className=\"map-manager-hidden\">\n <MapLayerSettingsMenu\n activeViewport={props.activeViewport}\n mapLayerSettings={activeLayer}\n onMenuItemSelection={props.onMenuItemSelected}\n disabled={props.disabled}\n />\n </div>\n </div>\n );\n };\n\n function renderDraggableContent(snapshot: DroppableStateSnapshot): React.ReactNode {\n let node: React.ReactNode;\n if (containsLayer) {\n // Render a <Draggable>\n node = props.layersList?.map((mapLayerSettings, i) => (\n <Draggable isDragDisabled={props.disabled} key={mapLayerSettings.name} draggableId={mapLayerSettings.name} index={i}>\n {renderItem}\n </Draggable>\n ));\n } else {\n // Render a label that provide a 'Drop here' hint\n const label = props.isOverlay ? noUnderlaysSpecifiedLabel : noBackgroundMapsSpecifiedLabel;\n node = (\n <div title={label} className=\"map-manager-no-layers-container\">\n {snapshot.isDraggingOver ? (\n <span className=\"map-manager-no-layers-label\">{dropLayerLabel}</span>\n ) : (\n <>\n <span className=\"map-manager-no-layers-label\">{label}</span>\n <AttachLayerPopupButton disabled={props.disabled} buttonType={AttachLayerButtonType.Blue} isOverlay={props.isOverlay} />\n </>\n )}\n </div>\n );\n }\n return node;\n }\n\n function renderDraggable(dropProvided: DroppableProvided, dropSnapshot: DroppableStateSnapshot): React.ReactElement<HTMLElement> {\n return (\n <div\n className={`map-manager-attachments${dropSnapshot.isDraggingOver && containsLayer ? \" is-dragging-map-over\" : \"\"}`}\n ref={dropProvided.innerRef}\n {...dropProvided.droppableProps}\n >\n {renderDraggableContent(dropSnapshot)}\n\n {/* We don't want a placeholder when displaying the 'Drop here' message\n Unfortunately, if don't add it, 'react-beautiful-dnd' show an error message in the console.\n So I simply make it hidden. See https://github.com/atlassian/react-beautiful-dnd/issues/518 */}\n <div className={containsLayer ? undefined : \"map-manager-display-none\"}>{dropProvided.placeholder}</div>\n </div>\n );\n }\n\n return (\n <StrictModeDroppable droppableId={droppableId} renderClone={renderItem} getContainerForClone={props.getContainerForClone as any}>\n {renderDraggable}\n </StrictModeDroppable>\n );\n}\n"]}
1
+ {"version":3,"file":"MapLayerDroppable.js","sourceRoot":"","sources":["../../../../src/ui/widget/MapLayerDroppable.tsx"],"names":[],"mappings":"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","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 *--------------------------------------------------------------------------------------------*/\n// cSpell:ignore droppable Sublayer Basemap\n\n// the following quiet warning caused by react-beautiful-dnd package\n\nimport \"./MapLayerDroppable.scss\";\nimport * as React from \"react\";\nimport { Draggable, Droppable } from \"react-beautiful-dnd\";\nimport { UiFramework } from \"@itwin/appui-react\";\nimport { assert } from \"@itwin/core-bentley\";\nimport { ImageMapLayerSettings } from \"@itwin/core-common\";\nimport { IModelApp, MapLayerImageryProviderStatus, MapTileTreeScaleRangeVisibility, NotifyMessageDetails, OutputMessagePriority } from \"@itwin/core-frontend\";\nimport { SvgStatusWarning, SvgVisibilityHide, SvgVisibilityShow } from \"@itwin/itwinui-icons-react\";\nimport { Checkbox, IconButton } from \"@itwin/itwinui-react\";\nimport { MapLayersUI } from \"../../mapLayers\";\nimport { AttachLayerButtonType, AttachLayerPopupButton } from \"./AttachLayerPopupButton\";\nimport { MapLayerSettingsMenu } from \"./MapLayerSettingsMenu\";\nimport { MapUrlDialog } from \"./MapUrlDialog\";\nimport { SubLayersPopupButton } from \"./SubLayersPopupButton\";\n\nimport type { DraggableChildrenFn, DroppableProps , DroppableProvided , DroppableStateSnapshot } from \"react-beautiful-dnd\";\nimport type { SubLayerId } from \"@itwin/core-common\";\nimport type { MapLayerIndex, ScreenViewport } from \"@itwin/core-frontend\";\nimport type { MapLayerOptions, StyleMapLayerSettings } from \"../Interfaces\";\nimport type { SourceState } from \"./MapUrlDialog\";\n\n\n/** @internal */\ninterface MapLayerDroppableProps {\n isOverlay: boolean;\n layersList?: StyleMapLayerSettings[];\n mapLayerOptions?: MapLayerOptions;\n getContainerForClone: () => HTMLElement;\n activeViewport: ScreenViewport;\n onMenuItemSelected: (action: string, mapLayerSettings: StyleMapLayerSettings) => void;\n onItemVisibilityToggleClicked: (mapLayerSettings: StyleMapLayerSettings) => void;\n onItemSelected: (isOverlay: boolean, index: number) => void;\n onItemEdited: () => void;\n disabled?: boolean;\n}\n\n// eslint-disable-next-line @typescript-eslint/unbound-method\nconst StrictModeDroppable = ({ children, ...props }: DroppableProps) =>{\n const [enabled, setEnabled] = React.useState(false);\n React.useEffect(() => {\n const animation = requestAnimationFrame(() => setEnabled(true));\n return () => {\n cancelAnimationFrame(animation);\n setEnabled(false);\n };\n }, []);\n if (!enabled) {\n return null;\n }\n return <Droppable {...props}>{children}</Droppable>;\n};\n\n\n/** @internal */\nexport function MapLayerDroppable(props: MapLayerDroppableProps) {\n const containsLayer = props.layersList && props.layersList.length > 0;\n const droppableId = props.isOverlay ? \"overlayMapLayers\" : \"backgroundMapLayers\";\n const [toggleVisibility] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.ToggleVisibility\"));\n const [requireAuthTooltip] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.RequireAuthTooltip\"));\n const [noBackgroundMapsSpecifiedLabel] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.NoBackgroundLayers\"));\n const [noUnderlaysSpecifiedLabel] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.NoOverlayLayers\"));\n const [dropLayerLabel] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.DropLayerLabel\"));\n const [outOfRangeTitle] = React.useState(MapLayersUI.localization.getLocalizedString(\"mapLayers:Widget.layerOutOfRange\"));\n\n const onSubLayerStateChange = (activeLayer: StyleMapLayerSettings, subLayerId: SubLayerId, isSelected: boolean) => {\n const mapLayerStyleIdx = props.activeViewport.displayStyle.findMapLayerIndexByNameAndSource(activeLayer.name, activeLayer.source, activeLayer.isOverlay);\n if (mapLayerStyleIdx !== -1 && activeLayer.subLayers) {\n props.activeViewport.displayStyle.changeMapSubLayerProps({ visible: isSelected }, subLayerId, {\n index: mapLayerStyleIdx,\n isOverlay: activeLayer.isOverlay,\n });\n }\n };\n\n const handleOk = React.useCallback(\n (index: MapLayerIndex, sourceState?: SourceState) => {\n UiFramework.dialogs.modal.close();\n\n const source = sourceState?.source;\n const vp = props?.activeViewport;\n if (vp === undefined || sourceState === undefined || source === undefined) {\n const error = MapLayersUI.localization.getLocalizedString(\"mapLayers:Messages.MapLayerAttachMissingViewOrSource\");\n const msg = MapLayersUI.localization.getLocalizedString(\"mapLayers:Messages.MapLayerAttachError\", { error, sourceName: source?.name ?? \"\" });\n IModelApp.notifications.outputMessage(new NotifyMessageDetails(OutputMessagePriority.Error, msg));\n return;\n }\n\n const validation = sourceState.validation;\n\n // Layer is already attached,\n // This calls invalidateRenderPlan()\n vp.displayStyle.changeMapLayerProps({ subLayers: validation.subLayers }, index);\n vp.displayStyle.changeMapLayerCredentials(index, source.userName, source.password);\n\n // Either initial attach/initialize failed or the layer failed to load at least one tile\n // because of an invalid token; in both cases tile tree needs to be fully reset\n const provider = vp.getMapLayerImageryProvider(index);\n provider?.resetStatus();\n vp.resetMapLayer(index);\n\n props.onItemEdited();\n },\n [props],\n );\n\n const renderItem: DraggableChildrenFn = (dragProvided, _, rubric) => {\n assert(props.layersList !== undefined);\n const activeLayer = props.layersList[rubric.source.index];\n const outOfRange = activeLayer.treeVisibility === MapTileTreeScaleRangeVisibility.Hidden;\n\n return (\n <div\n className=\"map-manager-source-item\"\n data-id={rubric.source.index}\n key={activeLayer.name}\n {...dragProvided.draggableProps}\n ref={dragProvided.innerRef}\n >\n {/* Checkbox */}\n <Checkbox\n data-testid={\"select-item-checkbox\"}\n checked={activeLayer.selected}\n onChange={(event: React.ChangeEvent<HTMLInputElement>) => {\n activeLayer.selected = event.target.checked;\n props.onItemSelected(props.isOverlay, rubric.source.index);\n }}\n ></Checkbox>\n {/* Visibility icon */}\n <IconButton\n disabled={props.disabled}\n size=\"small\"\n styleType=\"borderless\"\n className=\"map-manager-item-visibility\"\n label={toggleVisibility}\n onClick={() => {\n props.onItemVisibilityToggleClicked(activeLayer);\n }}\n >\n {activeLayer.visible ? <SvgVisibilityShow data-testid=\"layer-visibility-icon-show\" /> : <SvgVisibilityHide data-testid=\"layer-visibility-icon-hide\" />}\n </IconButton>\n\n {/* Label */}\n <span\n className={props.disabled || outOfRange ? \"map-manager-item-label-disabled\" : \"map-manager-item-label\"}\n title={outOfRange ? outOfRangeTitle : undefined}\n {...dragProvided.dragHandleProps}\n >\n {activeLayer.name}\n {/* eslint-disable-next-line @itwin/no-internal */}\n {activeLayer.provider?.status === MapLayerImageryProviderStatus.RequireAuth && (\n <IconButton\n disabled={props.disabled}\n size=\"small\"\n styleType=\"borderless\"\n onClick={() => {\n const indexInDisplayStyle = props.activeViewport?.displayStyle.findMapLayerIndexByNameAndSource(\n activeLayer.name,\n activeLayer.source,\n activeLayer.isOverlay,\n );\n if (indexInDisplayStyle !== undefined && indexInDisplayStyle >= 0) {\n const index = { index: indexInDisplayStyle, isOverlay: activeLayer.isOverlay };\n const layer = props.activeViewport.displayStyle.mapLayerAtIndex(index);\n if (layer instanceof ImageMapLayerSettings) {\n UiFramework.dialogs.modal.open(\n <MapUrlDialog\n activeViewport={props.activeViewport}\n signInModeArgs={{ layer }}\n onOkResult={(sourceState?: SourceState) => handleOk(index, sourceState)}\n onCancelResult={() => {\n UiFramework.dialogs.modal.close();\n }}\n mapLayerOptions={props.mapLayerOptions}\n />,\n );\n }\n }\n }}\n label={requireAuthTooltip}\n >\n <SvgStatusWarning />\n </IconButton>\n )}\n </span>\n\n {/* SubLayersPopupButton */}\n <div className=\"map-manager-item-sub-layer-container map-layer-settings-sublayers-menu\">\n {activeLayer.subLayers && activeLayer.subLayers.length > 1 && (\n <SubLayersPopupButton\n checkboxStyle=\"eye\"\n expandMode=\"rootGroupOnly\"\n subLayers={props.activeViewport ? activeLayer.subLayers : undefined}\n singleVisibleSubLayer={activeLayer.provider?.mutualExclusiveSubLayer}\n onSubLayerStateChange={(subLayerId: SubLayerId, isSelected: boolean) => {\n onSubLayerStateChange(activeLayer, subLayerId, isSelected);\n }}\n />\n )}\n </div>\n {/* eslint-disable-next-line @itwin/no-internal */}\n {activeLayer.provider?.status === MapLayerImageryProviderStatus.RequireAuth && (\n <IconButton\n disabled={props.disabled}\n size=\"small\"\n styleType=\"borderless\"\n onClick={() => {\n const indexInDisplayStyle = props.activeViewport?.displayStyle.findMapLayerIndexByNameAndSource(\n activeLayer.name,\n activeLayer.source,\n activeLayer.isOverlay,\n );\n if (indexInDisplayStyle !== undefined && indexInDisplayStyle >= 0) {\n const index = { index: indexInDisplayStyle, isOverlay: activeLayer.isOverlay };\n const layer = props.activeViewport.displayStyle.mapLayerAtIndex(index);\n if (layer instanceof ImageMapLayerSettings) {\n UiFramework.dialogs.modal.open(\n <MapUrlDialog\n activeViewport={props.activeViewport}\n signInModeArgs={{ layer }}\n onOkResult={(sourceState?: SourceState) => handleOk(index, sourceState)}\n onCancelResult={() => {\n UiFramework.dialogs.modal.close();\n }}\n mapLayerOptions={props.mapLayerOptions}\n />,\n );\n }\n }\n }}\n label={requireAuthTooltip}\n >\n <SvgStatusWarning />\n </IconButton>\n )}\n <div className=\"map-layer-settings-menu-wrapper\">\n <MapLayerSettingsMenu\n activeViewport={props.activeViewport}\n mapLayerSettings={activeLayer}\n onMenuItemSelection={props.onMenuItemSelected}\n disabled={props.disabled}\n />\n </div>\n </div>\n );\n };\n\n function renderDraggableContent(snapshot: DroppableStateSnapshot): React.ReactNode {\n let node: React.ReactNode;\n if (containsLayer) {\n // Render a <Draggable>\n node = props.layersList?.map((mapLayerSettings, i) => (\n <Draggable isDragDisabled={props.disabled} key={mapLayerSettings.name} draggableId={mapLayerSettings.name} index={i}>\n {renderItem}\n </Draggable>\n ));\n } else {\n // Render a label that provide a 'Drop here' hint\n const label = props.isOverlay ? noUnderlaysSpecifiedLabel : noBackgroundMapsSpecifiedLabel;\n node = (\n <div title={label} className=\"map-manager-no-layers-container\">\n {snapshot.isDraggingOver ? (\n <span className=\"map-manager-no-layers-label\">{dropLayerLabel}</span>\n ) : (\n <>\n <span className=\"map-manager-no-layers-label\">{label}</span>\n <AttachLayerPopupButton disabled={props.disabled} buttonType={AttachLayerButtonType.Blue} isOverlay={props.isOverlay} />\n </>\n )}\n </div>\n );\n }\n return node;\n }\n\n function renderDraggable(dropProvided: DroppableProvided, dropSnapshot: DroppableStateSnapshot): React.ReactElement<HTMLElement> {\n return (\n <div\n className={`map-manager-attachments${dropSnapshot.isDraggingOver && containsLayer ? \" is-dragging-map-over\" : \"\"}`}\n ref={dropProvided.innerRef}\n {...dropProvided.droppableProps}\n >\n {renderDraggableContent(dropSnapshot)}\n\n {/* We don't want a placeholder when displaying the 'Drop here' message\n Unfortunately, if don't add it, 'react-beautiful-dnd' show an error message in the console.\n So I simply make it hidden. See https://github.com/atlassian/react-beautiful-dnd/issues/518 */}\n <div className={containsLayer ? undefined : \"map-manager-display-none\"}>{dropProvided.placeholder}</div>\n </div>\n );\n }\n\n return (\n <StrictModeDroppable droppableId={droppableId} renderClone={renderItem} getContainerForClone={props.getContainerForClone as any}>\n {renderDraggable}\n </StrictModeDroppable>\n );\n}\n"]}
@@ -10,3 +10,18 @@
10
10
  .map-manager-display-none {
11
11
  display: none;
12
12
  }
13
+
14
+ // Hover-based visibility for settings menus
15
+ .map-manager-source-item {
16
+ .map-layer-settings-menu-wrapper,
17
+ .map-layer-settings-sublayers-menu {
18
+ visibility: hidden;
19
+ }
20
+
21
+ &:hover {
22
+ .map-layer-settings-menu-wrapper,
23
+ .map-layer-settings-sublayers-menu {
24
+ visibility: visible;
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,53 @@
1
+ import type { GuidString } from "@itwin/core-bentley";
2
+ /** @internal */
3
+ export interface BasemapColorPreferencesContent {
4
+ customColor?: string;
5
+ activeColor?: string;
6
+ }
7
+ /** A wrapper around user preferences to store basemap solid fill colors.
8
+ * Supports both user-selected custom colors and active colors (which may be preset or custom).
9
+ * @internal
10
+ */
11
+ export declare class BasemapColorPreferences {
12
+ private static readonly _preferenceNamespace;
13
+ private static readonly _preferenceKey;
14
+ /** Store the user-selected custom basemap color preference.
15
+ * This preserves the user's custom color choice even when they switch to presets.
16
+ * @param color TBGR color value as string
17
+ * @param iTwinId iTwin identifier
18
+ * @param iModelId iModel identifier (optional, if not provided stores at iTwin level)
19
+ */
20
+ static saveCustomColor(color: string, iTwinId: GuidString, iModelId?: GuidString): Promise<boolean>;
21
+ /** Store the currently active basemap color.
22
+ * This tracks what color is currently being used, whether it's custom or preset.
23
+ * @param color TBGR color value as string
24
+ * @param iTwinId iTwin identifier
25
+ * @param iModelId iModel identifier (optional, if not provided stores at iTwin level)
26
+ */
27
+ static saveActiveColor(color: string, iTwinId: GuidString, iModelId?: GuidString): Promise<boolean>;
28
+ /** Get the user's selected custom color.
29
+ * @param iTwinId iTwin identifier
30
+ * @param iModelId iModel identifier (optional)
31
+ * @returns The stored user-selected color as TBGR string, or undefined if not found
32
+ */
33
+ static getCustomColor(iTwinId: GuidString, iModelId?: GuidString): Promise<string | undefined>;
34
+ /** Get the currently active color.
35
+ * @param iTwinId iTwin identifier
36
+ * @param iModelId iModel identifier (optional)
37
+ * @returns The stored active color as TBGR string, or undefined if not found
38
+ */
39
+ static getActiveColor(iTwinId: GuidString, iModelId?: GuidString): Promise<string | undefined>;
40
+ /** Get all color preferences.
41
+ * @param iTwinId iTwin identifier
42
+ * @param iModelId iModel identifier (optional)
43
+ * @returns The stored preferences, or undefined if not found
44
+ */
45
+ static getPreferences(iTwinId: GuidString, iModelId?: GuidString): Promise<BasemapColorPreferencesContent | undefined>;
46
+ /** Save color preferences.
47
+ * @param preferences The preferences to save
48
+ * @param iTwinId iTwin identifier
49
+ * @param iModelId iModel identifier (optional)
50
+ */
51
+ private static savePreferences;
52
+ }
53
+ //# sourceMappingURL=BasemapColorPreferences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BasemapColorPreferences.d.ts","sourceRoot":"","sources":["../../src/BasemapColorPreferences.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,gBAAgB;AAChB,MAAM,WAAW,8BAA8B;IAC7C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAkC;IAC9E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAqB;IAE3D;;;;;OAKG;WACiB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAahH;;;;;OAKG;WACiB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAahH;;;;OAIG;WACiB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAK3G;;;;OAIG;WACiB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAK3G;;;;OAIG;WACiB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,8BAA8B,GAAG,SAAS,CAAC;IAyCnI;;;;OAIG;mBACkB,eAAe;CAsBrC"}
@@ -0,0 +1,138 @@
1
+ /*---------------------------------------------------------------------------------------------
2
+ * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3
+ * See LICENSE.md in the project root for license terms and full copyright notice.
4
+ *--------------------------------------------------------------------------------------------*/
5
+ import { IModelApp } from "@itwin/core-frontend";
6
+ import { MapLayersUI } from "./mapLayers";
7
+ /** A wrapper around user preferences to store basemap solid fill colors.
8
+ * Supports both user-selected custom colors and active colors (which may be preset or custom).
9
+ * @internal
10
+ */
11
+ export class BasemapColorPreferences {
12
+ static _preferenceNamespace = "BasemapColor-SettingsService";
13
+ static _preferenceKey = "solidFillColors";
14
+ /** Store the user-selected custom basemap color preference.
15
+ * This preserves the user's custom color choice even when they switch to presets.
16
+ * @param color TBGR color value as string
17
+ * @param iTwinId iTwin identifier
18
+ * @param iModelId iModel identifier (optional, if not provided stores at iTwin level)
19
+ */
20
+ static async saveCustomColor(color, iTwinId, iModelId) {
21
+ try {
22
+ const existing = await BasemapColorPreferences.getPreferences(iTwinId, iModelId);
23
+ const colorPreference = {
24
+ customColor: color,
25
+ activeColor: existing?.activeColor ?? color, // Keep existing active or set to this color
26
+ };
27
+ return await BasemapColorPreferences.savePreferences(colorPreference, iTwinId, iModelId);
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ /** Store the currently active basemap color.
34
+ * This tracks what color is currently being used, whether it's custom or preset.
35
+ * @param color TBGR color value as string
36
+ * @param iTwinId iTwin identifier
37
+ * @param iModelId iModel identifier (optional, if not provided stores at iTwin level)
38
+ */
39
+ static async saveActiveColor(color, iTwinId, iModelId) {
40
+ try {
41
+ const existing = await BasemapColorPreferences.getPreferences(iTwinId, iModelId);
42
+ const colorPreference = {
43
+ customColor: existing?.customColor, // Preserve user's custom color
44
+ activeColor: color,
45
+ };
46
+ return await BasemapColorPreferences.savePreferences(colorPreference, iTwinId, iModelId);
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ }
52
+ /** Get the user's selected custom color.
53
+ * @param iTwinId iTwin identifier
54
+ * @param iModelId iModel identifier (optional)
55
+ * @returns The stored user-selected color as TBGR string, or undefined if not found
56
+ */
57
+ static async getCustomColor(iTwinId, iModelId) {
58
+ const preferences = await BasemapColorPreferences.getPreferences(iTwinId, iModelId);
59
+ return preferences?.customColor;
60
+ }
61
+ /** Get the currently active color.
62
+ * @param iTwinId iTwin identifier
63
+ * @param iModelId iModel identifier (optional)
64
+ * @returns The stored active color as TBGR string, or undefined if not found
65
+ */
66
+ static async getActiveColor(iTwinId, iModelId) {
67
+ const preferences = await BasemapColorPreferences.getPreferences(iTwinId, iModelId);
68
+ return preferences?.activeColor;
69
+ }
70
+ /** Get all color preferences.
71
+ * @param iTwinId iTwin identifier
72
+ * @param iModelId iModel identifier (optional)
73
+ * @returns The stored preferences, or undefined if not found
74
+ */
75
+ static async getPreferences(iTwinId, iModelId) {
76
+ if (!MapLayersUI.iTwinConfig) {
77
+ return undefined;
78
+ }
79
+ try {
80
+ const accessToken = undefined !== IModelApp.authorizationClient ? await IModelApp.authorizationClient.getAccessToken() : undefined;
81
+ // Try to get from iModel level first (more specific)
82
+ if (iModelId) {
83
+ try {
84
+ const iModelResult = await MapLayersUI.iTwinConfig.get({
85
+ accessToken,
86
+ namespace: BasemapColorPreferences._preferenceNamespace,
87
+ key: BasemapColorPreferences._preferenceKey,
88
+ iTwinId,
89
+ iModelId,
90
+ });
91
+ if (iModelResult) {
92
+ return iModelResult;
93
+ }
94
+ }
95
+ catch {
96
+ // Fall through to try iTwin level
97
+ }
98
+ }
99
+ // Try iTwin level
100
+ const iTwinResult = await MapLayersUI.iTwinConfig.get({
101
+ accessToken,
102
+ namespace: BasemapColorPreferences._preferenceNamespace,
103
+ key: BasemapColorPreferences._preferenceKey,
104
+ iTwinId,
105
+ });
106
+ return iTwinResult;
107
+ }
108
+ catch {
109
+ return undefined;
110
+ }
111
+ }
112
+ /** Save color preferences.
113
+ * @param preferences The preferences to save
114
+ * @param iTwinId iTwin identifier
115
+ * @param iModelId iModel identifier (optional)
116
+ */
117
+ static async savePreferences(preferences, iTwinId, iModelId) {
118
+ if (!MapLayersUI.iTwinConfig) {
119
+ return false;
120
+ }
121
+ try {
122
+ const accessToken = undefined !== IModelApp.authorizationClient ? await IModelApp.authorizationClient.getAccessToken() : undefined;
123
+ await MapLayersUI.iTwinConfig.save({
124
+ accessToken,
125
+ content: preferences,
126
+ namespace: BasemapColorPreferences._preferenceNamespace,
127
+ key: BasemapColorPreferences._preferenceKey,
128
+ iTwinId,
129
+ iModelId,
130
+ });
131
+ return true;
132
+ }
133
+ catch {
134
+ return false;
135
+ }
136
+ }
137
+ }
138
+ //# sourceMappingURL=BasemapColorPreferences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BasemapColorPreferences.js","sourceRoot":"","sources":["../../src/BasemapColorPreferences.ts"],"names":[],"mappings":"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","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 *--------------------------------------------------------------------------------------------*/\n\nimport { IModelApp } from \"@itwin/core-frontend\";\nimport { MapLayersUI } from \"./mapLayers\";\n\nimport type { GuidString } from \"@itwin/core-bentley\";\n\n/** @internal */\nexport interface BasemapColorPreferencesContent {\n customColor?: string; // TBGR color value as string - user's custom color choice\n activeColor?: string; // TBGR color value as string - currently active color\n}\n\n/** A wrapper around user preferences to store basemap solid fill colors.\n * Supports both user-selected custom colors and active colors (which may be preset or custom).\n * @internal\n */\nexport class BasemapColorPreferences {\n private static readonly _preferenceNamespace = \"BasemapColor-SettingsService\";\n private static readonly _preferenceKey = \"solidFillColors\";\n\n /** Store the user-selected custom basemap color preference.\n * This preserves the user's custom color choice even when they switch to presets.\n * @param color TBGR color value as string\n * @param iTwinId iTwin identifier\n * @param iModelId iModel identifier (optional, if not provided stores at iTwin level)\n */\n public static async saveCustomColor(color: string, iTwinId: GuidString, iModelId?: GuidString): Promise<boolean> {\n try {\n const existing = await BasemapColorPreferences.getPreferences(iTwinId, iModelId);\n const colorPreference: BasemapColorPreferencesContent = {\n customColor: color,\n activeColor: existing?.activeColor ?? color, // Keep existing active or set to this color\n };\n return await BasemapColorPreferences.savePreferences(colorPreference, iTwinId, iModelId);\n } catch {\n return false;\n }\n }\n\n /** Store the currently active basemap color.\n * This tracks what color is currently being used, whether it's custom or preset.\n * @param color TBGR color value as string\n * @param iTwinId iTwin identifier\n * @param iModelId iModel identifier (optional, if not provided stores at iTwin level)\n */\n public static async saveActiveColor(color: string, iTwinId: GuidString, iModelId?: GuidString): Promise<boolean> {\n try {\n const existing = await BasemapColorPreferences.getPreferences(iTwinId, iModelId);\n const colorPreference: BasemapColorPreferencesContent = {\n customColor: existing?.customColor, // Preserve user's custom color\n activeColor: color,\n };\n return await BasemapColorPreferences.savePreferences(colorPreference, iTwinId, iModelId);\n } catch {\n return false;\n }\n }\n\n /** Get the user's selected custom color.\n * @param iTwinId iTwin identifier\n * @param iModelId iModel identifier (optional)\n * @returns The stored user-selected color as TBGR string, or undefined if not found\n */\n public static async getCustomColor(iTwinId: GuidString, iModelId?: GuidString): Promise<string | undefined> {\n const preferences = await BasemapColorPreferences.getPreferences(iTwinId, iModelId);\n return preferences?.customColor;\n }\n\n /** Get the currently active color.\n * @param iTwinId iTwin identifier\n * @param iModelId iModel identifier (optional)\n * @returns The stored active color as TBGR string, or undefined if not found\n */\n public static async getActiveColor(iTwinId: GuidString, iModelId?: GuidString): Promise<string | undefined> {\n const preferences = await BasemapColorPreferences.getPreferences(iTwinId, iModelId);\n return preferences?.activeColor;\n }\n\n /** Get all color preferences.\n * @param iTwinId iTwin identifier\n * @param iModelId iModel identifier (optional)\n * @returns The stored preferences, or undefined if not found\n */\n public static async getPreferences(iTwinId: GuidString, iModelId?: GuidString): Promise<BasemapColorPreferencesContent | undefined> {\n if (!MapLayersUI.iTwinConfig) {\n return undefined;\n }\n\n try {\n const accessToken = undefined !== IModelApp.authorizationClient ? await IModelApp.authorizationClient.getAccessToken() : undefined;\n\n // Try to get from iModel level first (more specific)\n if (iModelId) {\n try {\n const iModelResult = await MapLayersUI.iTwinConfig.get({\n accessToken,\n namespace: BasemapColorPreferences._preferenceNamespace,\n key: BasemapColorPreferences._preferenceKey,\n iTwinId,\n iModelId,\n });\n\n if (iModelResult) {\n return iModelResult;\n }\n } catch {\n // Fall through to try iTwin level\n }\n }\n\n // Try iTwin level\n const iTwinResult = await MapLayersUI.iTwinConfig.get({\n accessToken,\n namespace: BasemapColorPreferences._preferenceNamespace,\n key: BasemapColorPreferences._preferenceKey,\n iTwinId,\n });\n\n return iTwinResult;\n } catch {\n return undefined;\n }\n }\n\n /** Save color preferences.\n * @param preferences The preferences to save\n * @param iTwinId iTwin identifier\n * @param iModelId iModel identifier (optional)\n */\n private static async savePreferences(preferences: BasemapColorPreferencesContent, iTwinId: GuidString, iModelId?: GuidString): Promise<boolean> {\n if (!MapLayersUI.iTwinConfig) {\n return false;\n }\n\n try {\n const accessToken = undefined !== IModelApp.authorizationClient ? await IModelApp.authorizationClient.getAccessToken() : undefined;\n\n await MapLayersUI.iTwinConfig.save({\n accessToken,\n content: preferences,\n namespace: BasemapColorPreferences._preferenceNamespace,\n key: BasemapColorPreferences._preferenceKey,\n iTwinId,\n iModelId,\n });\n\n return true;\n } catch {\n return false;\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"BasemapPanel.d.ts","sourceRoot":"","sources":["../../../../src/ui/widget/BasemapPanel.tsx"],"names":[],"mappings":"AAMA,OAAO,qBAAqB,CAAC;AAmB7B,UAAU,iBAAiB;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,gBAAgB;AAChB,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,2CAsVpD"}
1
+ {"version":3,"file":"BasemapPanel.d.ts","sourceRoot":"","sources":["../../../../src/ui/widget/BasemapPanel.tsx"],"names":[],"mappings":"AAMA,OAAO,qBAAqB,CAAC;AAiC7B,UAAU,iBAAiB;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,gBAAgB;AAChB,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,2CAwYpD"}
@@ -10,9 +10,21 @@ import { BackgroundMapType, BaseLayerSettings, BaseMapLayerSettings, ColorByName
10
10
  import { IModelApp } from "@itwin/core-frontend";
11
11
  import { SvgVisibilityHide, SvgVisibilityShow } from "@itwin/itwinui-icons-react";
12
12
  import { ColorBuilder, ColorInputPanel, ColorPalette, ColorPicker, ColorSwatch, ColorValue, IconButton, Popover, Select } from "@itwin/itwinui-react";
13
+ import { BasemapColorPreferences } from "../../BasemapColorPreferences";
13
14
  import { MapLayersUI } from "../../mapLayers";
14
15
  import { useSourceMapContext } from "./MapLayerManager";
15
16
  import { TransparencyPopupButton } from "./TransparencyPopupButton";
17
+ // Define preset colors in a single place to avoid duplication
18
+ const PRESET_COLORS = [
19
+ ColorValue.fromTbgr(ColorByName.grey),
20
+ ColorValue.fromTbgr(ColorByName.lightGrey),
21
+ ColorValue.fromTbgr(ColorByName.darkGrey),
22
+ ColorValue.fromTbgr(ColorByName.lightBlue),
23
+ ColorValue.fromTbgr(ColorByName.lightGreen),
24
+ ColorValue.fromTbgr(ColorByName.darkGreen),
25
+ ColorValue.fromTbgr(ColorByName.tan),
26
+ ColorValue.fromTbgr(ColorByName.darkBrown),
27
+ ];
16
28
  const customBaseMapValue = "customBaseMap";
17
29
  /** @internal */
18
30
  export function BasemapPanel(props) {
@@ -56,7 +68,7 @@ export function BasemapPanel(props) {
56
68
  return mapImagery.backgroundBase.transparency;
57
69
  }
58
70
  else if (mapImagery.backgroundBase instanceof ColorDef) {
59
- return mapImagery.backgroundBase.getAlpha() / 255;
71
+ return 1.0 - (mapImagery.backgroundBase.getAlpha() / 255);
60
72
  }
61
73
  else {
62
74
  return 0;
@@ -121,8 +133,9 @@ export function BasemapPanel(props) {
121
133
  }
122
134
  }
123
135
  else if (baseMap instanceof ColorDef) {
124
- if (baseMap.getAlpha() !== baseMapTransparencyValue) {
125
- setBaseMapTransparencyValue(baseMap.getAlpha() / 255);
136
+ const transparency = 1.0 - (baseMap.getAlpha() / 255);
137
+ if (transparency !== baseMapTransparencyValue) {
138
+ setBaseMapTransparencyValue(transparency);
126
139
  }
127
140
  }
128
141
  }, [baseMapTransparencyValue, baseMapVisible, selectedBaseMap, updateBaseMapOptions]);
@@ -157,16 +170,55 @@ export function BasemapPanel(props) {
157
170
  setCustomBaseMap(selectedBaseMap);
158
171
  }
159
172
  }, [baseMapOptions, extraFormats, selectedBaseMap]);
160
- const [presetColors] = React.useState([
161
- ColorValue.fromTbgr(ColorByName.grey),
162
- ColorValue.fromTbgr(ColorByName.lightGrey),
163
- ColorValue.fromTbgr(ColorByName.darkGrey),
164
- ColorValue.fromTbgr(ColorByName.lightBlue),
165
- ColorValue.fromTbgr(ColorByName.lightGreen),
166
- ColorValue.fromTbgr(ColorByName.darkGreen),
167
- ColorValue.fromTbgr(ColorByName.tan),
168
- ColorValue.fromTbgr(ColorByName.darkBrown),
169
- ]);
173
+ const getPresetColorsWithSaved = React.useCallback(async () => {
174
+ const defaultColors = [...PRESET_COLORS];
175
+ // Add saved custom color from preferences as the first color if available
176
+ try {
177
+ const iModel = activeViewport?.iModel;
178
+ if (iModel?.iTwinId) {
179
+ const savedColor = await BasemapColorPreferences.getCustomColor(iModel.iTwinId, iModel.iModelId);
180
+ if (savedColor) {
181
+ const savedColorValue = ColorValue.fromTbgr(Number(savedColor));
182
+ // Remove the saved color from default colors if it exists there
183
+ const filteredColors = defaultColors.filter(color => color.toTbgr() !== savedColorValue.toTbgr());
184
+ // Always put the saved color as the first color
185
+ return [savedColorValue, ...filteredColors];
186
+ }
187
+ }
188
+ }
189
+ catch {
190
+ // Silently ignore preferences errors
191
+ }
192
+ return defaultColors;
193
+ }, [activeViewport]);
194
+ const [presetColors, setPresetColors] = React.useState(() => [...PRESET_COLORS]);
195
+ // Load saved color on component mount and when activeViewport changes
196
+ React.useEffect(() => {
197
+ const loadSavedColor = async () => {
198
+ const colors = await getPresetColorsWithSaved();
199
+ setPresetColors(colors);
200
+ };
201
+ void loadSavedColor();
202
+ }, [activeViewport, getPresetColorsWithSaved]);
203
+ // Persist a custom (non-preset) basemap color to user preferences and refresh preset list
204
+ const saveCustomBasemapColorPreference = React.useCallback(async (selectedColorTbgr, isPresetColor) => {
205
+ // Only save custom colors to preferences - preset colors don't overwrite user's custom color
206
+ if (isPresetColor)
207
+ return;
208
+ try {
209
+ const iModel = activeViewport?.iModel;
210
+ if (iModel?.iTwinId) {
211
+ const saved = await BasemapColorPreferences.saveCustomColor(selectedColorTbgr.toString(), iModel.iTwinId, iModel.iModelId);
212
+ if (saved) {
213
+ const colors = await getPresetColorsWithSaved();
214
+ setPresetColors(colors);
215
+ }
216
+ }
217
+ }
218
+ catch {
219
+ // Silently ignore preferences errors
220
+ }
221
+ }, [activeViewport, getPresetColorsWithSaved]);
170
222
  const baseIsColor = React.useMemo(() => selectedBaseMap instanceof ColorDef, [selectedBaseMap]);
171
223
  const baseIsMap = React.useMemo(() => !baseIsColor && selectedBaseMap !== undefined, [baseIsColor, selectedBaseMap]);
172
224
  // bgColor is a 32 bit number represented in TBGR format
@@ -212,9 +264,14 @@ export function BasemapPanel(props) {
212
264
  // change color and make sure previously set transparency is not lost.
213
265
  const curTransparency = activeViewport.displayStyle.backgroundMapBase instanceof ColorDef ? activeViewport.displayStyle.backgroundMapBase.getTransparency() : 0;
214
266
  activeViewport.displayStyle.backgroundMapBase = bgColorDef.withTransparency(curTransparency);
267
+ // Determine if this is a preset color or a custom color
268
+ const selectedColorTbgr = bgColorValue.toTbgr();
269
+ const isPresetColor = presetColors.some((presetColor) => presetColor.toTbgr() === selectedColorTbgr);
270
+ // Persist custom color (no-op if preset)
271
+ void saveCustomBasemapColorPreference(selectedColorTbgr, isPresetColor);
215
272
  setSelectedBaseMap(bgColorDef);
216
273
  }
217
- }, [activeViewport]);
274
+ }, [activeViewport, presetColors, saveCustomBasemapColorPreference]);
218
275
  const handleBaseMapSelection = React.useCallback((value) => {
219
276
  if (activeViewport && value) {
220
277
  if (value === customBaseMapValue && customBaseMap) {