Skip to content

Commit 1223dce

Browse files
committed
Allow theming of bubble dimensions
1 parent 62f422a commit 1223dce

File tree

7 files changed

+73
-54
lines changed

7 files changed

+73
-54
lines changed

packages/cells/src/cells/multi-select-cell.tsx

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ interface MultiSelectCellProps {
3636
readonly allowDuplicates?: boolean;
3737
}
3838

39-
const BUBBLE_HEIGHT = 20;
40-
const BUBBLE_PADDING = 6;
41-
const BUBBLE_MARGIN = 4;
4239
/* This prefix is used when allowDuplicates is enabled to make sure that
4340
all underlying values are unique. */
4441
const VALUE_PREFIX = "__value";
@@ -229,14 +226,14 @@ const Editor: ReturnType<ProvideEditorCallback<MultiSelectCell>> = p => {
229226
return {
230227
...styles,
231228
backgroundColor: data.color ?? theme.bgBubble,
232-
borderRadius: `${theme.roundingRadius ?? BUBBLE_HEIGHT / 2}px`,
229+
borderRadius: `${theme.roundingRadius ?? theme.bubbleHeight / 2}px`,
233230
};
234231
},
235232
multiValueLabel: (styles, { data, isDisabled }) => {
236233
return {
237234
...styles,
238-
paddingRight: isDisabled ? BUBBLE_PADDING : 0,
239-
paddingLeft: BUBBLE_PADDING,
235+
paddingRight: isDisabled ? theme.bubblePadding : 0,
236+
paddingLeft: theme.bubblePadding,
240237
paddingTop: 0,
241238
paddingBottom: 0,
242239
color: data.color
@@ -251,7 +248,7 @@ const Editor: ReturnType<ProvideEditorCallback<MultiSelectCell>> = p => {
251248
justifyContent: "center",
252249
alignItems: "center",
253250
display: "flex",
254-
height: BUBBLE_HEIGHT,
251+
height: theme.bubbleHeight,
255252
};
256253
},
257254
multiValueRemove: (styles, { data, isDisabled, isFocused }) => {
@@ -270,7 +267,7 @@ const Editor: ReturnType<ProvideEditorCallback<MultiSelectCell>> = p => {
270267
: "white"
271268
: theme.textBubble,
272269
backgroundColor: undefined,
273-
borderRadius: isFocused ? `${theme.roundingRadius ?? BUBBLE_HEIGHT / 2}px` : undefined,
270+
borderRadius: isFocused ? `${theme.roundingRadius ?? theme.bubbleHeight / 2}px` : undefined,
274271
":hover": {
275272
cursor: "pointer",
276273
},
@@ -398,32 +395,32 @@ const renderer: CustomRenderer<MultiSelectCell> = {
398395
width: rect.width - 2 * theme.cellHorizontalPadding,
399396
height: rect.height - 2 * theme.cellVerticalPadding,
400397
};
401-
const rows = Math.max(1, Math.floor(drawArea.height / (BUBBLE_HEIGHT + BUBBLE_PADDING)));
398+
const rows = Math.max(1, Math.floor(drawArea.height / (theme.bubbleHeight + theme.bubblePadding)));
402399

403400
let { x } = drawArea;
404401
let row = 1;
405402

406403
let y =
407404
rows === 1
408-
? drawArea.y + (drawArea.height - BUBBLE_HEIGHT) / 2
409-
: drawArea.y + (drawArea.height - rows * BUBBLE_HEIGHT - (rows - 1) * BUBBLE_PADDING) / 2;
405+
? drawArea.y + (drawArea.height - theme.bubbleHeight) / 2
406+
: drawArea.y + (drawArea.height - rows * theme.bubbleHeight - (rows - 1) * theme.bubblePadding) / 2;
410407
for (const value of values) {
411408
const matchedOption = options.find(t => t.value === value);
412409
const color = matchedOption?.color ?? (highlighted ? theme.bgBubbleSelected : theme.bgBubble);
413410
const displayText = matchedOption?.label ?? value;
414411
const metrics = measureTextCached(displayText, ctx);
415-
const width = metrics.width + BUBBLE_PADDING * 2;
416-
const textY = BUBBLE_HEIGHT / 2;
412+
const width = metrics.width + theme.bubblePadding * 2;
413+
const textY = theme.bubbleHeight / 2;
417414

418415
if (x !== drawArea.x && x + width > drawArea.x + drawArea.width && row < rows) {
419416
row++;
420-
y += BUBBLE_HEIGHT + BUBBLE_PADDING;
417+
y += theme.bubbleHeight + theme.bubblePadding;
421418
x = drawArea.x;
422419
}
423420

424421
ctx.fillStyle = color;
425422
ctx.beginPath();
426-
roundedRect(ctx, x, y, width, BUBBLE_HEIGHT, theme.roundingRadius ?? BUBBLE_HEIGHT / 2);
423+
roundedRect(ctx, x, y, width, theme.bubbleHeight, theme.roundingRadius ?? theme.bubbleHeight / 2);
427424
ctx.fill();
428425

429426
// If a color is set for this option, we use either black or white as the text color depending on the background.
@@ -433,33 +430,38 @@ const renderer: CustomRenderer<MultiSelectCell> = {
433430
? "#000000"
434431
: "#ffffff"
435432
: theme.textBubble;
436-
ctx.fillText(displayText, x + BUBBLE_PADDING, y + textY + getMiddleCenterBias(ctx, theme));
433+
ctx.fillText(displayText, x + theme.bubblePadding, y + textY + getMiddleCenterBias(ctx, theme));
437434

438-
x += width + BUBBLE_MARGIN;
435+
x += width + theme.bubbleMargin;
439436
if (x > drawArea.x + drawArea.width + theme.cellHorizontalPadding && row >= rows) {
440437
break;
441438
}
442439
}
443440

444441
return true;
445442
},
446-
measure: (ctx, cell, t) => {
443+
measure: (ctx, cell, theme) => {
447444
const { values, options } = cell.data;
448445

449446
if (!values) {
450-
return t.cellHorizontalPadding * 2;
447+
return theme.cellHorizontalPadding * 2;
451448
}
452449

453450
// Resolve the values to the actual display labels:
454451
const labels = resolveValues(values, prepareOptions(options ?? []), cell.data.allowDuplicates).map(
455452
x => x.label ?? x.value
456453
);
457454

458-
return (
459-
labels.reduce((acc, data) => ctx.measureText(data).width + acc + BUBBLE_PADDING * 2 + BUBBLE_MARGIN, 0) +
460-
2 * t.cellHorizontalPadding -
461-
4
455+
const bubblesWidth = labels.reduce(
456+
(acc, data) => ctx.measureText(data).width + acc + theme.bubblePadding * 2 + theme.bubbleMargin,
457+
0
462458
);
459+
460+
if (labels.length === 0) {
461+
return theme.cellHorizontalPadding * 2;
462+
}
463+
464+
return bubblesWidth + 2 * theme.cellHorizontalPadding - theme.bubbleMargin;
463465
},
464466
provideEditor: () => ({
465467
editor: Editor,

packages/cells/src/cells/tags-cell.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ interface TagsCellProps {
2121

2222
export type TagsCell = CustomCell<TagsCellProps>;
2323

24-
const tagHeight = 20;
25-
const innerPad = 6;
26-
2724
const EditorWrap = styled.div<{ tagHeight: number; innerPad: number }>`
2825
display: flex;
2926
flex-direction: column;
@@ -94,6 +91,8 @@ const renderer: CustomRenderer<TagsCell> = {
9491
width: rect.width - 2 * theme.cellHorizontalPadding,
9592
height: rect.height - 2 * theme.cellVerticalPadding,
9693
};
94+
const tagHeight = theme.bubbleHeight;
95+
const innerPad = theme.bubblePadding;
9796
const rows = Math.max(1, Math.floor(drawArea.height / (tagHeight + innerPad)));
9897

9998
let x = drawArea.x;
@@ -130,11 +129,14 @@ const renderer: CustomRenderer<TagsCell> = {
130129
provideEditor: () => {
131130
// eslint-disable-next-line react/display-name
132131
return p => {
133-
const { onChange, value } = p;
132+
const { onChange, value, theme } = p;
134133
const { readonly = false } = value;
135134
const { possibleTags, tags } = value.data;
136135
return (
137-
<EditorWrap tagHeight={tagHeight} innerPad={innerPad} className={readonly ? "gdg-readonly" : ""}>
136+
<EditorWrap
137+
tagHeight={theme.bubbleHeight}
138+
innerPad={theme.bubblePadding}
139+
className={readonly ? "gdg-readonly" : ""}>
138140
{possibleTags.map(t => {
139141
const selected = tags.indexOf(t.tag) !== -1;
140142
return (

packages/core/API.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,9 @@ The data grid uses the `Theme` provided to the DataEditer in the `theme` prop. T
387387
| fontFamily | string | --gdg-font-family | The font family used by the data grid. |
388388
| editorFontSize | string | --gdg-editor-font-size | The font size used by overlay editors. |
389389
| lineHeight | number | None | A unitless scaler which defines the height of a line of text relative to the ink size. |
390+
| bubbleHeight | number | --gdg-bubble-height | The height (in pixels) of a bubble. |
391+
| bubblePadding | number | --gdg-bubble-padding | The left & right padding (in pixels) of a bubble. |
392+
| bubbleMargin | number | --gdg-bubble-margin | The margin (in pixels) between bubbles. |
390393

391394
---
392395

packages/core/src/cells/bubble-cell.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@ export const bubbleCellRenderer: InternalCellRenderer<BubbleCell> = {
1212
needsHover: false,
1313
useLabel: false,
1414
needsHoverPosition: false,
15-
measure: (ctx, cell, t) =>
16-
cell.data.reduce((acc, data) => ctx.measureText(data).width + acc + 20, 0) + 2 * t.cellHorizontalPadding - 4,
15+
measure: (ctx, cell, theme) => {
16+
const bubblesWidth = cell.data.reduce(
17+
(acc, data) => ctx.measureText(data).width + acc + theme.bubblePadding * 2 + theme.bubbleMargin,
18+
0
19+
);
20+
if (cell.data.length === 0) return theme.cellHorizontalPadding * 2;
21+
return bubblesWidth + 2 * theme.cellHorizontalPadding - theme.bubbleMargin;
22+
},
1723
draw: a => drawBubbles(a, a.cell.data),
1824
provideEditor: () => p => {
1925
const { value } = p;
@@ -22,14 +28,10 @@ export const bubbleCellRenderer: InternalCellRenderer<BubbleCell> = {
2228
onPaste: () => undefined,
2329
};
2430

25-
const itemMargin = 4;
26-
2731
function drawBubbles(args: BaseDrawArgs, data: readonly string[]) {
2832
const { rect, theme, ctx, highlighted } = args;
2933
const { x, y, width: w, height: h } = rect;
30-
const bubbleHeight = 20;
31-
const bubblePad = 8;
32-
const bubbleMargin = itemMargin;
34+
3335
let renderX = x + theme.cellHorizontalPadding;
3436

3537
const renderBoxes: { x: number; width: number }[] = [];
@@ -41,18 +43,18 @@ function drawBubbles(args: BaseDrawArgs, data: readonly string[]) {
4143
width: textWidth,
4244
});
4345

44-
renderX += textWidth + bubblePad * 2 + bubbleMargin;
46+
renderX += textWidth + theme.bubblePadding * 2 + theme.bubbleMargin;
4547
}
4648

4749
ctx.beginPath();
4850
for (const rectInfo of renderBoxes) {
4951
roundedRect(
5052
ctx,
5153
rectInfo.x,
52-
y + (h - bubbleHeight) / 2,
53-
rectInfo.width + bubblePad * 2,
54-
bubbleHeight,
55-
theme.roundingRadius ?? bubbleHeight / 2
54+
y + (h - theme.bubbleHeight) / 2,
55+
rectInfo.width + theme.bubblePadding * 2,
56+
theme.bubbleHeight,
57+
theme.roundingRadius ?? theme.bubbleHeight / 2
5658
);
5759
}
5860
ctx.fillStyle = highlighted ? theme.bgBubbleSelected : theme.bgBubble;
@@ -61,6 +63,6 @@ function drawBubbles(args: BaseDrawArgs, data: readonly string[]) {
6163
for (const [i, rectInfo] of renderBoxes.entries()) {
6264
ctx.beginPath();
6365
ctx.fillStyle = theme.textBubble;
64-
ctx.fillText(data[i], rectInfo.x + bubblePad, y + h / 2 + getMiddleCenterBias(ctx, theme));
66+
ctx.fillText(data[i], rectInfo.x + theme.bubblePadding, y + h / 2 + getMiddleCenterBias(ctx, theme));
6567
}
6668
}

packages/core/src/cells/drilldown-cell.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,17 @@ export const drilldownCellRenderer: InternalCellRenderer<DrilldownCell> = {
1717
needsHover: false,
1818
useLabel: false,
1919
needsHoverPosition: false,
20-
measure: (ctx, cell, t) =>
20+
measure: (ctx, cell, theme) =>
2121
cell.data.reduce(
22-
(acc, data) => ctx.measureText(data.text).width + acc + 20 + (data.img !== undefined ? 18 : 0),
22+
(acc, data) =>
23+
ctx.measureText(data.text).width +
24+
acc +
25+
theme.bubblePadding * 2 +
26+
theme.bubbleMargin +
27+
(data.img !== undefined ? 18 : 0),
2328
0
2429
) +
25-
2 * t.cellHorizontalPadding -
30+
2 * theme.cellHorizontalPadding -
2631
4,
2732
draw: a => drawDrilldownCell(a, a.cell.data),
2833
provideEditor: () => p => {
@@ -32,8 +37,6 @@ export const drilldownCellRenderer: InternalCellRenderer<DrilldownCell> = {
3237
onPaste: () => undefined,
3338
};
3439

35-
const itemMargin = 4;
36-
3740
const drilldownCache: {
3841
[key: string]: HTMLCanvasElement;
3942
} = {};
@@ -133,8 +136,8 @@ function drawDrilldownCell(args: BaseDrawArgs, data: readonly DrilldownCellData[
133136
const y = Math.floor(rect.y + (rect.height - h) / 2);
134137

135138
const bubbleHeight = h - 10;
136-
const bubblePad = 8;
137-
const bubbleMargin = itemMargin;
139+
const bubblePad = theme.bubblePadding;
140+
const bubbleMargin = theme.bubbleMargin;
138141
let renderX = x + theme.cellHorizontalPadding;
139142
const rounding = theme.roundingRadius ?? 6;
140143

packages/core/src/common/styles.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ export function makeCSSStyle(theme: Theme): Record<string, string> {
2727
"--gdg-bg-header-hovered": theme.bgHeaderHovered,
2828
"--gdg-bg-bubble": theme.bgBubble,
2929
"--gdg-bg-bubble-selected": theme.bgBubbleSelected,
30+
"--gdg-bubble-height": `${theme.bubbleHeight}px`,
31+
"--gdg-bubble-padding": `${theme.bubblePadding}px`,
32+
"--gdg-bubble-margin": `${theme.bubbleMargin}px`,
3033
"--gdg-bg-search-result": theme.bgSearchResult,
3134
"--gdg-border-color": theme.borderColor,
3235
"--gdg-horizontal-border-color": theme.horizontalBorderColor ?? theme.borderColor,
@@ -72,6 +75,9 @@ export interface Theme {
7275
bgHeaderHovered: string;
7376
bgBubble: string;
7477
bgBubbleSelected: string;
78+
bubbleHeight: number;
79+
bubblePadding: number;
80+
bubbleMargin: number;
7581
bgSearchResult: string;
7682
borderColor: string;
7783
drilldownBorder: string;
@@ -116,6 +122,9 @@ const dataEditorBaseTheme: Theme = {
116122

117123
bgBubble: "#EDEDF3",
118124
bgBubbleSelected: "#FFFFFF",
125+
bubbleHeight: 20,
126+
bubblePadding: 6,
127+
bubbleMargin: 4,
119128

120129
bgSearchResult: "#fff9e3",
121130

packages/core/src/internal/data-grid-overlay-editor/private/bubbles-overlay-editor-style.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { styled } from "@linaria/react";
22

3-
const BUBBLE_HEIGHT = 20;
4-
53
export const BubblesOverlayEditorStyle = styled.div`
64
display: flex;
75
flex-wrap: wrap;
@@ -14,13 +12,13 @@ export const BubblesOverlayEditorStyle = styled.div`
1412
justify-content: center;
1513
align-items: center;
1614
17-
border-radius: var(--gdg-rounding-radius, ${BUBBLE_HEIGHT / 2}px);
15+
border-radius: var(--gdg-rounding-radius, calc(var(--gdg-bubble-height) / 2));
1816
19-
padding: 0 8px;
20-
height: ${BUBBLE_HEIGHT}px;
17+
padding: 0 var(--gdg-bubble-padding);
18+
height: var(--gdg-bubble-height);
2119
background-color: var(--gdg-bg-bubble);
2220
color: var(--gdg-text-dark);
23-
margin: 2px;
21+
margin: var(--gdg-bubble-margin);
2422
white-space: nowrap;
2523
}
2624

0 commit comments

Comments
 (0)