diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md
index c7a47bae9..bfadf2bd1 100644
--- a/ci/release/changelogs/next.md
+++ b/ci/release/changelogs/next.md
@@ -28,6 +28,7 @@
#### Bugfixes ⛑️
- Fixes groups overlapping in sequence diagrams when they end in a self loop. [#728](https://github.com/terrastruct/d2/pull/728)
-- Fixed dimensions of unlabeled squares or circles with only a set width or height. [#702](https://github.com/terrastruct/d2/pull/702)
-- Fixed scaling of actor shapes in sequence diagrams. [#702](https://github.com/terrastruct/d2/pull/702)
+- Fixes dimensions of unlabeled squares or circles with only a set width or height. [#702](https://github.com/terrastruct/d2/pull/702)
+- Fixes scaling of actor shapes in sequence diagrams. [#702](https://github.com/terrastruct/d2/pull/702)
- Images can now be set to sizes smaller than 128x128. [#702](https://github.com/terrastruct/d2/pull/702)
+- Fixes class height when there are no rows. [#756](https://github.com/terrastruct/d2/pull/756)
diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go
index a37c93b77..0b95146e9 100644
--- a/d2graph/d2graph.go
+++ b/d2graph/d2graph.go
@@ -828,7 +828,7 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R
rowHeight := GetTextDimensions(mtexts, ruler, anyRowText, go2.Pointer(d2fonts.SourceCodePro)).Height + d2target.VerticalPadding
dims.Height = rowHeight * (len(obj.Class.Fields) + len(obj.Class.Methods) + 2)
} else {
- dims.Height = go2.Max(12, labelDims.Height)
+ dims.Height = 2*go2.Max(12, labelDims.Height) + d2target.VerticalPadding
}
case d2target.ShapeSQLTable:
diff --git a/e2etests/regression_test.go b/e2etests/regression_test.go
index 02d82f9b5..4e70e1f5b 100644
--- a/e2etests/regression_test.go
+++ b/e2etests/regression_test.go
@@ -1,7 +1,10 @@
package e2etests
import (
+ "math"
"testing"
+
+ "oss.terrastruct.com/d2/d2target"
)
func testRegression(t *testing.T) {
@@ -446,6 +449,30 @@ b -> c
`,
},
+ {
+ name: "empty_class_height",
+ script: `
+class1: class with rows {
+ shape: class
+ -num: int
+ -timeout: int
+}
+
+class2: class without rows {
+ shape: class
+}
+`,
+ assertions: func(t *testing.T, g *d2target.Diagram) {
+ if len(g.Shapes) != 2 {
+ t.Fatal("expected 2 shapes")
+ }
+ c1Height := float64(g.Shapes[0].Height)
+ c2Height := float64(g.Shapes[1].Height)
+ if math.Round(c1Height/2.) != c2Height {
+ t.Fatal("expected rowless class to be 1/2 height of class with 2 rows")
+ }
+ },
+ },
}
runa(t, tcs)
diff --git a/e2etests/testdata/measured/empty-class/dagre/board.exp.json b/e2etests/testdata/measured/empty-class/dagre/board.exp.json
index 6a7752e8b..43926e6d3 100644
--- a/e2etests/testdata/measured/empty-class/dagre/board.exp.json
+++ b/e2etests/testdata/measured/empty-class/dagre/board.exp.json
@@ -10,7 +10,7 @@
"y": 0
},
"width": 112,
- "height": 12,
+ "height": 44,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
diff --git a/e2etests/testdata/measured/empty-class/dagre/sketch.exp.svg b/e2etests/testdata/measured/empty-class/dagre/sketch.exp.svg
index a87ea964c..6927edd4b 100644
--- a/e2etests/testdata/measured/empty-class/dagre/sketch.exp.svg
+++ b/e2etests/testdata/measured/empty-class/dagre/sketch.exp.svg
@@ -3,7 +3,7 @@
id="d2-svg"
style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
-width="316" height="216" viewBox="-102 -102 316 216">
\ No newline at end of file
diff --git a/e2etests/testdata/regression/empty_class_height/dagre/board.exp.json b/e2etests/testdata/regression/empty_class_height/dagre/board.exp.json
new file mode 100644
index 000000000..8ba549b2c
--- /dev/null
+++ b/e2etests/testdata/regression/empty_class_height/dagre/board.exp.json
@@ -0,0 +1,104 @@
+{
+ "name": "",
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "class1",
+ "type": "class",
+ "pos": {
+ "x": 0,
+ "y": 0
+ },
+ "width": 319,
+ "height": 184,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#0A0F25",
+ "stroke": "#FFFFFF",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": [
+ {
+ "name": "num",
+ "type": "int",
+ "visibility": "private"
+ },
+ {
+ "name": "timeout",
+ "type": "int",
+ "visibility": "private"
+ }
+ ],
+ "methods": null,
+ "columns": null,
+ "label": "class with rows",
+ "fontSize": 20,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 214,
+ "labelHeight": 31,
+ "zIndex": 0,
+ "level": 1,
+ "primaryAccentColor": "#0D32B2",
+ "secondaryAccentColor": "#4A6FF3",
+ "neutralAccentColor": "#676C7E"
+ },
+ {
+ "id": "class2",
+ "type": "class",
+ "pos": {
+ "x": 379,
+ "y": 46
+ },
+ "width": 362,
+ "height": 92,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#0A0F25",
+ "stroke": "#FFFFFF",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "class without rows",
+ "fontSize": 20,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 257,
+ "labelHeight": 31,
+ "zIndex": 0,
+ "level": 1,
+ "primaryAccentColor": "#0D32B2",
+ "secondaryAccentColor": "#4A6FF3",
+ "neutralAccentColor": "#676C7E"
+ }
+ ],
+ "connections": []
+}
diff --git a/e2etests/testdata/regression/empty_class_height/dagre/sketch.exp.svg b/e2etests/testdata/regression/empty_class_height/dagre/sketch.exp.svg
new file mode 100644
index 000000000..e27a99065
--- /dev/null
+++ b/e2etests/testdata/regression/empty_class_height/dagre/sketch.exp.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/regression/empty_class_height/elk/board.exp.json b/e2etests/testdata/regression/empty_class_height/elk/board.exp.json
new file mode 100644
index 000000000..e2cad4326
--- /dev/null
+++ b/e2etests/testdata/regression/empty_class_height/elk/board.exp.json
@@ -0,0 +1,104 @@
+{
+ "name": "",
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "class1",
+ "type": "class",
+ "pos": {
+ "x": 12,
+ "y": 12
+ },
+ "width": 319,
+ "height": 184,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#0A0F25",
+ "stroke": "#FFFFFF",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": [
+ {
+ "name": "num",
+ "type": "int",
+ "visibility": "private"
+ },
+ {
+ "name": "timeout",
+ "type": "int",
+ "visibility": "private"
+ }
+ ],
+ "methods": null,
+ "columns": null,
+ "label": "class with rows",
+ "fontSize": 20,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 214,
+ "labelHeight": 31,
+ "zIndex": 0,
+ "level": 1,
+ "primaryAccentColor": "#0D32B2",
+ "secondaryAccentColor": "#4A6FF3",
+ "neutralAccentColor": "#676C7E"
+ },
+ {
+ "id": "class2",
+ "type": "class",
+ "pos": {
+ "x": 351,
+ "y": 58
+ },
+ "width": 362,
+ "height": 92,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#0A0F25",
+ "stroke": "#FFFFFF",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "class without rows",
+ "fontSize": 20,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 257,
+ "labelHeight": 31,
+ "zIndex": 0,
+ "level": 1,
+ "primaryAccentColor": "#0D32B2",
+ "secondaryAccentColor": "#4A6FF3",
+ "neutralAccentColor": "#676C7E"
+ }
+ ],
+ "connections": []
+}
diff --git a/e2etests/testdata/regression/empty_class_height/elk/sketch.exp.svg b/e2etests/testdata/regression/empty_class_height/elk/sketch.exp.svg
new file mode 100644
index 000000000..58188b652
--- /dev/null
+++ b/e2etests/testdata/regression/empty_class_height/elk/sketch.exp.svg
@@ -0,0 +1,56 @@
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/regression/only_header_class_table/dagre/board.exp.json b/e2etests/testdata/regression/only_header_class_table/dagre/board.exp.json
index 4c412e4b6..87d63c1cb 100644
--- a/e2etests/testdata/regression/only_header_class_table/dagre/board.exp.json
+++ b/e2etests/testdata/regression/only_header_class_table/dagre/board.exp.json
@@ -10,7 +10,7 @@
"y": 0
},
"width": 1082,
- "height": 36,
+ "height": 92,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
@@ -50,7 +50,7 @@
"type": "sql_table",
"pos": {
"x": 341,
- "y": 136
+ "y": 192
},
"width": 401,
"height": 36,
@@ -93,7 +93,7 @@
"type": "sql_table",
"pos": {
"x": 341,
- "y": 272
+ "y": 328
},
"width": 401,
"height": 72,
@@ -189,19 +189,19 @@
"route": [
{
"x": 541,
- "y": 36
+ "y": 92
},
{
"x": 541,
- "y": 76
+ "y": 132
},
{
"x": 541,
- "y": 96
+ "y": 152
},
{
"x": 541,
- "y": 136
+ "y": 192
}
],
"isCurve": true,
@@ -237,19 +237,19 @@
"route": [
{
"x": 541,
- "y": 172
+ "y": 228
},
{
"x": 541,
- "y": 212
+ "y": 268
},
{
"x": 541,
- "y": 232
+ "y": 288
},
{
"x": 541,
- "y": 272
+ "y": 328
}
],
"isCurve": true,
diff --git a/e2etests/testdata/regression/only_header_class_table/dagre/sketch.exp.svg b/e2etests/testdata/regression/only_header_class_table/dagre/sketch.exp.svg
index d4104ee0f..e10f558fc 100644
--- a/e2etests/testdata/regression/only_header_class_table/dagre/sketch.exp.svg
+++ b/e2etests/testdata/regression/only_header_class_table/dagre/sketch.exp.svg
@@ -3,7 +3,7 @@
id="d2-svg"
style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
-width="1286" height="548" viewBox="-102 -102 1286 548">