Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
53 changes: 29 additions & 24 deletions packages/graph-explorer/src/core/StateProvider/graphStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,23 @@ export const ARROW_STYLES = [
] as const;
export type ArrowStyle = (typeof ARROW_STYLES)[number];

/** The visual appearance of a label badge (shared by edge and vertex labels). */
export type LabelVisualStyle = {
labelColor: string;
labelBackgroundOpacity: number;
labelBorderColor: string;
labelBorderStyle: LineStyle;
labelBorderWidth: number;
};

/**
* The visual appearance of a vertex — the fields that make sense for both a
* per-type style and a type-less global default. Every field is required: this
* is the resolved baseline shape a rendered vertex always has.
* is the resolved baseline shape a rendered vertex always has. Includes
* {@link LabelVisualStyle} so a vertex type can style its own label badge, the
* same way an edge type already can (see {@link EdgeVisualStyle}).
*/
export type VertexVisualStyle = {
export type VertexVisualStyle = LabelVisualStyle & {
/** Color overwrite for vertex */
color: string;
/** Icon overwrite for vertex */
Expand Down Expand Up @@ -91,15 +102,6 @@ export type VertexTypeStyle = {
longDisplayNameAttribute: string;
};

/** The visual appearance of a label badge (shared by edge and vertex labels). */
export type LabelVisualStyle = {
labelColor: string;
labelBackgroundOpacity: number;
labelBorderColor: string;
labelBorderStyle: LineStyle;
labelBorderWidth: number;
};

/** The visual appearance of an edge, shared by per-type styles and defaults. */
export type EdgeVisualStyle = LabelVisualStyle & {
lineColor: string;
Expand Down Expand Up @@ -135,7 +137,13 @@ export type EdgeStyle = Simplify<
Readonly<EdgeVisualStyle & EdgeTypeStyle & { type: EdgeType }>
>;

/** The default values to use when no user provided value is given. */
/**
* The default values to use when no user provided value is given. Label-badge
* fields mirror the node label config in
* `components/Graph/styles/defaultNodeStyle.ts` (`text.background` →
* `labelColor`, `text.opacity` → `labelBackgroundOpacity`) — keep in sync if
* that canvas style changes.
*/
export const appDefaultVertexStyle = {
displayNameAttribute: RESERVED_ID_PROPERTY,
longDisplayNameAttribute: RESERVED_TYPES_PROPERTY,
Expand All @@ -147,23 +155,20 @@ export const appDefaultVertexStyle = {
borderWidth: 0,
borderColor: "#128EE5",
borderStyle: "solid",
} as const satisfies Omit<VertexStyle, "type">;

/**
* The default appearance of a node's label badge. Nodes have no per-type label
* styling (see {@link VertexVisualStyle}), so this is the single source for how
* a node label looks. Values mirror the node label config in
* `components/Graph/styles/defaultNodeStyle.ts` (`text.background` →
* `labelColor`, `text.opacity` → `labelBackgroundOpacity`) — keep in sync if
* that canvas style changes.
*/
export const appDefaultNodeLabelStyle = {
labelColor: "#1d2531",
labelBackgroundOpacity: 0.7,
labelBorderColor: "#1d2531",
labelBorderStyle: "solid",
labelBorderWidth: 0,
} as const satisfies LabelVisualStyle;
} as const satisfies Omit<VertexStyle, "type">;

/**
* The default appearance of a node's label badge, for preview/legend UI that
* needs just the label fields (e.g. `VertexPreview.tsx`) — derived from
* {@link appDefaultVertexStyle}, which is now the single source of truth for
* a vertex type's label styling (see {@link VertexVisualStyle}).
*/
export const appDefaultNodeLabelStyle: LabelVisualStyle = appDefaultVertexStyle;

/** The default values to use when no user provided value is given. */
export const appDefaultEdgeStyle = {
Expand Down
5 changes: 5 additions & 0 deletions packages/graph-explorer/src/core/styling/stylingParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ const vertexEntrySchema = z
borderWidth: z.number().optional(),
borderColor: z.string().optional(),
borderStyle: z.enum(LINE_STYLES).optional(),
labelColor: z.string().optional(),
labelBackgroundOpacity: z.number().optional(),
labelBorderColor: z.string().optional(),
labelBorderStyle: z.enum(LINE_STYLES).optional(),
labelBorderWidth: z.number().optional(),
})
.transform(
({ icon, ...rest }): Omit<VertexStyleStorage, "type"> =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,47 @@ describe("useGraphStyles", () => {
shape: "ellipse",
width: 24,
height: 24,
color: "#FFFFFF",
"text-background-color": "#1d2531",
"text-background-opacity": 0.7,
"text-border-color": "#1d2531",
"text-border-style": "solid",
"text-border-width": 0,
});
});
});

it("should apply a vertex type's own label-badge style, not just the app default", async () => {
const vertexConfig = {
...createRandomVertexTypeConfig(),
...RASTER_ICON,
type: createVertexType("Person"),
color: "#128EE5",
backgroundOpacity: 0.8,
borderColor: "#000000",
borderWidth: 2,
borderStyle: "solid" as const,
shape: "ellipse" as const,
labelColor: "#f8fafc",
labelBackgroundOpacity: 0.94,
labelBorderColor: "#cbd5e1",
labelBorderWidth: 1,
labelBorderStyle: "solid" as const,
};
dbState.activeSchema.vertices = [vertexConfig];
dbState.addVertexStyle(vertexConfig.type, vertexConfig);

const { result } = renderHookWithState(() => useGraphStyles(), dbState);

await waitFor(() => {
const vertexStyle = getStyles(result)[`node[type="Person"]`] as any;
expect(vertexStyle).toMatchObject({
color: "#000000", // Black text for a light background
"text-background-color": "#f8fafc",
"text-background-opacity": 0.94,
"text-border-color": "#cbd5e1",
"text-border-width": 1,
"text-border-style": "solid",
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ function createGraphStyles(
shape: vtConfig.shape,
width: 24,
height: 24,
color: new Color(vtConfig.labelColor).isDark() ? "#FFFFFF" : "#000000",
"text-background-opacity": vtConfig.labelBackgroundOpacity,
"text-background-color": vtConfig.labelColor,
"text-border-width": vtConfig.labelBorderWidth,
"text-border-color": vtConfig.labelBorderColor,
"text-border-style": vtConfig.labelBorderStyle,
};
}

Expand Down