feat(css): support for text-overflow (#10369)

This commit is contained in:
Nathan Walker
2023-08-27 15:32:09 -07:00
committed by GitHub
parent e4fe276bed
commit 8d25d251cd
9 changed files with 120 additions and 12 deletions

View File

@ -14,6 +14,17 @@
<GridLayout marginTop="10" borderWidth="1" borderColor="#efefef" height="60" paddingLeft="5">
<Label text="Test Label 3: should be aligned top" verticalAlignment="top" />
</GridLayout>
<GridLayout marginTop="10" borderWidth="1" borderColor="#efefef" height="60" paddingLeft="5">
<Label text="Test Label text-overflow: ellipsis, this should be long sentence and clipped at very end." textOverflow="ellipsis" whiteSpace="nowrap" />
</GridLayout>
<GridLayout marginTop="10" borderWidth="1" borderColor="#efefef" height="60" paddingLeft="5">
<Button text="Test Button text-overflow: ellipsis, this should be long sentence and clipped at very end." textOverflow="ellipsis" whiteSpace="nowrap" />
</GridLayout>
<GridLayout marginTop="10" borderWidth="1" borderColor="#efefef" height="60" paddingLeft="5">
<Button text="Test Button text-overflow: initial, this should be long sentence and truncated in the middle with ellipsis." textOverflow="initial" whiteSpace="nowrap" />
</GridLayout>
<Label text="maxLines 2" fontWeight="bold" marginTop="10" />
<Label
text="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."

View File

@ -94,6 +94,14 @@ export namespace CoreTypes {
export const nowrap = 'nowrap';
}
export type TextOverflowType = 'clip' | 'ellipsis' | 'initial' | 'unset';
export namespace TextOverflow {
export const clip = 'clip';
export const ellipsis = 'ellipsis';
export const initial = 'initial';
export const unset = 'unset';
}
export type MaxLinesType = number;
export type OrientationType = 'horizontal' | 'vertical';

View File

@ -2,7 +2,7 @@ import { ControlStateChangeListener } from '../core/control-state-change';
import { ButtonBase } from './button-common';
import { View, PseudoClassHandler } from '../core/view';
import { backgroundColorProperty, borderTopWidthProperty, borderRightWidthProperty, borderBottomWidthProperty, borderLeftWidthProperty, paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty } from '../styling/style-properties';
import { textAlignmentProperty, whiteSpaceProperty } from '../text-base';
import { textAlignmentProperty, whiteSpaceProperty, textOverflowProperty } from '../text-base';
import { layout } from '../../utils';
import { CoreTypes } from '../../core-types';
import { Color } from '../../color';
@ -219,17 +219,42 @@ export class Button extends ButtonBase {
}
[whiteSpaceProperty.setNative](value: CoreTypes.WhiteSpaceType) {
this.adjustLineBreak();
}
[textOverflowProperty.setNative](value: CoreTypes.TextOverflowType) {
this.adjustLineBreak();
}
private adjustLineBreak() {
const whiteSpace = this.whiteSpace;
const textOverflow = this.textOverflow;
const nativeView = this.nativeViewProtected.titleLabel;
switch (value) {
switch (whiteSpace) {
case 'normal':
nativeView.lineBreakMode = NSLineBreakMode.ByWordWrapping;
nativeView.numberOfLines = this.maxLines;
break;
case 'nowrap':
case 'initial':
nativeView.lineBreakMode = NSLineBreakMode.ByTruncatingMiddle;
nativeView.numberOfLines = 1;
break;
case 'nowrap':
switch (textOverflow) {
case 'clip':
nativeView.lineBreakMode = NSLineBreakMode.ByClipping;
nativeView.numberOfLines = this.maxLines;
break;
case 'ellipsis':
nativeView.lineBreakMode = NSLineBreakMode.ByTruncatingTail;
nativeView.numberOfLines = 1;
break;
default:
nativeView.lineBreakMode = NSLineBreakMode.ByTruncatingMiddle;
nativeView.numberOfLines = 1;
break;
}
break;
}
}

View File

@ -68,7 +68,7 @@ export { CSSHelper } from './styling/css-selector';
export { Switch } from './switch';
export { TabView, TabViewItem } from './tab-view';
export { TextBase, getTransformedText, letterSpacingProperty, textAlignmentProperty, textDecorationProperty, textTransformProperty, textShadowProperty, whiteSpaceProperty, lineHeightProperty } from './text-base';
export { TextBase, getTransformedText, letterSpacingProperty, textAlignmentProperty, textDecorationProperty, textTransformProperty, textShadowProperty, whiteSpaceProperty, textOverflowProperty, lineHeightProperty } from './text-base';
export { FormattedString } from './text-base/formatted-string';
export { Span } from './text-base/span';
export { TextField } from './text-field';

View File

@ -4,7 +4,7 @@ import { Length, borderTopWidthProperty, borderRightWidthProperty, borderBottomW
import { booleanConverter } from '../core/view-base';
import { View, CSSType } from '../core/view';
import { CoreTypes } from '../../core-types';
import { TextBase, whiteSpaceProperty } from '../text-base';
import { TextBase, whiteSpaceProperty, textOverflowProperty } from '../text-base';
import { layout } from '../../utils';
import { ios } from '../styling/background';
@ -113,17 +113,38 @@ export class Label extends TextBase implements LabelDefinition {
}
[whiteSpaceProperty.setNative](value: CoreTypes.WhiteSpaceType) {
const nativeView = this.nativeTextViewProtected;
switch (value) {
this.adjustLineBreak();
}
[textOverflowProperty.setNative](value: CoreTypes.TextOverflowType) {
this.adjustLineBreak();
}
private adjustLineBreak() {
const whiteSpace = this.whiteSpace;
const textOverflow = this.textOverflow;
const nativeView = this.nativeViewProtected;
switch (whiteSpace) {
case 'normal':
nativeView.lineBreakMode = NSLineBreakMode.ByWordWrapping;
nativeView.numberOfLines = this.maxLines;
break;
case 'nowrap':
case 'initial':
nativeView.lineBreakMode = NSLineBreakMode.ByTruncatingTail;
nativeView.numberOfLines = 1;
break;
case 'nowrap':
switch (textOverflow) {
case 'clip':
nativeView.lineBreakMode = NSLineBreakMode.ByClipping;
nativeView.numberOfLines = this.maxLines;
break;
default:
nativeView.lineBreakMode = NSLineBreakMode.ByTruncatingTail;
nativeView.numberOfLines = 1;
break;
}
break;
}
}

View File

@ -172,6 +172,7 @@ export class Style extends Observable implements StyleDefinition {
public textTransform: CoreTypes.TextTransformType;
public textShadow: CSSShadow;
public whiteSpace: CoreTypes.WhiteSpaceType;
public textOverflow: CoreTypes.TextOverflowType;
public minWidth: CoreTypes.LengthType;
public minHeight: CoreTypes.LengthType;

View File

@ -1,5 +1,5 @@
// Types
import { getClosestPropertyValue, maxLinesProperty } from './text-base-common';
import { getClosestPropertyValue, maxLinesProperty, textOverflowProperty } from './text-base-common';
import { CSSShadow } from '../styling/css-shadow';
// Requires
@ -311,17 +311,36 @@ export class TextBase extends TextBaseCommon {
// Overridden in TextField because setSingleLine(false) will remove methodTransformation.
// and we don't want to allow TextField to be multiline
[whiteSpaceProperty.setNative](value: CoreTypes.WhiteSpaceType) {
this.adjustLineBreak();
}
[textOverflowProperty.setNative](value: CoreTypes.TextOverflowType) {
this.adjustLineBreak();
}
private adjustLineBreak() {
const whiteSpace = this.whiteSpace;
const textOverflow = this.textOverflow;
const nativeView = this.nativeTextViewProtected;
switch (value) {
switch (whiteSpace) {
case 'initial':
case 'normal':
nativeView.setSingleLine(false);
nativeView.setEllipsize(null);
break;
case 'nowrap':
switch (textOverflow) {
case 'initial':
case 'ellipsis':
nativeView.setSingleLine(true);
nativeView.setEllipsize(android.text.TextUtils.TruncateAt.END);
break;
default:
nativeView.setSingleLine(false);
nativeView.setEllipsize(android.text.TextUtils.TruncateAt.END);
break;
}
break;
}
}

View File

@ -63,6 +63,11 @@ export class TextBase extends View implements AddChildFromBuilder {
*/
whiteSpace: CoreTypes.WhiteSpaceType;
/**
* Gets or sets text-overflow style property.
*/
textOverflow: CoreTypes.TextOverflowType;
/**
* Gets or sets white space style property.
*/
@ -134,6 +139,7 @@ export const textDecorationProperty: CssProperty<Style, CoreTypes.TextDecoration
export const textTransformProperty: CssProperty<Style, CoreTypes.TextTransformType>;
export const textShadowProperty: CssProperty<Style, CSSShadow>;
export const whiteSpaceProperty: CssProperty<Style, CoreTypes.WhiteSpaceType>;
export const textOverflowProperty: CssProperty<Style, CoreTypes.TextOverflowType>;
export const letterSpacingProperty: CssProperty<Style, number>;
export const lineHeightProperty: CssProperty<Style, number>;

View File

@ -132,6 +132,13 @@ export abstract class TextBaseCommon extends View implements TextBaseDefinition
this.style.whiteSpace = value;
}
get textOverflow(): CoreTypes.TextOverflowType {
return this.style.textOverflow;
}
set textOverflow(value: CoreTypes.TextOverflowType) {
this.style.textOverflow = value;
}
get padding(): string | CoreTypes.LengthType {
return this.style.padding;
}
@ -291,6 +298,16 @@ export const whiteSpaceProperty = new CssProperty<Style, CoreTypes.WhiteSpaceTyp
});
whiteSpaceProperty.register(Style);
const textOverflowConverter = makeParser<CoreTypes.TextOverflowType>(makeValidator<CoreTypes.TextOverflowType>('clip', 'ellipsis', 'initial', 'unset'));
export const textOverflowProperty = new CssProperty<Style, CoreTypes.TextOverflowType>({
name: 'textOverflow',
cssName: 'text-overflow',
defaultValue: 'initial',
affectsLayout: global.isIOS,
valueConverter: textOverflowConverter,
});
textOverflowProperty.register(Style);
const textDecorationConverter = makeParser<CoreTypes.TextDecorationType>(makeValidator<CoreTypes.TextDecorationType>('none', 'underline', 'line-through', 'underline line-through'));
export const textDecorationProperty = new CssProperty<Style, CoreTypes.TextDecorationType>({
name: 'textDecoration',