Zmenu.tsx 2.96 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/**
 * See the NOTICE file distributed with this work for additional information
 * regarding copyright ownership.
 *
 * 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.
 */

17
import React from 'react';
18 19

import browserMessagingService from 'src/content/app/browser/browser-messaging-service';
20
import useRefWithRerender from 'src/shared/hooks/useRefWithRerender';
21

22 23 24 25 26
import {
  Toolbox,
  ToolboxPosition,
  ToolboxExpandableContent
} from 'src/shared/components/toolbox';
27
import ZmenuContent from './ZmenuContent';
28
import ZmenuInstantDownload from './ZmenuInstantDownload';
29

30
import { ZmenuData, ZmenuAction } from './zmenu-types';
31

32
import styles from './Zmenu.scss';
33 34 35 36 37 38

enum Direction {
  LEFT = 'left',
  RIGHT = 'right'
}

39
export type ZmenuProps = ZmenuData & {
40 41 42 43 44
  browserRef: React.RefObject<HTMLDivElement>;
  onEnter: (id: string) => void;
  onLeave: (id: string) => void;
};

45
const Zmenu = (props: ZmenuProps) => {
46
  const anchorRef = useRefWithRerender<HTMLDivElement>(null);
47 48 49 50 51 52
  const onOutsideClick = () =>
    browserMessagingService.send('bpane', {
      id: props.id,
      action: ZmenuAction.ACTIVITY_OUTSIDE
    });

53
  const direction = chooseDirection(props);
54 55 56 57 58
  const toolboxPosition =
    direction === Direction.LEFT ? ToolboxPosition.LEFT : ToolboxPosition.RIGHT;

  const mainContent = <ZmenuContent content={props.content} />;
  const anchorStyles = getAnchorInlineStyles(props);
59 60

  return (
61 62 63 64 65 66 67 68 69
    <div ref={anchorRef} className={styles.zmenuAnchor} style={anchorStyles}>
      {anchorRef.current && (
        <Toolbox
          onOutsideClick={onOutsideClick}
          anchor={anchorRef.current}
          position={toolboxPosition}
        >
          <ToolboxExpandableContent
            mainContent={mainContent}
70
            footerContent={getToolboxFooterContent(props.id)}
71 72 73
          />
        </Toolbox>
      )}
74 75 76 77
    </div>
  );
};

78 79 80 81 82 83 84 85 86 87
const getAnchorInlineStyles = (params: ZmenuProps) => {
  const {
    anchor_coordinates: { x, y }
  } = params;
  return {
    left: `${x}px`,
    top: `${y}px`
  };
};

88
// choose how to position zmenu relative to its anchor point
89
const chooseDirection = (params: ZmenuProps) => {
90 91 92 93 94 95
  const browserElement = params.browserRef.current as HTMLDivElement;
  const { width } = browserElement.getBoundingClientRect();
  const { x } = params.anchor_coordinates;
  return x > width / 2 ? Direction.LEFT : Direction.RIGHT;
};

96 97 98 99 100 101
const getToolboxFooterContent = (id: string) => (
  <div className={styles.zmenuFooterContent}>
    <ZmenuInstantDownload id={id} />
  </div>
);

102
export default Zmenu;