Browse Source

Fix tooltip typescript nightmare

pull/1/head
GreatBearShark 1 year ago
parent
commit
2a0176b978
  1. 2
      .eslintrc.json
  2. 1
      package.json
  3. 3
      src/components/MenuButton.tsx
  4. 114
      src/components/Tooltip.tsx
  5. 2
      src/components/elements/Block.tsx
  6. 56
      src/components/post-listing.tsx
  7. 1
      src/stories/PostListing.stories.tsx
  8. 2
      yarn.lock

2
.eslintrc.json

@ -29,7 +29,7 @@
"@typescript-eslint/no-empty-interface": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-this-alias": 0,
"@typescript-eslint/no-unused-vars": 0,
"@typescript-eslint/no-unused-vars": 1,
"@typescript-eslint/no-use-before-define": 0,
"@typescript-eslint/ban-ts-comment": 0,
"@typescript-eslint/no-useless-constructor": 0,

1
package.json

@ -23,6 +23,7 @@
"@reach/portal": "^0.11.2",
"@reach/tabs": "^0.11.2",
"@reach/tooltip": "^0.11.2",
"@reach/utils": "^0.11.2",
"@sentry/react": "^5.22.3",
"@theme-ui/color": "^0.3.1",
"@theme-ui/presets": "^0.3.0",

3
src/components/MenuButton.tsx

@ -21,11 +21,11 @@ export const MenuButton = props => <Button as={ReachMenuButton} {...props} />;
export const MenuList = props => (
<Block
bg="background"
position="relative"
css={{
borderRadius: '4px',
border: 0,
'::after': {
marginTop: '8px',
content: `''`,
boxShadow: '0 0 0 1px rgba(0,0,0,.05)',
borderRadius: '4px',
@ -33,6 +33,7 @@ export const MenuList = props => (
top: 0,
width: '100%',
height: '100%',
// height: 'calc(100% - 8px)',
pointerEvents: 'none',
},
}}

114
src/components/Tooltip.tsx

@ -1,23 +1,18 @@
import React, { cloneElement } from 'react';
import ReachTooltip, {
TooltipProps,
useTooltip,
TooltipPopup,
} from '@reach/tooltip';
import React, { cloneElement, ReactElement } from 'react';
import { TooltipProps, useTooltip, TooltipPopup } from '@reach/tooltip';
import Portal from '@reach/portal';
import '@reach/tooltip/styles.css';
import Block from './elements/Block';
import { useThemeUI } from 'theme-ui';
import { useThemeSystem } from './ThemeSystemProvider';
import { ForwardRefExoticComponentWithAs } from '@reach/utils';
const centered = (triggerRect: DOMRect, tooltipRect) => {
// if (!triggerRect) {
// return {
// left: 0,
// top: 0,
// };
// }
if (!tooltipRect || !triggerRect) {
throw new Error(
'Could not find a reference to calculate tooltip position.\nThis most likely means you forgot to use forwardRef to pass down a ref through a component:\nhttps://reactjs.org/docs/react-api.html#reactforwardref\n'
);
}
const triggerCenter = triggerRect.left + triggerRect.width / 2;
const left = triggerCenter - tooltipRect.width / 2;
const maxLeft = window.innerWidth - tooltipRect.width - 2;
@ -27,64 +22,24 @@ const centered = (triggerRect: DOMRect, tooltipRect) => {
};
};
// const TriangleTooltip = ({ children, label, 'aria-label': ariaLabel }) => {
// // get the props from useTooltip
// const [trigger, tooltip] = useTooltip();
// // destructure off what we need to position the triangle
// const { isVisible, triggerRect } = tooltip;
// const { currentTheme } = useThemeSystem();
// const { theme } = useThemeUI();
// const color = currentTheme === 'chapo' ? '#2F2F37' : theme.colors.muted;
// return (
// <>
// {cloneElement(children, trigger)}
// {isVisible && (
// // The Triangle. We position it relative to the trigger, not the popup
// // so that collisions don't have a triangle pointing off to nowhere.
// // Using a Portal may seem a little extreme, but we can keep the
// // positioning logic simpler here instead of needing to consider
// // the popup's position relative to the trigger and collisions
// <Portal>
// <div
// style={{
// position: 'absolute',
// left:
// triggerRect && triggerRect.left - 10 + triggerRect.width / 2,
// top: triggerRect && triggerRect.bottom + window.scrollY,
// width: 0,
// height: 0,
// borderLeft: '10px solid transparent',
// borderRight: '10px solid transparent',
// borderBottom: `10px solid ${color}`,
// }}
// />
// </Portal>
// )}
// <TooltipPopup
// {...tooltip}
// label={label}
// aria-label={ariaLabel}
// style={{
// backgroundColor: color,
// color: 'white',
// border: 'none',
// borderRadius: '6px',
// padding: '15px',
// fontSize: '15px',
// lineHeight: '18px',
// fontWeight: 500,
// }}
// position={centered}
// />
// </>
// );
// };
interface CustomTooltipProps extends TooltipProps {
style?: React.CSSProperties;
label: string; // text visually shown to user
'aria-label': string; // text read to screenreaders for accessibility
}
const TriangleTooltip = React.forwardRef(
({ children, label, 'aria-label': ariaLabel }: any, ref) => {
const TriangleTooltip: ForwardRefExoticComponentWithAs<
'div',
TooltipProps
> = React.forwardRef(
(
{
children,
label,
'aria-label': ariaLabel,
}: { children: ReactElement } & CustomTooltipProps,
ref
) => {
// get the props from useTooltip
const [trigger, tooltip] = useTooltip();
// destructure off what we need to position the triangle
@ -145,29 +100,12 @@ const TriangleTooltip = React.forwardRef(
}
);
// const Tooltip = React.forwardRef(
// (
// {
// style,
// 'aria-label': ariaLabel,
// ...props
// }: { style?: React.CSSProperties; 'aria-label': string } & TooltipProps,
// ref
// ) => {
// return <TriangleTooltip ref={ref} aria-label={ariaLabel} {...props} />;
// }
// );
const Tooltip = ({
style,
'aria-label': ariaLabel,
label,
...props
}: {
style?: React.CSSProperties;
label: string;
'aria-label': string;
} & TooltipProps) => {
}: CustomTooltipProps) => {
return <TriangleTooltip label={label} aria-label={ariaLabel} {...props} />;
};

2
src/components/elements/Block.tsx

@ -56,7 +56,7 @@ type StyledSystemProps = StyledSystem.LayoutProps &
IFontWeight &
ILineHeight;
const Block = styled(Box)<StyledSystemProps>({}, systemProps);
const Block = styled(Box)({}, systemProps);
export const Flex = styled(Block)(
{

56
src/components/post-listing.tsx

@ -217,7 +217,6 @@ export const VoteButton = ({
backgroundColor="transparent"
// color="text"
onClick={onClick}
data-tippy-content={i18n.t('upvote')}
color={my_vote === 1 ? upvoteColor : 'text'}
css={{
':hover': {
@ -239,7 +238,6 @@ export const VoteButton = ({
p={1}
backgroundColor="transparent"
onClick={onClick}
data-tippy-content={i18n.t('downvote')}
color={my_vote === -1 ? downvoteColor : 'text'}
css={{
':hover': {
@ -415,15 +413,11 @@ const MobilePostListing = ({
<MomentTime data={post} />
</Box>
{post.stickied && (
<small
className="unselectable pointer ml-1 font-italic"
data-tippy-content={i18n.t('stickied')}
>
{/* <svg className={`icon custom-icon text-success`}>
<use xlinkHref="#icon-pin"></use>
</svg> */}
<Icon className="icon text-success" name="pin" />
</small>
<Tooltip label={i18n.t('stickied')} aria-label={i18n.t('stickied')}>
<span className="pointer font-italic">
<Icon className="icon text-success" name="pin" />
</span>
</Tooltip>
)}
{post.locked && (
<small
@ -926,15 +920,11 @@ export class BasePostListing extends Component<
</Box>
</li>
{post.stickied && (
<small
className="unselectable pointer ml-1 font-italic"
data-tippy-content={i18n.t('stickied')}
>
{/* <svg className={`icon custom-icon text-success`}>
<use xlinkHref="#icon-pin"></use>
</svg> */}
<Icon className="icon text-success" name="pin" />
</small>
<Tooltip label={i18n.t('stickied')} aria-label={i18n.t('stickied')}>
<small className="unselectable pointer ml-1 font-italic">
<Icon className="icon text-success" name="pin" />
</small>
</Tooltip>
)}
{post.locked && (
<small
@ -995,21 +985,23 @@ export class BasePostListing extends Component<
{!this.props.showBody && (
<>
<li className="list-inline-item">
<PostListingButton
onClick={this.handleSavePostClick}
data-tippy-content={
<Tooltip
label={post.saved ? i18n.t('unsave') : i18n.t('save')}
aria-label={
post.saved ? i18n.t('unsave') : i18n.t('save')
}
>
<Icon
name={
this.state.localPostSaved ? 'star' : 'starOutline'
}
className={`icon icon-inline ${
this.state.localPostSaved && 'text-warning'
}`}
/>
</PostListingButton>
<PostListingButton onClick={this.handleSavePostClick}>
<Icon
name={
this.state.localPostSaved ? 'star' : 'starOutline'
}
className={`icon icon-inline ${
this.state.localPostSaved && 'text-warning'
}`}
/>
</PostListingButton>
</Tooltip>
</li>
<li className="list-inline-item">
<Link

1
src/stories/PostListing.stories.tsx

@ -102,6 +102,7 @@ export const Basic = () => {
return (
<MemoryRouter>
<AllThemes>
{/* @ts-ignore */}
<BasePostListing {...postListingProps} />
</AllThemes>
</MemoryRouter>

2
yarn.lock

@ -1903,7 +1903,7 @@
tslib "^2.0.0"
warning "^4.0.3"
"@reach/[email protected]":
"@reach/[email protected]", "@reach/[email protected]^0.11.2":
version "0.11.2"
resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.11.2.tgz#be1f03650db56fd67a16d3fc70e5262cdb139cec"
integrity sha512-fBTolYj+rKTROXmf0zHO0rCWSvw7J0ALmYj5QxW4DmITMOH5uyRuWDWOfqohIGFbOtF/sum50WTB3tvx76d+Aw==

Loading…
Cancel
Save