pretty big changes: added highlighted keys refactored Octave component to use a PianoKeyComponent and updated TS types to enums
This commit is contained in:
@@ -4,11 +4,10 @@ import {
|
||||
NoteNameBehavior,
|
||||
octaveKeys,
|
||||
Accidental,
|
||||
HighlightedKey,
|
||||
} from "../../models/Piano";
|
||||
import { Box, Row, Pressable, ZStack, Text } from "native-base";
|
||||
|
||||
const notesList: Array<Note> = ["C", "D", "E", "F", "G", "A", "B"];
|
||||
const accidentalsList: Array<Accidental> = ["#", "b", "##", "bb"];
|
||||
import { Box, Row, Pressable, Text } from "native-base";
|
||||
import PianoKeyComp from "./PianoKeyComp";
|
||||
|
||||
const getKeyIndex = (n: Note, keys: PianoKey[]) => {
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
@@ -25,14 +24,14 @@ const isNoteVisible = (
|
||||
isHovered: boolean,
|
||||
isHighlighted: boolean
|
||||
) => {
|
||||
if (showNoteNamesPolicy === "always") return true;
|
||||
if (showNoteNamesPolicy === "never") return false;
|
||||
if (showNoteNamesPolicy === NoteNameBehavior.always) return true;
|
||||
if (showNoteNamesPolicy === NoteNameBehavior.never) return false;
|
||||
|
||||
if (showNoteNamesPolicy === "onpress") {
|
||||
if (showNoteNamesPolicy === NoteNameBehavior.onpress) {
|
||||
return isPressed;
|
||||
} else if (showNoteNamesPolicy === "onhover") {
|
||||
} else if (showNoteNamesPolicy === NoteNameBehavior.onhover) {
|
||||
return isHovered;
|
||||
} else if (showNoteNamesPolicy === "onhighlight") {
|
||||
} else if (showNoteNamesPolicy === NoteNameBehavior.onhighlight) {
|
||||
return isHighlighted;
|
||||
}
|
||||
return false;
|
||||
@@ -44,13 +43,36 @@ type OctaveProps = Parameters<typeof Box>[0] & {
|
||||
endNote: Note;
|
||||
showNoteNames: NoteNameBehavior;
|
||||
showOctaveNumber: boolean;
|
||||
whiteKeyBg: string;
|
||||
whiteKeyBgPressed: string;
|
||||
whiteKeyBgHovered: string;
|
||||
blackKeyBg: string;
|
||||
blackKeyBgPressed: string;
|
||||
blackKeyBgHovered: string;
|
||||
highlightedNotes: Array<HighlightedKey>;
|
||||
defaultHighlightColor: string;
|
||||
onNoteDown: (note: PianoKey) => void;
|
||||
onNoteUp: (note: PianoKey) => void;
|
||||
};
|
||||
|
||||
const Octave = (props: OctaveProps) => {
|
||||
const { number, startNote, endNote, showNoteNames, showOctaveNumber, onNoteDown, onNoteUp } =
|
||||
props;
|
||||
const {
|
||||
number,
|
||||
startNote,
|
||||
endNote,
|
||||
showNoteNames,
|
||||
showOctaveNumber,
|
||||
whiteKeyBg,
|
||||
whiteKeyBgPressed,
|
||||
whiteKeyBgHovered,
|
||||
blackKeyBg,
|
||||
blackKeyBgPressed,
|
||||
blackKeyBgHovered,
|
||||
highlightedNotes,
|
||||
defaultHighlightColor,
|
||||
onNoteDown,
|
||||
onNoteUp,
|
||||
} = props;
|
||||
const oK: PianoKey[] = octaveKeys.map((k) => {
|
||||
return new PianoKey(k.note, k.accidental, number);
|
||||
});
|
||||
@@ -71,102 +93,61 @@ const Octave = (props: OctaveProps) => {
|
||||
<Box {...props}>
|
||||
<Row height={"100%"} width={"100%"}>
|
||||
{whiteKeys.map((key, i) => {
|
||||
const highlightedKey = highlightedNotes.find(
|
||||
(h) =>
|
||||
h.key.note === key.note && h.key.accidental === key.accidental
|
||||
);
|
||||
const isHighlighted = highlightedKey !== undefined;
|
||||
const highlightColor =
|
||||
highlightedKey?.bgColor ?? defaultHighlightColor;
|
||||
return (
|
||||
<Pressable
|
||||
width={whiteKeyWidthExpr}
|
||||
height={whiteKeyHeightExpr}
|
||||
key={i}
|
||||
onPressIn={() => onNoteDown(key)}
|
||||
onPressOut={() => onNoteUp(key)}
|
||||
>
|
||||
{({ isHovered, isPressed }) => (
|
||||
<Box
|
||||
bg={
|
||||
isHovered ? (isPressed ? "gray.300" : "gray.100") : "white"
|
||||
}
|
||||
w="100%"
|
||||
h="100%"
|
||||
borderWidth="1px"
|
||||
borderColor="black"
|
||||
justifyContent="flex-end"
|
||||
alignItems="center"
|
||||
>
|
||||
{isNoteVisible(
|
||||
showNoteNames,
|
||||
isPressed,
|
||||
isHovered,
|
||||
false
|
||||
) && (
|
||||
<Text
|
||||
style={{
|
||||
userSelect: "none",
|
||||
WebkitUserSelect: "none",
|
||||
MozUserSelect: "none",
|
||||
msUserSelect: "none",
|
||||
}}
|
||||
fontSize="xl"
|
||||
>
|
||||
{key.note}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</Pressable>
|
||||
<PianoKeyComp
|
||||
key={i}
|
||||
pianoKey={key}
|
||||
bg={isHighlighted ? highlightColor :whiteKeyBg}
|
||||
bgPressed={isHighlighted ? highlightColor : whiteKeyBgPressed}
|
||||
bgHovered={isHighlighted ? highlightColor : whiteKeyBgHovered}
|
||||
onKeyDown={() => onNoteDown(key)}
|
||||
onKeyUp={() => onNoteUp(key)}
|
||||
style={{
|
||||
width: whiteKeyWidthExpr,
|
||||
height: whiteKeyHeightExpr,
|
||||
}}
|
||||
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{blackKeys.map((key, i) => {
|
||||
const highlightedKey = highlightedNotes.find(
|
||||
(h) =>
|
||||
h.key.note === key.note && h.key.accidental === key.accidental
|
||||
);
|
||||
const isHighlighted = highlightedKey !== undefined;
|
||||
const highlightColor =
|
||||
highlightedKey?.bgColor ?? defaultHighlightColor;
|
||||
return (
|
||||
<Pressable
|
||||
<PianoKeyComp
|
||||
key={i}
|
||||
onPressIn={() => onNoteDown(key)}
|
||||
onPressOut={() => onNoteUp(key)}
|
||||
width={blackKeyWidthExpr}
|
||||
height={blackKeyHeightExpr}
|
||||
pianoKey={key}
|
||||
bg={isHighlighted ? highlightColor : blackKeyBg}
|
||||
bgPressed={isHighlighted ? highlightColor : blackKeyBgPressed}
|
||||
bgHovered={isHighlighted ? highlightColor : blackKeyBgHovered}
|
||||
onKeyDown={() => onNoteDown(key)}
|
||||
onKeyUp={() => onNoteUp(key)}
|
||||
style={{
|
||||
width: blackKeyWidthExpr,
|
||||
height: blackKeyHeightExpr,
|
||||
position: "absolute",
|
||||
left: `calc(calc(${whiteKeyWidthExpr} * ${
|
||||
i + ((i > 1) as unknown as number) + 1
|
||||
}) - calc(${blackKeyWidthExpr} / 2))`,
|
||||
top: "0px",
|
||||
}}
|
||||
>
|
||||
{({ isHovered, isPressed }) => (
|
||||
<Box
|
||||
bg={
|
||||
isHovered ? (isPressed ? "gray.700" : "gray.800") : "black"
|
||||
}
|
||||
w="100%"
|
||||
h="100%"
|
||||
borderWidth="1px"
|
||||
borderColor="black"
|
||||
color="white"
|
||||
style={{
|
||||
justifyContent: "flex-end",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
{isNoteVisible(
|
||||
showNoteNames,
|
||||
isPressed,
|
||||
isHovered,
|
||||
false
|
||||
) && (
|
||||
<Text
|
||||
style={{
|
||||
userSelect: "none",
|
||||
WebkitUserSelect: "none",
|
||||
MozUserSelect: "none",
|
||||
msUserSelect: "none",
|
||||
}}
|
||||
fontSize="xs"
|
||||
color="white"
|
||||
>
|
||||
{key.note + key.accidental}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</Pressable>
|
||||
text={{
|
||||
color: "white",
|
||||
fontSize: "xs",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
@@ -195,6 +176,16 @@ const Octave = (props: OctaveProps) => {
|
||||
Octave.defaultProps = {
|
||||
startNote: "C",
|
||||
endNote: "B",
|
||||
showNoteNames: "onpress",
|
||||
showOctaveNumber: false,
|
||||
whiteKeyBg: "white",
|
||||
whiteKeyBgPressed: "gray.200",
|
||||
whiteKeyBgHovered: "gray.100",
|
||||
blackKeyBg: "black",
|
||||
blackKeyBgPressed: "gray.600",
|
||||
blackKeyBgHovered: "gray.700",
|
||||
highlightedNotes: [],
|
||||
defaultHighlightColor: "#FF0000",
|
||||
onNoteDown: () => {},
|
||||
onNoteUp: () => {},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import { Box, Pressable, Text } from "native-base";
|
||||
import { Key } from "react";
|
||||
import { StyleProp, ViewStyle } from "react-native";
|
||||
import {
|
||||
Note,
|
||||
PianoKey,
|
||||
NoteNameBehavior,
|
||||
octaveKeys,
|
||||
Accidental,
|
||||
HighlightedKey,
|
||||
keyToStr,
|
||||
} from "../../models/Piano";
|
||||
|
||||
type PianoKeyProps = {
|
||||
key?: Key;
|
||||
pianoKey: PianoKey;
|
||||
showNoteNames: NoteNameBehavior;
|
||||
bg: string;
|
||||
bgPressed: string;
|
||||
bgHovered: string;
|
||||
onKeyDown: () => void;
|
||||
onKeyUp: () => void;
|
||||
text: Parameters<typeof Text>[0];
|
||||
style: StyleProp<ViewStyle>;
|
||||
};
|
||||
|
||||
const isNoteVisible = (
|
||||
noteNameBehavior: NoteNameBehavior,
|
||||
isPressed: boolean,
|
||||
isHovered: boolean
|
||||
) => {
|
||||
if (noteNameBehavior === NoteNameBehavior.always) return true;
|
||||
if (noteNameBehavior === NoteNameBehavior.never) return false;
|
||||
|
||||
if (noteNameBehavior === NoteNameBehavior.onpress) {
|
||||
return isPressed;
|
||||
} else if (noteNameBehavior === NoteNameBehavior.onhover) {
|
||||
return isHovered;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const PianoKeyComp = ({
|
||||
key,
|
||||
pianoKey,
|
||||
showNoteNames,
|
||||
bg,
|
||||
bgPressed,
|
||||
bgHovered,
|
||||
onKeyDown,
|
||||
onKeyUp,
|
||||
text,
|
||||
style,
|
||||
}: PianoKeyProps) => {
|
||||
const textDefaultProps = {
|
||||
style: {
|
||||
userSelect: "none",
|
||||
WebkitUserSelect: "none",
|
||||
MozUserSelect: "none",
|
||||
msUserSelect: "none",
|
||||
},
|
||||
fontSize: "xl",
|
||||
color: "black",
|
||||
} as Parameters<typeof Text>[0];
|
||||
|
||||
const textProps = { ...textDefaultProps, ...text };
|
||||
return (
|
||||
<Pressable
|
||||
key={key}
|
||||
onPressIn={onKeyDown}
|
||||
onPressOut={onKeyUp}
|
||||
style={style}
|
||||
>
|
||||
{({ isHovered, isPressed }) => (
|
||||
<Box
|
||||
bg={(() => {
|
||||
if (isPressed) return bgPressed;
|
||||
if (isHovered) return bgHovered;
|
||||
return bg;
|
||||
})()}
|
||||
w="100%"
|
||||
h="100%"
|
||||
borderWidth="1px"
|
||||
borderColor="black"
|
||||
justifyContent="flex-end"
|
||||
alignItems="center"
|
||||
>
|
||||
{isNoteVisible(showNoteNames, isPressed, isHovered) && (
|
||||
<Text {...textProps}>{keyToStr(pianoKey)}</Text>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
|
||||
PianoKeyComp.defaultProps = {
|
||||
key: octaveKeys[0],
|
||||
showNoteNames: NoteNameBehavior.onhover,
|
||||
keyBg: "white",
|
||||
keyBgPressed: "gray.200",
|
||||
keyBgHovered: "gray.100",
|
||||
onKeyDown: () => {},
|
||||
onKeyUp: () => {},
|
||||
text: {},
|
||||
style: {},
|
||||
};
|
||||
|
||||
export default PianoKeyComp;
|
||||
@@ -36,7 +36,15 @@ const VirtualPiano = ({
|
||||
keyPressStyle,
|
||||
vividKeyPressColor,
|
||||
}: VirtualPianoProps) => {
|
||||
const notesList: Array<Note> = ["C", "D", "E", "F", "G", "A", "B"];
|
||||
const notesList: Array<Note> = [
|
||||
Note.C,
|
||||
Note.D,
|
||||
Note.E,
|
||||
Note.F,
|
||||
Note.G,
|
||||
Note.A,
|
||||
Note.B,
|
||||
];
|
||||
const octaveList = [];
|
||||
|
||||
for (let octaveNum = startOctave; octaveNum <= endOctave; octaveNum++) {
|
||||
@@ -73,9 +81,9 @@ VirtualPiano.defaultProps = {
|
||||
console.log("Note up: " + n);
|
||||
},
|
||||
startOctave: 2,
|
||||
startNote: "C",
|
||||
startNote: Note.C,
|
||||
endOctave: 2,
|
||||
endNote: "B",
|
||||
endNote: Note.B,
|
||||
showNoteNames: "onhover",
|
||||
highlightedNotes: [],
|
||||
highlightColor: "red",
|
||||
|
||||
Reference in New Issue
Block a user