/library/src/scripts/embeddedContent/components/EmbedButton.tsx

https://github.com/vanilla/vanilla · TypeScript · 77 lines · 68 code · 4 blank · 5 comment · 25 complexity · 2f9fc902777043e270a9024b54bc49e5 MD5 · raw file

  1. /**
  2. * @author Dominic Lacaille <dominic.lacaille@vanillaforums.com>
  3. * @copyright 2009-2020 Vanilla Forums Inc.
  4. * @license gpl-2.0-only
  5. */
  6. import Button, { IButtonProps } from "@library/forms/Button";
  7. import { ButtonTypes } from "@library/forms/buttonTypes";
  8. import classNames from "classnames";
  9. import React, { PropsWithChildren, KeyboardEvent, useLayoutEffect, useState, useRef } from "react";
  10. import { embedButtonClasses } from "./embedButtonStyles";
  11. interface IProps extends IButtonProps {
  12. isActive?: boolean;
  13. }
  14. export function EmbedButton(props: PropsWithChildren<IProps>) {
  15. const { isActive, children, buttonRef, onKeyDown, ...otherProps } = props;
  16. const classes = embedButtonClasses();
  17. const [isFirst, setIsFirst] = useState(false);
  18. return (
  19. <Button
  20. buttonRef={(button) => {
  21. if (typeof buttonRef === "function") buttonRef(button);
  22. else if (buttonRef && typeof buttonRef === "object") (buttonRef as any).current = button;
  23. if (!button) return;
  24. setIsFirst(button.previousSibling === null);
  25. }}
  26. tabIndex={isFirst ? 0 : -1}
  27. onKeyDown={(e: React.KeyboardEvent<HTMLElement>) => {
  28. const key = e.key;
  29. let target = e.target as HTMLElement & EventTarget;
  30. const firstSibling = () => target.parentElement?.firstChild as HTMLElement | undefined;
  31. const lastSibling = () => target.parentElement?.lastChild as HTMLElement | undefined;
  32. switch (key) {
  33. case "ArrowRight": {
  34. e.preventDefault();
  35. let nextSibling = target.nextSibling as HTMLElement | undefined;
  36. if (!nextSibling && target.parentElement) {
  37. nextSibling = firstSibling();
  38. }
  39. (nextSibling as HTMLElement).focus();
  40. break;
  41. }
  42. case "ArrowLeft": {
  43. e.preventDefault();
  44. let previousSibling = target.previousSibling as HTMLElement | undefined;
  45. if (!previousSibling && target.parentElement) {
  46. previousSibling = lastSibling();
  47. }
  48. (previousSibling as HTMLElement).focus();
  49. break;
  50. }
  51. case "Home": {
  52. e.preventDefault();
  53. (firstSibling() as HTMLElement)?.focus();
  54. break;
  55. }
  56. case "End": {
  57. e.preventDefault();
  58. (lastSibling() as HTMLElement)?.focus();
  59. break;
  60. }
  61. default:
  62. break;
  63. }
  64. if (onKeyDown) onKeyDown(e);
  65. }}
  66. buttonType={ButtonTypes.CUSTOM}
  67. className={classNames({ [classes.button]: true, isActive })}
  68. {...otherProps}
  69. >
  70. {children}
  71. </Button>
  72. );
  73. }