From da60bf17d743f6232a232b845a1e430a88aab941 Mon Sep 17 00:00:00 2001 From: Kerry Archibald Date: Thu, 12 May 2022 11:27:09 +0200 Subject: [PATCH 1/4] pass optional tooltip prop down through markers Signed-off-by: Kerry Archibald --- src/components/views/beacon/BeaconMarker.tsx | 6 +- src/components/views/location/Marker.tsx | 44 ++++-- src/components/views/location/SmartMarker.tsx | 6 +- .../__snapshots__/BeaconMarker-test.tsx.snap | 138 +++++++++--------- .../LocationViewDialog-test.tsx.snap | 14 +- .../__snapshots__/Marker-test.tsx.snap | 14 +- .../__snapshots__/SmartMarker-test.tsx.snap | 28 ++-- .../__snapshots__/MLocationBody-test.tsx.snap | 14 +- 8 files changed, 149 insertions(+), 115 deletions(-) diff --git a/src/components/views/beacon/BeaconMarker.tsx b/src/components/views/beacon/BeaconMarker.tsx index f7f284b88ed..644482e48b3 100644 --- a/src/components/views/beacon/BeaconMarker.tsx +++ b/src/components/views/beacon/BeaconMarker.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useContext } from 'react'; +import React, { ReactNode, useContext } from 'react'; import maplibregl from 'maplibre-gl'; import { Beacon, @@ -29,12 +29,13 @@ import SmartMarker from '../location/SmartMarker'; interface Props { map: maplibregl.Map; beacon: Beacon; + tooltip?: ReactNode; } /** * Updates a map SmartMarker with latest location from given beacon */ -const BeaconMarker: React.FC = ({ map, beacon }) => { +const BeaconMarker: React.FC = ({ map, beacon, tooltip }) => { const latestLocationState = useEventEmitterState( beacon, BeaconEvent.LocationUpdate, @@ -58,6 +59,7 @@ const BeaconMarker: React.FC = ({ map, beacon }) => { id={beacon.identifier} geoUri={geoUri} roomMember={markerRoomMember} + tooltip={tooltip} useMemberColor />; }; diff --git a/src/components/views/location/Marker.tsx b/src/components/views/location/Marker.tsx index bacade71cf4..81321a810b9 100644 --- a/src/components/views/location/Marker.tsx +++ b/src/components/views/location/Marker.tsx @@ -14,13 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, { ReactNode } from 'react'; import classNames from 'classnames'; import { RoomMember } from 'matrix-js-sdk/src/matrix'; import { Icon as LocationIcon } from '../../../../res/img/element-icons/location.svg'; import { getUserNameColorClass } from '../../../utils/FormattingUtils'; import MemberAvatar from '../avatars/MemberAvatar'; +import TooltipTarget from '../elements/TooltipTarget'; +import { Alignment } from '../elements/Tooltip'; interface Props { id?: string; @@ -28,12 +30,26 @@ interface Props { roomMember?: RoomMember; // use member text color as background useMemberColor?: boolean; + tooltip?: ReactNode; } +// wrap children in tooltip target +// when tooltip is truthy +const OptionalTooltip: React.FC<{ + tooltip?: ReactNode; children: ReactNode; +}> = ({ tooltip, children }) => tooltip ? + + {children} + : + <>{children}; + /** * Generic location marker */ -const Marker = React.forwardRef(({ id, roomMember, useMemberColor }, ref) => { +const Marker = React.forwardRef(({ id, roomMember, useMemberColor, tooltip }, ref) => { const memberColorClass = useMemberColor && roomMember ? getUserNameColorClass(roomMember.userId) : ''; return
(({ id, roomMember, useMem "mx_Marker_defaultColor": !memberColorClass, })} > -
- { roomMember ? - - : - } -
+ +
+ { roomMember ? + + : + } +
+
; }); diff --git a/src/components/views/location/SmartMarker.tsx b/src/components/views/location/SmartMarker.tsx index c4a7c61e32b..13b7ef093ea 100644 --- a/src/components/views/location/SmartMarker.tsx +++ b/src/components/views/location/SmartMarker.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { ReactNode, useCallback, useEffect, useState } from 'react'; import maplibregl from 'maplibre-gl'; import { RoomMember } from 'matrix-js-sdk/src/matrix'; @@ -64,12 +64,13 @@ interface SmartMarkerProps { roomMember?: RoomMember; // use member text color as background useMemberColor?: boolean; + tooltip?: ReactNode; } /** * Generic location marker */ -const SmartMarker: React.FC = ({ id, map, geoUri, roomMember, useMemberColor }) => { +const SmartMarker: React.FC = ({ id, map, geoUri, roomMember, useMemberColor, tooltip }) => { const { onElementRef } = useMapMarker(map, geoUri); return ( @@ -84,6 +85,7 @@ const SmartMarker: React.FC = ({ id, map, geoUri, roomMember, id={id} roomMember={roomMember} useMemberColor={useMemberColor} + tooltip={tooltip} /> ); diff --git a/test/components/views/beacon/__snapshots__/BeaconMarker-test.tsx.snap b/test/components/views/beacon/__snapshots__/BeaconMarker-test.tsx.snap index e590cbcd9f3..7b64f143586 100644 --- a/test/components/views/beacon/__snapshots__/BeaconMarker-test.tsx.snap +++ b/test/components/views/beacon/__snapshots__/BeaconMarker-test.tsx.snap @@ -148,83 +148,85 @@ exports[` renders marker when beacon has location 1`] = ` className="mx_Marker mx_Username_color4" id="!room:server_@alice:server" > -
- +
- - - + A + + - - - -
+ title="@alice:server" + /> + + +
+
+ diff --git a/test/components/views/location/__snapshots__/LocationViewDialog-test.tsx.snap b/test/components/views/location/__snapshots__/LocationViewDialog-test.tsx.snap index 8a1910a5820..a9f7a03f07d 100644 --- a/test/components/views/location/__snapshots__/LocationViewDialog-test.tsx.snap +++ b/test/components/views/location/__snapshots__/LocationViewDialog-test.tsx.snap @@ -57,13 +57,15 @@ exports[` renders map correctly 1`] = ` className="mx_Marker mx_Marker_defaultColor" id="mx_LocationViewDialog_$2-marker" > -
+
-
+ className="mx_Marker_border" + > +
+
+
diff --git a/test/components/views/location/__snapshots__/Marker-test.tsx.snap b/test/components/views/location/__snapshots__/Marker-test.tsx.snap index b7596d1af8a..71391f9c08f 100644 --- a/test/components/views/location/__snapshots__/Marker-test.tsx.snap +++ b/test/components/views/location/__snapshots__/Marker-test.tsx.snap @@ -8,13 +8,15 @@ exports[` renders with location icon when no room member 1`] = ` className="mx_Marker mx_Marker_defaultColor" id="abc123" > -
+
-
+ className="mx_Marker_border" + > +
+
+
`; diff --git a/test/components/views/location/__snapshots__/SmartMarker-test.tsx.snap b/test/components/views/location/__snapshots__/SmartMarker-test.tsx.snap index d20c9bcd6ce..cfcba2e0dbe 100644 --- a/test/components/views/location/__snapshots__/SmartMarker-test.tsx.snap +++ b/test/components/views/location/__snapshots__/SmartMarker-test.tsx.snap @@ -24,13 +24,15 @@ exports[` creates a marker on mount 1`] = `
-
+
-
+ className="mx_Marker_border" + > +
+
+
@@ -61,13 +63,15 @@ exports[` removes marker on unmount 1`] = `
-
+
-
+ className="mx_Marker_border" + > +
+
+
diff --git a/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap b/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap index cc742223eba..58a413fdb78 100644 --- a/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap +++ b/test/components/views/messages/__snapshots__/MLocationBody-test.tsx.snap @@ -167,13 +167,15 @@ exports[`MLocationBody without error renders map correctly 1`] = className="mx_Marker mx_Marker_defaultColor" id="mx_MLocationBody_$2_1f9acffa-marker" > -
+
-
+ className="mx_Marker_border" + > +
+
+
From a68a0e9ffacbe45b5fc8c57b83a93624a0b16a3f Mon Sep 17 00:00:00 2001 From: Kerry Archibald Date: Thu, 12 May 2022 16:50:26 +0200 Subject: [PATCH 2/4] add beaconstatustooltip, handle overflow on beacon status label Signed-off-by: Kerry Archibald --- res/css/_components.scss | 3 +- .../views/beacon/_BeaconListItem.scss | 1 + .../views/beacon/_BeaconStatus.scss | 7 ++- .../views/beacon/_BeaconStatusTooltip.scss | 32 ++++++++++ .../views/beacon/BeaconStatusTooltip.tsx | 60 +++++++++++++++++++ .../views/beacon/BeaconViewDialog.tsx | 2 + src/components/views/location/Marker.tsx | 34 +++++++---- .../__snapshots__/BeaconMarker-test.tsx.snap | 1 + 8 files changed, 125 insertions(+), 15 deletions(-) create mode 100644 res/css/components/views/beacon/_BeaconStatusTooltip.scss create mode 100644 src/components/views/beacon/BeaconStatusTooltip.tsx diff --git a/res/css/_components.scss b/res/css/_components.scss index d1576d6ec8e..953f12d73ef 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -6,6 +6,7 @@ @import "./_spacing.scss"; @import "./components/views/beacon/_BeaconListItem.scss"; @import "./components/views/beacon/_BeaconStatus.scss"; +@import "./components/views/beacon/_BeaconStatusTooltip.scss"; @import "./components/views/beacon/_BeaconViewDialog.scss"; @import "./components/views/beacon/_DialogOwnBeaconStatus.scss"; @import "./components/views/beacon/_DialogSidebar.scss"; @@ -143,7 +144,6 @@ @import "./views/elements/_AddressSelector.scss"; @import "./views/elements/_AddressTile.scss"; @import "./views/elements/_CopyableText.scss"; -@import "./views/elements/_SearchWarning.scss"; @import "./views/elements/_DesktopCapturerSourcePicker.scss"; @import "./views/elements/_DialPadBackspaceButton.scss"; @import "./views/elements/_DirectorySearchBox.scss"; @@ -172,6 +172,7 @@ @import "./views/elements/_RoleButton.scss"; @import "./views/elements/_RoomAliasField.scss"; @import "./views/elements/_SSOButtons.scss"; +@import "./views/elements/_SearchWarning.scss"; @import "./views/elements/_ServerPicker.scss"; @import "./views/elements/_SettingsFlag.scss"; @import "./views/elements/_Slider.scss"; diff --git a/res/css/components/views/beacon/_BeaconListItem.scss b/res/css/components/views/beacon/_BeaconListItem.scss index 60311a4466f..dd99192cf56 100644 --- a/res/css/components/views/beacon/_BeaconListItem.scss +++ b/res/css/components/views/beacon/_BeaconListItem.scss @@ -40,6 +40,7 @@ limitations under the License. .mx_BeaconListItem_info { flex: 1 1 0; + width: 0; display: flex; flex-direction: column; align-items: stretch; diff --git a/res/css/components/views/beacon/_BeaconStatus.scss b/res/css/components/views/beacon/_BeaconStatus.scss index 4dd3d325475..95c41749111 100644 --- a/res/css/components/views/beacon/_BeaconStatus.scss +++ b/res/css/components/views/beacon/_BeaconStatus.scss @@ -46,14 +46,15 @@ limitations under the License. } .mx_BeaconStatus_description { - flex: 1; + flex: 1 1 0; display: flex; flex-direction: column; line-height: $font-14px; padding-right: $spacing-8; - // TODO handle text-overflow + white-space: nowrap; + overflow: hidden; } .mx_BeaconStatus_expiryTime { @@ -62,4 +63,6 @@ limitations under the License. .mx_BeaconStatus_label { margin-bottom: 2px; + overflow: hidden; + text-overflow: ellipsis; } diff --git a/res/css/components/views/beacon/_BeaconStatusTooltip.scss b/res/css/components/views/beacon/_BeaconStatusTooltip.scss new file mode 100644 index 00000000000..3504ad5452c --- /dev/null +++ b/res/css/components/views/beacon/_BeaconStatusTooltip.scss @@ -0,0 +1,32 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_BeaconStatusTooltip { + position: absolute; + max-width: 150px; + height: 38px; + box-sizing: border-box; + border-radius: 4px; + bottom: -44px; + margin-top: $spacing-4; + background: $menu-bg-color; + box-shadow: 4px 4px 12px 0 $menu-box-shadow-color; + + // override copyable text style to make compact + .mx_CopyableText_copyButton { + margin-left: 0 !important; + } +} diff --git a/src/components/views/beacon/BeaconStatusTooltip.tsx b/src/components/views/beacon/BeaconStatusTooltip.tsx new file mode 100644 index 00000000000..ec11f39d274 --- /dev/null +++ b/src/components/views/beacon/BeaconStatusTooltip.tsx @@ -0,0 +1,60 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { useContext } from 'react'; +import { Beacon } from 'matrix-js-sdk/src/matrix'; +import { LocationAssetType } from 'matrix-js-sdk/src/@types/location'; + +import MatrixClientContext from '../../../contexts/MatrixClientContext'; +import CopyableText from '../elements/CopyableText'; +import BeaconStatus from './BeaconStatus'; +import { BeaconDisplayStatus } from './displayStatus'; + +interface Props { + beacon: Beacon; +} + +const useBeaconName = (beacon: Beacon): string => { + const matrixClient = useContext(MatrixClientContext); + + // + if (beacon.beaconInfo.assetType !== LocationAssetType.Self) { + return beacon.beaconInfo.description; + } + const room = matrixClient.getRoom(beacon.roomId); + const member = room?.getMember(beacon.beaconInfoOwner); + + return member?.rawDisplayName || beacon.beaconInfoOwner; +}; + +const BeaconStatusTooltip: React.FC = ({ beacon }) => { + const label = useBeaconName(beacon); + + return + beacon.latestLocationState?.uri} + /> + ; +}; + +export default BeaconStatusTooltip; diff --git a/src/components/views/beacon/BeaconViewDialog.tsx b/src/components/views/beacon/BeaconViewDialog.tsx index e6c4a423fe9..a7cdb242d37 100644 --- a/src/components/views/beacon/BeaconViewDialog.tsx +++ b/src/components/views/beacon/BeaconViewDialog.tsx @@ -37,6 +37,7 @@ import { _t } from '../../../languageHandler'; import AccessibleButton from '../elements/AccessibleButton'; import DialogSidebar from './DialogSidebar'; import DialogOwnBeaconStatus from './DialogOwnBeaconStatus'; +import BeaconStatusTooltip from './BeaconStatusTooltip'; interface IProps extends IDialogProps { roomId: Room['roomId']; @@ -103,6 +104,7 @@ const BeaconViewDialog: React.FC = ({ key={beacon.identifier} map={map} beacon={beacon} + tooltip={} />) } diff --git a/src/components/views/location/Marker.tsx b/src/components/views/location/Marker.tsx index 81321a810b9..a07032e3079 100644 --- a/src/components/views/location/Marker.tsx +++ b/src/components/views/location/Marker.tsx @@ -14,15 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { ReactNode } from 'react'; +import React, { ReactNode, useState } from 'react'; import classNames from 'classnames'; import { RoomMember } from 'matrix-js-sdk/src/matrix'; import { Icon as LocationIcon } from '../../../../res/img/element-icons/location.svg'; import { getUserNameColorClass } from '../../../utils/FormattingUtils'; import MemberAvatar from '../avatars/MemberAvatar'; -import TooltipTarget from '../elements/TooltipTarget'; -import { Alignment } from '../elements/Tooltip'; interface Props { id?: string; @@ -36,15 +34,25 @@ interface Props { // wrap children in tooltip target // when tooltip is truthy const OptionalTooltip: React.FC<{ - tooltip?: ReactNode; children: ReactNode; -}> = ({ tooltip, children }) => tooltip ? - - {children} - : - <>{children}; + tooltip?: ReactNode; children: ReactNode; +}> = ({ tooltip, children }) => { + const [isVisible, setIsVisible] = useState(true); + if (!tooltip) { + return <>{ children }; + } + + const show = () => setIsVisible(true); + const hide = () => setIsVisible(false); + const toggleVisibility = (e: React.MouseEvent) => { + e.stopPropagation(); + setIsVisible(!isVisible); + }; + + return
+ { children } + { (isVisible || true) && tooltip } +
; +}; /** * Generic location marker @@ -66,6 +74,8 @@ const Marker = React.forwardRef(({ id, roomMember, useMem width={36} height={36} viewUserOnClick={false} + // no mxid on hover when marker has tooltip + hideTitle={!!tooltip} /> : } diff --git a/test/components/views/beacon/__snapshots__/BeaconMarker-test.tsx.snap b/test/components/views/beacon/__snapshots__/BeaconMarker-test.tsx.snap index 7b64f143586..a79a47b5892 100644 --- a/test/components/views/beacon/__snapshots__/BeaconMarker-test.tsx.snap +++ b/test/components/views/beacon/__snapshots__/BeaconMarker-test.tsx.snap @@ -154,6 +154,7 @@ exports[` renders marker when beacon has location 1`] = ` > Date: Thu, 12 May 2022 17:08:40 +0200 Subject: [PATCH 3/4] remove debug, fix mouseout Signed-off-by: Kerry Archibald --- .../views/beacon/_BeaconStatusTooltip.scss | 17 +++++++----- .../views/beacon/BeaconStatusTooltip.tsx | 26 ++++++++++--------- src/components/views/location/Marker.tsx | 4 +-- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/res/css/components/views/beacon/_BeaconStatusTooltip.scss b/res/css/components/views/beacon/_BeaconStatusTooltip.scss index 3504ad5452c..07b3a43cc01 100644 --- a/res/css/components/views/beacon/_BeaconStatusTooltip.scss +++ b/res/css/components/views/beacon/_BeaconStatusTooltip.scss @@ -16,17 +16,22 @@ limitations under the License. .mx_BeaconStatusTooltip { position: absolute; + top: 42px; max-width: 150px; height: 38px; - box-sizing: border-box; - border-radius: 4px; - bottom: -44px; - margin-top: $spacing-4; - background: $menu-bg-color; - box-shadow: 4px 4px 12px 0 $menu-box-shadow-color; + box-sizing: content-box; + padding-top: $spacing-8; // override copyable text style to make compact .mx_CopyableText_copyButton { margin-left: 0 !important; } } + +.mx_BeaconStatusTooltip_inner { + position: relative; + height: 100%; + border-radius: 4px; + background: $menu-bg-color; + box-shadow: 4px 4px 12px 0 $menu-box-shadow-color; +} diff --git a/src/components/views/beacon/BeaconStatusTooltip.tsx b/src/components/views/beacon/BeaconStatusTooltip.tsx index ec11f39d274..2a51c0355c4 100644 --- a/src/components/views/beacon/BeaconStatusTooltip.tsx +++ b/src/components/views/beacon/BeaconStatusTooltip.tsx @@ -43,18 +43,20 @@ const useBeaconName = (beacon: Beacon): string => { const BeaconStatusTooltip: React.FC = ({ beacon }) => { const label = useBeaconName(beacon); - return - beacon.latestLocationState?.uri} - /> - ; + return
+ + beacon.latestLocationState?.uri} + /> + +
; }; export default BeaconStatusTooltip; diff --git a/src/components/views/location/Marker.tsx b/src/components/views/location/Marker.tsx index a07032e3079..89cf8d10cce 100644 --- a/src/components/views/location/Marker.tsx +++ b/src/components/views/location/Marker.tsx @@ -36,7 +36,7 @@ interface Props { const OptionalTooltip: React.FC<{ tooltip?: ReactNode; children: ReactNode; }> = ({ tooltip, children }) => { - const [isVisible, setIsVisible] = useState(true); + const [isVisible, setIsVisible] = useState(false); if (!tooltip) { return <>{ children }; } @@ -50,7 +50,7 @@ const OptionalTooltip: React.FC<{ return
{ children } - { (isVisible || true) && tooltip } + { isVisible && tooltip }
; }; From 4f6f327452023302cd15eeaa15b6796cfa57c643 Mon Sep 17 00:00:00 2001 From: Kerry Archibald Date: Thu, 12 May 2022 17:13:36 +0200 Subject: [PATCH 4/4] tidy comments Signed-off-by: Kerry Archibald --- src/components/views/beacon/BeaconStatusTooltip.tsx | 1 - src/components/views/location/Marker.tsx | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/views/beacon/BeaconStatusTooltip.tsx b/src/components/views/beacon/BeaconStatusTooltip.tsx index 2a51c0355c4..bc9f3609395 100644 --- a/src/components/views/beacon/BeaconStatusTooltip.tsx +++ b/src/components/views/beacon/BeaconStatusTooltip.tsx @@ -30,7 +30,6 @@ interface Props { const useBeaconName = (beacon: Beacon): string => { const matrixClient = useContext(MatrixClientContext); - // if (beacon.beaconInfo.assetType !== LocationAssetType.Self) { return beacon.beaconInfo.description; } diff --git a/src/components/views/location/Marker.tsx b/src/components/views/location/Marker.tsx index 89cf8d10cce..075d2d092ef 100644 --- a/src/components/views/location/Marker.tsx +++ b/src/components/views/location/Marker.tsx @@ -31,8 +31,10 @@ interface Props { tooltip?: ReactNode; } -// wrap children in tooltip target -// when tooltip is truthy +/** + * Wrap with tooltip handlers when + * tooltip is truthy + */ const OptionalTooltip: React.FC<{ tooltip?: ReactNode; children: ReactNode; }> = ({ tooltip, children }) => { @@ -44,6 +46,7 @@ const OptionalTooltip: React.FC<{ const show = () => setIsVisible(true); const hide = () => setIsVisible(false); const toggleVisibility = (e: React.MouseEvent) => { + // stop map from zooming in on click e.stopPropagation(); setIsVisible(!isVisible); };