diff --git a/packages/alfa-css/src/value/percentage.ts b/packages/alfa-css/src/value/percentage.ts index dfde39d0cc..e64fdc9c4c 100644 --- a/packages/alfa-css/src/value/percentage.ts +++ b/packages/alfa-css/src/value/percentage.ts @@ -33,7 +33,7 @@ export class Percentage extends Numeric<"percentage"> { } public toString(): string { - return `${this._value}%`; + return `${this._value * 100}%`; } } diff --git a/packages/alfa-style/src/property.ts b/packages/alfa-style/src/property.ts index 5c0a2b6345..90a1d3fcff 100644 --- a/packages/alfa-style/src/property.ts +++ b/packages/alfa-style/src/property.ts @@ -219,6 +219,7 @@ const Longhands = { display: Display, "font-family": Font.Family, "font-size": Font.Size, + "font-stretch": Font.Stretch, "font-style": Font.Style, "font-weight": Font.Weight, height: Height, @@ -258,6 +259,7 @@ const Shorthands = { background: Background.Shorthand, "background-repeat": Background.Repeat.Shorthand, "background-position": Background.Position.Shorthand, + font: Font.Shorthand, "inset-block": Inset.Block.Shorthand, "inset-line": Inset.Line.Shorthand, outline: Outline.Shorthand, diff --git a/packages/alfa-style/src/property/box-insets.ts b/packages/alfa-style/src/property/box-insets.ts index d748f7350d..6f3d17d83a 100644 --- a/packages/alfa-style/src/property/box-insets.ts +++ b/packages/alfa-style/src/property/box-insets.ts @@ -4,7 +4,7 @@ import { Parser } from "@siteimprove/alfa-parser"; import { Property } from "../property"; import { Resolver } from "../resolver"; -const { either, map, oneOrMore, separatedList } = Parser; +const { either, map, separatedList } = Parser; /** * @see https://drafts.csswg.org/css-position/#insets @@ -67,17 +67,14 @@ export namespace Inset { */ export const Shorthand = Property.Shorthand.of( ["inset-block-start", "inset-block-end"], - map( - separatedList(parseInset, Token.parseWhitespace), - (values) => { - const [start, end] = [...values]; - - return [ - ["inset-block-start", start], - ["inset-block-end", end ?? start], - ]; - } - ) + map(separatedList(parseInset, Token.parseWhitespace), (values) => { + const [start, end] = [...values]; + + return [ + ["inset-block-start", start], + ["inset-block-end", end ?? start], + ]; + }) ); } @@ -91,17 +88,14 @@ export namespace Inset { */ export const Shorthand = Property.Shorthand.of( ["inset-line-start", "inset-line-end"], - map( - separatedList(parseInset, Token.parseWhitespace), - (values) => { - const [start, end] = [...values]; - - return [ - ["inset-line-start", start], - ["inset-line-end", end ?? start], - ]; - } - ) + map(separatedList(parseInset, Token.parseWhitespace), (values) => { + const [start, end] = [...values]; + + return [ + ["inset-line-start", start], + ["inset-line-end", end ?? start], + ]; + }) ); } } diff --git a/packages/alfa-style/src/property/font.ts b/packages/alfa-style/src/property/font.ts index 571ebc0a5e..86f00025f8 100644 --- a/packages/alfa-style/src/property/font.ts +++ b/packages/alfa-style/src/property/font.ts @@ -6,22 +6,38 @@ import { Calculation, String, Number, + Angle, } from "@siteimprove/alfa-css"; import { Parser } from "@siteimprove/alfa-parser"; +import { Result } from "@siteimprove/alfa-result"; import { Slice } from "@siteimprove/alfa-slice"; import { Property } from "../property"; import { Resolver } from "../resolver"; -const { map, filter, either, option, delimited, separatedList } = Parser; +import { Line } from "./line"; + +const { + delimited, + either, + filter, + map, + option, + pair, + right, + separatedList, +} = Parser; export namespace Font { export type Family = Family.Specified; export namespace Family { - export type Generic = Keyword< - "serif" | "sans-serif" | "cursive" | "fantasy" | "monospace" - >; + export type Generic = + | Keyword<"serif"> + | Keyword<"sans-serif"> + | Keyword<"cursive"> + | Keyword<"fantasy"> + | Keyword<"monospace">; export type Specified = Array; } @@ -56,18 +72,17 @@ export namespace Font { export type Size = Size.Specified | Size.Computed; export namespace Size { - export type Absolute = Keyword< - | "xx-small" - | "x-small" - | "small" - | "medium" - | "large" - | "x-large" - | "xx-large" - | "xxx-large" - >; - - export type Relative = Keyword<"larger" | "smaller">; + export type Absolute = + | Keyword<"xx-small"> + | Keyword<"x-small"> + | Keyword<"small"> + | Keyword<"medium"> + | Keyword<"large"> + | Keyword<"x-large"> + | Keyword<"xx-large"> + | Keyword<"xxx-large">; + + export type Relative = Keyword<"larger"> | Keyword<"smaller">; export type Specified = | Absolute @@ -198,10 +213,84 @@ export namespace Font { } ); - export type Style = Keyword<"normal" | "italic" | "oblique">; + export namespace Stretch { + export type Absolute = + | Keyword<"ultra-condensed"> + | Keyword<"extra-condensed"> + | Keyword<"condensed"> + | Keyword<"semi-condensed"> + | Keyword<"normal"> + | Keyword<"semi-expanded"> + | Keyword<"expanded"> + | Keyword<"extra-expanded"> + | Keyword<"ultra-expanded">; + + export type Specified = Absolute | Percentage; + + export type Computed = Percentage; + } + + /** + * @see https://drafts.csswg.org/css-fonts/#font-stretch-prop + */ + export const Stretch: Property< + Stretch.Specified, + Stretch.Computed + > = Property.of( + Percentage.of(1), + either( + Percentage.parse, + Keyword.parse( + "ultra-condensed", + "extra-condensed", + "condensed", + "semi-condensed", + "normal", + "semi-expanded", + "expanded", + "extra-expanded", + "ultra-expanded" + ) + ), + (style) => + style.specified("font-stretch").map((stretch) => { + if (stretch.type === "percentage") { + return stretch; + } + + switch (stretch.value) { + case "ultra-condensed": + return Percentage.of(0.5); + case "extra-condensed": + return Percentage.of(0.625); + case "condensed": + return Percentage.of(0.75); + case "semi-condensed": + return Percentage.of(0.875); + case "normal": + return Percentage.of(1); + case "semi-expanded": + return Percentage.of(1.125); + case "expanded": + return Percentage.of(1.25); + case "extra-expanded": + return Percentage.of(1.5); + case "ultra-expanded": + return Percentage.of(2); + } + }), + { inherits: true } + ); + + export type Style = + | Keyword<"normal"> + | Keyword<"italic"> + | Keyword<"oblique">; /** * @see https://drafts.csswg.org/css-fonts/#font-style-prop + * + * oblique accepting an angle has poor browser support and shouldn't affect Alfa currently. */ export const Style: Property