Skip to content
This repository was archived by the owner on Jul 13, 2024. It is now read-only.

Commit b73ce45

Browse files
authored
Merge pull request #289 from nicoespeon/custom-render-tags
Implement custom render for tags
2 parents 3cfab5f + bed23ff commit b73ce45

File tree

12 files changed

+127
-43
lines changed

12 files changed

+127
-43
lines changed

packages/gitgraph-core/src/commit.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { CommitStyle, TagStyle } from "./template";
22
import { Branch } from "./branch";
33
import { Refs } from "./refs";
44
import { Tag } from "./tag";
5+
import { GitgraphTagOptions } from "./user-api/gitgraph-user-api";
56

67
export { CommitRenderOptions, CommitOptions, Commit };
78

@@ -156,7 +157,7 @@ class Commit<TNode = SVGElement> {
156157
/**
157158
* List of tags attached
158159
*/
159-
public tags?: Tag[];
160+
public tags?: Array<Tag<TNode>>;
160161
/**
161162
* Callback to execute on click.
162163
*/
@@ -240,11 +241,17 @@ class Commit<TNode = SVGElement> {
240241

241242
public setTags(
242243
tags: Refs,
243-
getTagStyle: (name: Tag["name"]) => Partial<TagStyle>,
244+
getTagStyle: (name: Tag<TNode>["name"]) => Partial<TagStyle>,
245+
getTagRender: (
246+
name: Tag<TNode>["name"],
247+
) => GitgraphTagOptions<TNode>["render"],
244248
): this {
245249
this.tags = tags
246250
.getNames(this.hash)
247-
.map((name) => new Tag(name, getTagStyle(name), this.style));
251+
.map(
252+
(name) =>
253+
new Tag(name, getTagStyle(name), getTagRender(name), this.style),
254+
);
248255
return this;
249256
}
250257

packages/gitgraph-core/src/gitgraph.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { Orientation } from "./orientation";
1515
import {
1616
GitgraphUserApi,
1717
GitgraphBranchOptions,
18+
GitgraphTagOptions,
1819
} from "./user-api/gitgraph-user-api";
1920

2021
export { Mode, GitgraphOptions, RenderedData, GitgraphCore };
@@ -73,6 +74,9 @@ class GitgraphCore<TNode = SVGElement> {
7374
public refs = new Refs();
7475
public tags = new Refs();
7576
public tagStyles: { [name: string]: TemplateOptions["tag"] } = {};
77+
public tagRenders: {
78+
[name: string]: GitgraphTagOptions<TNode>["render"];
79+
} = {};
7680
public commits: Array<Commit<TNode>> = [];
7781
public branches: Map<Branch["name"], Branch<TNode>> = new Map();
7882
public currentBranch: Branch<TNode>;
@@ -228,8 +232,11 @@ class GitgraphCore<TNode = SVGElement> {
228232
)
229233
// Tags need commit style to be computed (with default color).
230234
.map((commit) =>
231-
commit.setTags(this.tags, (name) =>
232-
Object.assign({}, this.tagStyles[name], this.template.tag),
235+
commit.setTags(
236+
this.tags,
237+
(name) =>
238+
Object.assign({}, this.tagStyles[name], this.template.tag),
239+
(name) => this.tagRenders[name],
233240
),
234241
)
235242
);

packages/gitgraph-core/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export {
33
GitgraphUserApi,
44
GitgraphCommitOptions,
55
GitgraphBranchOptions,
6+
GitgraphTagOptions,
67
} from "./user-api/gitgraph-user-api";
78
export {
89
BranchUserApi,

packages/gitgraph-core/src/tag.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
import { TagStyle, CommitStyle, DEFAULT_FONT } from "./template";
22
import { numberOptionOr } from "./utils";
3+
import { GitgraphTagOptions } from "./user-api/gitgraph-user-api";
34

45
export { Tag };
56

6-
class Tag {
7+
class Tag<TNode> {
78
/**
89
* Name
910
*/
1011
public readonly name: string;
12+
/**
13+
* Custom render function
14+
*/
15+
public readonly render?: GitgraphTagOptions<TNode>["render"];
1116
/**
1217
* Style
1318
*/
@@ -27,11 +32,13 @@ class Tag {
2732

2833
constructor(
2934
name: string,
30-
tagStyle: Partial<TagStyle>,
35+
style: Partial<TagStyle>,
36+
render: GitgraphTagOptions<TNode>["render"],
3137
commitStyle: CommitStyle,
3238
) {
3339
this.name = name;
34-
this.tagStyle = tagStyle;
40+
this.tagStyle = style;
3541
this.commitStyle = commitStyle;
42+
this.render = render;
3643
}
3744
}

packages/gitgraph-core/src/user-api/branch-user-api.ts

+6-13
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { GitgraphCore, Mode } from "../gitgraph";
22
import {
33
GitgraphCommitOptions,
44
GitgraphBranchOptions,
5+
GitgraphTagOptions,
56
} from "./gitgraph-user-api";
67
import { TemplateOptions, CommitStyle } from "../template";
78
import { Commit } from "../commit";
@@ -25,10 +26,7 @@ interface GitgraphMergeOptions<TNode> {
2526
commitOptions?: GitgraphCommitOptions<TNode>;
2627
}
2728

28-
interface BranchTagOptions {
29-
name: string;
30-
style?: TemplateOptions["tag"];
31-
}
29+
type BranchTagOptions<TNode> = Omit<GitgraphTagOptions<TNode>, ["ref"]>;
3230

3331
class BranchUserApi<TNode> {
3432
/**
@@ -175,25 +173,20 @@ class BranchUserApi<TNode> {
175173
*
176174
* @param options Options of the tag
177175
*/
178-
public tag(options: BranchTagOptions): this;
176+
public tag(options: BranchTagOptions<TNode>): this;
179177
/**
180178
* Tag the last commit of the branch.
181179
*
182180
* @param name Name of the tag
183181
*/
184-
public tag(name: BranchTagOptions["name"]): this;
182+
public tag(name: BranchTagOptions<TNode>["name"]): this;
185183
public tag(options?: any): this {
186-
let name: BranchTagOptions["name"];
187-
let style: BranchTagOptions["style"];
188-
189184
if (typeof options === "string") {
190-
name = options;
185+
this._graph.getUserApi().tag({ name: options, ref: this._branch.name });
191186
} else {
192-
name = options.name;
193-
style = options.style;
187+
this._graph.getUserApi().tag({ ...options, ref: this._branch.name });
194188
}
195189

196-
this._graph.getUserApi().tag({ name, ref: this._branch.name, style });
197190
return this;
198191
}
199192

packages/gitgraph-core/src/user-api/gitgraph-user-api.ts

+20-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { TemplateOptions } from "../template";
1+
import { TagStyle, TemplateOptions } from "../template";
22
import { Commit, CommitRenderOptions, CommitOptions } from "../commit";
33
import {
44
Branch,
@@ -10,7 +10,12 @@ import { GitgraphCore } from "../gitgraph";
1010
import { Refs } from "../refs";
1111
import { BranchUserApi } from "./branch-user-api";
1212

13-
export { GitgraphCommitOptions, GitgraphBranchOptions, GitgraphUserApi };
13+
export {
14+
GitgraphCommitOptions,
15+
GitgraphBranchOptions,
16+
GitgraphTagOptions,
17+
GitgraphUserApi,
18+
};
1419

1520
interface GitgraphCommitOptions<TNode> extends CommitRenderOptions<TNode> {
1621
author?: string;
@@ -26,10 +31,11 @@ interface GitgraphCommitOptions<TNode> extends CommitRenderOptions<TNode> {
2631
onMouseOut?: (commit: Commit<TNode>) => void;
2732
}
2833

29-
interface GitgraphTagOptions {
34+
interface GitgraphTagOptions<TNode> {
3035
name: string;
31-
ref?: Commit["hash"] | Branch["name"];
3236
style?: TemplateOptions["tag"];
37+
ref?: Commit["hash"] | Branch["name"];
38+
render?: (name: string, style: TagStyle) => TNode;
3339
}
3440

3541
interface GitgraphBranchOptions<TNode> extends BranchRenderOptions<TNode> {
@@ -113,29 +119,32 @@ class GitgraphUserApi<TNode> {
113119
*
114120
* @param options Options of the tag
115121
*/
116-
public tag(options: GitgraphTagOptions): this;
122+
public tag(options: GitgraphTagOptions<TNode>): this;
117123
/**
118124
* Tag a specific commit.
119125
*
120126
* @param name Name of the tag
121127
* @param ref Commit or branch name or commit hash
122128
*/
123129
public tag(
124-
name: GitgraphTagOptions["name"],
125-
ref?: GitgraphTagOptions["ref"],
130+
name: GitgraphTagOptions<TNode>["name"],
131+
ref?: GitgraphTagOptions<TNode>["ref"],
126132
): this;
127133
public tag(...args: any[]): this {
128134
// Deal with shorter syntax
129-
let name: GitgraphTagOptions["name"];
130-
let ref: GitgraphTagOptions["ref"];
131-
let style: GitgraphTagOptions["style"];
135+
let name: GitgraphTagOptions<TNode>["name"];
136+
let ref: GitgraphTagOptions<TNode>["ref"];
137+
let style: GitgraphTagOptions<TNode>["style"];
138+
let render: GitgraphTagOptions<TNode>["render"];
139+
132140
if (typeof args[0] === "string") {
133141
name = args[0];
134142
ref = args[1];
135143
} else {
136144
name = args[0].name;
137145
ref = args[0].ref;
138146
style = args[0].style;
147+
render = args[0].render;
139148
}
140149

141150
if (!ref) {
@@ -162,6 +171,7 @@ class GitgraphUserApi<TNode> {
162171

163172
this._graph.tags.set(name, commitHash);
164173
this._graph.tagStyles[name] = style;
174+
this._graph.tagRenders[name] = render;
165175
this._onGraphUpdate();
166176
return this;
167177
}

packages/gitgraph-js/src/gitgraph.ts

+19-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
Mode,
1212
BranchUserApi,
1313
GitgraphBranchOptions,
14+
GitgraphTagOptions,
1415
GitgraphMergeOptions,
1516
Orientation,
1617
TemplateName,
@@ -38,6 +39,7 @@ import { createTooltip, PADDING as TOOLTIP_PADDING } from "./tooltip";
3839

3940
type CommitOptions = GitgraphCommitOptions<SVGElement>;
4041
type BranchOptions = GitgraphBranchOptions<SVGElement>;
42+
type TagOptions = GitgraphTagOptions<SVGElement>;
4143
type MergeOptions = GitgraphMergeOptions<SVGElement>;
4244
type Branch = BranchUserApi<SVGElement>;
4345

@@ -46,6 +48,7 @@ export {
4648
CommitOptions,
4749
Branch,
4850
BranchOptions,
51+
TagOptions,
4952
MergeOptions,
5053
Mode,
5154
Orientation,
@@ -208,8 +211,8 @@ function createGitgraph(
208211
moveElement(tag, x);
209212

210213
// BBox width misses box padding and offset
211-
// => they are set later, on branch label update.
212-
// We would need to make branch label update happen before to solve it.
214+
// => they are set later, on tag update.
215+
// We would need to make tag update happen before to solve it.
213216
const offset = parseFloat(tag.getAttribute("data-offset") || "0");
214217
const tagWidth = tag.getBBox().width + 2 * TAG_PADDING_X + offset;
215218
x += tagWidth + padding;
@@ -459,14 +462,23 @@ function createGitgraph(
459462
if (gitgraph.isHorizontal) return [];
460463

461464
return commit.tags.map((tag) => {
462-
const tagElement = createTag(tag);
463-
464-
setTagRef(commit, tagElement);
465-
466-
return createG({
465+
const tagElement = tag.render
466+
? tag.render(tag.name, tag.style)
467+
: createTag(tag);
468+
const tagContainer = createG({
467469
translate: { x: 0, y: commit.style.dot.size },
468470
children: [tagElement],
469471
});
472+
// `data-offset` is used to position tag element in `positionCommitsElements`.
473+
// => because when it's executed, tag offsets are not resolved yet
474+
tagContainer.setAttribute(
475+
"data-offset",
476+
tag.style.pointerWidth.toString(),
477+
);
478+
479+
setTagRef(commit, tagContainer);
480+
481+
return tagContainer;
470482
});
471483
}
472484

packages/gitgraph-js/src/tag.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export { createTag, PADDING_X };
66
const PADDING_X = 10;
77
const PADDING_Y = 5;
88

9-
function createTag(tag: Tag): SVGGElement {
9+
function createTag(tag: Tag<SVGElement>): SVGGElement {
1010
const path = createPath({
1111
d: "",
1212
fill: tag.style.bgColor,
@@ -20,9 +20,7 @@ function createTag(tag: Tag): SVGGElement {
2020
});
2121

2222
const result = createG({ children: [path] });
23-
// Pass computed box width to gitgraph so it can adapt.
2423
const offset = tag.style.pointerWidth;
25-
result.setAttribute("data-offset", offset.toString());
2624

2725
const observer = new MutationObserver(() => {
2826
const { height, width } = text.getBBox();

packages/gitgraph-react/src/Gitgraph.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
GitgraphUserApi,
66
GitgraphCommitOptions,
77
GitgraphBranchOptions,
8+
GitgraphTagOptions,
89
GitgraphMergeOptions,
910
BranchUserApi,
1011
Commit,
@@ -28,6 +29,7 @@ type ReactSvgElement = React.ReactElement<SVGElement>;
2829

2930
type CommitOptions = GitgraphCommitOptions<ReactSvgElement>;
3031
type BranchOptions = GitgraphBranchOptions<ReactSvgElement>;
32+
type TagOptions = GitgraphTagOptions<ReactSvgElement>;
3133
type MergeOptions = GitgraphMergeOptions<ReactSvgElement>;
3234
type Branch = BranchUserApi<ReactSvgElement>;
3335

@@ -37,6 +39,7 @@ export {
3739
GitgraphState,
3840
CommitOptions,
3941
BranchOptions,
42+
TagOptions,
4043
MergeOptions,
4144
Branch,
4245
TemplateName,
@@ -361,7 +364,7 @@ class Gitgraph extends React.Component<GitgraphProps, GitgraphState> {
361364
ref={ref}
362365
transform={`translate(0, ${commit.style.dot.size})`}
363366
>
364-
<Tag tag={tag} />
367+
{tag.render ? tag.render(tag.name, tag.style) : <Tag tag={tag} />}
365368
</g>
366369
);
367370
});

packages/gitgraph-react/src/Tag.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useState, useEffect, useRef } from "react";
33
import { Tag as CoreTag } from "@gitgraph/core";
44

55
interface Props {
6-
tag: CoreTag;
6+
tag: CoreTag<React.ReactElement<SVGElement>>;
77
}
88

99
export const TAG_PADDING_X = 10;

0 commit comments

Comments
 (0)