Skip to content

Commit

Permalink
feat(typograph): add text decoration (underline/strikethrough) suppor…
Browse files Browse the repository at this point in the history
…t to Typograph (#315)
  • Loading branch information
Westin Newell committed Nov 14, 2019
1 parent ec0ed31 commit 582e07f
Show file tree
Hide file tree
Showing 22 changed files with 184 additions and 21 deletions.
5 changes: 3 additions & 2 deletions examples/playground/design-system/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Color, IOSTextStyle, Font, Typograph} from '@diez/prefabs';
import {Color, IOSTextStyle, Font, Typograph, TextDecoration} from '@diez/prefabs';

const Fonts = {
Nunito: {
Expand Down Expand Up @@ -30,9 +30,10 @@ export class Typography {
tallLineHeight = new Typograph({
font: Fonts.Nunito.Regular,
fontSize: 16,
color: Color.rgb(0, 50, 50),
color: Color.rgb(0, 125, 0),
iosTextStyle: IOSTextStyle.Body,
lineHeight: 60,
decoration: [TextDecoration.Underline, TextDecoration.Strikethrough]
});
navigationTitle = new Typograph({
font: Fonts.Nunito.Bold,
Expand Down
2 changes: 1 addition & 1 deletion examples/playground/example-codebases/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ EXTERNAL SOURCES:
:path: "../../design-system/build/diez-playground-ios"

SPEC CHECKSUMS:
DiezPlayground: 75caf9b1b432b9445eeab1e8920bb4e55066429c
DiezPlayground: c2a83752bf75e6ac0bdd1322ac1c03d9d9ea62b5
lottie-ios: 43a472d22b2dd2bed292cc4010c0b4d2e66d3ba8
SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb

Expand Down
1 change: 1 addition & 0 deletions src/compiler/compiler-core/test/target.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('compiler', () => {
expect(Array.from(parser.rootComponentNames)).toEqual(['Filtered']);
const compiler = new TestCompiler(parser);
await compiler.start();

expect(compiler.writeSdkMock).toHaveBeenCalled();
expect(compiler.printUsageInstructionsMock).toHaveBeenCalled();
expect(compiler.output.processedComponents.has('Filtered')).toBe(true);
Expand Down
19 changes: 19 additions & 0 deletions src/framework/prefabs/src/typograph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,29 @@ export const enum TextAlignment {
Center = 'center',
}

/**
* An enumerated list of text decorations.
*/
export const enum TextDecoration {
Underline = 'underline',
Strikethrough = 'strikethrough',
}

/**
* Typograph data.
*/
export interface TypographData {
/**
* The `Font` of the `Typograph`.
*/
font: Font;
/**
* Negative values will be sanatized to `0`.
*/
fontSize: number;
/**
* The `Color` of the `Typograph`.
*/
color: Color;
/**
* The iOS `UIFont.TextStyle` of the `Typograph` (iOS only).
Expand Down Expand Up @@ -146,6 +160,10 @@ export interface TypographData {
* The alignment of the text.
*/
alignment: TextAlignment;
/**
* A list of `TextDecoration`s to apply to the `Typograph`.
*/
decoration: TextDecoration[];
}

/**
Expand All @@ -164,6 +182,7 @@ export class Typograph extends prefab<TypographData>() {
lineHeight: -1,
letterSpacing: 0,
alignment: TextAlignment.Natural,
decoration: [],
};

options = {
Expand Down
6 changes: 5 additions & 1 deletion src/framework/prefabs/test/typograph.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Color} from '../src/color';
import {Font, IOSTextStyle, TextAlignment, Typograph} from '../src/typograph';
import {Font, IOSTextStyle, TextAlignment, TextDecoration, Typograph} from '../src/typograph';

describe('typograph', () => {
test('basic functionality', () => {
Expand All @@ -12,6 +12,7 @@ describe('typograph', () => {
lineHeight: 20,
letterSpacing: 5,
alignment: TextAlignment.Center,
decoration: [TextDecoration.Underline, TextDecoration.Strikethrough],
});

expect(typograph.serialize()).toEqual({
Expand All @@ -29,6 +30,7 @@ describe('typograph', () => {
lineHeight: 20,
letterSpacing: 5,
alignment: 'center',
decoration: ['underline', 'strikethrough'],
});

const typographWithSpecificName = new Typograph({
Expand All @@ -53,6 +55,7 @@ describe('typograph', () => {
lineHeight: -1,
letterSpacing: 0,
alignment: 'natural',
decoration: [],
});
});

Expand Down Expand Up @@ -80,6 +83,7 @@ describe('typograph', () => {
lineHeight: 0,
letterSpacing: 0,
alignment: 'natural',
decoration: [],
});
});
});
17 changes: 17 additions & 0 deletions src/framework/stdlib/sources/android/bindings/Typograph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import android.util.Log
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.graphics.Paint

{{> androidDataClassStart }}

Expand Down Expand Up @@ -62,6 +63,22 @@ fun TextView.apply(typograph: Typograph) {
this.gravity = typograph.gravity
this.textAlignment = View.TEXT_ALIGNMENT_GRAVITY

var paintFlags = this.paintFlags

val hasUnderline = typograph.decoration.contains("underline")
paintFlags = when(hasUnderline) {
true -> paintFlags or Paint.UNDERLINE_TEXT_FLAG
else -> paintFlags and Paint.UNDERLINE_TEXT_FLAG.inv()
}

val hasStrikethrough = typograph.decoration.contains("strikethrough")
paintFlags = when(hasStrikethrough) {
true -> paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
else -> paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
}

this.paintFlags = paintFlags

// TODO: Test for `null` instead of a magic number.
if (typograph.lineHeight != -1f) {
val lineHeight = if (typograph.shouldScale) typograph.lineHeight.spToPxFloat() else typograph.lineHeight.dpToPxFloat()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,21 @@ extension Typograph {
preventLineHeightAdjustment: Bool = false,
preventBaselineOffset: Bool = false
) -> [NSAttributedString.Key: Any] {
let color = UIColor(color: self.color)
var attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor(color: color),
.foregroundColor: color,
.baselineOffset: 0,
.kern: scaledLetterSpacing,
]

if decoration.contains("underline") {
attributes[.underlineStyle] = NSUnderlineStyle.single.rawValue
}

if decoration.contains("strikethrough") {
attributes[.strikethroughStyle] = NSUnderlineStyle.single.rawValue
}

let paragraphStyle = NSMutableParagraphStyle()
if let lineHeight = scaledLineHeight, !preventLineHeightAdjustment {
paragraphStyle.minimumLineHeight = lineHeight
Expand Down Expand Up @@ -338,3 +347,11 @@ extension UIBarItem {
setTitleTextAttributes(attributes, for: state)
}
}

private struct TextDecoration: OptionSet {
let rawValue: Int

static let none = TextDecoration(rawValue: 0)
static let underline = TextDecoration(rawValue: 1 << 0)
static let strikethrough = TextDecoration(rawValue: 1 << 1)
}
1 change: 1 addition & 0 deletions src/framework/stdlib/sources/web/bindings/Typograph.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export declare class Typograph {
lineHeight?: string,
letterSpacing: number,
textAlign: "start" | "left" | "right" | "center",
textDecoration: string,
};
/**
* Applies the `Typograph` CSS styles to the given HTMLElement.
Expand Down
3 changes: 2 additions & 1 deletion src/framework/stdlib/sources/web/bindings/Typograph.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const {fontToCss, FontFormats, textAlignmentToCss} = require('@diez/web-sdk-common');
const {fontToCss, FontFormats, textAlignmentToCss, textDecorationsToCss} = require('@diez/web-sdk-common');

let styleSheet;
let cache;
Expand Down Expand Up @@ -44,6 +44,7 @@ Object.defineProperties(Typograph.prototype, {
color: this.color.color,
letterSpacing: `${this.letterSpacing}px`,
textAlign: textAlignmentToCss(this.alignment),
textDecoration: textDecorationsToCss(this.decoration),
};
if (this.lineHeight !== -1) {
style.lineHeight = `${this.lineHeight}px`;
Expand Down
3 changes: 2 additions & 1 deletion src/framework/stdlib/src/bindings/Typograph/web.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {diezVersion} from '@diez/cli-core';
import {Typograph} from '@diez/prefabs';
import {joinToKebabCase, WebBinding, WebLanguages} from '@diez/targets';
import {colorToCss, fontToCss, textAlignmentToCss} from '@diez/web-sdk-common';
import {colorToCss, fontToCss, textAlignmentToCss, textDecorationsToCss} from '@diez/web-sdk-common';
import {join} from 'path';
import {getQualifiedCssUrl, sourcesPath} from '../../utils';

Expand Down Expand Up @@ -52,6 +52,7 @@ const binding: WebBinding<Typograph> = {
color: colorValue,
'letter-spacing': `${instance.letterSpacing}px`,
'text-align': textAlignmentToCss(instance.alignment),
'text-decoration': textDecorationsToCss(instance.decoration),
};
if (instance.lineHeight !== -1) {
Object.assign(declaration, {'line-height': `${instance.lineHeight}px`});
Expand Down
2 changes: 2 additions & 0 deletions src/framework/stdlib/test/fixtures/Bindings/Bindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Panel,
Point2D,
Size2D,
TextDecoration,
Toward,
Typograph,
} from '@diez/prefabs';
Expand Down Expand Up @@ -38,6 +39,7 @@ export const bindings = {
fontSize: 50,
lineHeight: 100,
letterSpacing: 10,
decoration: [TextDecoration.Underline, TextDecoration.Strikethrough],
}),

linearGradient: LinearGradient.make(Toward.Right, Color.rgb(255, 0, 0), Color.rgb(0, 0, 255)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ package org.diez.stdlibTestStub
data class Bindings(
val image: Image = Image(File("assets/image%20with%20spaces.jpg", "image"), File("assets/image%20with%20spaces@2x.jpg", "image"), File("assets/image%20with%20spaces@3x.jpg", "image"), File("assets/image%20with%20spaces@4x.jpg", "image"), Size2D(246f, 246f)),
val lottie: Lottie = Lottie(File("assets/lottie.json", "raw"), true, true),
val typograph: Typograph = Typograph(Font(File("assets/SomeFont.ttf", "font"), "SomeFont"), 50f, Color(0.16666666666666666f, 1f, 0.5f, 1f), false, -1f, 0f, "natural"),
val tallTypograph: Typograph = Typograph(Font(File("assets/SomeFont.ttf", "font"), "SomeFont"), 50f, Color(0f, 0f, 0f, 1f), false, 100f, 10f, "natural"),
val typograph: Typograph = Typograph(Font(File("assets/SomeFont.ttf", "font"), "SomeFont"), 50f, Color(0.16666666666666666f, 1f, 0.5f, 1f), false, -1f, 0f, "natural", arrayOf<String>()),
val tallTypograph: Typograph = Typograph(Font(File("assets/SomeFont.ttf", "font"), "SomeFont"), 50f, Color(0f, 0f, 0f, 1f), false, 100f, 10f, "natural", arrayOf<String>("underline", "strikethrough")),
val linearGradient: LinearGradient = LinearGradient(arrayOf<GradientStop>(GradientStop(0f, Color(0f, 1f, 0.5f, 1f)), GradientStop(1f, Color(0.6666666666666666f, 1f, 0.5f, 1f))), Point2D(0f, 0.5f), Point2D(1f, 0.5f)),
val point: Point2D = Point2D(0.5f, 0.5f),
val size: Size2D = Size2D(400f, 300f),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import android.util.Log
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.graphics.Paint

data class Typograph(
val font: Font,
Expand All @@ -21,7 +22,8 @@ data class Typograph(
val shouldScale: Boolean,
val lineHeight: Float,
val letterSpacing: Float,
val alignment: String
val alignment: String,
val decoration: Array<String>
) {
companion object {}

Expand Down Expand Up @@ -74,6 +76,22 @@ fun TextView.apply(typograph: Typograph) {
this.gravity = typograph.gravity
this.textAlignment = View.TEXT_ALIGNMENT_GRAVITY

var paintFlags = this.paintFlags

val hasUnderline = typograph.decoration.contains("underline")
paintFlags = when(hasUnderline) {
true -> paintFlags or Paint.UNDERLINE_TEXT_FLAG
else -> paintFlags and Paint.UNDERLINE_TEXT_FLAG.inv()
}

val hasStrikethrough = typograph.decoration.contains("strikethrough")
paintFlags = when(hasStrikethrough) {
true -> paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
else -> paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
}

this.paintFlags = paintFlags

// TODO: Test for `null` instead of a magic number.
if (typograph.lineHeight != -1f) {
val lineHeight = if (typograph.shouldScale) typograph.lineHeight.spToPxFloat() else typograph.lineHeight.dpToPxFloat()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,21 @@ extension Typograph {
preventLineHeightAdjustment: Bool = false,
preventBaselineOffset: Bool = false
) -> [NSAttributedString.Key: Any] {
let color = UIColor(color: self.color)
var attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor(color: color),
.foregroundColor: color,
.baselineOffset: 0,
.kern: scaledLetterSpacing,
]

if decoration.contains("underline") {
attributes[.underlineStyle] = NSUnderlineStyle.single.rawValue
}

if decoration.contains("strikethrough") {
attributes[.strikethroughStyle] = NSUnderlineStyle.single.rawValue
}

let paragraphStyle = NSMutableParagraphStyle()
if let lineHeight = scaledLineHeight, !preventLineHeightAdjustment {
paragraphStyle.minimumLineHeight = lineHeight
Expand Down Expand Up @@ -341,3 +350,11 @@ extension UIBarItem {
setTitleTextAttributes(attributes, for: state)
}
}

private struct TextDecoration: OptionSet {
let rawValue: Int

static let none = TextDecoration(rawValue: 0)
static let underline = TextDecoration(rawValue: 1 << 0)
static let strikethrough = TextDecoration(rawValue: 1 << 1)
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ public final class Bindings: NSObject, RootComponent {
self.init(
image: Image(file: File(src: "assets/image%20with%20spaces.jpg", type: "image"), file2x: File(src: "assets/image%20with%20spaces@2x.jpg", type: "image"), file3x: File(src: "assets/image%20with%20spaces@3x.jpg", type: "image"), size: Size2D(width: 246, height: 246)),
lottie: Lottie(file: File(src: "assets/lottie.json", type: "raw"), loop: true, autoplay: true),
typograph: Typograph(font: Font(file: File(src: "assets/SomeFont.ttf", type: "font"), name: "SomeFont"), fontSize: 50, color: Color(h: 0.16666666666666666, s: 1, l: 0.5, a: 1), iosTextStyle: "body", shouldScale: false, lineHeight: -1, letterSpacing: 0, alignment: "natural"),
tallTypograph: Typograph(font: Font(file: File(src: "assets/SomeFont.ttf", type: "font"), name: "SomeFont"), fontSize: 50, color: Color(h: 0, s: 0, l: 0, a: 1), iosTextStyle: "body", shouldScale: false, lineHeight: 100, letterSpacing: 10, alignment: "natural"),
typograph: Typograph(font: Font(file: File(src: "assets/SomeFont.ttf", type: "font"), name: "SomeFont"), fontSize: 50, color: Color(h: 0.16666666666666666, s: 1, l: 0.5, a: 1), iosTextStyle: "body", shouldScale: false, lineHeight: -1, letterSpacing: 0, alignment: "natural", decoration: []),
tallTypograph: Typograph(font: Font(file: File(src: "assets/SomeFont.ttf", type: "font"), name: "SomeFont"), fontSize: 50, color: Color(h: 0, s: 0, l: 0, a: 1), iosTextStyle: "body", shouldScale: false, lineHeight: 100, letterSpacing: 10, alignment: "natural", decoration: ["underline", "strikethrough"]),
linearGradient: LinearGradient(stops: [GradientStop(position: 0, color: Color(h: 0, s: 1, l: 0.5, a: 1)), GradientStop(position: 1, color: Color(h: 0.6666666666666666, s: 1, l: 0.5, a: 1))], start: Point2D(x: 0, y: 0.5), end: Point2D(x: 1, y: 0.5)),
point: Point2D(x: 0.5, y: 0.5),
size: Size2D(width: 400, height: 300),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public final class Typograph: NSObject, Decodable {
@objc public internal(set) var lineHeight: CGFloat
@objc public internal(set) var letterSpacing: CGFloat
@objc public internal(set) var alignment: String
@objc public internal(set) var decoration: [String]

init(
font: Font,
Expand All @@ -23,7 +24,8 @@ public final class Typograph: NSObject, Decodable {
shouldScale: Bool,
lineHeight: CGFloat,
letterSpacing: CGFloat,
alignment: String
alignment: String,
decoration: [String]
) {
self.font = font
self.fontSize = fontSize
Expand All @@ -33,6 +35,7 @@ public final class Typograph: NSObject, Decodable {
self.lineHeight = lineHeight
self.letterSpacing = letterSpacing
self.alignment = alignment
self.decoration = decoration
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export declare class Typograph {
lineHeight?: string,
letterSpacing: number,
textAlign: "start" | "left" | "right" | "center",
textDecoration: string,
};
/**
* Applies the `Typograph` CSS styles to the given HTMLElement.
Expand Down

0 comments on commit 582e07f

Please sign in to comment.