4a4e65fe4a
# Introduction closes https://github.com/twentyhq/core-team-issues/issues/591 Same than for `twenty-shared` made in https://github.com/twentyhq/twenty/pull/11083. ## TODO - [x] Manual migrate twenty-website twenty-ui imports ## What's next: - Generate barrel and migration script factorization within own package + tests - Refactoring using preconstruct ? TimeBox - Lint circular dependencies - Lint import from barrel and forbid them ### Preconstruct We need custom rollup plugins addition, but preconstruct does not expose its rollup configuration. It might be possible to handle this using the babel overrides. But was a big tunnel. We could give it a try afterwards ! ( allowing cjs interop and stuff like that ) Stuck to vite lib app Closed related PRs: - https://github.com/twentyhq/twenty/pull/11294 - https://github.com/twentyhq/twenty/pull/11203
87 lines
2.3 KiB
TypeScript
87 lines
2.3 KiB
TypeScript
import { styled } from '@linaria/react';
|
|
import { useContext, useState } from 'react';
|
|
|
|
import { useClearField } from '@/object-record/record-field/hooks/useClearField';
|
|
import { RATING_VALUES } from '@/object-record/record-field/meta-types/constants/RatingValues';
|
|
import { FieldRatingValue } from '@/object-record/record-field/types/FieldMetadata';
|
|
import { IconTwentyStarFilled } from 'twenty-ui/display';
|
|
import { THEME_COMMON, ThemeContext } from 'twenty-ui/theme';
|
|
|
|
const StyledContainer = styled.div`
|
|
align-items: center;
|
|
display: flex;
|
|
`;
|
|
|
|
const StyledRatingIconContainer = styled.div<{
|
|
color: string;
|
|
}>`
|
|
color: ${({ color }) => color};
|
|
display: inline-flex;
|
|
`;
|
|
|
|
type RatingInputProps = {
|
|
onChange?: (newValue: FieldRatingValue) => void;
|
|
value: FieldRatingValue;
|
|
readonly?: boolean;
|
|
};
|
|
|
|
const iconSizeMd = THEME_COMMON.icon.size.md;
|
|
|
|
export const RatingInput = ({
|
|
onChange,
|
|
value,
|
|
readonly,
|
|
}: RatingInputProps) => {
|
|
const { theme } = useContext(ThemeContext);
|
|
const clearField = useClearField();
|
|
|
|
const activeColor = theme.font.color.secondary;
|
|
const inactiveColor = theme.background.quaternary;
|
|
|
|
const [hoveredValue, setHoveredValue] = useState<FieldRatingValue>(null);
|
|
|
|
const currentValue = hoveredValue ?? value;
|
|
|
|
const selectedIndex =
|
|
currentValue !== null ? RATING_VALUES.indexOf(currentValue) : -1;
|
|
|
|
const canClick = !readonly;
|
|
|
|
const handleClick = (newValue: FieldRatingValue) => {
|
|
if (!canClick) return;
|
|
if (newValue === value) {
|
|
setHoveredValue(null);
|
|
clearField();
|
|
} else {
|
|
onChange?.(newValue);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<StyledContainer
|
|
role="slider"
|
|
aria-label="Rating"
|
|
aria-valuemax={RATING_VALUES.length}
|
|
aria-valuemin={1}
|
|
aria-valuenow={selectedIndex + 1}
|
|
tabIndex={0}
|
|
>
|
|
{RATING_VALUES.map((value, index) => {
|
|
const isActive = index <= selectedIndex;
|
|
|
|
return (
|
|
<StyledRatingIconContainer
|
|
key={index}
|
|
color={isActive ? activeColor : inactiveColor}
|
|
onClick={() => handleClick(value)}
|
|
onMouseEnter={readonly ? undefined : () => setHoveredValue(value)}
|
|
onMouseLeave={readonly ? undefined : () => setHoveredValue(null)}
|
|
>
|
|
<IconTwentyStarFilled size={iconSizeMd} />
|
|
</StyledRatingIconContainer>
|
|
);
|
|
})}
|
|
</StyledContainer>
|
|
);
|
|
};
|