Merge pull request #3306 from NativeScript/font-refactor

FontStyle and FontWeight enums everywhere
This commit is contained in:
Rossen Hristov
2016-12-16 17:02:07 +02:00
committed by GitHub
8 changed files with 130 additions and 82 deletions

View File

@ -9,7 +9,7 @@ import {
gestureFromString, isIOS, traceEnabled, traceWrite, traceCategories, traceNotifyEvent, printUnregisteredProperties gestureFromString, isIOS, traceEnabled, traceWrite, traceCategories, traceNotifyEvent, printUnregisteredProperties
} from "./view-base"; } from "./view-base";
import { observe as gestureObserve, GesturesObserver, GestureTypes, GestureEventData } from "ui/gestures"; import { observe as gestureObserve, GesturesObserver, GestureTypes, GestureEventData } from "ui/gestures";
import { Font, parseFont } from "ui/styling/font"; import { Font, parseFont, FontStyle, FontWeight } from "ui/styling/font";
import { fontSizeConverter } from "../styling/converters"; import { fontSizeConverter } from "../styling/converters";
// TODO: Remove this and start using string as source (for android). // TODO: Remove this and start using string as source (for android).
@ -1815,12 +1815,8 @@ export const fontSizeProperty = new InheritedCssProperty<Style, number>({
}); });
fontSizeProperty.register(Style); fontSizeProperty.register(Style);
export const fontStyleProperty = new InheritedCssProperty<Style, "normal" | "italic">({ export const fontStyleProperty = new InheritedCssProperty<Style, FontStyle>({
name: "fontStyle", cssName: "font-style", defaultValue: "normal", valueChanged: (target, newValue) => { name: "fontStyle", cssName: "font-style", defaultValue: FontStyle.NORMAL, valueConverter: FontStyle.parse, valueChanged: (target, newValue) => {
if (!(newValue === "normal" || newValue === "italic")) {
throw new Error(`font-style should be 'normal' or 'italic'. value: ${newValue}`)
}
let currentFont = target.fontInternal; let currentFont = target.fontInternal;
if (currentFont.fontStyle !== newValue) { if (currentFont.fontStyle !== newValue) {
target.fontInternal = currentFont.withFontStyle(newValue); target.fontInternal = currentFont.withFontStyle(newValue);
@ -1829,20 +1825,8 @@ export const fontStyleProperty = new InheritedCssProperty<Style, "normal" | "ita
}); });
fontStyleProperty.register(Style); fontStyleProperty.register(Style);
export const fontWeightProperty = new InheritedCssProperty<Style, "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900">({ export const fontWeightProperty = new InheritedCssProperty<Style, FontWeight>({
name: "fontWeight", cssName: "font-weight", defaultValue: "normal", valueChanged: (target, newValue) => { name: "fontWeight", cssName: "font-weight", defaultValue: FontWeight.NORMAL, valueConverter: FontWeight.parse, valueChanged: (target, newValue) => {
if (!newValue) {
console.trace();
}
// TODO: Console.log errors or throw error?
if (!(newValue === "normal" || newValue === "bold"
|| newValue === "100" || newValue === "200" || newValue === "300"
|| newValue === "400" || newValue === "500" || newValue === "600"
|| newValue === "700" || newValue === "800" || newValue === "900")) {
throw new Error(`Invalid font-weight value: ${newValue}`);
}
let currentFont = target.fontInternal; let currentFont = target.fontInternal;
if (currentFont.fontWeight !== newValue) { if (currentFont.fontWeight !== newValue) {
target.fontInternal = currentFont.withFontWeight(newValue); target.fontInternal = currentFont.withFontWeight(newValue);

View File

@ -1,22 +1,23 @@
import { Font as FontDefinition, ParsedFont } from "ui/styling/font"; import { Font as FontDefinition, ParsedFont } from "ui/styling/font";
import { makeValidator, makeParser} from "ui/core/view";
export abstract class FontBase implements FontDefinition { export abstract class FontBase implements FontDefinition {
public static default = undefined; public static default = undefined;
private _fontFamily: string; private _fontFamily: string;
private _fontStyle: "normal" | "italic"; private _fontStyle: FontStyle;
private _fontWeight: "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900"; private _fontWeight: FontWeight;
private _fontSize: number; private _fontSize: number;
get fontFamily(): string { get fontFamily(): string {
return this._fontFamily; return this._fontFamily;
} }
get fontStyle(): "normal" | "italic" { get fontStyle(): FontStyle {
return this._fontStyle; return this._fontStyle;
} }
get fontWeight(): "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900" { get fontWeight(): FontWeight {
return this._fontWeight; return this._fontWeight;
} }
@ -24,16 +25,16 @@ export abstract class FontBase implements FontDefinition {
return this._fontSize; return this._fontSize;
} }
get isBold(): boolean {
return this._fontWeight.toLowerCase() === "bold"
|| this._fontWeight.toLowerCase() === "700";
}
get isItalic(): boolean { get isItalic(): boolean {
return this._fontStyle.toLowerCase() === "italic"; return this._fontStyle === FontStyle.ITALIC;
} }
protected constructor(family: string, size: number, style: "normal" | "italic", weight: "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900") { get isBold(): boolean {
return this._fontWeight === FontWeight.BOLD
|| this._fontWeight === "700";
}
protected constructor(family: string, size: number, style: FontStyle, weight: FontWeight) {
this._fontFamily = family; this._fontFamily = family;
this._fontSize = size; this._fontSize = size;
this._fontStyle = style; this._fontStyle = style;
@ -65,6 +66,29 @@ export abstract class FontBase implements FontDefinition {
} }
} }
export type FontStyle = "normal" | "italic";
export namespace FontStyle {
export const NORMAL: "normal" = "normal";
export const ITALIC: "italic" = "italic";
export const isValid = makeValidator<FontStyle>(NORMAL, ITALIC);
export const parse = makeParser(isValid, NORMAL);
}
export type FontWeight = "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900";
export namespace FontWeight {
export const THIN: "100" = "100";
export const EXTRA_LIGHT: "200" = "200";
export const LIGHT: "300" = "300";
export const NORMAL: "normal" = "normal";
export const MEDIUM: "500" = "500";
export const SEMI_BOLD: "600" = "600";
export const BOLD: "bold" = "bold";
export const EXTRA_BOLD: "800" = "800";
export const BLACK: "900" = "900";
export const isValid = makeValidator<FontWeight>(THIN, EXTRA_LIGHT, LIGHT, NORMAL, "400", MEDIUM, SEMI_BOLD, BOLD, "700", EXTRA_BOLD, BLACK);
export const parse = makeParser(isValid, NORMAL);
}
export function parseFontFamily(value: string): Array<string> { export function parseFontFamily(value: string): Array<string> {
const result = new Array<string>(); const result = new Array<string>();
if (!value) { if (!value) {
@ -89,7 +113,10 @@ export module genericFontFamilies {
} }
const styles = new Set(); const styles = new Set();
["italic", "oblique"].forEach((val, i, a) => styles.add(val)); [
FontStyle.NORMAL,
FontStyle.ITALIC
].forEach((val, i, a) => styles.add(val));
// http://www.w3schools.com/cssref/pr_font_weight.asp // http://www.w3schools.com/cssref/pr_font_weight.asp
//- normal(same as 400) //- normal(same as 400)
@ -104,7 +131,19 @@ const styles = new Set();
//- 800(Extra Bold / Ultra Bold) (API16 -bold) //- 800(Extra Bold / Ultra Bold) (API16 -bold)
//- 900(Black / Heavy) (API21 -black) //- 900(Black / Heavy) (API21 -black)
const weights = new Set(); const weights = new Set();
["normal", "bold", "100", "200", "300", "400", "500", "600", "700", "800", "900"].forEach((val, i, a) => weights.add(val)); [
FontWeight.THIN,
FontWeight.EXTRA_LIGHT,
FontWeight.LIGHT,
FontWeight.NORMAL,
"400",
FontWeight.MEDIUM,
FontWeight.SEMI_BOLD,
FontWeight.BOLD,
"700",
FontWeight.EXTRA_BOLD,
FontWeight.BLACK
].forEach((val, i, a) => weights.add(val));
export function parseFont(fontValue: string): ParsedFont { export function parseFont(fontValue: string): ParsedFont {
let result: ParsedFont = { let result: ParsedFont = {

View File

@ -1,4 +1,4 @@
import { FontBase, parseFontFamily, genericFontFamilies, parseFont } from "./font-common"; import { FontBase, parseFontFamily, genericFontFamilies, parseFont, FontWeight } from "./font-common";
import { enabled as traceEnabled, write as traceWrite, categories as traceCategories, messageType as traceMessageType } from "trace"; import { enabled as traceEnabled, write as traceWrite, categories as traceCategories, messageType as traceMessageType } from "trace";
import * as application from "application"; import * as application from "application";
import * as fs from "file-system"; import * as fs from "file-system";
@ -9,14 +9,12 @@ const FONTS_BASE_PATH = "/fonts/";
const typefaceCache = new Map<string, android.graphics.Typeface>(); const typefaceCache = new Map<string, android.graphics.Typeface>();
let appAssets: android.content.res.AssetManager; let appAssets: android.content.res.AssetManager;
type fontWeight = "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900";
export class Font extends FontBase { export class Font extends FontBase {
public static default = new Font(undefined, undefined, "normal", "normal"); public static default = new Font(undefined, undefined, "normal", "normal");
private _typeface: android.graphics.Typeface; private _typeface: android.graphics.Typeface;
constructor(family: string, size: number, style: "normal" | "italic", weight: fontWeight) { constructor(family: string, size: number, style: "normal" | "italic", weight: FontWeight) {
super(family, size, style, weight); super(family, size, style, weight);
} }
@ -28,7 +26,7 @@ export class Font extends FontBase {
return new Font(this.fontFamily, this.fontSize, style, this.fontWeight); return new Font(this.fontFamily, this.fontSize, style, this.fontWeight);
} }
public withFontWeight(weight: fontWeight): Font { public withFontWeight(weight: FontWeight): Font {
return new Font(this.fontFamily, this.fontSize, this.fontStyle, weight); return new Font(this.fontFamily, this.fontSize, this.fontStyle, weight);
} }
@ -134,26 +132,26 @@ function createTypeface(font: Font): android.graphics.Typeface {
return null; return null;
} }
function getFontWeightSuffix(fontWeight: string): string { function getFontWeightSuffix(fontWeight: FontWeight): string {
switch (fontWeight) { switch (fontWeight) {
case "100": case FontWeight.THIN:
return android.os.Build.VERSION.SDK_INT >= 16 ? "-thin" : ""; return android.os.Build.VERSION.SDK_INT >= 16 ? "-thin" : "";
case "200": case FontWeight.EXTRA_LIGHT:
case "300": case FontWeight.LIGHT:
return android.os.Build.VERSION.SDK_INT >= 16 ? "-light" : ""; return android.os.Build.VERSION.SDK_INT >= 16 ? "-light" : "";
case "normal": case FontWeight.NORMAL:
case "400": case "400":
case undefined: case undefined:
case null: case null:
return ""; return "";
case "500": case FontWeight.MEDIUM:
case "600": case FontWeight.SEMI_BOLD:
return android.os.Build.VERSION.SDK_INT >= 21 ? "-medium" : ""; return android.os.Build.VERSION.SDK_INT >= 21 ? "-medium" : "";
case "bold": case FontWeight.BOLD:
case "700": case "700":
case "800": case FontWeight.EXTRA_BOLD:
return ""; return "";
case "900": case FontWeight.BLACK:
return android.os.Build.VERSION.SDK_INT >= 21 ? "-black" : ""; return android.os.Build.VERSION.SDK_INT >= 21 ? "-black" : "";
default: default:
throw new Error(`Invalid font weight: "${fontWeight}"`); throw new Error(`Invalid font weight: "${fontWeight}"`);

View File

@ -3,8 +3,8 @@
public static default: Font; public static default: Font;
public fontFamily: string; public fontFamily: string;
public fontStyle: "normal" | "italic"; public fontStyle: FontStyle;
public fontWeight: "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900"; public fontWeight: FontWeight;
public fontSize: number; public fontSize: number;
public isBold: boolean; public isBold: boolean;
@ -23,10 +23,33 @@
public static equals(value1: Font, value2: Font): boolean; public static equals(value1: Font, value2: Font): boolean;
} }
export type FontStyle = "normal" | "italic";
export namespace FontStyle {
export const NORMAL: "normal";
export const ITALIC: "italic";
export function isValid(value: any): boolean;
export function parse(value: string): FontStyle;
}
export type FontWeight = "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900";
export namespace FontWeight {
export const THIN: "100";
export const EXTRA_LIGHT: "200";
export const LIGHT: "300";
export const NORMAL: "normal";
export const MEDIUM: "500";
export const SEMI_BOLD: "600";
export const BOLD: "bold";
export const EXTRA_BOLD: "800";
export const BLACK: "900";
export function isValid(value: any): boolean;
export function parse(value: string): FontWeight;
}
interface ParsedFont { interface ParsedFont {
fontStyle?: "normal" | "italic"; fontStyle?: FontStyle;
fontVariant?: string; fontVariant?: string;
fontWeight?: "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900", fontWeight?: FontWeight,
lineHeight?: string, lineHeight?: string,
fontSize?: string, fontSize?: string,
fontFamily?: string fontFamily?: string

View File

@ -1,14 +1,14 @@
import { FontBase, parseFontFamily, genericFontFamilies, parseFont } from "./font-common"; import { FontBase, parseFontFamily, genericFontFamilies, parseFont, FontStyle, FontWeight } from "./font-common";
import { enabled as traceEnabled, write as traceWrite, categories as traceCategories, messageType as traceMessageType } from "trace"; import { enabled as traceEnabled, write as traceWrite, categories as traceCategories, messageType as traceMessageType } from "trace";
import fs = require("file-system"); import fs = require("file-system");
import * as utils from "utils/utils"; import * as utils from "utils/utils";
export class Font extends FontBase { export class Font extends FontBase {
public static default = new Font(undefined, undefined, "normal", "normal"); public static default = new Font(undefined, undefined, FontStyle.NORMAL, FontWeight.NORMAL);
private _uiFont: UIFont; private _uiFont: UIFont;
constructor(family: string, size: number, style: "normal" | "italic", weight: "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900") { constructor(family: string, size: number, style: FontStyle, weight: FontWeight) {
super(family, size, style, weight); super(family, size, style, weight);
} }
@ -16,11 +16,11 @@ export class Font extends FontBase {
return new Font(family, this.fontSize, this.fontStyle, this.fontWeight); return new Font(family, this.fontSize, this.fontStyle, this.fontWeight);
} }
public withFontStyle(style: "normal" | "italic"): Font { public withFontStyle(style: FontStyle): Font {
return new Font(this.fontFamily, this.fontSize, style, this.fontWeight); return new Font(this.fontFamily, this.fontSize, style, this.fontWeight);
} }
public withFontWeight(weight: "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900"): Font { public withFontWeight(weight: FontWeight): Font {
return new Font(this.fontFamily, this.fontSize, this.fontStyle, weight); return new Font(this.fontFamily, this.fontSize, this.fontStyle, weight);
} }
@ -187,33 +187,33 @@ declare const UIFontWeightBold: number; //0.4
declare const UIFontWeightHeavy: number; //0.56 declare const UIFontWeightHeavy: number; //0.56
declare const UIFontWeightBlack: number; //0.62 declare const UIFontWeightBlack: number; //0.62
function getiOSFontWeight(fontWeight: string): number { function getiOSFontWeight(fontWeight: FontWeight): number {
if (!(<any>UIFont).systemFontOfSizeWeight) { if (!(<any>UIFont).systemFontOfSizeWeight) {
throw new Error("Font weight is available in iOS 8.2 and later."); throw new Error("Font weight is available in iOS 8.2 and later.");
} }
switch (fontWeight) { switch (fontWeight) {
case "100": case FontWeight.THIN:
return UIFontWeightThin; return UIFontWeightThin;
case "200": case FontWeight.EXTRA_LIGHT:
return UIFontWeightUltraLight; return UIFontWeightUltraLight;
case "300": case FontWeight.LIGHT:
return UIFontWeightLight; return UIFontWeightLight;
case "normal": case FontWeight.NORMAL:
case "400": case "400":
case undefined: case undefined:
case null: case null:
return UIFontWeightRegular; return UIFontWeightRegular;
case "500": case FontWeight.MEDIUM:
return UIFontWeightMedium; return UIFontWeightMedium;
case "600": case FontWeight.SEMI_BOLD:
return UIFontWeightSemibold; return UIFontWeightSemibold;
case "bold": case FontWeight.BOLD:
case "700": case "700":
return UIFontWeightBold; return UIFontWeightBold;
case "800": case FontWeight.EXTRA_BOLD:
return UIFontWeightHeavy; return UIFontWeightHeavy;
case "900": case FontWeight.BLACK:
return UIFontWeightBlack; return UIFontWeightBlack;
default: default:
throw new Error(`Invalid font weight: "${fontWeight}"`); throw new Error(`Invalid font weight: "${fontWeight}"`);
@ -248,39 +248,39 @@ function findCorrectWeightString(fontFamily: string, weightStringAlternatives: A
return weightStringAlternatives[0]; return weightStringAlternatives[0];
} }
function getiOSFontFace(fontFamily: string, fontWeight: string, isItalic: boolean): string { function getiOSFontFace(fontFamily: string, fontWeight: FontWeight, isItalic: boolean): string {
// ... with a lot of fuzzy logic and artificial intelligence thanks to the lack of font naming standards. // ... with a lot of fuzzy logic and artificial intelligence thanks to the lack of font naming standards.
let weight: string; let weight: string;
switch (fontWeight) { switch (fontWeight) {
case "100": case FontWeight.THIN:
weight = "Thin"; weight = "Thin";
break; break;
case "200": case FontWeight.EXTRA_LIGHT:
weight = findCorrectWeightString(fontFamily, ["Ultra Light", "UltraLight", "Extra Light", "ExtraLight", "Ultra light", "Ultralight", "Extra light", "Extralight"], isItalic); weight = findCorrectWeightString(fontFamily, ["Ultra Light", "UltraLight", "Extra Light", "ExtraLight", "Ultra light", "Ultralight", "Extra light", "Extralight"], isItalic);
break; break;
case "300": case FontWeight.LIGHT:
weight = "Light"; weight = "Light";
break; break;
case "normal": case FontWeight.NORMAL:
case "400": case "400":
case undefined: case undefined:
case null: case null:
weight = ""; // We dont' need to write Regular weight = ""; // We dont' need to write Regular
break; break;
case "500": case FontWeight.MEDIUM:
weight = "Medium"; weight = "Medium";
break; break;
case "600": case FontWeight.SEMI_BOLD:
weight = findCorrectWeightString(fontFamily, ["Demi Bold", "DemiBold", "Semi Bold", "SemiBold", "Demi bold", "Demibold", "Semi bold", "Semibold"], isItalic); weight = findCorrectWeightString(fontFamily, ["Demi Bold", "DemiBold", "Semi Bold", "SemiBold", "Demi bold", "Demibold", "Semi bold", "Semibold"], isItalic);
break; break;
case "bold": case FontWeight.BOLD:
case "700": case "700":
weight = "Bold"; weight = "Bold";
break; break;
case "800": case FontWeight.EXTRA_BOLD:
weight = findCorrectWeightString(fontFamily, ["Heavy", "Extra Bold", "ExtraBold", "Extra bold", "Extrabold"], isItalic); weight = findCorrectWeightString(fontFamily, ["Heavy", "Extra Bold", "ExtraBold", "Extra bold", "Extrabold"], isItalic);
break; break;
case "900": case FontWeight.BLACK:
weight = "Black"; weight = "Black";
break; break;
default: default:

View File

@ -1,6 +1,7 @@
declare module "ui/styling/style" { declare module "ui/styling/style" {
import { Length, PercentLength, Color, Background, Font, ViewBase, Observable } from "ui/core/view"; import { Length, PercentLength, Color, Background, Font, ViewBase, Observable } from "ui/core/view";
import { TextAlignment, TextDecoration, TextTransform, WhiteSpace } from "ui/text-base"; import { TextAlignment, TextDecoration, TextTransform, WhiteSpace } from "ui/text-base";
import { FontStyle, FontWeight } from "ui/styling/font";
export interface Thickness { export interface Thickness {
left: number; left: number;
@ -77,8 +78,8 @@ declare module "ui/styling/style" {
public fontSize: number; public fontSize: number;
public fontFamily: string; public fontFamily: string;
public fontStyle: "normal" | "italic"; public fontStyle: FontStyle;
public fontWeight: "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900"; public fontWeight: FontWeight;
public font: string; public font: string;
public zIndex: number; public zIndex: number;

View File

@ -9,6 +9,7 @@ import {
} from "ui/layouts/flexbox-layout"; } from "ui/layouts/flexbox-layout";
import { TextAlignment, TextDecoration, TextTransform, WhiteSpace } from "ui/text-base"; import { TextAlignment, TextDecoration, TextTransform, WhiteSpace } from "ui/text-base";
import { FontStyle, FontWeight } from "ui/styling/font";
export class Style extends Observable implements StyleDefinition { export class Style extends Observable implements StyleDefinition {
constructor(public view: ViewBase) { constructor(public view: ViewBase) {
@ -56,8 +57,8 @@ export class Style extends Observable implements StyleDefinition {
public fontSize: number; public fontSize: number;
public fontFamily: string; public fontFamily: string;
public fontStyle: "normal" | "italic"; public fontStyle: FontStyle;
public fontWeight: "100" | "200" | "300" | "normal" | "400" | "500" | "600" | "bold" | "700" | "800" | "900"; public fontWeight: FontWeight;
public font: string; public font: string;
public zIndex: number; public zIndex: number;

View File

@ -17,6 +17,8 @@
] ]
}, },
"exclude": [ "exclude": [
"apps",
"tests",
"tns-platform-declarations/node_modules/", "tns-platform-declarations/node_modules/",
"tns-platform-declarations/package/", "tns-platform-declarations/package/",
"tns-core-modules/node_modules/", "tns-core-modules/node_modules/",