[fix] various text (#1350)
This PR updates tests for the text shape, as well as updating the logic of `getTextLines`. We now: - allow leading whitespace - allow white space to cause line breaks, trim the whitespace off of the end of the line. Crazy times! - fix a bug with geo shapes changes width when growY changes Note that this is not a "full solution" to line breaks that are caused by whitespace + wrapping. AFAIK this is impossible to fix in SVG-land without measuring the SVG element in order to collapse whitespace in the same way that it collapses in HTML layout. ### Change Type - [x] `patch` — Bug Fix - [ ] `minor` — New Feature - [ ] `major` — Breaking Change - [ ] `dependencies` — Dependency Update (publishes a `patch` release, for devDependencies use `internal`) - [ ] `documentation` — Changes to the documentation only (will not publish a new version) - [ ] `tests` — Changes to any testing-related code only (will not publish a new version) - [ ] `internal` — Any other changes that don't affect the published package (will not publish a new version) ### Test Plan - [x] Webdriver tests ### Release Notes - Allow leading whitespace
This commit is contained in:
parent
3437ca89d9
commit
a722e3e6f0
8 changed files with 78 additions and 21 deletions
|
@ -20,4 +20,7 @@
|
|||
**/setupJest.js
|
||||
apps/webdriver/www
|
||||
apps/vscode/extension/editor
|
||||
apps/examples/www
|
||||
apps/examples/www
|
||||
apps/docs/content.json
|
||||
apps/vscode/extension/editor/index.js
|
||||
apps/vscode/extension/editor/tldraw-assets.json
|
|
@ -8,4 +8,8 @@
|
|||
**/.tsbuild*
|
||||
**/.next/*
|
||||
*.mdx
|
||||
**/_archive/*
|
||||
**/_archive/*
|
||||
apps/docs/content.json
|
||||
apps/vscode/extension/editor/index.js
|
||||
apps/vscode/extension/editor/tldraw-assets.json
|
||||
apps/webdriver/www/index.js
|
|
@ -179,7 +179,7 @@ describe('text measurement', () => {
|
|||
expect(lines).toEqual(['testing', 'testing'])
|
||||
})
|
||||
|
||||
it('should strip whitespace at the end of unwrapped lines', async () => {
|
||||
it('strips whitespace at the end of unwrapped lines', async () => {
|
||||
await ui.app.setup()
|
||||
const lines = await browser.execute((options) => {
|
||||
return window.app.textMeasure.getTextLines({
|
||||
|
@ -192,7 +192,7 @@ describe('text measurement', () => {
|
|||
expect(lines).toEqual(['testing testing'])
|
||||
})
|
||||
|
||||
it('should strip whitespace from the start of an unwrapped line', async () => {
|
||||
it('preserves whitespace at the start of an unwrapped line', async () => {
|
||||
await ui.app.setup()
|
||||
const lines = await browser.execute((options) => {
|
||||
return window.app.textMeasure.getTextLines({
|
||||
|
@ -202,7 +202,7 @@ describe('text measurement', () => {
|
|||
})
|
||||
}, getTextLinesOptions)
|
||||
|
||||
expect(lines).toEqual(['testing testing'])
|
||||
expect(lines).toEqual([' testing testing'])
|
||||
})
|
||||
|
||||
it('should place starting whitespace on its own line if it has to', async () => {
|
||||
|
@ -217,7 +217,43 @@ describe('text measurement', () => {
|
|||
expect(lines).toEqual(['', 'testing', 'testing'])
|
||||
})
|
||||
|
||||
it('should place ending whitespace on its own line if it has to', async () => {
|
||||
it('trims ending whitespace', async () => {
|
||||
await ui.app.setup()
|
||||
const lines = await browser.execute((options) => {
|
||||
return window.app.textMeasure.getTextLines({
|
||||
...options,
|
||||
text: 'testing testing ',
|
||||
})
|
||||
}, getTextLinesOptions)
|
||||
|
||||
expect(lines).toEqual(['testing', 'testing'])
|
||||
})
|
||||
|
||||
it('allows whitespace to cause breaks, however trims it at the end anyway', async () => {
|
||||
await ui.app.setup()
|
||||
const lines = await browser.execute((options) => {
|
||||
return window.app.textMeasure.getTextLines({
|
||||
...options,
|
||||
text: 'ok hi testing',
|
||||
})
|
||||
}, getTextLinesOptions)
|
||||
|
||||
expect(lines).toEqual(['ok hi', 'testing'])
|
||||
})
|
||||
|
||||
it('respects leading whitespace', async () => {
|
||||
await ui.app.setup()
|
||||
const lines = await browser.execute((options) => {
|
||||
return window.app.textMeasure.getTextLines({
|
||||
...options,
|
||||
text: ' ok hi testing ',
|
||||
})
|
||||
}, getTextLinesOptions)
|
||||
|
||||
expect(lines).toEqual([' ok hi', 'testing'])
|
||||
})
|
||||
|
||||
it('should handle multiline text', async () => {
|
||||
await ui.app.setup()
|
||||
const lines = await browser.execute((options) => {
|
||||
return window.app.textMeasure.getTextLines({
|
||||
|
@ -228,6 +264,19 @@ describe('text measurement', () => {
|
|||
|
||||
expect(lines).toEqual(['testing', 'testing'])
|
||||
})
|
||||
|
||||
it('should break long strings of text', async () => {
|
||||
await ui.app.setup()
|
||||
const lines = await browser.execute((options) => {
|
||||
return window.app.textMeasure.getTextLines({
|
||||
...options,
|
||||
text: 'testingtestingtestingtestingtestingtesting',
|
||||
})
|
||||
}, getTextLinesOptions)
|
||||
|
||||
expect(lines).toEqual(['testingt', 'estingte', 'stingtes', 'tingtest', 'ingtesti', 'ng'])
|
||||
})
|
||||
|
||||
it('should return an empty array if the text is empty', async () => {
|
||||
await ui.app.setup()
|
||||
const lines = await browser.execute((options) => {
|
||||
|
|
|
@ -19,6 +19,9 @@ export class TextManager {
|
|||
constructor(public app: App) {}
|
||||
|
||||
getTextElement() {
|
||||
const oldElm = document.querySelector('.tl-text-measure')
|
||||
oldElm?.remove()
|
||||
|
||||
const elm = document.createElement('div')
|
||||
this.app.getContainer().appendChild(elm)
|
||||
|
||||
|
@ -59,8 +62,6 @@ export class TextManager {
|
|||
|
||||
const rect = elm.getBoundingClientRect()
|
||||
|
||||
elm.remove()
|
||||
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
@ -252,7 +253,7 @@ export class TextManager {
|
|||
elm.remove()
|
||||
|
||||
// We're done! Join the words in each line.
|
||||
const result: string[] = lines.map((line) => line.join(''))
|
||||
const result: string[] = lines.map((line) => line.join('').trimEnd())
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -910,13 +910,13 @@ export class TLArrowUtil extends TLShapeUtil<TLArrowShape> {
|
|||
props: { text },
|
||||
} = shape
|
||||
|
||||
if (text.trim() !== shape.props.text) {
|
||||
if (text.trimEnd() !== shape.props.text) {
|
||||
this.app.updateShapes([
|
||||
{
|
||||
id,
|
||||
type,
|
||||
props: {
|
||||
text: text.trim(),
|
||||
text: text.trimEnd(),
|
||||
},
|
||||
},
|
||||
])
|
||||
|
|
|
@ -324,13 +324,13 @@ export class TLGeoUtil extends TLBoxUtil<TLGeoShape> {
|
|||
props: { text },
|
||||
} = shape
|
||||
|
||||
if (text.trim() !== shape.props.text) {
|
||||
if (text.trimEnd() !== shape.props.text) {
|
||||
this.app.updateShapes([
|
||||
{
|
||||
id,
|
||||
type,
|
||||
props: {
|
||||
text: text.trim(),
|
||||
text: text.trimEnd(),
|
||||
},
|
||||
},
|
||||
])
|
||||
|
@ -808,8 +808,8 @@ export class TLGeoUtil extends TLBoxUtil<TLGeoShape> {
|
|||
}
|
||||
|
||||
onBeforeUpdate = (prev: TLGeoShape, next: TLGeoShape) => {
|
||||
const prevText = prev.props.text.trim()
|
||||
const nextText = next.props.text.trim()
|
||||
const prevText = prev.props.text.trimEnd()
|
||||
const nextText = next.props.text.trimEnd()
|
||||
|
||||
if (
|
||||
prevText === nextText &&
|
||||
|
@ -876,7 +876,7 @@ export class TLGeoUtil extends TLBoxUtil<TLGeoShape> {
|
|||
props: {
|
||||
...next.props,
|
||||
growY,
|
||||
w: nextWidth,
|
||||
w: Math.max(next.props.w, nextWidth),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -921,7 +921,7 @@ export class TLGeoUtil extends TLBoxUtil<TLGeoShape> {
|
|||
}
|
||||
|
||||
function getLabelSize(app: App, shape: TLGeoShape) {
|
||||
const text = shape.props.text.trim()
|
||||
const text = shape.props.text.trimEnd()
|
||||
|
||||
if (!text) {
|
||||
return { w: 0, h: 0 }
|
||||
|
|
|
@ -206,13 +206,13 @@ export class TLNoteUtil extends TLShapeUtil<TLNoteShape> {
|
|||
props: { text },
|
||||
} = shape
|
||||
|
||||
if (text.trim() !== shape.props.text) {
|
||||
if (text.trimEnd() !== shape.props.text) {
|
||||
this.app.updateShapes([
|
||||
{
|
||||
id,
|
||||
type,
|
||||
props: {
|
||||
text: text.trim(),
|
||||
text: text.trimEnd(),
|
||||
},
|
||||
},
|
||||
])
|
||||
|
|
|
@ -263,7 +263,7 @@ export class TLTextUtil extends TLShapeUtil<TLTextShape> {
|
|||
props: { text },
|
||||
} = shape
|
||||
|
||||
const trimmedText = shape.props.text.trim()
|
||||
const trimmedText = shape.props.text.trimEnd()
|
||||
|
||||
if (trimmedText.length === 0) {
|
||||
this.app.deleteShapes([shape.id])
|
||||
|
@ -274,7 +274,7 @@ export class TLTextUtil extends TLShapeUtil<TLTextShape> {
|
|||
id,
|
||||
type,
|
||||
props: {
|
||||
text: text.trim(),
|
||||
text: text.trimEnd(),
|
||||
},
|
||||
},
|
||||
])
|
||||
|
|
Loading…
Reference in a new issue