[improvement] set horizontal position using text alignment (#1419)
This PR makes it so that horizontal alignment in geo and sticky note shapes also effects the position of the text within the shape. <img width="1169" alt="image" src="https://github.com/tldraw/tldraw/assets/23072548/96b28a7d-0f13-46ba-9ea1-82d02b4f870b"> <img width="1274" alt="image" src="https://github.com/tldraw/tldraw/assets/23072548/fa768c71-4e9e-4cfe-ad8a-94d7700c445d"> This PR also places the shape's label at the center when there is no text and the shape is not editing. ### Change Type - [x] `minor` — New Feature ### Test Plan 1. Create shapes with labels 2. Confirm that their labels are positioned correctly 3. Export the shapes and verify the export ### Release Notes - Geo shapes and sticky notes now position their labels based on their alignment.
This commit is contained in:
parent
818972f222
commit
2a7b2dcdfd
5 changed files with 25 additions and 27 deletions
|
@ -1002,6 +1002,7 @@ input,
|
|||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: var(--color-text);
|
||||
text-shadow: var(--tl-text-outline);
|
||||
overflow: hidden;
|
||||
|
|
|
@ -672,8 +672,16 @@ export class TLGeoUtil extends TLBoxUtil<TLGeoShape> {
|
|||
width: labelSize.w,
|
||||
})
|
||||
|
||||
// yuck, include padding as magic number
|
||||
textBgEl.setAttribute('transform', `translate(${(bounds.width - labelSize.w) / 2}, 0)`)
|
||||
switch (shape.props.align) {
|
||||
case 'middle': {
|
||||
textBgEl.setAttribute('transform', `translate(${(bounds.width - labelSize.w) / 2}, 0)`)
|
||||
break
|
||||
}
|
||||
case 'end': {
|
||||
textBgEl.setAttribute('transform', `translate(${bounds.width - labelSize.w}, 0)`)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const textElm = textBgEl.cloneNode(true) as SVGTextElement
|
||||
textElm.setAttribute('fill', colors.fill[shape.props.labelColor])
|
||||
|
|
|
@ -151,27 +151,7 @@ export class TLNoteUtil extends TLShapeUtil<TLNoteShape> {
|
|||
...opts,
|
||||
})
|
||||
|
||||
const maxWidth = lines.reduce((max, line) => {
|
||||
return Math.max(
|
||||
max,
|
||||
this.app.textMeasure.measureText({
|
||||
...TEXT_PROPS,
|
||||
text: line.trim(),
|
||||
fontFamily: opts.fontFamily,
|
||||
fontSize: opts.fontSize,
|
||||
width: 'fit-content',
|
||||
padding: `0px`,
|
||||
}).w
|
||||
)
|
||||
}, 0)
|
||||
|
||||
if (shape.props.align === 'start') {
|
||||
opts.padding = (bounds.width - maxWidth) / 2
|
||||
} else if (shape.props.align === 'end') {
|
||||
opts.padding = -(bounds.width - maxWidth) / 2
|
||||
} else {
|
||||
opts.padding = PADDING
|
||||
}
|
||||
opts.padding = PADDING
|
||||
opts.width = bounds.width
|
||||
|
||||
const textElm = getTextSvgElement(this.app, {
|
||||
|
|
|
@ -48,6 +48,8 @@ export const TextLabel = React.memo(function TextLabel<
|
|||
} = useEditableText(id, type, text)
|
||||
|
||||
const isInteractive = isEditing || isEditableFromHover
|
||||
const finalText = TextHelpers.normalizeTextForDom(text)
|
||||
const hasText = finalText.trim().length > 0
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -57,7 +59,14 @@ export const TextLabel = React.memo(function TextLabel<
|
|||
data-hastext={!isEmpty}
|
||||
data-isediting={isEditing}
|
||||
data-textwrap={!!wrap}
|
||||
style={{ alignItems: verticalAlign === 'middle' ? 'center' : verticalAlign }}
|
||||
style={
|
||||
hasText || isInteractive
|
||||
? {
|
||||
justifyContent: align === 'middle' ? 'center' : align,
|
||||
alignItems: verticalAlign === 'middle' ? 'center' : verticalAlign,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="tl-text-label__inner"
|
||||
|
@ -70,7 +79,7 @@ export const TextLabel = React.memo(function TextLabel<
|
|||
}}
|
||||
>
|
||||
<div className="tl-text tl-text-content" dir="ltr">
|
||||
{TextHelpers.normalizeTextForDom(text)}
|
||||
{finalText}
|
||||
</div>
|
||||
{isInteractive ? (
|
||||
// Consider replacing with content-editable
|
||||
|
|
|
@ -41,6 +41,8 @@ export function getTextSvgElement(
|
|||
|
||||
const innerHeight = lines.length * (opts.lineHeight * opts.fontSize)
|
||||
|
||||
const offsetX = padding
|
||||
|
||||
let offsetY: number
|
||||
switch (opts.verticalTextAlign) {
|
||||
case 'start': {
|
||||
|
@ -56,8 +58,6 @@ export function getTextSvgElement(
|
|||
}
|
||||
}
|
||||
|
||||
const offsetX = padding
|
||||
|
||||
// Create text span elements for each line
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan')
|
||||
|
|
Loading…
Reference in a new issue