Fix newlines in text geo shapes (#2059)
Previously, entering a geo shape and adding a bunch of newlines wouldn't correctly update the shape's height. This fixes that. ### Change Type - [x] `patch` — Bug fix ### Test Plan 1. Create a geo shape 2. Enter text editing mode 3. Spam the enter key 4. See that the shape grows appropriately 5. Exit editing and check that the trailing newlines have been deleted. - [ ] Unit Tests - [x] End to end tests --------- Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com> Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
|
@ -7,7 +7,30 @@ import { setupPage } from '../shared-e2e'
|
|||
declare const editor: Editor
|
||||
|
||||
test.describe('Export snapshots', () => {
|
||||
const snapshots = {} as Record<string, TLShapePartial[]>
|
||||
const snapshots = {
|
||||
'Exports geo text with leading line breaks': [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'geo',
|
||||
props: {
|
||||
w: 100,
|
||||
h: 30,
|
||||
text: '\n\n\n\n\n\ntext',
|
||||
},
|
||||
},
|
||||
],
|
||||
'Exports geo text with trailing line breaks': [
|
||||
{
|
||||
id: 'shape:testShape' as TLShapeId,
|
||||
type: 'geo',
|
||||
props: {
|
||||
w: 100,
|
||||
h: 30,
|
||||
text: 'text\n\n\n\n\n\n',
|
||||
},
|
||||
},
|
||||
],
|
||||
} as Record<string, TLShapePartial[]>
|
||||
|
||||
for (const fill of ['none', 'semi', 'solid', 'pattern']) {
|
||||
snapshots[`geo fill=${fill}`] = [
|
||||
|
|
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 4.7 KiB |
|
@ -218,4 +218,28 @@ test.describe('text measurement', () => {
|
|||
|
||||
expect(formatLines(spans)).toEqual([])
|
||||
})
|
||||
|
||||
test('should handle trailing newlines', async () => {
|
||||
const spans = await page.evaluate<
|
||||
{ text: string; box: Box2dModel }[],
|
||||
typeof measureTextSpansOptions
|
||||
>(
|
||||
async (options) => editor.textMeasure.measureTextSpans('hi\n\n\n', options),
|
||||
measureTextSpansOptions
|
||||
)
|
||||
|
||||
expect(formatLines(spans)).toEqual([['hi', '\n'], [' \n'], [' \n'], [' ']])
|
||||
})
|
||||
|
||||
test('should handle only newlines', async () => {
|
||||
const spans = await page.evaluate<
|
||||
{ text: string; box: Box2dModel }[],
|
||||
typeof measureTextSpansOptions
|
||||
>(
|
||||
async (options) => editor.textMeasure.measureTextSpans('\n\n\n', options),
|
||||
measureTextSpansOptions
|
||||
)
|
||||
|
||||
expect(formatLines(spans)).toEqual([[' \n'], [' \n'], [' \n'], [' ']])
|
||||
})
|
||||
})
|
||||
|
|
|
@ -40,8 +40,6 @@ const spaceCharacterRegex = /\s/
|
|||
export class TextManager {
|
||||
constructor(public editor: Editor) {}
|
||||
|
||||
private textElement: HTMLDivElement | null = null
|
||||
|
||||
private getTextElement() {
|
||||
const oldElm = document.querySelector('.tl-text-measure')
|
||||
oldElm?.remove()
|
||||
|
@ -198,6 +196,8 @@ export class TextManager {
|
|||
textToMeasure: string,
|
||||
opts: TLMeasureTextSpanOpts
|
||||
): { text: string; box: Box2dModel }[] {
|
||||
if (textToMeasure === '') return []
|
||||
|
||||
const shouldTruncateToFirstLine =
|
||||
opts.overflow === 'truncate-ellipsis' || opts.overflow === 'truncate-clip'
|
||||
|
||||
|
@ -218,6 +218,8 @@ export class TextManager {
|
|||
element.style.setProperty('word-break', 'break-all')
|
||||
}
|
||||
|
||||
textToMeasure = normalizeTextForDom(textToMeasure)
|
||||
|
||||
// Render the text into the measurement element:
|
||||
element.textContent = textToMeasure
|
||||
|
||||
|
|
|
@ -930,8 +930,8 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
|
|||
}
|
||||
|
||||
override onBeforeUpdate = (prev: TLGeoShape, next: TLGeoShape) => {
|
||||
const prevText = prev.props.text.trimEnd()
|
||||
const nextText = next.props.text.trimEnd()
|
||||
const prevText = prev.props.text
|
||||
const nextText = next.props.text
|
||||
|
||||
if (
|
||||
prevText === nextText &&
|
||||
|
@ -1043,7 +1043,7 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
|
|||
}
|
||||
|
||||
function getLabelSize(editor: Editor, shape: TLGeoShape) {
|
||||
const text = shape.props.text.trimEnd()
|
||||
const text = shape.props.text
|
||||
|
||||
if (!text) {
|
||||
return { w: 0, h: 0 }
|
||||
|
|
|
@ -55,7 +55,7 @@ export const TextLabel = React.memo(function TextLabel<
|
|||
} = useEditableText(id, type, text)
|
||||
|
||||
const finalText = TextHelpers.normalizeTextForDom(text)
|
||||
const hasText = finalText.trim().length > 0
|
||||
const hasText = finalText.length > 0
|
||||
|
||||
const legacyAlign = isLegacyAlign(align)
|
||||
const theme = useDefaultColorTheme()
|
||||
|
|