@material-ui/core#ButtonBase TypeScript Examples

The following examples show how to use @material-ui/core#ButtonBase. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ActionButton.tsx    From anchor-web-app with Apache License 2.0 6 votes vote down vote up
ActionButton = styled(ButtonBase).attrs({ disableRipple: true })`
  ${buttonBaseStyle};

  background-color: ${({ theme }) => theme.actionButton.backgroundColor};

  &:hover {
    background-color: ${({ theme }) => theme.actionButton.backgroundHoverColor};
  }

  &:active {
    ${({ theme }) =>
      pressed({
        color: theme.actionButton.backgroundHoverColor,
        backgroundColor: theme.actionButton.backgroundHoverColor,
        distance: 1,
        intensity: theme.intensity,
      })};
  }

  &:disabled,
  &[aria-disabled='true'] {
    opacity: 0.3;
  }
`
Example #2
Source File: BarChartSteps.tsx    From backstage with Apache License 2.0 6 votes vote down vote up
BarChartSteps = ({
  steps,
  activeStep,
  onClick,
}: BarChartStepsProps) => {
  const classes = useStyles();
  const handleOnClick =
    (index: number) =>
    (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
      event.preventDefault();
      onClick(index);
    };

  return (
    <div className={classes.steps}>
      {[...new Array(steps)].map((_, index) => (
        <ButtonBase key={index} centerRipple onClick={handleOnClick(index)}>
          <div
            data-testid="bar-chart-step"
            className={`${classes.step} ${
              index === activeStep ? classes.stepActive : ''
            }`}
          />
        </ButtonBase>
      ))}
    </div>
  );
}
Example #3
Source File: BarChartStepperButton.tsx    From backstage with Apache License 2.0 6 votes vote down vote up
BarChartStepperButton = forwardRef(
  (
    {
      name,
      children,
      ...buttonBaseProps
    }: PropsWithChildren<BarChartStepperButtonProps>,
    ref: Ref<HTMLButtonElement>,
  ) => {
    const classes = useStyles();
    return (
      <ButtonBase
        ref={ref}
        classes={classes}
        disableRipple
        data-testid={`bar-chart-stepper-button-${name}`}
        {...buttonBaseProps}
      >
        {children}
      </ButtonBase>
    );
  },
)
Example #4
Source File: InlineCell.tsx    From firetable with Apache License 2.0 6 votes vote down vote up
SingleSelect = React.forwardRef(function SingleSelect(
  { value, showPopoverCell, disabled }: IPopoverInlineCellProps,
  ref: React.Ref<any>
) {
  const classes = useStyles();

  return (
    <ButtonBase
      className={clsx("cell-collapse-padding", classes.root)}
      onClick={() => showPopoverCell(true)}
      ref={ref}
      disabled={disabled}
    >
      <div className={classes.value}>{sanitiseValue(value)}</div>

      <ArrowDropDownIcon
        className={clsx(classes.icon, disabled && classes.disabled)}
      />
    </ButtonBase>
  );
})
Example #5
Source File: InlineCell.tsx    From firetable with Apache License 2.0 6 votes vote down vote up
ConnectService = React.forwardRef(function ConnectService(
  { value, showPopoverCell, disabled, column }: IPopoverInlineCellProps,
  ref: React.Ref<any>
) {
  const classes = useStyles();
  const config = column.config ?? {};

  return (
    <ButtonBase
      className={clsx("cell-collapse-padding", classes.root)}
      onClick={() => showPopoverCell(true)}
      ref={ref}
      disabled={disabled}
    >
      <Grid
        container
        wrap="nowrap"
        alignItems="center"
        spacing={1}
        className={classes.value}
      >
        {Array.isArray(value) &&
          value.map((doc: any) => (
            <Grid item key={doc.primaryKey}>
              <Chip
                label={config.titleKey}
                className={classes.chip}
                size="small"
              />
            </Grid>
          ))}
      </Grid>

      <ArrowDropDownIcon
        className={clsx(classes.icon, disabled && classes.disabled)}
      />
    </ButtonBase>
  );
})
Example #6
Source File: InlineCell.tsx    From firetable with Apache License 2.0 6 votes vote down vote up
Color = React.forwardRef(function Color(
  { value, showPopoverCell, disabled }: IPopoverInlineCellProps,
  ref: React.Ref<any>
) {
  const classes = useStyles();

  return (
    <Grid
      container
      alignItems="center"
      spacing={1}
      className={clsx("cell-collapse-padding", classes.root)}
      component={ButtonBase}
      onClick={() => showPopoverCell(true)}
      ref={ref}
      disabled={disabled}
    >
      <Grid item>
        <div
          className={classes.colorIndicator}
          style={{ backgroundColor: value?.hex }}
        />
      </Grid>

      <Grid item xs>
        {value?.hex}
      </Grid>
    </Grid>
  );
})
Example #7
Source File: TextButton.tsx    From anchor-web-app with Apache License 2.0 6 votes vote down vote up
TextButton = styled(ButtonBase).attrs({ disableRipple: true })`
  ${buttonBaseStyle};

  color: ${({ theme }) => theme.textButton.textColor};

  ${({ theme }) =>
    flat({
      color: theme.sectionBackgroundColor,
      distance: 0.1,
      intensity: theme.intensity,
    })};

  &:hover {
    ${({ theme }) =>
      flat({
        color: theme.sectionBackgroundColor,
        distance: 1,
        intensity: theme.intensity,
      })};
    background-color: ${({ theme }) => theme.hoverBackgroundColor};
  }

  &:active {
    ${({ theme }) =>
      pressed({
        color: theme.sectionBackgroundColor,
        distance: 1,
        intensity: theme.intensity,
      })};
    background-color: ${({ theme }) => theme.hoverBackgroundColor};
  }

  &:disabled {
    color: ${({ theme }) => c(theme.textButton.textColor).alpha(0.3).string()};
  }
`
Example #8
Source File: FlatButton.tsx    From anchor-web-app with Apache License 2.0 6 votes vote down vote up
FlatButton = styled(ButtonBase).attrs({ disableRipple: true })`
  ${buttonBaseStyle};

  background-color: ${({ theme }) => theme.actionButton.backgroundColor};

  &:hover {
    background-color: ${({ theme }) => theme.actionButton.backgroundHoverColor};
  }

  &:disabled {
    opacity: 0.3;
  }
`
Example #9
Source File: BorderButton.tsx    From anchor-web-app with Apache License 2.0 6 votes vote down vote up
BorderButton = styled(ButtonBase).attrs({ disableRipple: true })`
  ${buttonBaseStyle};

  color: ${({ theme }) => theme.borderButton.textColor};
  border: 1px solid ${({ theme }) => theme.borderButton.borderColor};

  &:hover {
    border: 1px solid ${({ theme }) => theme.borderButton.borderHoverColor};
    background-color: ${({ theme }) => theme.hoverBackgroundColor};
    color: ${({ theme }) => theme.borderButton.hoverTextColor};
  }

  &:disabled {
    opacity: 0.3;
  }
`
Example #10
Source File: EmbossButton.tsx    From anchor-web-app with Apache License 2.0 6 votes vote down vote up
EmbossButton = styled(ButtonBase).attrs({ disableRipple: true })`
  ${buttonBaseStyle};

  border-radius: 5px;

  color: ${({ theme }) => theme.textColor};

  ${({ theme }) =>
    flat({
      color: theme.selector.backgroundColor,
      backgroundColor: theme.backgroundColor,
      distance: 1,
      intensity: theme.intensity,
    })};

  &:active {
    ${({ theme }) =>
      pressed({
        color: theme.selector.backgroundColor,
        backgroundColor: theme.backgroundColor,
        distance: 1,
        intensity: theme.intensity,
      })};
  }

  &:disabled {
    opacity: 0.3;
  }
`
Example #11
Source File: MenuAction.tsx    From parity-bridges-ui with GNU General Public License v3.0 5 votes vote down vote up
MenuAction = ({ actions, changeMenu, action }: MenuActionProps) => {
  const classes = useStyles();
  const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null);
  const [id, setId] = React.useState<string | undefined>(undefined);
  const [open, setOpen] = React.useState<boolean>(false);

  const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
    setAnchorEl(event.currentTarget);
    setOpen(!open);
  };

  useEffect(() => {
    setOpen(Boolean(anchorEl));
    setId(anchorEl ? 'simple-popover' : undefined);
  }, [anchorEl]);

  const item = actions.find(({ type }) => type === action);

  return (
    <>
      <ButtonBase className={`${classes.item} current`} onClick={handleClick}>
        {item?.title || '-'}
        <ArrowDropDownIcon />
      </ButtonBase>
      <Popover
        id={id}
        open={open}
        anchorEl={anchorEl}
        onClose={() => setOpen(false)}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'right'
        }}
        transformOrigin={{
          vertical: 'top',
          horizontal: 24
        }}
        PaperProps={{
          className: classes.menu
        }}
      >
        {actions.map((i, n) => (
          <ButtonBase
            className={`${classes.item} ${!i.isEnabled && 'disabled'}`}
            key={n}
            onClick={() => {
              setOpen(!open);
              changeMenu(i.type);
            }}
          >
            {i.title}
          </ButtonBase>
        ))}
      </Popover>
    </>
  );
}
Example #12
Source File: index.tsx    From uno-game with MIT License 5 votes vote down vote up
ChooseColorModal: ChooseColorModalType & React.FC<ChooseColorModalProps> = (props) => {
	const classes = useStyles()

	const { callback } = props

	const [opened, setOpened] = useState(true)

	const handleClose = (color: CardColors) => {
		callback(color)
		setOpened(false)
	}

	return (
		<ThemeProvider theme={theme}>
			<Dialog
				open={opened}
				className={classes.dialog}
				PaperProps={{
					className: classes.dialogPaper,
				}}
			>
				<Grid
					container
					alignItems="center"
					justify="center"
					direction="column"
					className={classes.dialogContainer}
				>
					<Grid
						container
						justify="center"
					>
						<img
							src={chooseColorTextImg}
							alt="Choose a color!"
							className={classes.chooseColorImg}
						/>
					</Grid>

					<Divider orientation="horizontal" size={5} />

					<Grid
						container
						alignItems="center"
						justify="center"
						wrap="wrap"
						className={classes.colorSelectorContainer}
					>
						{Object.entries(coloredButtonMap)
							.map(([colorName, info]) => (
								<Grid
									className={classes.colorSelectorButton}
									component={ButtonBase}
									style={{
										backgroundColor: info?.color,
										border: `8px solid ${info?.borderColor}`,
										boxShadow: `0 0 16px ${info?.color}`,
									}}
									onClick={() => handleClose(colorName as CardColors)}
								/>
							))}
					</Grid>
				</Grid>
			</Dialog>
		</ThemeProvider>
	)
}
Example #13
Source File: SideDrawerField.tsx    From firetable with Apache License 2.0 5 votes vote down vote up
export default function Checkbox({
  column,
  control,
  disabled,
}: ISideDrawerFieldProps) {
  const classes = useStyles();
  const fieldClasses = useFieldStyles();
  const switchClasses = useSwitchStyles();

  return (
    <Controller
      control={control}
      name={column.key}
      render={({ onChange, onBlur, value }) => {
        const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
          onChange(event.target.checked);
        };

        return (
          <ButtonBase
            className={clsx(fieldClasses.root, classes.root)}
            disabled={disabled}
          >
            <FormControlLabel
              control={
                <Switch
                  checked={value}
                  onChange={handleChange}
                  onBlur={onBlur}
                  disabled={disabled}
                  classes={switchClasses}
                />
              }
              label={column.name}
              labelPlacement="start"
              classes={{ root: classes.formControlLabel, label: classes.label }}
            />
          </ButtonBase>
        );
      }}
    />
  );
}
Example #14
Source File: SideDrawerField.tsx    From firetable with Apache License 2.0 5 votes vote down vote up
export default function Color({
  column,
  control,
  disabled,
}: ISideDrawerFieldProps) {
  const classes = useStyles();
  const fieldClasses = useFieldStyles();

  const [showPicker, setShowPicker] = useState(false);
  const toggleOpen = () => setShowPicker((s) => !s);

  return (
    <Controller
      control={control}
      name={column.key}
      render={({ onChange, onBlur, value }) => (
        <>
          <Grid
            container
            alignItems="center"
            spacing={1}
            className={classes.root}
            onClick={() => {
              toggleOpen();
              onBlur();
            }}
            component={ButtonBase}
            focusRipple
            disabled={disabled}
          >
            <Grid item>
              <div
                className={classes.colorIndicator}
                style={{ backgroundColor: value?.hex }}
              />
            </Grid>

            <Grid item xs>
              <Typography
                variant="body1"
                color={value?.hex ? "textPrimary" : "textSecondary"}
              >
                {value?.hex ?? "Choose a color…"}
              </Typography>
            </Grid>
          </Grid>

          <Collapse in={showPicker}>
            <ChromePicker color={value?.rgb} onChangeComplete={onChange} />
          </Collapse>
        </>
      )}
    />
  );
}
Example #15
Source File: InlineCell.tsx    From firetable with Apache License 2.0 5 votes vote down vote up
ConnectTable = React.forwardRef(function ConnectTable(
  { value, showPopoverCell, disabled, column }: IPopoverInlineCellProps,
  ref: React.Ref<any>
) {
  const classes = useStyles();
  const config = column.config ?? {};

  return (
    <ButtonBase
      className={clsx("cell-collapse-padding", classes.root)}
      onClick={() => showPopoverCell(true)}
      ref={ref}
      disabled={disabled}
    >
      <Grid
        container
        wrap="nowrap"
        alignItems="center"
        spacing={1}
        className={classes.value}
      >
        {Array.isArray(value) &&
          value.map((doc: any) => (
            <Grid item key={doc.docPath}>
              <Chip
                label={config.primaryKeys
                  .map((key: string) => doc.snapshot[key])
                  .join(" ")}
                size="small"
                className={classes.chip}
              />
            </Grid>
          ))}
      </Grid>

      <ArrowDropDownIcon
        className={clsx(classes.icon, disabled && classes.disabled)}
      />
    </ButtonBase>
  );
})
Example #16
Source File: InlineCell.tsx    From firetable with Apache License 2.0 5 votes vote down vote up
MultiSelect = React.forwardRef(function MultiSelect(
  { value, showPopoverCell, disabled, onSubmit }: IPopoverInlineCellProps,
  ref: React.Ref<any>
) {
  const classes = useStyles();

  if (typeof value === "string" && value !== "")
    return <ConvertStringToArray value={value} onSubmit={onSubmit} />;

  return (
    <ButtonBase
      className={clsx("cell-collapse-padding", classes.root)}
      onClick={() => showPopoverCell(true)}
      ref={ref}
      disabled={disabled}
    >
      <Grid
        container
        wrap="nowrap"
        alignItems="center"
        spacing={1}
        className={classes.value}
      >
        {sanitiseValue(value).map(
          (item) =>
            typeof item === "string" && (
              <Grid item key={item}>
                <FormattedChip
                  label={item}
                  classes={{ root: classes.chip, label: classes.chipLabel }}
                />
              </Grid>
            )
        )}
      </Grid>

      <ArrowDropDownIcon
        className={clsx(classes.icon, disabled && classes.disabled)}
      />
    </ButtonBase>
  );
})
Example #17
Source File: SideDrawerField.tsx    From firetable with Apache License 2.0 4 votes vote down vote up
function ControlledImageUploader({
  onChange,
  value,
  column,
  docRef,
  disabled,
}) {
  const classes = useStyles();
  const fieldClasses = useFieldStyles();
  const { updateCell } = useFiretableContext();

  const { requestConfirmation } = useConfirmation();
  const { uploaderState, upload, deleteUpload } = useUploader();
  const { progress } = uploaderState;

  // Store a preview image locally while uploading
  const [localImage, setLocalImage] = useState<string>("");

  const onDrop = useCallback(
    (acceptedFiles) => {
      const imageFile = acceptedFiles[0];

      if (docRef && imageFile) {
        upload({
          docRef,
          fieldName: column.key,
          files: [imageFile],
          previousValue: value ?? [],
          onComplete: (newValue) => {
            if (updateCell) updateCell(docRef, column.key, newValue);
            onChange(newValue);
            setLocalImage("");
          },
        });
        setLocalImage(URL.createObjectURL(imageFile));
      }
    },
    [docRef, value]
  );

  const handleDelete = (index: number) => {
    const newValue = [...value];
    const toBeDeleted = newValue.splice(index, 1);
    toBeDeleted.length && deleteUpload(toBeDeleted[0]);
    onChange(newValue);
  };

  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    multiple: false,
    accept: IMAGE_MIME_TYPES,
  });

  return (
    <>
      {!disabled && (
        <ButtonBase
          className={clsx(
            fieldClasses.root,
            classes.dropzoneButton,
            isDragActive && classes.dropzoneDragActive
          )}
          {...getRootProps()}
        >
          <input id={`sidedrawer-field-${column.key}`} {...getInputProps()} />
          <AddIcon />
          <Typography variant="body1" color="inherit">
            {isDragActive ? "Drop your image here" : "Upload image"}
          </Typography>
        </ButtonBase>
      )}

      <Grid container spacing={1} className={classes.imagesContainer}>
        {Array.isArray(value) &&
          value.map((image, i) => (
            <Grid item key={image.downloadURL}>
              {disabled ? (
                <Tooltip title="Click to open">
                  <ButtonBase
                    className={classes.img}
                    onClick={() => window.open(image.downloadURL, "_blank")}
                  >
                    <Thumbnail
                      imageUrl={image.downloadURL}
                      size="200x200"
                      objectFit="contain"
                      className={classes.thumbnail}
                    />
                    <Grid
                      container
                      justify="center"
                      alignItems="center"
                      className={clsx(classes.overlay, classes.deleteImgHover)}
                    >
                      {disabled ? <OpenIcon /> : <DeleteIcon color="inherit" />}
                    </Grid>
                  </ButtonBase>
                </Tooltip>
              ) : (
                <Tooltip title="Click to delete">
                  <div>
                    <ButtonBase
                      className={classes.img}
                      onClick={() =>
                        requestConfirmation({
                          title: "Delete Image",
                          body: "Are you sure you want to delete this image?",
                          confirm: "Delete",
                          handleConfirm: () => handleDelete(i),
                        })
                      }
                    >
                      <Thumbnail
                        imageUrl={image.downloadURL}
                        size="200x200"
                        objectFit="contain"
                        className={classes.thumbnail}
                      />
                      <Grid
                        container
                        justify="center"
                        alignItems="center"
                        className={clsx(
                          classes.overlay,
                          classes.deleteImgHover
                        )}
                      >
                        <DeleteIcon color="inherit" />
                      </Grid>
                    </ButtonBase>
                  </div>
                </Tooltip>
              )}
            </Grid>
          ))}

        {localImage && (
          <Grid item>
            <ButtonBase
              className={classes.img}
              style={{ backgroundImage: `url("${localImage}")` }}
            >
              <Grid
                container
                justify="center"
                alignItems="center"
                className={classes.overlay}
              >
                <CircularProgress
                  color="inherit"
                  size={48}
                  variant={progress === 0 ? "indeterminate" : "static"}
                  value={progress}
                />
              </Grid>
            </ButtonBase>
          </Grid>
        )}
      </Grid>
    </>
  );
}
Example #18
Source File: NoteCard.tsx    From vscode-crossnote with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function NoteCard(props: Props) {
  const classes = useStyles(props);
  const note = props.note;
  const [header, setHeader] = useState<string>("");
  const [summary, setSummary] = useState<Summary>(null);
  const [images, setImages] = useState<string[]>([]);
  const { t } = useTranslation();
  const duration = formatDistanceStrict(note.config.modifiedAt, Date.now())
    .replace(/\sseconds?/, "s")
    .replace(/\sminutes?/, "m")
    .replace(/\shours?/, "h")
    .replace(/\sdays?/, "d")
    .replace(/\sweeks?/, "w")
    .replace(/\smonths?/, "mo")
    .replace(/\syears?/, "y");

  const openNote = useCallback(() => {
    if (!note) {
      return;
    }
    const message: Message = {
      action: MessageAction.OpenNote,
      data: note,
    };
    vscode.postMessage(message);
    props.setSelectedNote(note);
  }, [note, props.setSelectedNote]);

  useEffect(() => {
    setHeader(
      (note.config.encryption && note.config.encryption.title) ||
        getHeaderFromMarkdown(note.markdown)
    );
    generateSummaryFromMarkdown(
      note.config.encryption
        ? `? ${t("general/encrypted")}`
        : note.markdown.trim() || t("general/this-note-is-empty")
    )
      .then((summary) => {
        setSummary(summary);

        // render images
        const images = summary.images
          .map((image) => {
            return resolveNoteImageSrc(note, image);
          })
          .filter((x) => x)
          .slice(0, 3); // TODO: Support local image
        setImages(images);
      })
      .catch((error) => {});
  }, [note.markdown, note.config.encryption, t]);

  /*
  useEffect(() => {
    crossnoteContainer.crossnote.getStatus(note).then((status) => {
      setGitStatus(status);
    });
  }, [
    note.markdown,
    note.config.modifiedAt,
    note,
    crossnoteContainer.crossnote,
  ]);
  */

  return (
    <ButtonBase
      className={clsx(
        classes.noteCard,
        props.selectedNote &&
          props.selectedNote.filePath === note.filePath &&
          props.selectedNote.notebookPath === note.notebookPath
          ? classes.selected
          : classes.unselected
      )}
      onClick={openNote}
    >
      <Box className={clsx(classes.leftPanel)}>
        <Tooltip
          title={
            <>
              <p>
                {t("general/created-at") +
                  " " +
                  formatRelative(new Date(note.config.createdAt), new Date())}
              </p>
              <p>
                {t("general/modified-at") +
                  " " +
                  formatRelative(new Date(note.config.modifiedAt), new Date())}
              </p>
            </>
          }
          arrow
        >
          <Typography className={clsx(classes.duration)}>{duration}</Typography>
        </Tooltip>

        {note.config.pinned && <Pin className={clsx(classes.pin)}></Pin>}
      </Box>
      <Box className={clsx(classes.rightPanel)}>
        {header && (
          <Typography
            style={{ fontWeight: "bold" }}
            variant={"body1"}
            className={clsx(classes.header)}
          >
            {header}
          </Typography>
        )}
        {summary && summary.summary.trim().length > 0 && (
          <Typography className={clsx(classes.summary)}>
            {summary && summary.summary}
          </Typography>
        )}
        {images.length > 0 && (
          <Box className={clsx(classes.images)}>
            <Box className={clsx(classes.imagesWrapper)}>
              {images.map((image, offset) => (
                <div
                  key={`${image}-${offset}`}
                  className={clsx(classes.image)}
                  style={{
                    backgroundImage: `url(${image})`,
                  }}
                ></div>
              ))}
            </Box>
          </Box>
        )}
        <Typography variant={"caption"} className={clsx(classes.filePath)}>
          {basename(note.filePath).startsWith("unnamed_") ? "" : note.filePath}
        </Typography>
      </Box>
    </ButtonBase>
  );
}
Example #19
Source File: tictactoe.tsx    From Figurify with Apache License 2.0 4 votes vote down vote up
export function TicTacToe(props: {
    size: number,
    onBoardChange: (x: number[][]) => void, onPlayerChange: (x: number) => void
}) {

    // 0 = None
    // 1 = P1
    // 2 = P2
    const [board, setBoard] = useState(Array.from({length: props.size},
        () => Array.from({length: props.size},
            () => 0
        )
    ) as number[][]);

    const [current, setCurrent] = useState(1);

    const [ended, setEnded] = useState(false);

    function winningConditions(): number[][] {
        return props.size === 3 ? [
            [0, 1, 2],
            [3, 4, 5],
            [6, 7, 8],
            [0, 3, 6],
            [1, 4, 7],
            [2, 5, 8],
            [0, 4, 8],
            [2, 4, 6]
        ] : props.size === 4 ? [
            [0, 1, 2, 3],
            [4, 5, 6, 7],
            [8, 9, 10, 11],
            [12, 13, 14, 15],
            [0, 4, 8, 12],
            [1, 5, 9, 13],
            [2, 6, 10, 14],
            [3, 7, 11, 15],
            [0, 5, 10, 15],
            [3, 6, 9, 12]
        ] : [];
    }

    useEffect(() => {
        props.onBoardChange(board);
        props.onPlayerChange(current);

        (() => {
            if (board.flat().filter(x => x === 0).length == 0) setEnded(null);
            let roundWon = false;
            let bo = board.flat();
            for (let i = 0; i < winningConditions().length; i++) {
                const winCondition = winningConditions()[i];
                let a = bo[winCondition[0]];
                let b = bo[winCondition[1]];
                let c = bo[winCondition[2]];
                let d = props.size === 4 ? bo[winCondition[3]] : c;
                if (a === 0 || b === 0 || c === 0 || d == 0) {
                    continue;
                }
                if (a === b && b === c && c == d && d == a) {
                    roundWon = true;
                    break;
                }
            }
            if (roundWon) {
                setEnded(true);
            }
        })();
    }, [board]);

    return <div>
        {
            board.map(
                (x, row) => {
                    let cols = x.map(
                        (y, col) => (
                            <Grid key={col} item>
                                <Tooltip title={"#" + String(props.size * row + col + 1)} arrow={true}>
                                    <ButtonBase
                                        style={{...noBorder, margin: "1vw"}}
                                    >
                                        <Paper
                                            onClick={() => {
                                                if (board[row][col] !== 0 || ended) return;

                                                let k = {...board};

                                                k[row][col] = current;
                                                setBoard(Object.values(k) as unknown as number[][]);

                                                setCurrent(current ^ 3); // 1 -> 2, 2 -> 1
                                            }}
                                            elevation={4}
                                            data-coord={row + ':' + col}
                                            style={{width: "6vw", height: "6vw", padding: "0.25vw"}}
                                        >
                                            <div>
                                                {[
                                                    <Typography variant={"h5"}
                                                                style={{fontSize: "3vw", marginTop: "1.55vw"}}>
                                                        {"#" + String(props.size * row + col + 1)}
                                                    </Typography>,
                                                    <FilterVintageIcon style={{fontSize: "5vw", marginTop: "0.25vw"}}/>,
                                                    <StarsIcon style={{fontSize: "5vw", marginTop: "0.25vw"}}/>
                                                ][y]}
                                            </div>
                                        </Paper>
                                    </ButtonBase>
                                </Tooltip>
                            </Grid>
                        )
                    );
                    return <Grid
                        key={row}
                        container
                        justify="center"
                        //spacing={4}
                    >
                        {cols}
                    </Grid>;
                }
            ) as JSX.Element[]
        }

        <div className="text-center">
            <br/>
            <br/>
            <Typography variant={"h5"}>
                {
                    ended === null ? "Draw!" :
                        ended === true ? <>
                            Player {[
                            " ",
                            <FilterVintageIcon style={{fontSize: "2vw"}}/>,
                            <StarsIcon style={{fontSize: "2vw"}}/>
                        ][current ^ 3]} Won!
                        </> : <>
                            Player {[
                            " ",
                            <FilterVintageIcon style={{fontSize: "2vw"}}/>,
                            <StarsIcon style={{fontSize: "2vw"}}/>
                        ][current]}'s turn
                        </>
                }
                <Tooltip title={"Reset Board"}>
                    <IconButton style={{...noBorder}} onClick={() => {
                        setBoard(Array.from({length: props.size},
                            () => Array.from({length: props.size},
                                () => 0
                            )));
                        setCurrent(1);
                        setEnded(false);
                    }}>
                        <RotateLeftIcon/>
                    </IconButton>
                </Tooltip>
            </Typography>
        </div>
    </div>;
}
Example #20
Source File: ModTableRow.tsx    From ow-mod-manager with MIT License 4 votes vote down vote up
ModTableRow: React.FunctionComponent<Props> = ({ mod }) => {
  const styles = useStyles();
  const theme = useTheme();
  const missingDependencyNames = useRecoilValue(missingDependencyIdsState(mod));
  const isModOutdated = isOutdated(mod);
  const isModBroken = isBroken(mod);
  const addonMods = useRecoilValue(addonModList);
  const [isAddonsExpanded, setIsAddonsExpanded] = useState(false);
  const isAddon = mod.parent && !mod.localVersion;
  const enabledMods = useRecoilValue(enabledModList);
  const forceExpandAddons = useRecoilValue(isFiltering);
  const shouldExpandAddons = forceExpandAddons || isAddonsExpanded;
  const rowRef = useRef<HTMLTableRowElement>(null);
  const isLoading = useRecoilValue(modIsLoadingState(mod.uniqueName));

  useEffect(() => {
    if (!isLoading || !rowRef.current) return;

    rowRef.current.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
      inline: 'nearest',
    });
  }, [isLoading]);

  const addons = useMemo(
    () => addonMods.filter((addon) => addon.parent === mod.uniqueName),
    [addonMods, mod.uniqueName]
  );

  const conflictingMods = useMemo(
    () =>
      mod.conflicts && mod.conflicts.length > 0
        ? enabledMods
            .filter((enabledMod) =>
              mod.conflicts?.includes(enabledMod.uniqueName)
            )
            .map((enabledMod) => enabledMod.name)
        : [],
    [enabledMods, mod.conflicts]
  );

  const isModConflicting = mod.isEnabled && conflictingMods.length > 0;

  const handleExpandClick = () =>
    setIsAddonsExpanded((isExpanded) => !isExpanded);

  const getVersionColor = () => {
    if (isModBroken) {
      return 'default';
    }
    if (isModOutdated) {
      return 'secondary';
    }
    if (isInstalled(mod)) {
      return 'primary';
    }
    return 'default';
  };

  const getVersion = () => {
    if (isInstalled(mod)) {
      return mod.localVersion;
    }
    if (mod.remoteVersion) {
      return mod.remoteVersion;
    }
    return modsText.versionNotAvailable;
  };

  const getClassName = () => {
    let className = styles.tableRow;
    if (isModBroken || isModConflicting) {
      className += ` ${styles.brokenRow}`;
    } else if (isLoading) {
      className += ` ${styles.loading}`;
    } else if (missingDependencyNames.length > 0) {
      className += ` ${styles.missingDependencyRow}`;
    } else if (isAddon) {
      className += ` ${styles.addonRow}`;
    }
    return className;
  };

  const getModText = () => {
    if (isModBroken) {
      return modsText.modLoadError(mod.errors);
    }
    if (missingDependencyNames.length > 0) {
      return modsText.missingDependencyWarning(
        missingDependencyNames.join(', ')
      );
    }
    if (isModConflicting) {
      return modsText.conflictingModWarning(conflictingMods.join(', '));
    }
    return mod.description;
  };

  return (
    <>
      <TableRow className={getClassName()} key={mod.uniqueName} ref={rowRef}>
        <TableCell className={styles.tableCell}>
          <Box display="flex">
            {isAddon && (
              <Box
                bgcolor={theme.palette.background.paper}
                width="8px"
                minWidth="8px"
                marginRight={2}
                marginLeft={1}
                borderRadius="8px"
              />
            )}
            <Box width="100%">
              <Typography variant="subtitle1">
                <Box display="inline-block" mr={2}>
                  {mod.name}
                </Box>
                <Typography className={styles.modAuthor} variant="caption">
                  {' by '}
                  {mod.author}
                </Typography>
                <Typography variant="caption" />
              </Typography>
              <Box
                color={
                  isModBroken || isModConflicting
                    ? theme.palette.secondary.light
                    : theme.palette.text.secondary
                }
              >
                <Typography className={styles.modText} variant="caption">
                  {getModText()}
                </Typography>
              </Box>
              {addons.length > 0 && !forceExpandAddons && (
                <ButtonBase
                  className={styles.addonExpander}
                  onClick={handleExpandClick}
                >
                  <Box
                    display="flex"
                    alignItems="center"
                    borderRadius={theme.shape.borderRadius}
                    maxWidth="100%"
                  >
                    {shouldExpandAddons ? <ExpandLess /> : <ExpandMore />}

                    <Typography variant="caption" noWrap>
                      {addons.length}
                      {' addons available: '}
                      {addons.map((addon) => addon.name).join(', ')}
                    </Typography>
                  </Box>
                </ButtonBase>
              )}
            </Box>
          </Box>
        </TableCell>
        <TableCell className={styles.tableCell} align="right">
          {mod.downloadCount || '-'}
        </TableCell>
        <TableCell className={styles.tableCell}>
          <Chip
            color={getVersionColor()}
            label={getVersion()}
            className={styles.versionChip}
          />
          {!isModBroken && isModOutdated && (
            <div className={styles.outdatedChip}>{modsText.outdated}</div>
          )}
        </TableCell>
        <TableCell className={styles.tableCell}>
          <ModActions mod={mod} />
        </TableCell>
      </TableRow>
      {shouldExpandAddons &&
        addons.map((addon) => (
          <ModTableRow key={addon.uniqueName} mod={addon} />
        ))}
    </>
  );
}
Example #21
Source File: TableCell.tsx    From firetable with Apache License 2.0 4 votes vote down vote up
export default function Image_({
  column,
  row,
  value,
  onSubmit,
  disabled,
}: IHeavyCellProps) {
  const { tableState, updateCell } = useFiretableContext();
  const { requestConfirmation } = useConfirmation();
  const classes = useStyles({ rowHeight: tableState?.config?.rowHeight ?? 44 });

  const { uploaderState, upload, deleteUpload } = useUploader();
  const { progress, isLoading } = uploaderState;

  // Store a preview image locally while uploading
  const [localImage, setLocalImage] = useState<string>("");

  const onDrop = useCallback(
    (acceptedFiles) => {
      const imageFile = acceptedFiles[0];

      if (imageFile) {
        upload({
          docRef: row.ref,
          fieldName: column.key as string,
          files: [imageFile],
          previousValue: value,
          onComplete: (newValue) => {
            if (updateCell) updateCell(row.ref, column.key, newValue);
            setLocalImage("");
          },
        });
        setLocalImage(URL.createObjectURL(imageFile));
      }
    },
    [value]
  );

  const handleDelete = (ref: string) => () => {
    const newValue = [...value];
    const index = _findIndex(newValue, ["ref", ref]);
    const toBeDeleted = newValue.splice(index, 1);
    toBeDeleted.length && deleteUpload(toBeDeleted[0]);
    onSubmit(newValue);
  };

  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    multiple: false,
    accept: IMAGE_MIME_TYPES,
  });

  const dropzoneProps = getRootProps();

  let thumbnailSize = "100x100";
  if (tableState?.config?.rowHeight) {
    if (tableState!.config!.rowHeight! > 50) thumbnailSize = "200x200";
    if (tableState!.config!.rowHeight! > 100) thumbnailSize = "400x400";
  }

  return (
    <Grid
      container
      className={clsx(
        "cell-collapse-padding",
        classes.root,
        isDragActive && classes.dragActive
      )}
      wrap="nowrap"
      alignItems="center"
      spacing={1}
      {...dropzoneProps}
      onClick={undefined}
    >
      <input {...getInputProps()} />

      <Grid item xs className={classes.imglistContainer}>
        <Grid container spacing={1} wrap="nowrap">
          {Array.isArray(value) &&
            value.map((file: FileValue) => (
              <Grid item key={file.downloadURL}>
                {disabled ? (
                  <Tooltip title="Click to open">
                    <ButtonBase
                      className={classes.img}
                      onClick={() => window.open(file.downloadURL, "_blank")}
                    >
                      <Thumbnail
                        imageUrl={file.downloadURL}
                        size={thumbnailSize}
                        objectFit="contain"
                        className={classes.thumbnail}
                      />
                      <Grid
                        container
                        justify="center"
                        alignItems="center"
                        className={classes.deleteImgHover}
                      >
                        {disabled ? (
                          <OpenIcon />
                        ) : (
                          <DeleteIcon color="inherit" />
                        )}
                      </Grid>
                    </ButtonBase>
                  </Tooltip>
                ) : (
                  <Tooltip title="Click to delete">
                    <div>
                      <ButtonBase
                        className={classes.img}
                        onClick={() => {
                          requestConfirmation({
                            title: "Delete Image",
                            body: "Are you sure you want to delete this image?",
                            confirm: "Delete",
                            handleConfirm: handleDelete(file.ref),
                          });
                        }}
                      >
                        <Thumbnail
                          imageUrl={file.downloadURL}
                          size={thumbnailSize}
                          objectFit="contain"
                          className={classes.thumbnail}
                        />
                        <Grid
                          container
                          justify="center"
                          alignItems="center"
                          className={classes.deleteImgHover}
                        >
                          <DeleteIcon color="inherit" />
                        </Grid>
                      </ButtonBase>
                    </div>
                  </Tooltip>
                )}
              </Grid>
            ))}

          {localImage && (
            <Grid item>
              <div
                className={clsx(classes.img, classes.localImgPreview)}
                style={{ backgroundImage: `url("${localImage}")` }}
              />
            </Grid>
          )}
        </Grid>
      </Grid>

      <Grid item className={classes.endButtonContainer}>
        {!isLoading ? (
          !disabled && (
            <IconButton
              size="small"
              className="row-hover-iconButton"
              onClick={(e) => {
                dropzoneProps.onClick!(e);
                e.stopPropagation();
              }}
              color="inherit"
            >
              <AddIcon />
            </IconButton>
          )
        ) : (
          <CircularProgress
            size={24}
            variant={progress === 0 ? "indeterminate" : "static"}
            value={progress}
            thickness={4.6}
            className={classes.circularProgress}
          />
        )}
      </Grid>
    </Grid>
  );
}
Example #22
Source File: Step2NewColumns.tsx    From firetable with Apache License 2.0 4 votes vote down vote up
export default function Step2NewColumns({
  csvData,
  config,
  setConfig,
  isXs,
}: IStepProps) {
  const classes = useStyles();

  const [fieldToEdit, setFieldToEdit] = useState(0);

  const handleChange = (e) => {
    const newColumns = [...config.newColumns];
    newColumns[fieldToEdit].type = e.target.value;

    setConfig((config) => ({ ...config, newColumns }));
  };

  const currentPair = _find(config.pairs, {
    columnKey: config.newColumns[fieldToEdit]?.key,
  });
  const rowData = csvData.rows.map((row) => row[currentPair?.csvKey ?? ""]);

  return (
    <>
      <div>
        <Grid container spacing={2} className={classes.typeSelectRow}>
          <Grid item xs={12} sm={6}>
            <Typography variant="overline" gutterBottom component="h2">
              New Firetable Columns
            </Typography>
            <Divider />

            <FadeList>
              {config.newColumns.map(({ key, name, type }, i) => (
                <li key={key}>
                  <ButtonBase
                    className={classes.buttonBase}
                    onClick={() => setFieldToEdit(i)}
                    aria-label={`Edit column ${key}`}
                    focusRipple
                  >
                    <Column
                      label={name}
                      type={type}
                      active={i === fieldToEdit}
                      secondaryItem={i === fieldToEdit && <ChevronRightIcon />}
                    />
                  </ButtonBase>
                </li>
              ))}
            </FadeList>
          </Grid>
          <Grid item xs={12} sm={6}>
            <Typography
              variant="overline"
              noWrap
              component="h2"
              className={classes.typeHeading}
            >
              Column Type: {config.newColumns[fieldToEdit].name}
            </Typography>

            <FieldsDropdown
              value={config.newColumns[fieldToEdit].type}
              onChange={handleChange}
              hideLabel
              options={SELECTABLE_TYPES}
            />
          </Grid>
        </Grid>
      </div>

      <div>
        <Grid container spacing={3}>
          {!isXs && (
            <Grid item xs={12} sm={6}>
              <Typography variant="overline" gutterBottom component="h2">
                Raw Data
              </Typography>
            </Grid>
          )}
          <Grid item xs={12} sm={6}>
            <Typography variant="overline" gutterBottom component="h2">
              Column Preview
            </Typography>
          </Grid>
        </Grid>

        <Divider className={classes.previewDivider} />

        <Grid container spacing={3}>
          {!isXs && (
            <Grid item xs={12} sm={6}>
              <Column label={config.newColumns[fieldToEdit].key} />
            </Grid>
          )}
          <Grid item xs={12} sm={6}>
            <Column
              label={config.newColumns[fieldToEdit].name}
              type={config.newColumns[fieldToEdit].type}
            />
          </Grid>
        </Grid>

        <FadeList classes={{ list: classes.previewList }}>
          {rowData.slice(0, 20).map((cell, i) => (
            <Grid container key={i} wrap="nowrap">
              {!isXs && (
                <Grid item xs className={classes.cellContainer}>
                  <Cell
                    field={config.newColumns[fieldToEdit].key}
                    value={(JSON.stringify(cell) || "")
                      .replace(/^"/, "")
                      .replace(/"$/, "")}
                    type={FieldType.shortText}
                  />
                </Grid>
              )}

              {!isXs && <Grid item className={classes.previewSpacer} />}

              <Grid item xs className={classes.cellContainer}>
                <Cell
                  field={config.newColumns[fieldToEdit].key}
                  value={
                    config.newColumns[fieldToEdit].type === FieldType.date ||
                    config.newColumns[fieldToEdit].type === FieldType.dateTime
                      ? parseJSON(cell).getTime()
                      : cell
                  }
                  type={config.newColumns[fieldToEdit].type}
                  name={config.newColumns[fieldToEdit].name}
                />
              </Grid>
            </Grid>
          ))}
        </FadeList>
      </div>
    </>
  );
}
Example #23
Source File: SideDrawerField.tsx    From firetable with Apache License 2.0 4 votes vote down vote up
function ControlledFileUploader({
  onChange,

  value,
  column,
  docRef,
  disabled,
}) {
  const classes = useStyles();
  const fieldClasses = useFieldStyles();
  const { updateCell } = useFiretableContext();

  const { uploaderState, upload, deleteUpload } = useUploader();
  const { progress } = uploaderState;

  // Store a preview image locally while uploading
  const [localFile, setLocalFile] = useState<string>("");

  const onDrop = useCallback(
    (acceptedFiles: File[]) => {
      const file = acceptedFiles[0];

      if (docRef && file) {
        upload({
          docRef,
          fieldName: column.key,
          files: [file],
          previousValue: value ?? [],
          onComplete: (newValue) => {
            if (updateCell) updateCell(docRef, column.key, newValue);
            onChange(newValue);
            setLocalFile("");
          },
        });
        setLocalFile(file.name);
      }
    },
    [docRef, value]
  );

  const handleDelete = (index: number) => {
    const newValue = [...value];
    const toBeDeleted = newValue.splice(index, 1);
    toBeDeleted.length && deleteUpload(toBeDeleted[0]);
    onChange(newValue);
  };

  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    multiple: false,
  });

  return (
    <>
      {!disabled && (
        <ButtonBase
          className={clsx(
            fieldClasses.root,
            classes.dropzoneButton,
            isDragActive && classes.dropzoneDragActive
          )}
          {...getRootProps()}
        >
          <input id={`sidedrawer-field-${column.key}`} {...getInputProps()} />
          <UploadIcon />
          <Typography variant="body1" color="textSecondary">
            Upload file
          </Typography>
        </ButtonBase>
      )}

      <Grid container spacing={1} className={classes.chipList}>
        {Array.isArray(value) &&
          value.map((file: FileValue, i) => (
            <Grid item key={file.name} className={classes.chipGridItem}>
              <Tooltip
                title={`File last modified ${format(
                  file.lastModifiedTS,
                  DATE_TIME_FORMAT
                )}`}
              >
                <div>
                  <Confirmation
                    message={{
                      title: "Delete File",
                      body: "Are you sure you want to delete this file?",
                      confirm: "Delete",
                    }}
                    functionName={!disabled ? "onDelete" : ""}
                  >
                    <Chip
                      size="medium"
                      icon={<FileIcon />}
                      label={file.name}
                      onClick={() => window.open(file.downloadURL)}
                      onDelete={!disabled ? () => handleDelete(i) : undefined}
                      className={classes.chip}
                    />
                  </Confirmation>
                </div>
              </Tooltip>
            </Grid>
          ))}

        {localFile && (
          <Grid item className={classes.chipGridItem}>
            <Chip
              size="medium"
              icon={<FileIcon />}
              label={localFile}
              className={classes.chip}
              //onDelete={() => {}}
              deleteIcon={
                <CircularProgress size={20} thickness={4.5} color="inherit" />
              }
            />
          </Grid>
        )}
      </Grid>
    </>
  );
}
Example #24
Source File: Step3Types.tsx    From firetable with Apache License 2.0 4 votes vote down vote up
export default function Step3Types({ config, updateConfig, isXs }: IStepProps) {
  const classes = useStyles();

  const [fieldToEdit, setFieldToEdit] = useState(Object.keys(config)[0]);

  const handleChange = (e) =>
    updateConfig({ [fieldToEdit]: { type: e.target.value } });

  const { tableState } = useFiretableContext();

  return (
    <div>
      <Grid container spacing={2} className={classes.typeSelectRow}>
        <Grid item xs={12} sm={6}>
          <Typography variant="overline" gutterBottom component="h2">
            Firetable Columns
          </Typography>
          <Divider />

          <FadeList>
            {Object.entries(config).map(([field, { name, type }]) => (
              <li key={field}>
                <ButtonBase
                  className={classes.buttonBase}
                  onClick={() => setFieldToEdit(field)}
                  aria-label={`Edit column ${field}`}
                  focusRipple
                >
                  <Column
                    label={name}
                    type={type}
                    active={field === fieldToEdit}
                    secondaryItem={
                      field === fieldToEdit && <ChevronRightIcon />
                    }
                  />
                </ButtonBase>
              </li>
            ))}
          </FadeList>
        </Grid>
        <Grid item xs={12} sm={6}>
          <Typography
            variant="overline"
            noWrap
            component="h2"
            className={classes.typeHeading}
          >
            Column Type: {config[fieldToEdit].name}
          </Typography>

          <FieldsDropdown
            value={config[fieldToEdit].type}
            onChange={handleChange}
            hideLabel
            options={SELECTABLE_TYPES}
          />
        </Grid>
      </Grid>

      <Grid container spacing={3}>
        {!isXs && (
          <Grid item xs={12} sm={6}>
            <Typography variant="overline" gutterBottom component="h2">
              Raw Data
            </Typography>
          </Grid>
        )}
        <Grid item xs={12} sm={6}>
          <Typography variant="overline" gutterBottom component="h2">
            Column Preview
          </Typography>
        </Grid>
      </Grid>

      <Divider className={classes.previewDivider} />

      <Grid container spacing={3}>
        {!isXs && (
          <Grid item xs={12} sm={6}>
            <Column label={fieldToEdit} />
          </Grid>
        )}
        <Grid item xs={12} sm={6}>
          <Column
            label={config[fieldToEdit].name}
            type={config[fieldToEdit].type}
          />
        </Grid>
      </Grid>

      <FadeList classes={{ list: classes.previewList }}>
        {tableState!.rows!.slice(0, 20).map((row) => (
          <Grid container key={row.id} wrap="nowrap">
            {!isXs && (
              <Grid item xs className={classes.cellContainer}>
                <Cell
                  field={fieldToEdit}
                  value={(JSON.stringify(row[fieldToEdit]) || "")
                    .replace(/^"/, "")
                    .replace(/"$/, "")}
                  type={FieldType.shortText}
                />
              </Grid>
            )}

            {!isXs && <Grid item className={classes.previewSpacer} />}

            <Grid item xs className={classes.cellContainer}>
              <Cell
                field={fieldToEdit}
                value={row[fieldToEdit]}
                type={config[fieldToEdit].type}
                name={config[fieldToEdit].name}
              />
            </Grid>
          </Grid>
        ))}
      </FadeList>
    </div>
  );
}
Example #25
Source File: Step2Rename.tsx    From firetable with Apache License 2.0 4 votes vote down vote up
export default function Step2Rename({
  config,
  updateConfig,
  isXs,
}: IStepProps) {
  const classes = useStyles();

  const [fieldToRename, setFieldToRename] = useState("");
  const [renameTextField, setRenameTextField] = useState("");
  const handleRename = () => {
    updateConfig({ [fieldToRename]: { name: renameTextField } });
    setFieldToRename("");
    setRenameTextField("");
  };

  return (
    <div>
      <Grid container spacing={3}>
        {!isXs && (
          <Grid item xs={12} sm={6}>
            <Typography variant="overline" gutterBottom component="h2">
              Field Names
            </Typography>
          </Grid>
        )}
        <Grid item xs={12} sm={6}>
          <Typography variant="overline" gutterBottom component="h2">
            Set Column Names
          </Typography>
        </Grid>
      </Grid>

      <Divider />

      <FadeList>
        {Object.entries(config).map(([field, { name }]) => (
          <Grid container key={field} component="li" wrap="nowrap">
            {!isXs && (
              <Grid item xs>
                <Column label={field} />
              </Grid>
            )}
            {!isXs && <Grid item className={classes.spacer} />}
            <Grid item xs>
              {fieldToRename === field ? (
                <TextField
                  value={renameTextField}
                  onChange={(e) => setRenameTextField(e.target.value)}
                  onKeyDown={(e) => {
                    if (e.key === "Enter") handleRename();
                  }}
                  InputProps={{
                    endAdornment: (
                      <InputAdornment position="end">
                        <IconButton
                          aria-label="Finished fieldToRename"
                          color="primary"
                          className={classes.doneButton}
                          onClick={handleRename}
                        >
                          <DoneIcon />
                        </IconButton>
                      </InputAdornment>
                    ),
                    classes: {
                      root: classes.inputBaseRoot,
                      inputHiddenLabel: classes.inputHiddenLabel,
                    },
                  }}
                  hiddenLabel
                  fullWidth
                  autoFocus
                  classes={{ root: classes.textField }}
                />
              ) : (
                <ButtonBase
                  className={classes.buttonBase}
                  onClick={() => {
                    setFieldToRename(field);
                    setRenameTextField(name);
                  }}
                  aria-label={`Rename column ${field}`}
                  focusRipple
                >
                  <Column label={name} secondaryItem={<EditIcon />} />
                </ButtonBase>
              )}
            </Grid>
          </Grid>
        ))}
      </FadeList>
    </div>
  );
}