Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Make empty style panel sections easier to recognize as empty #4497

Merged
merged 10 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const Section = () => {
onAdd={() => {
addRepeatedStyleItem(styles, parseCssFragment("none", ["background"]));
}}
noContent={false}
>
<Flex gap={1} direction="column">
<RepeatedStyle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export const Section = () => {
styles,
})
);
const dots = getDots(styles);

return (
<CollapsibleSectionRoot
Expand All @@ -156,7 +157,8 @@ export const Section = () => {
onOpenChange={setIsOpen}
trigger={
<SectionTitle
dots={getDots(styles)}
inactive={dots.length === 0}
dots={dots}
suffix={
<Flex gap="1" align="center">
<TransformAdvancedPopover />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export const Section = () => {
selectedOrLastStyleSourceSelector &&
selectedOrLastStyleSourceSelector.state === undefined;
const styles = useComputedStyles(transitionLongHandProperties);
const dots = getDots(styles);

return (
<CollapsibleSectionRoot
Expand All @@ -102,7 +103,8 @@ export const Section = () => {
onOpenChange={setIsOpen}
trigger={
<SectionTitle
dots={getDots(styles)}
inactive={dots.length === 0}
dots={dots}
suffix={
<Tooltip
content={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const getDots = (styles: ComputedStyleDecl[]) => {
styleDecl.usedValue.type === "unparsed" ||
styleDecl.usedValue.type === "guaranteedInvalid"
) {
return;
return [];
}

const source = styleDecl.source.name;
Expand Down Expand Up @@ -68,10 +68,13 @@ export const RepeatedStyleSection = (props: {
properties: [StyleProperty, ...StyleProperty[]];
onAdd: () => void;
children: ReactNode;
noContent?: boolean;
}) => {
const { label, description, children, properties, onAdd } = props;
const { label, description, children, properties, onAdd, noContent } = props;
const [isOpen, setIsOpen] = useOpenState(props);
const styles = useComputedStyles(properties);
const dots = getDots(styles);

return (
<CollapsibleSectionRoot
fullWidth
Expand All @@ -80,6 +83,7 @@ export const RepeatedStyleSection = (props: {
onOpenChange={setIsOpen}
trigger={
<SectionTitle
inactive={noContent === undefined ? dots.length === 0 : noContent}
dots={getDots(styles)}
suffix={
<SectionTitleButton
Expand Down
8 changes: 8 additions & 0 deletions packages/design-system/src/components/label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const labelColors = [
"overwritten",
"remote",
"code",
"inactive",
] as const;

const StyledLabel = styled(RadixLabel, {
Expand Down Expand Up @@ -96,6 +97,13 @@ const StyledLabel = styled(RadixLabel, {
backgroundColor: theme.colors.backgroundHover,
},
},
// Example is collapsible section title label when section has no content.
inactive: {
color: theme.colors.foregroundTextSubtle,
"&:hover": {
color: theme.colors.foregroundMain,
},
},
},
truncate: {
true: {
Expand Down
7 changes: 7 additions & 0 deletions packages/design-system/src/components/nested-icon-label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ const colors = {
backgroundHover: theme.colors.backgroundHover,
icon: theme.colors.foregroundIconMain,
},
inactive: {
border: "transparent",
background: "transparent",
backgroundHover: "transparent",
icon: theme.colors.foregroundSubtle,
},
} as const;

const perColorStyle = (color: (typeof labelColors)[number]) => ({
Expand Down Expand Up @@ -77,6 +83,7 @@ const style = css({
overwritten: perColorStyle("overwritten"),
remote: perColorStyle("remote"),
code: perColorStyle("code"),
inactive: perColorStyle("inactive"),
},
},
defaultVariants: { color: "default" },
Expand Down
16 changes: 14 additions & 2 deletions packages/design-system/src/components/section-title.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,22 @@ const Wrap = ({ children }: { children: React.ReactNode }) => (

const Variants = ({
state,
inactive,
}: {
state: ComponentProps<typeof SectionTitle>["data-state"];
inactive?: ComponentProps<typeof SectionTitle>["inactive"];
}) => (
<>
<Wrap>
<SectionTitle data-state={state}>
<SectionTitle data-state={state} inactive={inactive}>
<SectionTitleLabel>Simplest</SectionTitleLabel>
</SectionTitle>
</Wrap>
<Wrap>
<SectionTitle
suffix={<SectionTitleButton prefix={<PlusIcon />} />}
data-state={state}
inactive={inactive}
>
<SectionTitleLabel>With button</SectionTitleLabel>
</SectionTitle>
Expand All @@ -39,6 +42,7 @@ const Variants = ({
dots={["local", "remote"]}
suffix={<SectionTitleButton prefix={<PlusIcon />} />}
data-state={state}
inactive={inactive}
>
<SectionTitleLabel>With dots</SectionTitleLabel>
</SectionTitle>
Expand All @@ -48,6 +52,7 @@ const Variants = ({
dots={["local"]}
suffix={<SectionTitleButton prefix={<PlusIcon />} />}
data-state={state}
inactive={inactive}
>
<SectionTitleLabel color="local">With label</SectionTitleLabel>
</SectionTitle>
Expand All @@ -57,14 +62,15 @@ const Variants = ({
dots={["local", "remote"]}
suffix={<SectionTitleButton prefix={<PlusIcon />} />}
data-state={state}
inactive={inactive}
>
<SectionTitleLabel>
Some title so long that it cannot possibly fit
</SectionTitleLabel>
</SectionTitle>
</Wrap>
<Wrap>
<SectionTitle data-state={state}>
<SectionTitle data-state={state} inactive={inactive}>
<SectionTitleLabel>
Some title so long that it cannot possibly fit
</SectionTitleLabel>
Expand Down Expand Up @@ -100,6 +106,12 @@ export const Demo = () => (
<Variants state="open" />
</StoryGrid>
</StorySection>

<StorySection title="Inactive">
<StoryGrid>
<Variants inactive state="closed" />
</StoryGrid>
</StorySection>
</>
);

Expand Down
43 changes: 28 additions & 15 deletions packages/design-system/src/components/section-title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const chevronStyle = css({
transform: "rotate(90deg)",
},
closed: {},
inactive: {},
},
},
});
Expand All @@ -100,7 +101,7 @@ const dotStyle = css({
},
});

const context = createContext<{ state: "open" | "closed" }>({
const context = createContext<{ state: "open" | "closed" | "inactive" }>({
state: "closed",
});

Expand All @@ -112,8 +113,10 @@ export const SectionTitle = forwardRef(
css,
children,
suffix,
inactive = false,
...props
}: ComponentProps<"button"> & {
inactive?: boolean;
/** https://www.radix-ui.com/docs/primitives/components/collapsible#trigger */
"data-state"?: "open" | "closed";
dots?: Array<"local" | "overwritten" | "remote">;
Expand All @@ -123,7 +126,7 @@ export const SectionTitle = forwardRef(
},
ref: Ref<HTMLButtonElement>
) => {
const state = props["data-state"] ?? "closed";
const state = inactive ? "inactive" : (props["data-state"] ?? "closed");
const finalDots = state === "open" ? [] : (dots ?? []);

return (
Expand All @@ -132,25 +135,30 @@ export const SectionTitle = forwardRef(
render={({ handleKeyDown }) => (
<Flex
align="center"
className={containerStyle({ className, css })}
className={containerStyle({
className,
css,
color: inactive ? "disabled" : "default",
})}
data-state={state}
onKeyDown={handleKeyDown}
>
<button
className={titleButtonStyle()}
data-state={state}
ref={ref}
{...props}
>
<ChevronRightIcon className={chevronStyle({ state })} />
</button>

{inactive === false && (
<button
className={titleButtonStyle()}
data-state={state}
ref={ref}
{...props}
>
<ChevronRightIcon className={chevronStyle({ state })} />
</button>
)}
{/*
If the label is itself a button, we don't want to nest a button inside another button.
Therefore, we render the label in a layer above the SectionTitle button
*/}
<div className={labelContainerStyle()}>
<div className={titleButtonLayoutStyle()}>
<div className={titleButtonLayoutStyle({ state })}>
{children}

{finalDots.length > 0 && (
Expand Down Expand Up @@ -190,8 +198,12 @@ export const SectionTitleLabel = forwardRef(
const { state } = useContext(context);

const commonCss = { flex: "0 1 auto" };

const color = state === "closed" ? undefined : props.color;
const stateColorMap = {
open: props.color,
closed: "default",
inactive: "inactive",
} as const;
const color = stateColorMap[state] ?? props.color;

const isButton = isLabelButton(color);

Expand All @@ -205,6 +217,7 @@ export const SectionTitleLabel = forwardRef(
color: state === "closed" ? `var(${labelTextColor})` : undefined,
...commonCss,
...css,

// When we use a SectionTitle button, we can't directly render a label inside it.
// Instead, we need to render the label using a div that has position:absolute and pointer-events:none
// However, if the label itself is a button, we need to make sure that it remains clickable.
Expand Down
Loading