All files / src/components/music/form DutyCycleSelect.tsx

0% Statements 0/24
0% Branches 0/11
0% Functions 0/8
0% Lines 0/22

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112                                                                                                                                                                                                                               
import React, { FC, useCallback, useMemo } from "react";
import { Select, SelectCommonProps } from "ui/form/Select";
import { SingleValue } from "react-select";
import styled from "styled-components";
 
interface DutyCycleOption {
  value: number;
  label: string;
  width: number;
}
 
interface DutyCycleSelectProps extends SelectCommonProps {
  name: string;
  value?: number;
  onChange?: (newValue: number) => void;
  noneLabel?: string;
  note?: number;
  effectCode?: number;
  effectParam?: number;
  isEffectParam?: boolean;
}
 
const StyledDutyCycleOptionLabel = styled.div`
  display: flex;
  align-items: center;
  span {
    flex-grow: 1;
  }
  svg {
    justify-self: flex-end;
    fill: transparent;
    stroke: ${(props) => props.theme.colors.text};
    opacity: 0.5;
  }
`;
 
const DutyCyclePreview = ({ width }: { width: number }) => {
  const cycleWidth = 40;
  const upWidth = width * cycleWidth;
  const downWidth = cycleWidth - upWidth;
  const path = `M 2 16 v -13 h ${upWidth} v 13 h ${downWidth} v -13 h ${upWidth} v 13 h ${downWidth}`;
  return (
    <svg width={cycleWidth * 2} height={17}>
      <path d={path} />
    </svg>
  );
};
 
export const DutyCycleSelect: FC<DutyCycleSelectProps> = ({
  value,
  onChange,
  isEffectParam,
  ...selectProps
}) => {
  const options: DutyCycleOption[] = useMemo(
    () => [
      {
        value: 0,
        label: "12.5%",
        width: 0.125,
      },
      {
        value: isEffectParam ? 0x40 : 1,
        label: "25%",
        width: 0.25,
      },
      {
        value: isEffectParam ? 0x80 : 2,
        label: "50%",
        width: 0.5,
      },
      {
        value: isEffectParam ? 0xc0 : 3,
        label: "75%",
        width: 0.75,
      },
    ],
    [isEffectParam],
  );
 
  const currentValue = useMemo(
    () => options.find((i) => i.value === value),
    [options, value],
  );
 
  const onSelectChange = (newValue: SingleValue<DutyCycleOption>) => {
    Iif (newValue) {
      onChange?.(newValue.value);
    }
  };
 
  const formatOptionLabel = useCallback(
    (option: DutyCycleOption) => (
      <StyledDutyCycleOptionLabel>
        <span>{option.label}</span>
        <DutyCyclePreview width={option.width} />
      </StyledDutyCycleOptionLabel>
    ),
    [],
  );
 
  return (
    <Select
      value={currentValue}
      options={options}
      onChange={onSelectChange}
      formatOptionLabel={formatOptionLabel}
      {...selectProps}
    />
  );
};