From 582e07f9231a8092471a34ee252e442c58d4a988 Mon Sep 17 00:00:00 2001 From: Westin Newell Date: Thu, 17 Oct 2019 12:41:19 -0700 Subject: [PATCH] feat(typograph): add text decoration (underline/strikethrough) support to Typograph (#315) --- .../playground/design-system/src/constants.ts | 5 +-- .../example-codebases/ios/Podfile.lock | 2 +- .../compiler-core/test/target.test.ts | 1 + src/framework/prefabs/src/typograph.ts | 19 ++++++++++ src/framework/prefabs/test/typograph.test.ts | 6 +++- .../sources/android/bindings/Typograph.kt | 17 +++++++++ .../ios/bindings/Typograph+Binding.swift | 19 +++++++++- .../sources/web/bindings/Typograph.d.ts | 1 + .../stdlib/sources/web/bindings/Typograph.js | 3 +- .../stdlib/src/bindings/Typograph/web.ts | 3 +- .../stdlib/test/fixtures/Bindings/Bindings.ts | 2 ++ .../java/org/diez/stdlibTestStub/Bindings.kt | 4 +-- .../java/org/diez/stdlibTestStub/Typograph.kt | 20 ++++++++++- .../Bindings/Typograph+Binding.swift | 19 +++++++++- .../Components/Bindings.swift | 4 +-- .../Components/Typograph.swift | 5 ++- .../diez-stdlib-test-stub-web/index.d.ts | 1 + .../diez-stdlib-test-stub-web/index.js | 11 +++--- .../static/styles.css | 2 ++ .../static/styles.scss | 2 ++ .../web-sdk-common/src/css-typograph.ts | 23 +++++++++++- .../web-sdk-common/test/css-typograph.test.ts | 36 +++++++++++++++++-- 22 files changed, 184 insertions(+), 21 deletions(-) diff --git a/examples/playground/design-system/src/constants.ts b/examples/playground/design-system/src/constants.ts index 25581d254..714ffd6a1 100644 --- a/examples/playground/design-system/src/constants.ts +++ b/examples/playground/design-system/src/constants.ts @@ -1,4 +1,4 @@ -import {Color, IOSTextStyle, Font, Typograph} from '@diez/prefabs'; +import {Color, IOSTextStyle, Font, Typograph, TextDecoration} from '@diez/prefabs'; const Fonts = { Nunito: { @@ -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, diff --git a/examples/playground/example-codebases/ios/Podfile.lock b/examples/playground/example-codebases/ios/Podfile.lock index ef120d025..009318da7 100644 --- a/examples/playground/example-codebases/ios/Podfile.lock +++ b/examples/playground/example-codebases/ios/Podfile.lock @@ -18,7 +18,7 @@ EXTERNAL SOURCES: :path: "../../design-system/build/diez-playground-ios" SPEC CHECKSUMS: - DiezPlayground: 75caf9b1b432b9445eeab1e8920bb4e55066429c + DiezPlayground: c2a83752bf75e6ac0bdd1322ac1c03d9d9ea62b5 lottie-ios: 43a472d22b2dd2bed292cc4010c0b4d2e66d3ba8 SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb diff --git a/src/compiler/compiler-core/test/target.test.ts b/src/compiler/compiler-core/test/target.test.ts index 87a776fab..273615372 100644 --- a/src/compiler/compiler-core/test/target.test.ts +++ b/src/compiler/compiler-core/test/target.test.ts @@ -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); diff --git a/src/framework/prefabs/src/typograph.ts b/src/framework/prefabs/src/typograph.ts index ed9df3b22..b1048f9f3 100644 --- a/src/framework/prefabs/src/typograph.ts +++ b/src/framework/prefabs/src/typograph.ts @@ -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). @@ -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[]; } /** @@ -164,6 +182,7 @@ export class Typograph extends prefab() { lineHeight: -1, letterSpacing: 0, alignment: TextAlignment.Natural, + decoration: [], }; options = { diff --git a/src/framework/prefabs/test/typograph.test.ts b/src/framework/prefabs/test/typograph.test.ts index 19ae047e0..798476e63 100644 --- a/src/framework/prefabs/test/typograph.test.ts +++ b/src/framework/prefabs/test/typograph.test.ts @@ -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', () => { @@ -12,6 +12,7 @@ describe('typograph', () => { lineHeight: 20, letterSpacing: 5, alignment: TextAlignment.Center, + decoration: [TextDecoration.Underline, TextDecoration.Strikethrough], }); expect(typograph.serialize()).toEqual({ @@ -29,6 +30,7 @@ describe('typograph', () => { lineHeight: 20, letterSpacing: 5, alignment: 'center', + decoration: ['underline', 'strikethrough'], }); const typographWithSpecificName = new Typograph({ @@ -53,6 +55,7 @@ describe('typograph', () => { lineHeight: -1, letterSpacing: 0, alignment: 'natural', + decoration: [], }); }); @@ -80,6 +83,7 @@ describe('typograph', () => { lineHeight: 0, letterSpacing: 0, alignment: 'natural', + decoration: [], }); }); }); diff --git a/src/framework/stdlib/sources/android/bindings/Typograph.kt b/src/framework/stdlib/sources/android/bindings/Typograph.kt index 54e498026..877bd4a5a 100644 --- a/src/framework/stdlib/sources/android/bindings/Typograph.kt +++ b/src/framework/stdlib/sources/android/bindings/Typograph.kt @@ -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 }} @@ -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() diff --git a/src/framework/stdlib/sources/ios/bindings/Typograph+Binding.swift b/src/framework/stdlib/sources/ios/bindings/Typograph+Binding.swift index 3a900a784..300089380 100644 --- a/src/framework/stdlib/sources/ios/bindings/Typograph+Binding.swift +++ b/src/framework/stdlib/sources/ios/bindings/Typograph+Binding.swift @@ -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 @@ -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) +} diff --git a/src/framework/stdlib/sources/web/bindings/Typograph.d.ts b/src/framework/stdlib/sources/web/bindings/Typograph.d.ts index 576356aee..77d736ba5 100644 --- a/src/framework/stdlib/sources/web/bindings/Typograph.d.ts +++ b/src/framework/stdlib/sources/web/bindings/Typograph.d.ts @@ -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. diff --git a/src/framework/stdlib/sources/web/bindings/Typograph.js b/src/framework/stdlib/sources/web/bindings/Typograph.js index f7e7da36d..12fefea1b 100644 --- a/src/framework/stdlib/sources/web/bindings/Typograph.js +++ b/src/framework/stdlib/sources/web/bindings/Typograph.js @@ -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; @@ -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`; diff --git a/src/framework/stdlib/src/bindings/Typograph/web.ts b/src/framework/stdlib/src/bindings/Typograph/web.ts index 86f2167dd..9f1f1f7d1 100644 --- a/src/framework/stdlib/src/bindings/Typograph/web.ts +++ b/src/framework/stdlib/src/bindings/Typograph/web.ts @@ -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'; @@ -52,6 +52,7 @@ const binding: WebBinding = { 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`}); diff --git a/src/framework/stdlib/test/fixtures/Bindings/Bindings.ts b/src/framework/stdlib/test/fixtures/Bindings/Bindings.ts index fbd1f8b5a..e6074fbc1 100644 --- a/src/framework/stdlib/test/fixtures/Bindings/Bindings.ts +++ b/src/framework/stdlib/test/fixtures/Bindings/Bindings.ts @@ -11,6 +11,7 @@ import { Panel, Point2D, Size2D, + TextDecoration, Toward, Typograph, } from '@diez/prefabs'; @@ -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)), diff --git a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-android/src/main/java/org/diez/stdlibTestStub/Bindings.kt b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-android/src/main/java/org/diez/stdlibTestStub/Bindings.kt index d0ff76c1d..0707bbfac 100644 --- a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-android/src/main/java/org/diez/stdlibTestStub/Bindings.kt +++ b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-android/src/main/java/org/diez/stdlibTestStub/Bindings.kt @@ -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()), + val tallTypograph: Typograph = Typograph(Font(File("assets/SomeFont.ttf", "font"), "SomeFont"), 50f, Color(0f, 0f, 0f, 1f), false, 100f, 10f, "natural", arrayOf("underline", "strikethrough")), val linearGradient: LinearGradient = LinearGradient(arrayOf(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), diff --git a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-android/src/main/java/org/diez/stdlibTestStub/Typograph.kt b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-android/src/main/java/org/diez/stdlibTestStub/Typograph.kt index 03e1124ac..161cf9fac 100644 --- a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-android/src/main/java/org/diez/stdlibTestStub/Typograph.kt +++ b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-android/src/main/java/org/diez/stdlibTestStub/Typograph.kt @@ -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, @@ -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 ) { companion object {} @@ -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() diff --git a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Bindings/Typograph+Binding.swift b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Bindings/Typograph+Binding.swift index 8e62e9e18..6274f10e9 100644 --- a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Bindings/Typograph+Binding.swift +++ b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Bindings/Typograph+Binding.swift @@ -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 @@ -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) +} diff --git a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Components/Bindings.swift b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Components/Bindings.swift index 71f60a7a0..0146e5f7f 100644 --- a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Components/Bindings.swift +++ b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Components/Bindings.swift @@ -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), diff --git a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Components/Typograph.swift b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Components/Typograph.swift index d5cd9f653..9834e178e 100644 --- a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Components/Typograph.swift +++ b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-ios/Sources/DiezStdlibTestStub/Components/Typograph.swift @@ -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, @@ -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 @@ -33,6 +35,7 @@ public final class Typograph: NSObject, Decodable { self.lineHeight = lineHeight self.letterSpacing = letterSpacing self.alignment = alignment + self.decoration = decoration } } diff --git a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/index.d.ts b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/index.d.ts index 94dcd8ded..e32d3e239 100644 --- a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/index.d.ts +++ b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/index.d.ts @@ -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. diff --git a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/index.js b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/index.js index 881b8264a..7c7558934 100644 --- a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/index.js +++ b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/index.js @@ -283,7 +283,8 @@ class Typograph { color, lineHeight, letterSpacing, - alignment + alignment, + decoration }) { this.font = new Font(font); this.fontSize = fontSize; @@ -291,13 +292,14 @@ class Typograph { this.lineHeight = lineHeight; this.letterSpacing = letterSpacing; this.alignment = alignment; + this.decoration = decoration; } } module.exports.Typograph = Typograph; -const {fontToCss, FontFormats, textAlignmentToCss} = require('@diez/web-sdk-common'); +const {fontToCss, FontFormats, textAlignmentToCss, textDecorationsToCss} = require('@diez/web-sdk-common'); let styleSheet; let cache; @@ -343,6 +345,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`; @@ -539,8 +542,8 @@ class Bindings { constructor({ image = {file: {src: "assets/image%20with%20spaces.jpg", type: "image"}, file2x: {src: "assets/image%20with%20spaces@2x.jpg", type: "image"}, file3x: {src: "assets/image%20with%20spaces@3x.jpg", type: "image"}, size: {width: 246, height: 246}}, lottie = {file: {src: "assets/lottie.json", type: "raw"}, loop: true, autoplay: true}, - typograph = {font: {file: {src: "assets/SomeFont.ttf", type: "font"}, name: "SomeFont", fallbacks: ["Verdana", "serif"], weight: 700, style: "normal"}, fontSize: 50, color: {h: 0.16666666666666666, s: 1, l: 0.5, a: 1}, lineHeight: -1, letterSpacing: 0, alignment: "natural"}, - tallTypograph = {font: {file: {src: "assets/SomeFont.ttf", type: "font"}, name: "SomeFont", fallbacks: ["Verdana", "serif"], weight: 700, style: "normal"}, fontSize: 50, color: {h: 0, s: 0, l: 0, a: 1}, lineHeight: 100, letterSpacing: 10, alignment: "natural"}, + typograph = {font: {file: {src: "assets/SomeFont.ttf", type: "font"}, name: "SomeFont", fallbacks: ["Verdana", "serif"], weight: 700, style: "normal"}, fontSize: 50, color: {h: 0.16666666666666666, s: 1, l: 0.5, a: 1}, lineHeight: -1, letterSpacing: 0, alignment: "natural", decoration: []}, + tallTypograph = {font: {file: {src: "assets/SomeFont.ttf", type: "font"}, name: "SomeFont", fallbacks: ["Verdana", "serif"], weight: 700, style: "normal"}, fontSize: 50, color: {h: 0, s: 0, l: 0, a: 1}, lineHeight: 100, letterSpacing: 10, alignment: "natural", decoration: ["underline", "strikethrough"]}, linearGradient = {stops: [{position: 0, color: {h: 0, s: 1, l: 0.5, a: 1}}, {position: 1, color: {h: 0.6666666666666666, s: 1, l: 0.5, a: 1}}], start: {x: 0, y: 0.5}, end: {x: 1, y: 0.5}}, point = {x: 0.5, y: 0.5}, size = {width: 400, height: 300}, diff --git a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/static/styles.css b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/static/styles.css index f3dafdf1b..1550bb69c 100644 --- a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/static/styles.css +++ b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/static/styles.css @@ -66,6 +66,7 @@ color: hsla(60, 100%, 50%, 1); letter-spacing: 0px; text-align: start; + text-decoration: none; } .bindings-tall-typograph { @@ -76,6 +77,7 @@ color: hsla(0, 0%, 0%, 1); letter-spacing: 10px; text-align: start; + text-decoration: underline line-through; line-height: 100px; } diff --git a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/static/styles.scss b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/static/styles.scss index 8432e09a6..e6d02b155 100644 --- a/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/static/styles.scss +++ b/src/framework/stdlib/test/goldens/Bindings/diez-stdlib-test-stub-web/static/styles.scss @@ -60,6 +60,7 @@ $bindings-file: url("/diez/assets/SomeFile.txt"); color: hsla(60, 100%, 50%, 1); letter-spacing: 0px; text-align: start; + text-decoration: none; } @mixin bindings-tall-typograph { @@ -70,6 +71,7 @@ $bindings-file: url("/diez/assets/SomeFile.txt"); color: hsla(0, 0%, 0%, 1); letter-spacing: 10px; text-align: start; + text-decoration: underline line-through; line-height: 100px; } diff --git a/src/framework/web-sdk-common/src/css-typograph.ts b/src/framework/web-sdk-common/src/css-typograph.ts index b4c172ebd..4566fe7fe 100644 --- a/src/framework/web-sdk-common/src/css-typograph.ts +++ b/src/framework/web-sdk-common/src/css-typograph.ts @@ -1,6 +1,6 @@ // Only used as a type. // tslint:disable-next-line: no-implicit-dependencies -import {TextAlignment} from '@diez/prefabs'; +import {TextAlignment, TextDecoration} from '@diez/prefabs'; /** * Returns a string with a valid CSS value from the provided `TextAlignment`. @@ -19,3 +19,24 @@ export const textAlignmentToCss = (alignment: TextAlignment) => { throw Error(`Unsupported text alignment: ${alignment}`); } }; + +/** + * Returns a string with a valid CSS value from the provided `TextDecoration`. + */ +export const textDecorationsToCss = (decorations: TextDecoration[]) => { + const components: string[] = []; + + if (decorations.includes(TextDecoration.Underline)) { + components.push('underline'); + } + + if (decorations.includes(TextDecoration.Strikethrough)) { + components.push('line-through'); + } + + if (components.length === 0) { + return 'none'; + } + + return components.join(' '); +}; diff --git a/src/framework/web-sdk-common/test/css-typograph.test.ts b/src/framework/web-sdk-common/test/css-typograph.test.ts index 977ab39bb..93592f411 100644 --- a/src/framework/web-sdk-common/test/css-typograph.test.ts +++ b/src/framework/web-sdk-common/test/css-typograph.test.ts @@ -1,5 +1,5 @@ -import {TextAlignment} from '@diez/prefabs'; -import {textAlignmentToCss} from '../src'; +import {TextAlignment, TextDecoration} from '@diez/prefabs'; +import {textAlignmentToCss, textDecorationsToCss} from '../src'; describe('textAlignmentToCss', () => { test('natrual', () => { @@ -18,3 +18,35 @@ describe('textAlignmentToCss', () => { expect(textAlignmentToCss(TextAlignment.Center)).toBe('center'); }); }); + +describe('textDecorationsToCss', () => { + test('none', () => { + expect(textDecorationsToCss([])).toBe('none'); + }); + + test('underline', () => { + expect(textDecorationsToCss([TextDecoration.Underline])).toBe('underline'); + }); + + test('strikethrough', () => { + expect(textDecorationsToCss([TextDecoration.Strikethrough])).toBe('line-through'); + }); + + test('all', () => { + const decoration = [ + TextDecoration.Strikethrough, + TextDecoration.Underline, + ]; + expect(textDecorationsToCss(decoration)).toBe('underline line-through'); + }); + + test('more than one of each', () => { + const decoration = [ + TextDecoration.Strikethrough, + TextDecoration.Underline, + TextDecoration.Underline, + TextDecoration.Strikethrough, + ]; + expect(textDecorationsToCss(decoration)).toBe('underline line-through'); + }); +});