Extract the JSON visualizer component in twenty-ui (#10937)
- Move the JsonTree component and the other components to twenty-ui - Rely on a React Context to provide translations ## Future work It would be good to migrate the `createRequiredContext` function to `twenty-ui`. I didn't want to migrate it in this PR but would have liked to use it.
This commit is contained in:
committed by
GitHub
parent
428499e222
commit
093d6c0a1a
@ -0,0 +1,52 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { VisibilityHidden } from '@ui/accessibility';
|
||||
import { IconChevronDown } from '@ui/display';
|
||||
import { useJsonTreeContextOrThrow } from '@ui/json-visualizer/hooks/useJsonTreeContextOrThrow';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
const StyledButton = styled(motion.button)`
|
||||
align-items: center;
|
||||
border-color: ${({ theme }) => theme.border.color.medium};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-inline: ${({ theme }) => theme.spacing(1)};
|
||||
background-color: ${({ theme }) => theme.background.transparent.lighter};
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const MotionIconChevronDown = motion.create(IconChevronDown);
|
||||
|
||||
export const JsonArrow = ({
|
||||
isOpen,
|
||||
onClick,
|
||||
}: {
|
||||
isOpen: boolean;
|
||||
onClick: () => void;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const { arrowButtonCollapsedLabel, arrowButtonExpandedLabel } =
|
||||
useJsonTreeContextOrThrow();
|
||||
|
||||
return (
|
||||
<StyledButton onClick={onClick}>
|
||||
<VisibilityHidden>
|
||||
{isOpen ? arrowButtonExpandedLabel : arrowButtonCollapsedLabel}
|
||||
</VisibilityHidden>
|
||||
|
||||
<MotionIconChevronDown
|
||||
size={theme.icon.size.md}
|
||||
color={theme.font.color.secondary}
|
||||
initial={false}
|
||||
animate={{ rotate: isOpen ? -180 : 0 }}
|
||||
/>
|
||||
</StyledButton>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,18 @@
|
||||
import { css } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledList = styled.ul<{ depth: number }>`
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
display: grid;
|
||||
row-gap: ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
${({ theme, depth }) =>
|
||||
depth > 0 &&
|
||||
css`
|
||||
padding-left: ${theme.spacing(8)};
|
||||
`}
|
||||
`;
|
||||
|
||||
export { StyledList as JsonList };
|
||||
@ -0,0 +1,10 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledListItem = styled.li`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
list-style-type: none;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
export { StyledListItem as JsonListItem };
|
||||
@ -0,0 +1,46 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { IconComponent } from '@ui/display';
|
||||
|
||||
const StyledLabelContainer = styled.span<{ isHighlighted?: boolean }>`
|
||||
align-items: center;
|
||||
background-color: ${({ theme }) => theme.background.transparent.lighter};
|
||||
border-color: ${({ theme }) => theme.border.color.medium};
|
||||
color: ${({ theme, isHighlighted }) =>
|
||||
isHighlighted ? theme.color.blue : theme.font.color.primary};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
height: 24px;
|
||||
box-sizing: border-box;
|
||||
column-gap: ${({ theme }) => theme.spacing(2)};
|
||||
display: flex;
|
||||
font-variant-numeric: tabular-nums;
|
||||
justify-content: center;
|
||||
padding-block: ${({ theme }) => theme.spacing(1)};
|
||||
padding-inline: ${({ theme }) => theme.spacing(2)};
|
||||
width: fit-content;
|
||||
`;
|
||||
|
||||
export const JsonNodeLabel = ({
|
||||
label,
|
||||
Icon,
|
||||
isHighlighted,
|
||||
}: {
|
||||
label: string;
|
||||
Icon: IconComponent;
|
||||
isHighlighted?: boolean;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledLabelContainer isHighlighted={isHighlighted}>
|
||||
<Icon
|
||||
size={theme.icon.size.md}
|
||||
color={isHighlighted ? theme.color.blue : theme.font.color.tertiary}
|
||||
/>
|
||||
|
||||
<span>{label}</span>
|
||||
</StyledLabelContainer>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,16 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledText = styled.span<{ isHighlighted?: boolean }>`
|
||||
color: ${({ theme, isHighlighted }) =>
|
||||
isHighlighted ? theme.adaptiveColors.blue4 : theme.font.color.tertiary};
|
||||
`;
|
||||
|
||||
export const JsonNodeValue = ({
|
||||
valueAsString,
|
||||
isHighlighted,
|
||||
}: {
|
||||
valueAsString: string;
|
||||
isHighlighted?: boolean;
|
||||
}) => {
|
||||
return <StyledText isHighlighted={isHighlighted}>{valueAsString}</StyledText>;
|
||||
};
|
||||
Reference in New Issue
Block a user