Prefer using React memoization instead of mem when using inside React.master
@@ -20,8 +20,7 @@ | |||||
"build-storybook": "build-storybook" | "build-storybook": "build-storybook" | ||||
}, | }, | ||||
"dependencies": { | "dependencies": { | ||||
"mem": "^6.1.0", | |||||
"styled-components": "^5.1.1" | |||||
"mem": "^6.1.0" | |||||
}, | }, | ||||
"peerDependencies": { | "peerDependencies": { | ||||
"react": ">=16" | "react": ">=16" | ||||
@@ -1,40 +1,36 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import * as PropTypes from 'prop-types' | import * as PropTypes from 'prop-types' | ||||
import styled from 'styled-components' | |||||
import keyPropTypes from '../../services/keyPropTypes' | import keyPropTypes from '../../services/keyPropTypes' | ||||
const Base = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'var(--color-accidental-key, currentColor)', | |||||
border: '1px solid', | |||||
boxSizing: 'border-box', | |||||
position: 'relative', | |||||
}) | |||||
const Highlight = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
opacity: 0.75, | |||||
}) | |||||
type Props = PropTypes.InferProps<typeof keyPropTypes> | type Props = PropTypes.InferProps<typeof keyPropTypes> | ||||
const AccidentalKey: React.FC<Props> = ({ keyChannels }) => ( | const AccidentalKey: React.FC<Props> = ({ keyChannels }) => ( | ||||
<Base> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'var(--color-accidental-key, currentColor)', | |||||
border: '1px solid', | |||||
boxSizing: 'border-box', | |||||
position: 'relative', | |||||
}} | |||||
> | |||||
{Array.isArray(keyChannels!) && | {Array.isArray(keyChannels!) && | ||||
keyChannels.map((c) => ( | keyChannels.map((c) => ( | ||||
<Highlight | |||||
<div | |||||
key={c!.channel} | key={c!.channel} | ||||
style={{ | style={{ | ||||
width: '100%', | |||||
height: '100%', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
opacity: 0.75, | |||||
backgroundColor: `var(--color-channel-${c!.channel}, Highlight)`, | backgroundColor: `var(--color-channel-${c!.channel}, Highlight)`, | ||||
}} | }} | ||||
/> | /> | ||||
))} | ))} | ||||
</Base> | |||||
</div> | |||||
) | ) | ||||
AccidentalKey.propTypes = keyPropTypes | AccidentalKey.propTypes = keyPropTypes | ||||
@@ -1,28 +1,11 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import * as PropTypes from 'prop-types' | import * as PropTypes from 'prop-types' | ||||
import styled from 'styled-components' | |||||
import mem from 'mem' | |||||
import isNaturalKeyUnmemoized from '../../services/isNaturalKey' | import isNaturalKeyUnmemoized from '../../services/isNaturalKey' | ||||
import getKeyWidthUnmemoized from '../../services/getKeyWidth' | import getKeyWidthUnmemoized from '../../services/getKeyWidth' | ||||
import getKeyLeftUnmemoized from '../../services/getKeyLeft' | import getKeyLeftUnmemoized from '../../services/getKeyLeft' | ||||
import generateKeys from '../../services/generateKeys' | import generateKeys from '../../services/generateKeys' | ||||
import * as DefaultAccidentalKey from '../AccidentalKey/AccidentalKey' | |||||
import * as DefaultNaturalKey from '../NaturalKey/NaturalKey' | |||||
const Base = styled('div')({ | |||||
position: 'relative', | |||||
backgroundColor: 'currentColor', | |||||
overflow: 'hidden', | |||||
}) | |||||
const Key = styled('div')({ | |||||
position: 'absolute', | |||||
top: 0, | |||||
}) | |||||
const getKeyWidth = mem(getKeyWidthUnmemoized, { cacheKey: (args) => args.join(':') }) | |||||
const getKeyLeft = mem(getKeyLeftUnmemoized, { cacheKey: (args) => args.join(':') }) | |||||
const isNaturalKey = mem(isNaturalKeyUnmemoized) | |||||
import DefaultAccidentalKey from '../AccidentalKey/AccidentalKey' | |||||
import DefaultNaturalKey from '../NaturalKey/NaturalKey' | |||||
export const propTypes = { | export const propTypes = { | ||||
/** | /** | ||||
@@ -97,47 +80,49 @@ const Keyboard: React.FC<Props> = ({ | |||||
}) => { | }) => { | ||||
const [keys, setKeys] = React.useState<number[]>([]) | const [keys, setKeys] = React.useState<number[]>([]) | ||||
const { natural: NaturalKey = DefaultNaturalKey, accidental: AccidentalKey = DefaultAccidentalKey } = keyComponents! | |||||
const getKeyWidth = React.useCallback((k) => getKeyWidthUnmemoized(startKey, endKey)(k), [startKey, endKey]) | |||||
const getKeyLeft = React.useCallback((k) => getKeyLeftUnmemoized(startKey, endKey)(k), [startKey, endKey]) | |||||
const isNaturalKey = React.useCallback((k) => isNaturalKeyUnmemoized(k), []) | |||||
React.useEffect(() => { | React.useEffect(() => { | ||||
setKeys(generateKeys(startKey!, endKey!)) | setKeys(generateKeys(startKey!, endKey!)) | ||||
}, [startKey, endKey]) | }, [startKey, endKey]) | ||||
const { | |||||
natural: NaturalKey = DefaultNaturalKey.default, | |||||
accidental: AccidentalKey = DefaultAccidentalKey.default, | |||||
} = keyComponents! | |||||
return ( | return ( | ||||
<Base | |||||
<div | |||||
style={{ | style={{ | ||||
width: width!, | width: width!, | ||||
height: height!, | height: height!, | ||||
position: 'relative', | |||||
backgroundColor: 'currentColor', | |||||
overflow: 'hidden', | |||||
}} | }} | ||||
role="presentation" | role="presentation" | ||||
> | > | ||||
{keys.map((k) => { | |||||
const isNatural = isNaturalKey(k) | |||||
{keys.map((key) => { | |||||
const isNatural = isNaturalKey(key) | |||||
const Component: any = isNatural ? NaturalKey! : AccidentalKey! | const Component: any = isNatural ? NaturalKey! : AccidentalKey! | ||||
const width = getKeyWidth(startKey!, endKey!)(k) | |||||
const height = isNatural ? 100 : 100 * accidentalKeyLengthRatio! | |||||
const left = getKeyLeft(startKey!, endKey!)(k) | |||||
const currentKeyChannels = Array.isArray(keyChannels!) ? keyChannels.filter((kc) => kc!.key === k) : null | |||||
const currentKeyChannels = Array.isArray(keyChannels!) ? keyChannels.filter((kc) => kc!.key === key) : null | |||||
return ( | return ( | ||||
<Key | |||||
key={k} | |||||
<div | |||||
key={key} | |||||
style={{ | style={{ | ||||
zIndex: isNatural ? 0 : 2, | zIndex: isNatural ? 0 : 2, | ||||
width: width + '%', | |||||
height: height + '%', | |||||
left: left + '%', | |||||
width: getKeyWidth(key) + '%', | |||||
height: (isNatural ? 100 : 100 * accidentalKeyLengthRatio!) + '%', | |||||
left: getKeyLeft(key) + '%', | |||||
position: 'absolute', | |||||
top: 0, | |||||
}} | }} | ||||
> | > | ||||
<Component keyChannels={currentKeyChannels} /> | <Component keyChannels={currentKeyChannels} /> | ||||
</Key> | |||||
</div> | |||||
) | ) | ||||
})} | })} | ||||
</Base> | |||||
</div> | |||||
) | ) | ||||
} | } | ||||
@@ -1,40 +1,36 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import * as PropTypes from 'prop-types' | import * as PropTypes from 'prop-types' | ||||
import styled from 'styled-components' | |||||
import keyPropTypes from '../../services/keyPropTypes' | import keyPropTypes from '../../services/keyPropTypes' | ||||
const Base = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'var(--color-natural-key, white)', | |||||
border: '1px solid', | |||||
boxSizing: 'border-box', | |||||
position: 'relative', | |||||
}) | |||||
const Highlight = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
opacity: 0.75, | |||||
}) | |||||
type Props = PropTypes.InferProps<typeof keyPropTypes> | type Props = PropTypes.InferProps<typeof keyPropTypes> | ||||
const NaturalKey: React.FC<Props> = ({ keyChannels }) => ( | const NaturalKey: React.FC<Props> = ({ keyChannels }) => ( | ||||
<Base> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'var(--color-natural-key, white)', | |||||
border: '1px solid', | |||||
boxSizing: 'border-box', | |||||
position: 'relative', | |||||
}} | |||||
> | |||||
{Array.isArray(keyChannels!) && | {Array.isArray(keyChannels!) && | ||||
keyChannels.map((c) => ( | keyChannels.map((c) => ( | ||||
<Highlight | |||||
<div | |||||
key={c!.channel} | key={c!.channel} | ||||
style={{ | style={{ | ||||
width: '100%', | |||||
height: '100%', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
opacity: 0.75, | |||||
backgroundColor: `var(--color-channel-${c!.channel}, Highlight)`, | backgroundColor: `var(--color-channel-${c!.channel}, Highlight)`, | ||||
}} | }} | ||||
/> | /> | ||||
))} | ))} | ||||
</Base> | |||||
</div> | |||||
) | ) | ||||
NaturalKey.propTypes = keyPropTypes | NaturalKey.propTypes = keyPropTypes | ||||
@@ -1,246 +1,215 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import * as PropTypes from 'prop-types' | import * as PropTypes from 'prop-types' | ||||
import styled from 'styled-components' | |||||
import keyPropTypes from '../../services/keyPropTypes' | import keyPropTypes from '../../services/keyPropTypes' | ||||
const DEFAULT_COLOR = '#35313b' | const DEFAULT_COLOR = '#35313b' | ||||
const LIGHT_COLOR = 'white' | const LIGHT_COLOR = 'white' | ||||
const Base = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
position: 'relative', | |||||
}) | |||||
const B2 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
backgroundColor: `var(--color-accidental-key, ${DEFAULT_COLOR})`, | |||||
maskImage: 'linear-gradient(to bottom, white, rgba(0, 0, 0, 0.9))', | |||||
}) | |||||
const B3 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: `var(--color-accidental-key, ${DEFAULT_COLOR})`, | |||||
}) | |||||
const B4 = styled('div')({ | |||||
width: '100%', | |||||
height: 'calc(4px * var(--size-scale-factor, 1))', | |||||
padding: 'calc(1px * var(--size-scale-factor, 1)) 0 0 0', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
}) | |||||
const B5 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
opacity: '0.12', | |||||
}) | |||||
const B6 = styled('div')({ | |||||
width: 'calc(2px * var(--size-scale-factor, 1))', | |||||
height: 'calc(11px * var(--size-scale-factor, 1))', | |||||
padding: | |||||
'calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) 0', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: 0, | |||||
right: 0, | |||||
}) | |||||
const B7 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
maskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
opacity: '0.4', | |||||
}) | |||||
const B8 = styled('div')({ | |||||
width: 'calc(2px * var(--size-scale-factor, 1))', | |||||
height: '100%', | |||||
padding: | |||||
'calc(10px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) calc(6px * var(--size-scale-factor, 1)) 0', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: 0, | |||||
right: 0, | |||||
}) | |||||
const B9 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
opacity: '0.4', | |||||
borderBottomRightRadius: 'calc(1px * var(--size-scale-factor, 1))', | |||||
}) | |||||
const B10 = styled('div')({ | |||||
width: '100%', | |||||
padding: | |||||
'0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: 0, | |||||
left: 0, | |||||
}) | |||||
const B11 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
borderRadius: | |||||
'calc(4px * var(--size-scale-factor, 1)) calc(4px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
opacity: '0.12', | |||||
}) | |||||
const B12 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
padding: | |||||
'calc(3px * var(--size-scale-factor, 1)) calc(3px * var(--size-scale-factor, 1)) calc(7px * var(--size-scale-factor, 1)) calc(3px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
}) | |||||
const B13 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
maskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
borderRadius: 99999, | |||||
}) | |||||
const B14 = styled('div')({ | |||||
width: '100%', | |||||
height: 'calc(6px * var(--size-scale-factor, 1))', | |||||
padding: | |||||
'0 calc(1px * var(--size-scale-factor, 1)) calc(5px * var(--size-scale-factor, 1)) calc(2px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: 0, | |||||
left: 0, | |||||
}) | |||||
const B15 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
opacity: '0.4', | |||||
}) | |||||
const B16 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
}) | |||||
const B17 = styled('div')({ | |||||
width: '100%', | |||||
height: 'calc(6 / 50 * 100%)', | |||||
padding: '0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: 0, | |||||
left: 0, | |||||
}) | |||||
const B18 = styled('div')({ | |||||
width: '100%', | |||||
height: 'calc(44 / 50 * 100%)', | |||||
padding: 'calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) 0', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
}) | |||||
const B19 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
borderRadius: 'calc(1px * var(--size-scale-factor, 1))', | |||||
boxShadow: '0 0 0 calc(1px * var(--size-scale-factor, 1)) rgba(0, 0, 0, 0.25)', | |||||
}) | |||||
type Props = PropTypes.InferProps<typeof keyPropTypes> | type Props = PropTypes.InferProps<typeof keyPropTypes> | ||||
const StyledAccidentalKey: React.FC<Props> = ({ keyChannels }) => { | const StyledAccidentalKey: React.FC<Props> = ({ keyChannels }) => { | ||||
const hasKeyChannels = Array.isArray(keyChannels!) && keyChannels.length > 0 | const hasKeyChannels = Array.isArray(keyChannels!) && keyChannels.length > 0 | ||||
return ( | return ( | ||||
<Base | |||||
<div | |||||
style={{ | style={{ | ||||
width: '100%', | |||||
height: '100%', | |||||
position: 'relative', | |||||
// @ts-ignore | // @ts-ignore | ||||
'--color-accidental-key': hasKeyChannels ? `var(--color-channel-${keyChannels![0]!.channel})` : undefined, | '--color-accidental-key': hasKeyChannels ? `var(--color-channel-${keyChannels![0]!.channel})` : undefined, | ||||
}} | }} | ||||
> | > | ||||
<B19 /> | |||||
<B16 /> | |||||
<B17> | |||||
<B2 | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
borderRadius: 'calc(1px * var(--size-scale-factor, 1))', | |||||
boxShadow: '0 0 0 calc(1px * var(--size-scale-factor, 1)) rgba(0, 0, 0, 0.25)', | |||||
}} | |||||
/> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
}} | |||||
/> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: 'calc(6 / 50 * 100%)', | |||||
padding: '0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: 0, | |||||
left: 0, | |||||
}} | |||||
> | |||||
<div | |||||
style={{ | style={{ | ||||
width: '100%', | |||||
height: '100%', | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
backgroundColor: `var(--color-accidental-key, ${DEFAULT_COLOR})`, | |||||
maskImage: 'linear-gradient(to bottom, white, rgba(0, 0, 0, 0.9))', | |||||
WebkitMaskImage: 'linear-gradient(to bottom, white, rgba(0, 0, 0, 0.9))', | |||||
opacity: hasKeyChannels ? 0.75 : '1', | opacity: hasKeyChannels ? 0.75 : '1', | ||||
}} | }} | ||||
/> | /> | ||||
</B17> | |||||
<B18> | |||||
<B3 | |||||
</div> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: 'calc(44 / 50 * 100%)', | |||||
padding: 'calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) 0', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
}} | |||||
> | |||||
<div | |||||
style={{ | style={{ | ||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: `var(--color-accidental-key, ${DEFAULT_COLOR})`, | |||||
opacity: hasKeyChannels ? 0.75 : '1', | opacity: hasKeyChannels ? 0.75 : '1', | ||||
}} | }} | ||||
/> | /> | ||||
</B18> | |||||
<B4> | |||||
<B5 /> | |||||
</B4> | |||||
<B6 | |||||
</div> | |||||
<div | |||||
style={{ | style={{ | ||||
width: '100%', | |||||
height: 'calc(4px * var(--size-scale-factor, 1))', | |||||
padding: 'calc(1px * var(--size-scale-factor, 1)) 0 0 0', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
}} | |||||
> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
opacity: '0.12', | |||||
}} | |||||
/> | |||||
</div> | |||||
<div | |||||
style={{ | |||||
width: 'calc(2px * var(--size-scale-factor, 1))', | |||||
height: 'calc(11px * var(--size-scale-factor, 1))', | |||||
padding: | |||||
'calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) 0', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: 0, | |||||
right: 0, | |||||
opacity: hasKeyChannels ? 0.5 : '1', | opacity: hasKeyChannels ? 0.5 : '1', | ||||
}} | }} | ||||
> | > | ||||
<B7 /> | |||||
</B6> | |||||
<B8 | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
maskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
WebkitMaskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
opacity: '0.4', | |||||
}} | |||||
/> | |||||
</div> | |||||
<div | |||||
style={{ | style={{ | ||||
width: 'calc(2px * var(--size-scale-factor, 1))', | |||||
height: '100%', | |||||
padding: | |||||
'calc(10px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) calc(6px * var(--size-scale-factor, 1)) 0', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: 0, | |||||
right: 0, | |||||
paddingBottom: hasKeyChannels | paddingBottom: hasKeyChannels | ||||
? 'calc(3px * var(--size-scale-factor, 1))' | ? 'calc(3px * var(--size-scale-factor, 1))' | ||||
: 'calc(5px * var(--size-scale-factor, 1))', | : 'calc(5px * var(--size-scale-factor, 1))', | ||||
opacity: hasKeyChannels ? 0.5 : '1', | opacity: hasKeyChannels ? 0.5 : '1', | ||||
}} | }} | ||||
> | > | ||||
<B9 /> | |||||
</B8> | |||||
<B10 | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
opacity: '0.4', | |||||
borderBottomRightRadius: 'calc(1px * var(--size-scale-factor, 1))', | |||||
}} | |||||
/> | |||||
</div> | |||||
<div | |||||
style={{ | style={{ | ||||
width: '100%', | |||||
padding: | |||||
'0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: 0, | |||||
left: 0, | |||||
opacity: hasKeyChannels ? 3 : '4', | opacity: hasKeyChannels ? 3 : '4', | ||||
}} | }} | ||||
> | > | ||||
<B11 /> | |||||
</B10> | |||||
<B12> | |||||
<B13 | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
borderRadius: | |||||
'calc(4px * var(--size-scale-factor, 1)) calc(4px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
opacity: '0.12', | |||||
}} | |||||
/> | |||||
</div> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
padding: | |||||
'calc(3px * var(--size-scale-factor, 1)) calc(3px * var(--size-scale-factor, 1)) calc(7px * var(--size-scale-factor, 1)) calc(3px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: 0, | |||||
left: 0, | |||||
}} | |||||
> | |||||
<div | |||||
style={{ | style={{ | ||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
maskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
WebkitMaskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
borderRadius: 99999, | |||||
opacity: hasKeyChannels ? 0.06 : '0.12', | opacity: hasKeyChannels ? 0.06 : '0.12', | ||||
}} | }} | ||||
/> | /> | ||||
</B12> | |||||
<B14 | |||||
</div> | |||||
<div | |||||
style={{ | style={{ | ||||
width: '100%', | |||||
padding: | |||||
'0 calc(1px * var(--size-scale-factor, 1)) calc(5px * var(--size-scale-factor, 1)) calc(2px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: 0, | |||||
left: 0, | |||||
height: hasKeyChannels | height: hasKeyChannels | ||||
? 'calc(4px * var(--size-scale-factor, 1))' | ? 'calc(4px * var(--size-scale-factor, 1))' | ||||
: 'calc(6px * var(--size-scale-factor, 1))', | : 'calc(6px * var(--size-scale-factor, 1))', | ||||
@@ -250,9 +219,17 @@ const StyledAccidentalKey: React.FC<Props> = ({ keyChannels }) => { | |||||
opacity: hasKeyChannels ? 0.5 : '1', | opacity: hasKeyChannels ? 0.5 : '1', | ||||
}} | }} | ||||
> | > | ||||
<B15 /> | |||||
</B14> | |||||
</Base> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
opacity: '0.4', | |||||
}} | |||||
/> | |||||
</div> | |||||
</div> | |||||
) | ) | ||||
} | } | ||||
@@ -1,210 +1,199 @@ | |||||
import * as React from 'react' | import * as React from 'react' | ||||
import * as PropTypes from 'prop-types' | import * as PropTypes from 'prop-types' | ||||
import styled from 'styled-components' | |||||
import keyPropTypes from '../../services/keyPropTypes' | import keyPropTypes from '../../services/keyPropTypes' | ||||
const DEFAULT_COLOR = '#e3e3e5' | const DEFAULT_COLOR = '#e3e3e5' | ||||
const LIGHT_COLOR = 'white' | const LIGHT_COLOR = 'white' | ||||
const Base = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
position: 'relative', | |||||
}) | |||||
const N1 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
position: 'relative', | |||||
}) | |||||
const N2 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
position: 'absolute', | |||||
top: '0', | |||||
left: '0', | |||||
}) | |||||
const N3 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
padding: | |||||
'calc(1px * var(--size-scale-factor, 1)) 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: '0', | |||||
left: '0', | |||||
}) | |||||
const N4 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: `var(--color-natural-key, ${DEFAULT_COLOR})`, | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
}) | |||||
const N5 = styled('div')({ | |||||
width: '100%', | |||||
height: 'calc(33 / 80 * 100%)', | |||||
padding: | |||||
'0 calc(1px * var(--size-scale-factor, 1)) calc(2px * var(--size-scale-factor, 1)) calc(2px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
backgroundClip: 'content-box', | |||||
position: 'absolute', | |||||
bottom: '0', | |||||
left: '0', | |||||
opacity: '0.25', | |||||
maskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
}) | |||||
const N6 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
padding: | |||||
'calc(1px * var(--size-scale-factor, 1)) calc(2px * var(--size-scale-factor, 1)) calc(3px * var(--size-scale-factor, 1)) calc(3px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
backgroundClip: 'content-box', | |||||
position: 'absolute', | |||||
bottom: '0', | |||||
left: '0', | |||||
opacity: '0.08', | |||||
maskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
}) | |||||
const N7 = styled('div')({ | |||||
width: '100%', | |||||
height: 'calc(2px * var(--size-scale-factor, 1))', | |||||
padding: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: '0', | |||||
left: '0', | |||||
}) | |||||
const N8 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
opacity: '0.25', | |||||
}) | |||||
const N9 = styled('div')({ | |||||
width: 'calc(2px * var(--size-scale-factor, 1))', | |||||
height: '100%', | |||||
padding: | |||||
'calc(1px * var(--size-scale-factor, 1)) 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: '0', | |||||
left: '0', | |||||
}) | |||||
const N10 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
borderRadius: '0 0 0 calc(1px * var(--size-scale-factor, 1))', | |||||
opacity: '0.07', | |||||
}) | |||||
const N11 = styled('div')({ | |||||
width: '100%', | |||||
height: 'calc(6px * var(--size-scale-factor, 1))', | |||||
padding: 'calc(1px * var(--size-scale-factor, 1)) 0 0 calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: '0', | |||||
left: '0', | |||||
}) | |||||
const N12 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
maskImage: 'linear-gradient(to bottom, white, transparent)', | |||||
opacity: '0.12', | |||||
}) | |||||
const N13 = styled('div')({ | |||||
width: '100%', | |||||
padding: 'calc(1px * var(--size-scale-factor, 1)) 0 0 calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: '0', | |||||
left: '0', | |||||
}) | |||||
const N14 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
opacity: '0.12', | |||||
}) | |||||
const N15 = styled('div')({ | |||||
width: 'calc(1px * var(--size-scale-factor, 1))', | |||||
height: '100%', | |||||
padding: 'calc(1px * var(--size-scale-factor, 1)) 0 calc(1px * var(--size-scale-factor, 1)) 0', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: '0', | |||||
right: '0', | |||||
}) | |||||
const N16 = styled('div')({ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) 0', | |||||
opacity: '0.12', | |||||
}) | |||||
type Props = PropTypes.InferProps<typeof keyPropTypes> | type Props = PropTypes.InferProps<typeof keyPropTypes> | ||||
const StyledNaturalKey: React.FC<Props> = ({ keyChannels }) => { | const StyledNaturalKey: React.FC<Props> = ({ keyChannels }) => { | ||||
const hasKeyChannels = Array.isArray(keyChannels!) && keyChannels.length > 0 | const hasKeyChannels = Array.isArray(keyChannels!) && keyChannels.length > 0 | ||||
return ( | return ( | ||||
<Base | |||||
<div | |||||
style={{ | style={{ | ||||
width: '100%', | |||||
height: '100%', | |||||
position: 'relative', | |||||
// @ts-ignore | // @ts-ignore | ||||
'--color-natural-key': hasKeyChannels ? `var(--color-channel-${keyChannels![0]!.channel})` : undefined, | '--color-natural-key': hasKeyChannels ? `var(--color-channel-${keyChannels![0]!.channel})` : undefined, | ||||
}} | }} | ||||
> | > | ||||
<N1> | |||||
<N2 /> | |||||
<N3> | |||||
<N4 | |||||
style={{ | |||||
opacity: hasKeyChannels ? 0.75 : 1, | |||||
}} | |||||
/> | |||||
</N3> | |||||
<N5 | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
position: 'absolute', | |||||
top: '0', | |||||
left: '0', | |||||
}} | |||||
/> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
padding: | |||||
'calc(1px * var(--size-scale-factor, 1)) 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: '0', | |||||
left: '0', | |||||
}} | |||||
> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: `var(--color-natural-key, ${DEFAULT_COLOR})`, | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
opacity: hasKeyChannels ? 0.75 : 1, | |||||
}} | |||||
/> | |||||
</div> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: 'calc(33 / 80 * 100%)', | |||||
padding: | |||||
'0 calc(1px * var(--size-scale-factor, 1)) calc(2px * var(--size-scale-factor, 1)) calc(2px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
backgroundClip: 'content-box', | |||||
position: 'absolute', | |||||
bottom: '0', | |||||
left: '0', | |||||
maskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
WebkitMaskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
backgroundColor: hasKeyChannels ? 'black' : LIGHT_COLOR, | |||||
opacity: hasKeyChannels ? 0.12 : 0.25, | |||||
}} | |||||
/> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
padding: | |||||
'calc(1px * var(--size-scale-factor, 1)) calc(2px * var(--size-scale-factor, 1)) calc(3px * var(--size-scale-factor, 1)) calc(3px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
backgroundClip: 'content-box', | |||||
position: 'absolute', | |||||
bottom: '0', | |||||
left: '0', | |||||
opacity: '0.08', | |||||
maskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
WebkitMaskImage: 'linear-gradient(to bottom, transparent, white)', | |||||
}} | |||||
/> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: 'calc(2px * var(--size-scale-factor, 1))', | |||||
padding: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: '0', | |||||
left: '0', | |||||
}} | |||||
> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
opacity: '0.25', | |||||
}} | |||||
/> | |||||
</div> | |||||
<div | |||||
style={{ | |||||
width: 'calc(2px * var(--size-scale-factor, 1))', | |||||
height: '100%', | |||||
padding: | |||||
'calc(1px * var(--size-scale-factor, 1)) 0 calc(1px * var(--size-scale-factor, 1)) calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: '0', | |||||
left: '0', | |||||
}} | |||||
> | |||||
<div | |||||
style={{ | style={{ | ||||
backgroundColor: hasKeyChannels ? 'black' : LIGHT_COLOR, | |||||
opacity: hasKeyChannels ? 0.12 : 0.25, | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
borderRadius: '0 0 0 calc(1px * var(--size-scale-factor, 1))', | |||||
opacity: '0.07', | |||||
}} | }} | ||||
/> | /> | ||||
<N6 /> | |||||
<N7> | |||||
<N8 /> | |||||
</N7> | |||||
<N9> | |||||
<N10 /> | |||||
</N9> | |||||
<N11> | |||||
<N12 /> | |||||
</N11> | |||||
<N13 | |||||
</div> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: 'calc(6px * var(--size-scale-factor, 1))', | |||||
padding: 'calc(1px * var(--size-scale-factor, 1)) 0 0 calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: '0', | |||||
left: '0', | |||||
}} | |||||
> | |||||
<div | |||||
style={{ | style={{ | ||||
height: hasKeyChannels | |||||
? 'calc(4px * var(--size-scale-factor, 1))' | |||||
: 'calc(3px * var(--size-scale-factor, 1))', | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
maskImage: 'linear-gradient(to bottom, white, transparent)', | |||||
WebkitMaskImage: 'linear-gradient(to bottom, white, transparent)', | |||||
opacity: '0.12', | |||||
}} | }} | ||||
> | |||||
<N14 /> | |||||
</N13> | |||||
<N15> | |||||
<N16 /> | |||||
</N15> | |||||
</N1> | |||||
</Base> | |||||
/> | |||||
</div> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
padding: 'calc(1px * var(--size-scale-factor, 1)) 0 0 calc(1px * var(--size-scale-factor, 1))', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
top: '0', | |||||
left: '0', | |||||
height: hasKeyChannels | |||||
? 'calc(4px * var(--size-scale-factor, 1))' | |||||
: 'calc(3px * var(--size-scale-factor, 1))', | |||||
}} | |||||
> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: 'black', | |||||
opacity: '0.12', | |||||
}} | |||||
/> | |||||
</div> | |||||
<div | |||||
style={{ | |||||
width: 'calc(1px * var(--size-scale-factor, 1))', | |||||
height: '100%', | |||||
padding: 'calc(1px * var(--size-scale-factor, 1)) 0 calc(1px * var(--size-scale-factor, 1)) 0', | |||||
boxSizing: 'border-box', | |||||
position: 'absolute', | |||||
bottom: '0', | |||||
right: '0', | |||||
}} | |||||
> | |||||
<div | |||||
style={{ | |||||
width: '100%', | |||||
height: '100%', | |||||
backgroundColor: LIGHT_COLOR, | |||||
borderRadius: '0 0 calc(1px * var(--size-scale-factor, 1)) 0', | |||||
opacity: '0.12', | |||||
}} | |||||
/> | |||||
</div> | |||||
</div> | |||||
) | ) | ||||
} | } | ||||
@@ -9,7 +9,7 @@ const getOctaveCount = mem(getOctaveCountUnmemoized, { cacheKey: (args) => args. | |||||
const getFractionalOctaveCount = mem(getFractionalOctaveCountUnmemoized, { cacheKey: (args) => args.join(':') }) | const getFractionalOctaveCount = mem(getFractionalOctaveCountUnmemoized, { cacheKey: (args) => args.join(':') }) | ||||
const getKeyOctave = mem(getKeyOctaveUnmemoized) | const getKeyOctave = mem(getKeyOctaveUnmemoized) | ||||
interface GetKeyLeft { | |||||
export interface GetKeyLeft { | |||||
(k: number): number | (k: number): number | ||||
} | } | ||||
@@ -4,7 +4,7 @@ import getOctaveCountUnmemoized from './getOctaveCount' | |||||
import getFractionalOctaveCountUnmemoized from './getFractionalOctaveCount' | import getFractionalOctaveCountUnmemoized from './getFractionalOctaveCount' | ||||
import { ACCIDENTAL_KEY_TO_NATURAL_KEY_WIDTH_RATIO } from './constants' | import { ACCIDENTAL_KEY_TO_NATURAL_KEY_WIDTH_RATIO } from './constants' | ||||
interface GetKeyWidth { | |||||
export interface GetKeyWidth { | |||||
(k: number): number | (k: number): number | ||||
} | } | ||||