Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial work on tool tip integration #1516

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion components/search/bills/BillSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { useBillRefinements } from "./useBillRefinements"
import { SortBy, SortByWithConfigurationItem } from "../SortBy"
import { getServerConfig } from "../common"
import { useBillSort } from "./useBillSort"
import { FC } from "react"
import { FC, RefObject, useEffect, useRef } from "react"
import { QuestionTooltip } from "components/tooltip"

const searchClient = new TypesenseInstantSearchAdapter({
server: getServerConfig(),
Expand Down Expand Up @@ -73,13 +74,52 @@ const useSearchStatus = () => {
}
}

const addToolTipForCity = (nodeRef: RefObject<HTMLDivElement>) => {
// fetch the city search refinement form
const citySearch = document.querySelector<HTMLFormElement>(".city-search form")!;
citySearch?.setAttribute("style", "gap: 5px;");
// fetch the city search refinement form input
const input = document.querySelector<HTMLFormElement>(".city-search form .ais-SearchBox-input")!;
input?.setAttribute("style", "padding-right: 0");
// create the tool tip div to be added beside the input
const toolTip = document.createElement("div")!;
toolTip.classList.add(".city-tooltip");
toolTip.style.margin = "auto 0";
// add the tooltip div at the beginning of the form
citySearch?.prepend(toolTip);
// add the component to the div using the ref
toolTip.append(nodeRef?.current!);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • we should try to use the search library tools/options to customize the widget. I haven't seen the option to add a tooltip yet, but we should keep digging. I would think there would be something in there for this common req.
  • we should go back and talk to design--I'm sure design team can generate plenty of other great solutions to add a tooltip without having to alter the widget ui and without having to directly interacting with the dom.

I realize part of the tooltip existing in the project may have been built like this way back when (by me, probably). Sorry for the bum steer if so. I don't remember why I did it this way then, but we should make a different choice now...likely not the best choice at the time either? we'll never know for sure ....

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did spend quite a bit of time looking into the search library options. It looked to me as we are using a package that is very customised for the use case, so most of the general documentation is not of very much help :(

Although the refinement list and it's elements are customisable, it does not fit in with the components which we have used :(

}

const Layout: FC<
React.PropsWithChildren<{ items: SortByWithConfigurationItem[] }>
> = ({ items }) => {
const refinements = useBillRefinements()
const status = useSearchStatus()
const nodeRef = useRef<HTMLDivElement>(null);

// add the tooltip beside city refinement box on page load
useEffect(() => {
addToolTipForCity(nodeRef);
}, []);

return (
<SearchContainer>
<QuestionTooltip placement={"top"} nodeRef={nodeRef}>
<p className="mb-0">
This filter only captures bills submitted via the
{" "}
<a
className="text-light"
href="https://www.somervillecdc.org/news/what-is-a-home-rule-petition/#:~:text=A%20Home%20Rule%20Petition%20is,an%20aspect%20of%20state%20law"
target="_blank"
>
home rule
</a>
{" "}
petition; not every bill that concerns a city
</p>
</QuestionTooltip>
<Row>
<SearchBox placeholder="Search For Bills" className="mt-2 mb-3" />
</Row>
Expand Down
1 change: 1 addition & 0 deletions components/search/bills/useBillRefinements.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const useBillRefinements = () => {
useRefinementListUiProps({
attribute: "city",
searchablePlaceholder: "City",
className: "city-search",
...baseProps
}),
useRefinementListUiProps({
Expand Down
49 changes: 35 additions & 14 deletions components/tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,43 @@
import "@fortawesome/fontawesome-svg-core/styles.css"
import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import React from "react"
import React, { FC, RefObject, useState } from "react"
import { OverlayTrigger, Tooltip } from "react-bootstrap"
import { Placement } from "react-bootstrap/esm/types"

export const QuestionTooltip = ({ text }: { text: string }) => {
export const QuestionTooltip: FC<
React.PropsWithChildren<{
placement: Placement,
nodeRef: RefObject<HTMLDivElement>
}>
> = ({ placement, nodeRef, children }) => {
const [show, setShow] = useState(false);
const onMouseOver = (s: boolean) => setShow(s);
return (
<OverlayTrigger
placement="auto"
overlay={
<Tooltip id="tooltip-text">
<p>{text}</p>
</Tooltip>
}
>
<span className="m-1">
<FontAwesomeIcon icon={faQuestionCircle} className="text-secondary" />
</span>
</OverlayTrigger>
<div ref={nodeRef}>
<OverlayTrigger
show={show}
placement={placement}
overlay={
<Tooltip
onMouseEnter={() => onMouseOver(true)}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we shouldn't have to show/hide the overlay manually, bootstrap overlaytrigger should be taking care of that...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bootstrap overlay trigger does take care of it, but when we have a link in tooltip, then clicking on the link did not seem possible unless state is maintained like I have done so.

onMouseLeave={() => onMouseOver(false)}
id="tooltip-text"
>
{children}
</Tooltip>
}
>
<span className="m-1">
<FontAwesomeIcon
onMouseEnter={() => onMouseOver(true)}
onMouseLeave={() => onMouseOver(false)}
size={"lg"}
icon={faQuestionCircle}
className="text-secondary"
/>
</span>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could pass the Icon in as a(n optional) prop and make this the base tooltip component for the project. (Keep the faquetioncircle icon as the default/fallback icon.)

</OverlayTrigger>
</div>
)
}
Loading