From 14e1ef6dc625a8d73a6a9a50469a289fdeb4e4c7 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 13 May 2025 14:26:00 -0700 Subject: [PATCH] fix: Fix regressions in `Field`. (#9011) --- core/field.ts | 28 +++++++++++++++++++++++++++- core/field_image.ts | 1 - core/field_input.ts | 20 ++++++++++++++++++++ core/field_variable.ts | 1 - 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/core/field.ts b/core/field.ts index 7aa348d52..5e9092f88 100644 --- a/core/field.ts +++ b/core/field.ts @@ -84,6 +84,9 @@ export abstract class Field */ DEFAULT_VALUE: T | null = null; + /** Non-breaking space. */ + static readonly NBSP = '\u00A0'; + /** * A value used to signal when a field's constructor should *not* set the * field's value or run configure_, and should allow a subclass to do that @@ -106,7 +109,28 @@ export abstract class Field * field is not yet initialized. Is *not* guaranteed to be accurate. */ private tooltip: Tooltip.TipInfo | null = null; - protected size_: Size; + + /** This field's dimensions. */ + private size: Size = new Size(0, 0); + + /** + * Gets the size of this field. Because getSize() and updateSize() have side + * effects, this acts as a shim for subclasses which wish to adjust field + * bounds when setting/getting the size without triggering unwanted rendering + * or other side effects. Note that subclasses must override *both* get and + * set if either is overridden; the implementation may just call directly + * through to super, but it must exist per the JS spec. + */ + protected get size_(): Size { + return this.size; + } + + /** + * Sets the size of this field. + */ + protected set size_(newValue: Size) { + this.size = newValue; + } /** The rendered field's SVG group element. */ protected fieldGroup_: SVGGElement | null = null; @@ -969,6 +993,8 @@ export abstract class Field // Truncate displayed string and add an ellipsis ('...'). text = text.substring(0, this.maxDisplayLength - 2) + '…'; } + // Replace whitespace with non-breaking spaces so the text doesn't collapse. + text = text.replace(/\s/g, Field.NBSP); if (this.sourceBlock_ && this.sourceBlock_.RTL) { // The SVG is LTR, force text to be RTL by adding an RLM. text += '\u200F'; diff --git a/core/field_image.ts b/core/field_image.ts index b65b77ae2..761294a8c 100644 --- a/core/field_image.ts +++ b/core/field_image.ts @@ -27,7 +27,6 @@ export class FieldImage extends Field { * of the field. */ private static readonly Y_PADDING = 1; - protected override size_: Size; protected readonly imageHeight: number; /** The function to be called when this field is clicked. */ diff --git a/core/field_input.ts b/core/field_input.ts index 2cdd80565..f329e0991 100644 --- a/core/field_input.ts +++ b/core/field_input.ts @@ -100,6 +100,26 @@ export abstract class FieldInput extends Field< */ override SERIALIZABLE = true; + /** + * Sets the size of this field. Although this appears to be a no-op, it must + * exist since the getter is overridden below. + */ + protected override set size_(newValue: Size) { + super.size_ = newValue; + } + + /** + * Returns the size of this field, with a minimum width of 14. + */ + protected override get size_() { + const s = super.size_; + if (s.width < 14) { + s.width = 14; + } + + return s; + } + /** * @param value The initial value of the field. Should cast to a string. * Defaults to an empty string if null or undefined. Also accepts diff --git a/core/field_variable.ts b/core/field_variable.ts index b54b113cd..aa4fdfe31 100644 --- a/core/field_variable.ts +++ b/core/field_variable.ts @@ -49,7 +49,6 @@ export class FieldVariable extends FieldDropdown { * dropdown. */ variableTypes: string[] | null = []; - protected override size_: Size; /** The variable model associated with this field. */ private variable: IVariableModel | null = null;