From 7c5dfeecf27e4415d735201d2ef266c3e448d699 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 8 Mar 2024 00:35:37 +0000 Subject: [PATCH 1/3] feat: add min and max to size --- core/utils/size.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/utils/size.ts b/core/utils/size.ts index ab88d2c8446..f386eff21a0 100644 --- a/core/utils/size.ts +++ b/core/utils/size.ts @@ -43,4 +43,20 @@ export class Size { } return a.width === b.width && a.height === b.height; } + + /** + * Returns a new size with the maximum width and heigh values out of both + * sizes. + */ + static max(a: Size, b: Size): Size { + return new Size(Math.max(a.width, b.width), Math.max(a.height, b.height)); + } + + /** + * Returns a new size with the minimum width and heigh values out of both + * sizes. + */ + static min(a: Size, b: Size): Size { + return new Size(Math.min(a.width, b.width), Math.min(a.height, b.height)); + } } From cddbee5c6e85ff699992b49fcc7dc916e36d2178 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 8 Mar 2024 01:27:01 +0000 Subject: [PATCH 2/3] fix: properly calculate the minimum size of the comment --- core/comments/comment_view.ts | 80 ++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/core/comments/comment_view.ts b/core/comments/comment_view.ts index 21d2ebcfd06..a37dfc882b6 100644 --- a/core/comments/comment_view.ts +++ b/core/comments/comment_view.ts @@ -13,7 +13,6 @@ import * as css from '../css.js'; import {Coordinate, Size, browserEvents} from '../utils.js'; import * as touch from '../touch.js'; -const MIN_SIZE = new Size(100, 60); export class CommentView implements IRenderedElement { /** The root group element of the comment view. */ private svgRoot: SVGGElement; @@ -257,19 +256,19 @@ export class CommentView implements IRenderedElement { * elements to reflect the new size. */ setSize(size: Size) { - size = new Size( - Math.max(size.width, MIN_SIZE.width), - Math.max(size.height, MIN_SIZE.height), - ); - - const oldSize = this.size; - this.size = size; const topBarSize = this.topBar.getBBox(); const deleteSize = this.deleteIcon.getBBox(); const foldoutSize = this.foldoutIcon.getBBox(); const textPreviewSize = this.textPreview.getBBox(); const resizeSize = this.resizeHandle.getBBox(); + size = Size.max( + size, + this.calcMinSize(topBarSize, foldoutSize, deleteSize), + ); + const oldSize = this.size; + this.size = size; + this.svgRoot.setAttribute('height', `${size.height}`); this.svgRoot.setAttribute('width', `${size.width}`); @@ -292,6 +291,51 @@ export class CommentView implements IRenderedElement { this.onSizeChange(oldSize, this.size); } + /** + * Calculates the minimum size for the uncollapsed comment based on text + * size and visible icons. + * + * The minimum width is based on the width of the truncated preview text. + * + * The minimum height is based on the height of the top bar. + */ + private calcMinSize( + topBarSize: Size, + foldoutSize: Size, + deleteSize: Size, + ): Size { + this.updateTextPreview(this.textArea.value ?? ''); + const textPreviewWidth = dom.getTextWidth(this.textPreview); + + const foldoutMargin = this.calcFoldoutMargin(topBarSize, foldoutSize); + const deleteMargin = this.calcDeleteMargin(topBarSize, deleteSize); + + let width = textPreviewWidth; + if (this.foldoutIcon.checkVisibility()) { + width += foldoutSize.width + foldoutMargin * 2; + } else if (textPreviewWidth) { + width += 4; // Arbitrary margin before text. + } + if (this.deleteIcon.checkVisibility()) { + width += deleteSize.width + deleteMargin * 2; + } else if (textPreviewWidth) { + width += 4; // Arbitrary margin after text. + } + + // Arbitrary additional height. + const height = topBarSize.height + 20; + + return new Size(width, height); + } + + private calcDeleteMargin(topBarSize: Size, deleteSize: Size) { + return (topBarSize.height - deleteSize.height) / 2; + } + + private calcFoldoutMargin(topBarSize: Size, foldoutSize: Size) { + return (topBarSize.height - foldoutSize.height) / 2; + } + /** Updates the size of the text area elements to reflect the new size. */ private updateTextAreaSize(size: Size, topBarSize: Size) { this.foreignObject.setAttribute( @@ -313,7 +357,7 @@ export class CommentView implements IRenderedElement { topBarSize: Size, deleteSize: Size, ) { - const deleteMargin = (topBarSize.height - deleteSize.height) / 2; + const deleteMargin = this.calcDeleteMargin(topBarSize, deleteSize); this.deleteIcon.setAttribute('y', `${deleteMargin}`); this.deleteIcon.setAttribute( 'x', @@ -325,7 +369,7 @@ export class CommentView implements IRenderedElement { * Updates the position of the foldout icon elements to reflect the new size. */ private updateFoldoutIconPosition(topBarSize: Size, foldoutSize: Size) { - const foldoutMargin = (topBarSize.height - foldoutSize.height) / 2; + const foldoutMargin = this.calcFoldoutMargin(topBarSize, foldoutSize); this.foldoutIcon.setAttribute('y', `${foldoutMargin}`); this.foldoutIcon.setAttribute('x', `${foldoutMargin}`); } @@ -341,8 +385,8 @@ export class CommentView implements IRenderedElement { foldoutSize: Size, ) { const textPreviewMargin = (topBarSize.height - textPreviewSize.height) / 2; - const deleteMargin = (topBarSize.height - deleteSize.height) / 2; - const foldoutMargin = (topBarSize.height - foldoutSize.height) / 2; + const deleteMargin = this.calcDeleteMargin(topBarSize, deleteSize); + const foldoutMargin = this.calcFoldoutMargin(topBarSize, foldoutSize); const textPreviewWidth = size.width - @@ -578,13 +622,19 @@ export class CommentView implements IRenderedElement { private onTextChange() { const oldText = this.text; this.text = this.textArea.value; - this.textPreviewNode.textContent = this.truncateText(this.text); + this.updateTextPreview(this.text); + // Update size in case our minimum size increased. + this.setSize(this.size); // Loop through listeners backwards in case they remove themselves. for (let i = this.textChangeListeners.length - 1; i >= 0; i--) { this.textChangeListeners[i](oldText, this.text); } } + private updateTextPreview(text: string) { + this.textPreviewNode.textContent = this.truncateText(text); + } + /** Truncates the text to fit within the top view. */ private truncateText(text: string): string { return text.length >= 12 ? `${text.substring(0, 9)}...` : text; @@ -703,11 +753,11 @@ css.register(` .blocklyComment .blocklyCommentPreview.blocklyText { fill: var(--commentIconColour); dominant-baseline: middle; - display: none; + visibility: hidden; } .blocklyCollapsed.blocklyComment .blocklyCommentPreview { - display: block; + visibility: visible; } .blocklyCollapsed.blocklyComment .blocklyCommentForeignObject, From b39568055b67b77053acf970eb6cf43e204dd284 Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Mon, 11 Mar 2024 20:55:52 +0000 Subject: [PATCH 3/3] fix: inline docs --- core/comments/comment_view.ts | 3 +++ core/utils/size.ts | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/comments/comment_view.ts b/core/comments/comment_view.ts index a37dfc882b6..05491f0aceb 100644 --- a/core/comments/comment_view.ts +++ b/core/comments/comment_view.ts @@ -328,10 +328,12 @@ export class CommentView implements IRenderedElement { return new Size(width, height); } + /** Calculates the margin that should exist around the delete icon. */ private calcDeleteMargin(topBarSize: Size, deleteSize: Size) { return (topBarSize.height - deleteSize.height) / 2; } + /** Calculates the margin that should exist around the foldout icon. */ private calcFoldoutMargin(topBarSize: Size, foldoutSize: Size) { return (topBarSize.height - foldoutSize.height) / 2; } @@ -631,6 +633,7 @@ export class CommentView implements IRenderedElement { } } + /** Updates the preview text element to reflect the given text. */ private updateTextPreview(text: string) { this.textPreviewNode.textContent = this.truncateText(text); } diff --git a/core/utils/size.ts b/core/utils/size.ts index f386eff21a0..705dc2c2897 100644 --- a/core/utils/size.ts +++ b/core/utils/size.ts @@ -45,7 +45,7 @@ export class Size { } /** - * Returns a new size with the maximum width and heigh values out of both + * Returns a new size with the maximum width and height values out of both * sizes. */ static max(a: Size, b: Size): Size { @@ -53,7 +53,7 @@ export class Size { } /** - * Returns a new size with the minimum width and heigh values out of both + * Returns a new size with the minimum width and height values out of both * sizes. */ static min(a: Size, b: Size): Size {