UNPKG

@nativescript/core

Version:

A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.

323 lines • 11.1 kB
import { booleanConverter } from '../core/view-base'; // Requires. import { FormattedString } from './formatted-string'; import { View } from '../core/view'; import { Property, CssProperty, InheritedCssProperty, makeValidator, makeParser } from '../core/properties'; import { Style } from '../styling/style'; import { Observable } from '../../data/observable'; import { parseCSSShadow } from '../styling/css-shadow'; import { parseCSSStroke } from '../styling/css-stroke'; const CHILD_SPAN = 'Span'; const CHILD_FORMATTED_TEXT = 'formattedText'; const CHILD_FORMATTED_STRING = 'FormattedString'; export class TextBaseCommon extends View { /*** * In the NativeScript Core; by default the nativeTextViewProtected points to the same value as nativeViewProtected. * At this point no internal NS components need this indirection functionality. * This indirection is used to allow support usage by third party components so they don't have to duplicate functionality. * * A third party component can just override the `nativeTextViewProtected` getter and return a different internal view and that view would be * what all TextView/TextInput class features would be applied to. * * A example is the Android MaterialDesign TextInput class, it has a wrapper view of a TextInputLayout * https://developer.android.com/reference/com/google/android/material/textfield/TextInputLayout * which wraps the actual TextInput. This wrapper layout (TextInputLayout) must be assigned to the nativeViewProtected as the entire * NS Core uses nativeViewProtected for everything related to layout, so that it can be measured, added to the parent view as a child, ect. * * However, its internal view would be the actual TextView/TextInput and to allow that sub-view to have the normal TextView/TextInput * class features, which we expose and to allow them to work on it, the internal TextView/TextInput is what the needs to have the class values applied to it. * * So all code that works on what is expected to be a TextView/TextInput should use `nativeTextViewProtected` so that any third party * components that need to have two separate components can work properly without them having to duplicate all the TextBase (and decendants) functionality * by just overriding the nativeTextViewProtected getter. **/ get nativeTextViewProtected() { return this.nativeViewProtected; } get fontFamily() { return this.style.fontFamily; } set fontFamily(value) { this.style.fontFamily = value; } get fontSize() { return this.style.fontSize; } set fontSize(value) { this.style.fontSize = value; } get fontStyle() { return this.style.fontStyle; } set fontStyle(value) { this.style.fontStyle = value; } get fontWeight() { return this.style.fontWeight; } set fontWeight(value) { this.style.fontWeight = value; } get letterSpacing() { return this.style.letterSpacing; } set letterSpacing(value) { this.style.letterSpacing = value; } get lineHeight() { return this.style.lineHeight; } set lineHeight(value) { this.style.lineHeight = value; } get maxLines() { return this.style.maxLines; } set maxLines(value) { this.style.maxLines = value; } get textAlignment() { return this.style.textAlignment; } set textAlignment(value) { this.style.textAlignment = value; } get textDecoration() { return this.style.textDecoration; } set textDecoration(value) { this.style.textDecoration = value; } get textTransform() { return this.style.textTransform; } set textTransform(value) { this.style.textTransform = value; } get textShadow() { return this.style.textShadow; } set textShadow(value) { this.style.textShadow = value; } get textStroke() { return this.style.textStroke; } set textStroke(value) { this.style.textStroke = value; } get whiteSpace() { return this.style.whiteSpace; } set whiteSpace(value) { this.style.whiteSpace = value; } get textOverflow() { return this.style.textOverflow; } set textOverflow(value) { this.style.textOverflow = value; } get padding() { return this.style.padding; } set padding(value) { this.style.padding = value; } get paddingTop() { return this.style.paddingTop; } set paddingTop(value) { this.style.paddingTop = value; } get paddingRight() { return this.style.paddingRight; } set paddingRight(value) { this.style.paddingRight = value; } get paddingBottom() { return this.style.paddingBottom; } set paddingBottom(value) { this.style.paddingBottom = value; } get paddingLeft() { return this.style.paddingLeft; } set paddingLeft(value) { this.style.paddingLeft = value; } _onFormattedTextContentsChanged(data) { if (this.nativeViewProtected) { // Notifications from the FormattedString start arriving before the Android view is even created. this[formattedTextProperty.setNative](data.value); } } _addChildFromBuilder(name, value) { if (name === CHILD_SPAN) { if (!this.formattedText) { const formattedText = new FormattedString(); formattedText.spans.push(value); this.formattedText = formattedText; } else { this.formattedText.spans.push(value); } } else if (name === CHILD_FORMATTED_TEXT || name === CHILD_FORMATTED_STRING) { this.formattedText = value; } } _requestLayoutOnTextChanged() { this.requestLayout(); } eachChild(callback) { const text = this.formattedText; if (text) { callback(text); } } _setNativeText(reset = false) { // } } TextBaseCommon.iosTextAnimationFallback = true; TextBaseCommon.prototype._isSingleLine = false; export const textProperty = new Property({ name: 'text', defaultValue: '', affectsLayout: __ANDROID__, }); textProperty.register(TextBaseCommon); export const formattedTextProperty = new Property({ name: 'formattedText', affectsLayout: true, valueChanged: onFormattedTextPropertyChanged, }); formattedTextProperty.register(TextBaseCommon); export const iosTextAnimationProperty = new Property({ name: 'iosTextAnimation', defaultValue: 'inherit', affectsLayout: false, valueConverter(value) { try { return booleanConverter(value); } catch (e) { return 'inherit'; } }, }); iosTextAnimationProperty.register(TextBaseCommon); function onFormattedTextPropertyChanged(textBase, oldValue, newValue) { if (oldValue) { oldValue.off(Observable.propertyChangeEvent, textBase._onFormattedTextContentsChanged, textBase); textBase._removeView(oldValue); } if (newValue) { const oldParent = newValue.parent; // In case formattedString is attached to new TextBase if (oldParent) { oldParent._removeView(newValue); } textBase._addView(newValue); newValue.on(Observable.propertyChangeEvent, textBase._onFormattedTextContentsChanged, textBase); } } export function getClosestPropertyValue(property, span) { if (property.isSet(span.style)) { return span.style[property.name]; } else if (property.isSet(span.parent.style)) { // parent is FormattedString return span.parent.style[property.name]; } else if (property.isSet(span.parent.parent.style)) { // parent.parent is TextBase return span.parent.parent.style[property.name]; } } const textAlignmentConverter = makeParser(makeValidator('left', 'center', 'right', 'justify')); export const textAlignmentProperty = new InheritedCssProperty({ name: 'textAlignment', cssName: 'text-align', defaultValue: 'initial', valueConverter: textAlignmentConverter, }); textAlignmentProperty.register(Style); const textTransformConverter = makeParser(makeValidator('none', 'capitalize', 'uppercase', 'lowercase')); export const textTransformProperty = new InheritedCssProperty({ name: 'textTransform', cssName: 'text-transform', defaultValue: 'initial', valueConverter: textTransformConverter, }); textTransformProperty.register(Style); export const textShadowProperty = new InheritedCssProperty({ name: 'textShadow', cssName: 'text-shadow', affectsLayout: __APPLE__, valueConverter: (value) => { return parseCSSShadow(value); }, }); textShadowProperty.register(Style); export const textStrokeProperty = new InheritedCssProperty({ name: 'textStroke', cssName: 'text-stroke', affectsLayout: __APPLE__, valueConverter: (value) => { return parseCSSStroke(value); }, }); textStrokeProperty.register(Style); const whiteSpaceConverter = makeParser(makeValidator('normal', 'nowrap')); export const whiteSpaceProperty = new InheritedCssProperty({ name: 'whiteSpace', cssName: 'white-space', defaultValue: 'initial', affectsLayout: __APPLE__, valueConverter: whiteSpaceConverter, }); whiteSpaceProperty.register(Style); const textOverflowConverter = makeParser(makeValidator('clip', 'ellipsis')); export const textOverflowProperty = new CssProperty({ name: 'textOverflow', cssName: 'text-overflow', defaultValue: 'initial', affectsLayout: __APPLE__, valueConverter: textOverflowConverter, }); textOverflowProperty.register(Style); const textDecorationConverter = makeParser(makeValidator('none', 'underline', 'line-through', 'underline line-through')); export const textDecorationProperty = new CssProperty({ name: 'textDecoration', cssName: 'text-decoration', defaultValue: 'none', valueConverter: textDecorationConverter, }); textDecorationProperty.register(Style); export const letterSpacingProperty = new InheritedCssProperty({ name: 'letterSpacing', cssName: 'letter-spacing', defaultValue: 0, affectsLayout: __APPLE__, valueConverter: (v) => parseFloat(v), }); letterSpacingProperty.register(Style); export const lineHeightProperty = new InheritedCssProperty({ name: 'lineHeight', cssName: 'line-height', affectsLayout: __APPLE__, valueConverter: (v) => parseFloat(v), }); lineHeightProperty.register(Style); export const maxLinesProperty = new CssProperty({ name: 'maxLines', cssName: 'max-lines', valueConverter: (v) => (v === 'none' ? 0 : parseInt(v, 10)), }); maxLinesProperty.register(Style); export const resetSymbol = Symbol('textPropertyDefault'); //# sourceMappingURL=text-base-common.js.map