@emotion/react#Interpolation TypeScript Examples
The following examples show how to use
@emotion/react#Interpolation.
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: Button.tsx From tobira with Apache License 2.0 | 5 votes |
css = (kind: Kind, extraCss: Interpolation<Theme> = {}): Interpolation<Theme> => {
const notDisabledStyle = match(kind, {
"normal": () => ({
border: "1px solid var(--grey65)",
color: "black",
"&:hover": {
border: "1px solid var(--grey40)",
backgroundColor: "var(--grey92)",
},
}),
"danger": () => ({
border: "1px solid var(--danger-color)",
color: "var(--danger-color)",
"&:hover": {
border: "1px solid var(--danger-color-darker)",
backgroundColor: "var(--danger-color)",
color: "var(--danger-color-bw-contrast)",
},
}),
"happy": () => ({
border: "1px solid var(--happy-color-dark)",
color: "var(--happy-color-bw-contrast)",
backgroundColor: "var(--happy-color)",
"&:hover": {
border: "1px solid var(--happy-color-dark)",
backgroundColor: "var(--happy-color-darker)",
color: "var(--happy-color-bw-contrast)",
},
}),
});
return {
borderRadius: 4,
display: "inline-flex",
alignItems: "center",
padding: "4px 10px",
gap: 12,
backgroundColor: "var(--grey97)",
transition: "background-color 0.15s, border-color 0.15s",
"& > svg": {
fontSize: 20,
},
"&:disabled": {
border: "1px solid var(--grey80)",
color: "var(--grey65)",
},
"&:focus-visible": {
boxShadow: "0 0 0 3px var(--grey65)",
outline: "none",
},
"&:not([disabled])": {
cursor: "pointer",
...notDisabledStyle,
},
...extraCss as Record<string, unknown>,
};
}
Example #2
Source File: option-chain-control.tsx From utopia with MIT License | 4 votes |
OptionChainControl: React.FunctionComponent<
React.PropsWithChildren<DEPRECATEDControlProps<any>>
> = React.memo(({ style, ...props }) => {
const options = props.options as Array<OptionChainOption<string | number>>
const labelBelow = (props.DEPRECATED_controlOptions as DEPRECATEDGenericControlOptions)
?.labelBelow
if (!Array.isArray(props.options)) {
throw new Error('OptionControl needs an array of `options`')
}
const optionCSS: Interpolation<any> = React.useMemo(() => {
return {
position: 'relative',
// This is the divider in between controls
'&:not(:first-of-type)::after': {
content: '""',
height: 10,
backgroundColor: props.controlStyles.borderColor,
position: 'absolute',
left: 0,
top: 6,
},
}
}, [props.controlStyles.borderColor])
const containerCSS: Interpolation<any> = React.useMemo(() => {
return {
display: 'flex',
flexDirection: 'column',
marginBottom: 0,
width: '100%',
...(style as any), // TODO Emotion and React 18 types don't like each other
}
}, [style])
return (
<div id={props.id} key={props.key} css={containerCSS}>
<div
style={{
display: 'flex',
flexDirection: 'row',
height: UtopiaTheme.layout.inputHeight.default,
width: '100%',
}}
className={`option-chain-control-container ${Utils.pathOr(
'',
['controlClassName'],
props,
)}`}
onContextMenu={props.onContextMenu}
>
{options.map((option: OptionChainOption<number | string>, index) => (
<OptionControl
{...props}
css={optionCSS}
key={'option-' + index}
DEPRECATED_controlOptions={{
tooltip: option.tooltip,
icon: option.icon,
labelInner: option.label,
}}
value={props.value === option.value}
// eslint-disable-next-line react/jsx-no-bind
onSubmitValue={(value: boolean) => {
if (value) {
props.onSubmitValue(option.value)
}
}}
/>
))}
</div>
{labelBelow == null ? null : (
<label
htmlFor={props.id}
onContextMenu={props.onContextMenu}
style={{ fontSize: 10, color: props.controlStyles.mainColor, paddingTop: 2 }}
>
<span className='label-container'>{labelBelow}</span>
</label>
)}
</div>
)
})
Example #3
Source File: number-input.tsx From utopia with MIT License | 4 votes |
NumberInput = React.memo<NumberInputProps>(
({
value: propsValue,
style,
testId,
inputProps = {},
id,
className,
DEPRECATED_labelBelow,
labelInner,
minimum: unscaledMinimum = -Infinity,
maximum: unscaledMaximum = Infinity,
stepSize: unscaledStepSize,
incrementControls = true,
chained = 'not-chained',
height = UtopiaTheme.layout.inputHeight.default,
roundCorners = 'all',
onSubmitValue,
onTransientSubmitValue,
onForcedSubmitValue,
controlStatus = 'simple',
focusOnMount = false,
numberType,
defaultUnitToHide,
setGlobalCursor,
}) => {
const nonNullPropsValue: CSSNumber = propsValue ?? cssNumber(0)
const ref = React.useRef<HTMLInputElement>(null)
const controlStyles = getControlStyles(controlStatus)
const colorTheme = useColorTheme()
const backgroundImage = React.useMemo(
() => `linear-gradient(to right, transparent 0, ${controlStyles.backgroundColor} 6px)`,
[controlStyles],
)
const { showContent } = controlStyles
const [mixed, setMixed] = React.useState<boolean>(controlStyles.mixed)
const [stateValue, setStateValueDirectly, forceStateValueToUpdateFromProps] =
usePropControlledState(
getDisplayValue(propsValue ?? null, defaultUnitToHide, mixed, showContent),
)
const updateStateValue = React.useCallback(
(newValue: CSSNumber) =>
setStateValueDirectly(getDisplayValue(newValue, defaultUnitToHide, false, true)),
[defaultUnitToHide, setStateValueDirectly],
)
const parsedStateValue = parseDisplayValue(stateValue, numberType, defaultUnitToHide)
const parsedStateValueUnit = foldEither(
() => null,
(v) => v.unit,
parsedStateValue,
)
const [isActuallyFocused, setIsActuallyFocused] = React.useState<boolean>(false)
const [isFauxcused, setIsFauxcused] = React.useState<boolean>(false)
const isFocused = isActuallyFocused || isFauxcused
const [labelDragDirection, setLabelDragDirection] =
React.useState<LabelDragDirection>('horizontal')
const [, setValueAtDragOriginState] = React.useState<number>(0)
const valueAtDragOrigin = React.useRef(0)
const setValueAtDragOrigin = (n: number) => {
valueAtDragOrigin.current = n
setValueAtDragOriginState(n)
}
const [, setDragOriginXState] = React.useState<number>(-Infinity)
const dragOriginX = React.useRef(-Infinity)
const setDragOriginX = (n: number) => {
dragOriginX.current = n
setDragOriginXState(n)
}
const [, setDragOriginYState] = React.useState<number>(-Infinity)
const dragOriginY = React.useRef(-Infinity)
const setDragOriginY = (n: number) => {
dragOriginY.current = n
setDragOriginYState(n)
}
const [, setScrubThresholdPassedState] = React.useState<boolean>(false)
const scrubThresholdPassed = React.useRef(false)
const setScrubThresholdPassed = (b: boolean) => {
scrubThresholdPassed.current = b
setScrubThresholdPassedState(b)
}
const [valueChangedSinceFocus, setValueChangedSinceFocus] = React.useState<boolean>(false)
const scaleFactor = parsedStateValueUnit === '%' ? 100 : 1
const minimum = scaleFactor * unscaledMinimum
const maximum = scaleFactor * unscaledMaximum
const stepSize = unscaledStepSize == null ? 1 : unscaledStepSize * scaleFactor
const repeatedValueRef = React.useRef(nonNullPropsValue)
const incrementBy = React.useCallback(
(
currentValue: CSSNumber,
incrementStepSize: number,
shiftKey: boolean,
transient: boolean,
) => {
const delta = incrementStepSize * (shiftKey ? 10 : 1)
const newNumericValue = clampValue(currentValue.value + delta, minimum, maximum)
const newValue = setCSSNumberValue(currentValue, newNumericValue)
if (transient) {
if (onTransientSubmitValue != null) {
onTransientSubmitValue(newValue)
} else if (onSubmitValue != null) {
onSubmitValue(newValue)
}
} else {
if (onForcedSubmitValue != null) {
onForcedSubmitValue(newValue)
} else if (onSubmitValue != null) {
onSubmitValue(newValue)
}
}
updateStateValue(newValue)
repeatedValueRef.current = newValue
return newValue
},
[
updateStateValue,
maximum,
minimum,
onForcedSubmitValue,
onSubmitValue,
onTransientSubmitValue,
],
)
const repeatIncrement = React.useCallback(
(
currentValue: CSSNumber,
incrementStepSize: number,
shiftKey: boolean,
transient: boolean,
) => {
const newValue = incrementBy(currentValue, incrementStepSize, shiftKey, transient)
incrementAnimationFrame = window.requestAnimationFrame(() =>
repeatIncrement(newValue, incrementStepSize, shiftKey, transient),
)
},
[incrementBy],
)
const setScrubValue = React.useCallback(
(
unit: CSSNumberUnit | null,
screenX: number,
screenY: number,
scrubDragOriginX: number,
scrubDragOriginY: number,
transient: boolean,
) => {
const primaryAxisDelta = calculateDragDelta(
scrubDragOriginX,
scrubDragOriginY,
screenX,
screenY,
labelDragDirection,
)
const numericValue = clampValue(
valueAtDragOrigin.current - stepSize * primaryAxisDelta,
minimum,
maximum,
)
const newValue = cssNumber(numericValue, unit)
if (transient) {
if (onTransientSubmitValue != null) {
onTransientSubmitValue(newValue)
} else if (onSubmitValue != null) {
onSubmitValue(newValue)
}
} else {
if (onForcedSubmitValue != null) {
onForcedSubmitValue(newValue)
} else if (onSubmitValue != null) {
onSubmitValue(newValue)
}
}
updateStateValue(newValue)
return newValue
},
[
labelDragDirection,
maximum,
minimum,
stepSize,
onForcedSubmitValue,
onSubmitValue,
onTransientSubmitValue,
updateStateValue,
],
)
React.useEffect(() => {
if (focusOnMount && ref.current != null) {
ref.current.focus()
}
}, [focusOnMount, ref])
const onThresholdPassed = (e: MouseEvent, fn: () => void) => {
const thresholdPassed =
scrubThresholdPassed.current || Math.abs(e.screenX - dragOriginX.current) >= ScrubThreshold
if (thresholdPassed) {
fn()
}
}
const scrubOnMouseMove = React.useCallback(
(e: MouseEvent) => {
onThresholdPassed(e, () => {
if (!scrubThresholdPassed.current) {
setScrubThresholdPassed(true)
}
setScrubValue(
parsedStateValueUnit,
e.screenX,
e.screenY,
dragOriginX.current,
dragOriginY.current,
true,
)
})
},
[setScrubValue, parsedStateValueUnit],
)
const scrubOnMouseUp = React.useCallback(
(e: MouseEvent) => {
window.removeEventListener('mouseup', scrubOnMouseUp)
window.removeEventListener('mousemove', scrubOnMouseMove)
setIsFauxcused(false)
ref.current?.focus()
onThresholdPassed(e, () => {
setScrubValue(
parsedStateValueUnit,
e.screenX,
e.screenY,
dragOriginX.current,
dragOriginY.current,
false,
)
})
setScrubThresholdPassed(false)
setGlobalCursor?.(null)
},
[scrubOnMouseMove, setScrubValue, parsedStateValueUnit, ref, setGlobalCursor],
)
const rc = roundCorners == null ? 'all' : roundCorners
const borderRadiusStyles = getBorderRadiusStyles(chained, rc)
const onFocus = React.useCallback(
(e: React.FocusEvent<HTMLInputElement>) => {
setIsActuallyFocused(true)
e.target.select()
if (inputProps.onFocus != null) {
inputProps.onFocus(e)
}
},
[inputProps],
)
const onKeyDown = React.useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'ArrowUp') {
incrementBy(nonNullPropsValue, stepSize, e.shiftKey, false)
} else if (e.key === 'ArrowDown') {
incrementBy(nonNullPropsValue, -stepSize, e.shiftKey, false)
} else if (e.key === 'Enter' || e.key === 'Escape') {
e.nativeEvent.stopImmediatePropagation()
e.preventDefault()
ref.current?.blur()
}
},
[incrementBy, nonNullPropsValue, stepSize, ref],
)
const onKeyUp = React.useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
// todo make sure this isn't doubling up the value submit
if ((e.key === 'ArrowUp' || e.key === 'ArrowDown') && onForcedSubmitValue != null) {
onForcedSubmitValue(nonNullPropsValue)
}
},
[onForcedSubmitValue, nonNullPropsValue],
)
const onBlur = React.useCallback(
(e: React.FocusEvent<HTMLInputElement>) => {
setIsActuallyFocused(false)
if (inputProps.onBlur != null) {
inputProps.onBlur(e)
}
if (valueChangedSinceFocus) {
setValueChangedSinceFocus(false)
if (onSubmitValue != null) {
if (stateValue === '') {
onSubmitValue(emptyInputValue())
forceStateValueToUpdateFromProps()
} else if (isRight(parsedStateValue)) {
onSubmitValue(parsedStateValue.value)
} else {
onSubmitValue(unknownInputValue(stateValue))
forceStateValueToUpdateFromProps()
}
}
}
},
[
inputProps,
onSubmitValue,
stateValue,
parsedStateValue,
valueChangedSinceFocus,
forceStateValueToUpdateFromProps,
],
)
const onChange = React.useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value
if (inputProps.onChange != null) {
inputProps.onChange(e)
}
setValueChangedSinceFocus(true)
setMixed(false)
setStateValueDirectly(value)
},
[inputProps, setStateValueDirectly],
)
const onIncrementMouseUp = React.useCallback(() => {
window.removeEventListener('mouseup', onIncrementMouseUp)
setIsFauxcused(false)
ref.current?.focus()
if (incrementTimeout != null) {
window.clearTimeout(incrementTimeout)
incrementTimeout = undefined
}
if (incrementAnimationFrame != null) {
window.cancelAnimationFrame(incrementAnimationFrame ?? 0)
incrementAnimationFrame = undefined
}
// Clear transient state by setting the final value
if (onSubmitValue != null) {
onSubmitValue(repeatedValueRef.current)
}
updateStateValue(repeatedValueRef.current)
}, [ref, onSubmitValue, updateStateValue])
const onIncrementMouseDown = React.useCallback(
(e: React.MouseEvent) => {
if (e.button === 0) {
e.stopPropagation()
setIsFauxcused(true)
window.addEventListener('mouseup', onIncrementMouseUp)
const shiftKey = e.shiftKey
const newValue = incrementBy(nonNullPropsValue, stepSize, shiftKey, false)
incrementTimeout = window.setTimeout(() => {
repeatIncrement(newValue, stepSize, shiftKey, true)
}, repeatThreshold)
}
},
[incrementBy, nonNullPropsValue, stepSize, repeatIncrement, onIncrementMouseUp],
)
const onDecrementMouseUp = React.useCallback(() => {
window.removeEventListener('mouseup', onDecrementMouseUp)
setIsFauxcused(false)
ref.current?.focus()
if (incrementTimeout != null) {
window.clearTimeout(incrementTimeout)
incrementTimeout = undefined
}
if (incrementAnimationFrame != null) {
window.cancelAnimationFrame(incrementAnimationFrame ?? 0)
incrementAnimationFrame = undefined
}
// Clear transient state by setting the final value
if (onSubmitValue != null) {
onSubmitValue(repeatedValueRef.current)
}
updateStateValue(repeatedValueRef.current)
}, [ref, onSubmitValue, updateStateValue])
const onDecrementMouseDown = React.useCallback(
(e: React.MouseEvent) => {
if (e.button === 0) {
e.stopPropagation()
setIsFauxcused(true)
window.addEventListener('mouseup', onDecrementMouseUp)
const shiftKey = e.shiftKey
const newValue = incrementBy(nonNullPropsValue, -stepSize, shiftKey, false)
incrementTimeout = window.setTimeout(
() => repeatIncrement(newValue, -stepSize, shiftKey, true),
repeatThreshold,
)
}
},
[incrementBy, nonNullPropsValue, stepSize, repeatIncrement, onDecrementMouseUp],
)
const onLabelMouseDown = React.useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
if (e.button === 0) {
e.stopPropagation()
setIsFauxcused(true)
window.addEventListener('mousemove', scrubOnMouseMove)
window.addEventListener('mouseup', scrubOnMouseUp)
setLabelDragDirection('horizontal')
setValueAtDragOrigin(nonNullPropsValue.value)
setDragOriginX(e.screenX)
setDragOriginY(e.screenY)
setGlobalCursor?.(CSSCursor.ResizeEW)
}
},
[nonNullPropsValue, scrubOnMouseMove, scrubOnMouseUp, setGlobalCursor],
)
let placeholder: string = ''
if (controlStyles.unknown) {
placeholder = 'unknown'
} else if (controlStyles.mixed) {
placeholder = 'mixed'
}
const chainedStyles: Interpolation<any> | undefined =
(chained === 'first' || chained === 'middle') && !isFocused
? {
'&:not(:hover)::after': {
content: '""',
width: 1,
height: UtopiaTheme.layout.inputHeight.default / 2,
backgroundColor: controlStyles.borderColor,
zIndex: 2,
position: 'absolute',
top: UtopiaTheme.layout.inputHeight.default / 2,
right: 0,
transform: 'translateX(0.5px)',
},
}
: undefined
return (
<div style={style}>
<div
className='number-input-container'
css={{
color: controlStyles.mainColor,
backgroundColor: controlStyles.backgroundColor,
zIndex: isFocused ? 3 : undefined,
position: 'relative',
borderRadius: 2,
...chainedStyles,
'&:hover': {
boxShadow: `inset 0px 0px 0px 1px ${colorTheme.border3.value}`,
},
'&:focus-within': {
boxShadow: `inset 0px 0px 0px 1px ${colorTheme.primary.value}`,
},
'&:hover input': {
color: controlStyles.mainColor,
},
'&:focus-within input': {
color: controlStyles.mainColor,
},
}}
>
<InspectorInput
{...inputProps}
chained={chained}
controlStyles={controlStyles}
controlStatus={controlStatus}
testId={testId}
focused={isFocused}
hasLabel={labelInner != null}
roundCorners={roundCorners}
mixed={mixed}
value={stateValue}
ref={ref}
style={{ color: controlStyles.mainColor }}
className='number-input'
height={height}
id={id}
placeholder={placeholder}
onFocus={onFocus}
onKeyDown={onKeyDown}
onKeyUp={onKeyUp}
onBlur={onBlur}
onChange={onChange}
/>
{labelInner != null ? (
<div
className='number-input-innerLabel'
style={{
position: 'absolute',
top: 0,
left: 0,
userSelect: 'none',
pointerEvents: 'none',
width: 20,
height: 20,
display: 'block',
}}
>
<div
style={{
position: 'absolute',
pointerEvents: 'none',
left: 0,
top: 2,
textAlign: 'center',
fontWeight: 600,
fontSize: '9px',
width: '100%',
height: '100%',
color: controlStyles.secondaryColor,
}}
>
{typeof labelInner === 'object' && 'type' in labelInner ? (
<Icn {...labelInner} />
) : (
labelInner
)}
</div>
</div>
) : null}
{incrementControls && controlStyles.interactive ? (
<div
className='number-input-increment-controls'
css={{
position: 'absolute',
top: 0,
right: 1,
flexDirection: 'column',
alignItems: 'stretch',
width: 11,
height: UtopiaTheme.layout.inputHeight.default,
boxShadow: `1px 0 ${controlStyles.borderColor} inset`,
display: 'none',
'.number-input-container:hover &': {
display: 'block',
},
'.number-input-container:focus-within &': {
display: 'block',
},
}}
>
<div
css={{
height: '50%',
opacity: 0.6,
position: 'relative',
borderTopRightRadius: borderRadiusStyles.borderTopRightRadius,
':active': {
opacity: 1,
},
'::after': {
content: '""',
width: 'calc(100% - 1px)',
height: 1,
position: 'absolute',
right: 1,
bottom: 0,
transform: 'translateY(0.5px)',
pointerEvents: 'none',
},
}}
onMouseDown={onIncrementMouseDown}
>
<Icn category='controls/input' type='up' color='secondary' width={11} height={11} />
</div>
<div
css={{
height: '50%',
opacity: 0.6,
position: 'relative',
borderBottomRightRadius: borderRadiusStyles.borderBottomRightRadius,
':active': {
opacity: 1,
},
'::after': {
content: '""',
width: 'calc(100% - 1px)',
height: 1,
position: 'absolute',
right: 1,
bottom: 0,
transform: 'translateY(0.5px)',
pointerEvents: 'none',
},
}}
onMouseDown={onDecrementMouseDown}
>
<Icn
category='controls/input'
type='down'
color='secondary'
width={11}
height={11}
/>
</div>
</div>
) : null}
</div>
{DEPRECATED_labelBelow == null && controlStatus != 'off' ? null : (
<React.Fragment>
{isFauxcused ? (
<div
style={{
position: 'fixed',
left: 0,
top: 0,
bottom: 0,
right: 0,
background: 'transparent',
zIndex: 1,
}}
></div>
) : null}
<div
onMouseDown={onLabelMouseDown}
style={{
cursor: CSSCursor.ResizeEW,
fontSize: 9,
textAlign: 'center',
display: 'block',
color: controlStyles.secondaryColor,
paddingTop: 2,
}}
>
{DEPRECATED_labelBelow}
</div>
</React.Fragment>
)}
</div>
)
},
)