diff --git a/.changeset/few-clouds-play.md b/.changeset/few-clouds-play.md new file mode 100644 index 0000000000..f9a7faff4e --- /dev/null +++ b/.changeset/few-clouds-play.md @@ -0,0 +1,5 @@ +--- +"@siteimprove/alfa-style": minor +--- + +**Added:** CSS shorthand property `mask` and corresponding longhand properties are now supported. diff --git a/.changeset/rare-lies-invent.md b/.changeset/rare-lies-invent.md new file mode 100644 index 0000000000..8e00a347cd --- /dev/null +++ b/.changeset/rare-lies-invent.md @@ -0,0 +1,5 @@ +--- +"@siteimprove/alfa-css": minor +--- + +**Added:** `List#cutOrExtend` is now available. diff --git a/.changeset/tame-ants-work.md b/.changeset/tame-ants-work.md new file mode 100644 index 0000000000..ff74dd7842 --- /dev/null +++ b/.changeset/tame-ants-work.md @@ -0,0 +1,5 @@ +--- +"@siteimprove/alfa-css": minor +--- + +**Added:** `List#size` is now available. diff --git a/docs/review/api/alfa-css.api.md b/docs/review/api/alfa-css.api.md index 3d34cdd4a2..96329c2336 100644 --- a/docs/review/api/alfa-css.api.md +++ b/docs/review/api/alfa-css.api.md @@ -201,10 +201,19 @@ export type Box = Keyword<"border-box"> | Keyword<"padding-box"> | Keyword<"cont // @public (undocumented) export namespace Box { // (undocumented) - export type Geometry = Shape | Keyword<"fill-box"> | Keyword<"stroke-box"> | Keyword<"view-box">; + export type CoordBox = PaintBox | Keyword<"view-box">; const // (undocumented) parse: Parser; // (undocumented) + export namespace CoordBox { + // (undocumented) + export type JSON = PaintBox.JSON | Keyword.JSON<"view-box">; + } + // (undocumented) + export type Geometry = Shape | Keyword<"fill-box"> | Keyword<"stroke-box"> | Keyword<"view-box">; + const // (undocumented) + parseShape: Parser; + // (undocumented) export namespace Geometry { // (undocumented) export type JSON = Shape.JSON | Keyword.JSON<"fill-box"> | Keyword.JSON<"stroke-box"> | Keyword.JSON<"view-box">; @@ -212,7 +221,16 @@ export namespace Box { // (undocumented) export type JSON = Keyword.JSON<"border-box"> | Keyword.JSON<"padding-box"> | Keyword.JSON<"content-box">; const // (undocumented) - parseShape: Parser; + parseGeometry: Parser; + // (undocumented) + export type PaintBox = VisualBox | Keyword<"fill-box"> | Keyword<"stroke-box">; + // (undocumented) + export namespace PaintBox { + // (undocumented) + export type JSON = VisualBox.JSON | Keyword.JSON<"fill-box"> | Keyword.JSON<"stroke-box">; + } + const // (undocumented) + parseVisualBox: Parser; // (undocumented) export type Shape = Box | Keyword<"margin-box">; // (undocumented) @@ -221,7 +239,17 @@ export namespace Box { export type JSON = Box.JSON | Keyword.JSON<"margin-box">; } const // (undocumented) - parseGeometry: Parser; + parsePaintBox: Parser; + // (undocumented) + export type VisualBox = Keyword<"content-box"> | Keyword<"padding-box"> | Keyword<"border-box">; + // (undocumented) + export namespace VisualBox { + // (undocumented) + export type JSON = Keyword.JSON<"content-box"> | Keyword.JSON<"padding-box"> | Keyword.JSON<"border-box">; + } + const // (undocumented) + parseCoordBox: Parser; + {}; } // Warning: (ae-forgotten-export) The symbol "BasicShape" needs to be exported by the entry point index.d.ts @@ -1230,6 +1258,7 @@ export namespace Lexer { export class List extends Value<"list", Value.HasCalculation<[V]>> implements Iterable_2, Resolvable>, Resolvable.Resolver>, PartiallyResolvable>, Resolvable.PartialResolver> { // (undocumented) [Symbol.iterator](): Iterator; + cutOrExtend(length: number): List; // (undocumented) equals(value: List): boolean; // (undocumented) @@ -1245,6 +1274,8 @@ export class List extends Value<"list", Value.HasCalculation<[V // (undocumented) resolve(resolver?: Resolvable.Resolver): List>; // (undocumented) + get size(): number; + // (undocumented) toJSON(): List.JSON; // (undocumented) toString(): string; diff --git a/docs/review/api/alfa-style.api.md b/docs/review/api/alfa-style.api.md index c6dfaff6d3..3fda69cdc9 100644 --- a/docs/review/api/alfa-style.api.md +++ b/docs/review/api/alfa-style.api.md @@ -56,7 +56,14 @@ import { Specified as Specified_13 } from './property/font-stretch.js'; import { Specified as Specified_14 } from './property/font-variant-east-asian.js'; import { Specified as Specified_15 } from './property/font-variant-ligatures.js'; import { Specified as Specified_16 } from './property/font-variant-numeric.js'; +import { Specified as Specified_17 } from './property/mask-clip.js'; +import { Specified as Specified_18 } from './property/mask-composite.js'; +import { Specified as Specified_19 } from './property/mask-image.js'; import { Specified as Specified_2 } from './property/background-image.js'; +import { Specified as Specified_20 } from './property/mask-mode.js'; +import { Specified as Specified_21 } from './property/mask-position.js'; +import { Specified as Specified_22 } from './property/mask-repeat.js'; +import { Specified as Specified_23 } from './property/mask-size.js'; import { Specified as Specified_3 } from './property/background-position-x.js'; import { Specified as Specified_4 } from './property/background-position-y.js'; import { Specified as Specified_5 } from './property/background-repeat-x.js'; @@ -224,6 +231,14 @@ export namespace Longhands { readonly "margin-left": Longhand, Length | Percentage | Keyword<"auto">>; readonly "margin-right": Longhand, Length | Percentage | Keyword<"auto">>; readonly "margin-top": Longhand, Length | Percentage | Keyword<"auto">>; + readonly "mask-clip": Longhand, List>; + readonly "mask-composite": Longhand, List>; + readonly "mask-image": Longhand, List>; + readonly "mask-mode": Longhand, List>; + readonly "mask-origin": Longhand, List>; + readonly "mask-position": Longhand, List>; + readonly "mask-repeat": Longhand, List | Keyword<"space"> | Keyword<"round"> | Keyword<"no-repeat">, Keyword<"repeat"> | Keyword<"space"> | Keyword<"round"> | Keyword<"no-repeat">]>>>; + readonly "mask-size": Longhand, List>; readonly "min-height": Longhand | Keyword<"fit-content"> | Keyword<"max-content"> | Keyword<"min-content">, Length | Percentage | Keyword<"auto"> | Keyword<"fit-content"> | Keyword<"max-content"> | Keyword<"min-content">>; readonly "min-width": Longhand | Keyword<"fit-content"> | Keyword<"max-content"> | Keyword<"min-content">, Length | Percentage | Keyword<"auto"> | Keyword<"fit-content"> | Keyword<"max-content"> | Keyword<"min-content">>; readonly "mix-blend-mode": Longhand, Keyword.ToKeywords<"screen" | "color" | "hue" | "saturation" | "normal" | "multiply" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "luminosity" | "plus-darker" | "plus-lighter">>; @@ -270,6 +285,7 @@ export namespace Longhands { // // @internal export namespace Resolver { + export function layers(style: Style, name: "mask-image" | "background-image"): (value: List) => List; // (undocumented) export function length(style: Style): Length.Resolver; // (undocumented) @@ -305,7 +321,7 @@ export namespace Shorthands { export function isName(name: string): name is Name; const // (undocumented) shortHands: { - readonly background: Shorthand<"background-attachment" | "background-clip" | "background-color" | "background-image" | "background-origin" | "background-position-x" | "background-position-y" | "background-repeat-x" | "background-repeat-y" | "background-size">; + readonly background: Shorthand<"background-image" | "background-attachment" | "background-clip" | "background-color" | "background-origin" | "background-position-x" | "background-position-y" | "background-repeat-x" | "background-repeat-y" | "background-size">; readonly "background-position": Shorthand<"background-position-x" | "background-position-y">; readonly "background-repeat": Shorthand<"background-repeat-x" | "background-repeat-y">; readonly "border-block-color": Shorthand<"border-block-end-color" | "border-block-start-color">; @@ -337,6 +353,7 @@ export namespace Shorthands { readonly "inset-inline": Shorthand<"inset-inline-end" | "inset-inline-start">; readonly inset: Shorthand<"top" | "bottom" | "left" | "right">; readonly margin: Shorthand<"margin-bottom" | "margin-left" | "margin-right" | "margin-top">; + readonly mask: Shorthand<"mask-image" | "mask-clip" | "mask-composite" | "mask-mode" | "mask-origin" | "mask-position" | "mask-repeat" | "mask-size">; readonly outline: Shorthand<"outline-color" | "outline-style" | "outline-width">; readonly overflow: Shorthand<"overflow-x" | "overflow-y">; readonly "text-decoration": Shorthand<"text-decoration-color" | "text-decoration-line" | "text-decoration-style" | "text-decoration-thickness">; @@ -499,159 +516,168 @@ export namespace Value { // Warnings were encountered during analysis: // -// src/longhands.ts:188:7 - (ae-incompatible-release-tags) The symbol ""background-attachment"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:189:7 - (ae-incompatible-release-tags) The symbol ""background-clip"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:190:7 - (ae-incompatible-release-tags) The symbol ""background-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:191:7 - (ae-incompatible-release-tags) The symbol ""background-image"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:192:7 - (ae-incompatible-release-tags) The symbol ""background-origin"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:193:7 - (ae-incompatible-release-tags) The symbol ""background-position-x"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:194:7 - (ae-incompatible-release-tags) The symbol ""background-position-y"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:195:7 - (ae-incompatible-release-tags) The symbol ""background-repeat-x"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:196:7 - (ae-incompatible-release-tags) The symbol ""background-repeat-y"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:197:7 - (ae-incompatible-release-tags) The symbol ""background-size"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:198:7 - (ae-incompatible-release-tags) The symbol ""border-block-end-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:199:7 - (ae-incompatible-release-tags) The symbol ""border-block-end-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:200:7 - (ae-incompatible-release-tags) The symbol ""border-block-end-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:201:7 - (ae-incompatible-release-tags) The symbol ""border-block-start-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:202:7 - (ae-incompatible-release-tags) The symbol ""border-block-start-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:203:7 - (ae-incompatible-release-tags) The symbol ""border-block-start-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:204:7 - (ae-incompatible-release-tags) The symbol ""border-bottom-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:205:7 - (ae-incompatible-release-tags) The symbol ""border-bottom-left-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:206:7 - (ae-incompatible-release-tags) The symbol ""border-bottom-right-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:207:7 - (ae-incompatible-release-tags) The symbol ""border-bottom-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:208:7 - (ae-incompatible-release-tags) The symbol ""border-bottom-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:209:7 - (ae-incompatible-release-tags) The symbol ""border-collapse"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:210:7 - (ae-incompatible-release-tags) The symbol ""border-end-end-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:211:7 - (ae-incompatible-release-tags) The symbol ""border-end-start-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:212:7 - (ae-incompatible-release-tags) The symbol ""border-image-outset"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:213:7 - (ae-incompatible-release-tags) The symbol ""border-image-repeat"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:214:7 - (ae-incompatible-release-tags) The symbol ""border-image-slice"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:215:7 - (ae-incompatible-release-tags) The symbol ""border-image-source"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:216:7 - (ae-incompatible-release-tags) The symbol ""border-image-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:217:7 - (ae-incompatible-release-tags) The symbol ""border-inline-end-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:218:7 - (ae-incompatible-release-tags) The symbol ""border-inline-end-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:219:7 - (ae-incompatible-release-tags) The symbol ""border-inline-end-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:220:7 - (ae-incompatible-release-tags) The symbol ""border-inline-start-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:221:7 - (ae-incompatible-release-tags) The symbol ""border-inline-start-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:222:7 - (ae-incompatible-release-tags) The symbol ""border-inline-start-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:223:7 - (ae-incompatible-release-tags) The symbol ""border-left-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:224:7 - (ae-incompatible-release-tags) The symbol ""border-left-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:225:7 - (ae-incompatible-release-tags) The symbol ""border-left-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:226:7 - (ae-incompatible-release-tags) The symbol ""border-right-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:227:7 - (ae-incompatible-release-tags) The symbol ""border-right-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:228:7 - (ae-incompatible-release-tags) The symbol ""border-right-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:229:7 - (ae-incompatible-release-tags) The symbol ""border-start-end-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:230:7 - (ae-incompatible-release-tags) The symbol ""border-start-start-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:231:7 - (ae-incompatible-release-tags) The symbol ""border-top-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:232:7 - (ae-incompatible-release-tags) The symbol ""border-top-left-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:233:7 - (ae-incompatible-release-tags) The symbol ""border-top-right-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:234:7 - (ae-incompatible-release-tags) The symbol ""border-top-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:235:7 - (ae-incompatible-release-tags) The symbol ""border-top-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:236:7 - (ae-incompatible-release-tags) The symbol "bottom" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:237:7 - (ae-incompatible-release-tags) The symbol ""box-shadow"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:238:7 - (ae-incompatible-release-tags) The symbol ""clip-path"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:239:7 - (ae-incompatible-release-tags) The symbol "clip" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:240:7 - (ae-incompatible-release-tags) The symbol "color" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:241:7 - (ae-incompatible-release-tags) The symbol "contain" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:242:7 - (ae-incompatible-release-tags) The symbol ""container-type"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:243:7 - (ae-incompatible-release-tags) The symbol "cursor" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:244:7 - (ae-incompatible-release-tags) The symbol "display" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:245:7 - (ae-incompatible-release-tags) The symbol ""flex-direction"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:246:7 - (ae-incompatible-release-tags) The symbol ""flex-wrap"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:247:7 - (ae-incompatible-release-tags) The symbol "float" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:248:7 - (ae-incompatible-release-tags) The symbol ""font-family"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:249:7 - (ae-incompatible-release-tags) The symbol ""font-size"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:250:7 - (ae-incompatible-release-tags) The symbol ""font-stretch"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:251:7 - (ae-incompatible-release-tags) The symbol ""font-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:252:7 - (ae-incompatible-release-tags) The symbol ""font-variant-caps"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:253:7 - (ae-incompatible-release-tags) The symbol ""font-variant-east-asian"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:254:7 - (ae-incompatible-release-tags) The symbol ""font-variant-ligatures"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:255:7 - (ae-incompatible-release-tags) The symbol ""font-variant-numeric"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:256:7 - (ae-incompatible-release-tags) The symbol ""font-variant-position"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:257:7 - (ae-incompatible-release-tags) The symbol ""font-weight"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:258:7 - (ae-incompatible-release-tags) The symbol "height" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:259:7 - (ae-incompatible-release-tags) The symbol ""inset-block-end"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:260:7 - (ae-incompatible-release-tags) The symbol ""inset-block-start"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:261:7 - (ae-incompatible-release-tags) The symbol ""inset-inline-end"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:262:7 - (ae-incompatible-release-tags) The symbol ""inset-inline-start"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:263:7 - (ae-incompatible-release-tags) The symbol "isolation" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:264:7 - (ae-incompatible-release-tags) The symbol "left" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:265:7 - (ae-incompatible-release-tags) The symbol ""letter-spacing"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:266:7 - (ae-incompatible-release-tags) The symbol ""line-height"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:267:7 - (ae-incompatible-release-tags) The symbol ""margin-bottom"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:268:7 - (ae-incompatible-release-tags) The symbol ""margin-left"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:269:7 - (ae-incompatible-release-tags) The symbol ""margin-right"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:270:7 - (ae-incompatible-release-tags) The symbol ""margin-top"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:271:7 - (ae-incompatible-release-tags) The symbol ""min-height"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:272:7 - (ae-incompatible-release-tags) The symbol ""min-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:273:7 - (ae-incompatible-release-tags) The symbol ""mix-blend-mode"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:274:7 - (ae-incompatible-release-tags) The symbol "opacity" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:275:7 - (ae-incompatible-release-tags) The symbol ""outline-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:276:7 - (ae-incompatible-release-tags) The symbol ""outline-offset"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:277:7 - (ae-incompatible-release-tags) The symbol ""outline-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:278:7 - (ae-incompatible-release-tags) The symbol ""outline-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:279:7 - (ae-incompatible-release-tags) The symbol ""overflow-x"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:280:7 - (ae-incompatible-release-tags) The symbol ""overflow-y"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:281:7 - (ae-incompatible-release-tags) The symbol "perspective" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:282:7 - (ae-incompatible-release-tags) The symbol ""pointer-events"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:283:7 - (ae-incompatible-release-tags) The symbol "position" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:284:7 - (ae-incompatible-release-tags) The symbol "right" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:285:7 - (ae-incompatible-release-tags) The symbol "rotate" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:286:7 - (ae-incompatible-release-tags) The symbol "scale" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:287:7 - (ae-incompatible-release-tags) The symbol ""text-align"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:288:7 - (ae-incompatible-release-tags) The symbol ""text-decoration-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:289:7 - (ae-incompatible-release-tags) The symbol ""text-decoration-line"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:290:7 - (ae-incompatible-release-tags) The symbol ""text-decoration-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:291:7 - (ae-incompatible-release-tags) The symbol ""text-decoration-thickness"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:292:7 - (ae-incompatible-release-tags) The symbol ""text-indent"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:293:7 - (ae-incompatible-release-tags) The symbol ""text-overflow"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:294:7 - (ae-incompatible-release-tags) The symbol ""text-shadow"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:295:7 - (ae-incompatible-release-tags) The symbol ""text-transform"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:296:7 - (ae-incompatible-release-tags) The symbol "top" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:297:7 - (ae-incompatible-release-tags) The symbol "transform" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:298:7 - (ae-incompatible-release-tags) The symbol "translate" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:299:7 - (ae-incompatible-release-tags) The symbol ""vertical-align"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:300:7 - (ae-incompatible-release-tags) The symbol "visibility" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:301:7 - (ae-incompatible-release-tags) The symbol ""white-space"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:302:7 - (ae-incompatible-release-tags) The symbol "width" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:303:7 - (ae-incompatible-release-tags) The symbol ""will-change"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:304:7 - (ae-incompatible-release-tags) The symbol ""word-spacing"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/longhands.ts:305:7 - (ae-incompatible-release-tags) The symbol ""z-index"" is marked as @public, but its signature references "Longhand" which is marked as @internal -// src/shorthands.ts:47:14 - (ae-incompatible-release-tags) The symbol "background" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:48:14 - (ae-incompatible-release-tags) The symbol ""background-position"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:49:14 - (ae-incompatible-release-tags) The symbol ""background-repeat"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:50:14 - (ae-incompatible-release-tags) The symbol ""border-block-color"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:51:14 - (ae-incompatible-release-tags) The symbol ""border-block-end"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:52:14 - (ae-incompatible-release-tags) The symbol ""border-block-start"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:53:14 - (ae-incompatible-release-tags) The symbol ""border-block-style"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:54:14 - (ae-incompatible-release-tags) The symbol ""border-block"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:55:14 - (ae-incompatible-release-tags) The symbol ""border-block-width"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:56:14 - (ae-incompatible-release-tags) The symbol ""border-bottom"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:57:14 - (ae-incompatible-release-tags) The symbol ""border-color"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:58:14 - (ae-incompatible-release-tags) The symbol ""border-image"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:59:14 - (ae-incompatible-release-tags) The symbol ""border-inline-color"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:60:14 - (ae-incompatible-release-tags) The symbol ""border-inline-end"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:61:14 - (ae-incompatible-release-tags) The symbol ""border-inline-start"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:62:14 - (ae-incompatible-release-tags) The symbol ""border-inline-style"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:63:14 - (ae-incompatible-release-tags) The symbol ""border-inline"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:64:14 - (ae-incompatible-release-tags) The symbol ""border-inline-width"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:65:14 - (ae-incompatible-release-tags) The symbol ""border-left"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:66:14 - (ae-incompatible-release-tags) The symbol ""border-radius"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:67:14 - (ae-incompatible-release-tags) The symbol ""border-right"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:68:14 - (ae-incompatible-release-tags) The symbol ""border-style"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:69:14 - (ae-incompatible-release-tags) The symbol ""border-top"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:70:14 - (ae-incompatible-release-tags) The symbol "border" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:71:14 - (ae-incompatible-release-tags) The symbol ""border-width"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:72:14 - (ae-incompatible-release-tags) The symbol ""flex-flow"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:73:14 - (ae-incompatible-release-tags) The symbol "font" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:74:14 - (ae-incompatible-release-tags) The symbol ""font-variant"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:75:14 - (ae-incompatible-release-tags) The symbol ""inset-block"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:76:14 - (ae-incompatible-release-tags) The symbol ""inset-inline"" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:77:14 - (ae-incompatible-release-tags) The symbol "inset" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:78:14 - (ae-incompatible-release-tags) The symbol "margin" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:79:14 - (ae-incompatible-release-tags) The symbol "outline" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:80:14 - (ae-incompatible-release-tags) The symbol "overflow" is marked as @public, but its signature references "Shorthand" which is marked as @internal -// src/shorthands.ts:81:14 - (ae-incompatible-release-tags) The symbol ""text-decoration"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/longhands.ts:196:7 - (ae-incompatible-release-tags) The symbol ""background-attachment"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:197:7 - (ae-incompatible-release-tags) The symbol ""background-clip"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:198:7 - (ae-incompatible-release-tags) The symbol ""background-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:199:7 - (ae-incompatible-release-tags) The symbol ""background-image"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:200:7 - (ae-incompatible-release-tags) The symbol ""background-origin"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:201:7 - (ae-incompatible-release-tags) The symbol ""background-position-x"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:202:7 - (ae-incompatible-release-tags) The symbol ""background-position-y"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:203:7 - (ae-incompatible-release-tags) The symbol ""background-repeat-x"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:204:7 - (ae-incompatible-release-tags) The symbol ""background-repeat-y"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:205:7 - (ae-incompatible-release-tags) The symbol ""background-size"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:206:7 - (ae-incompatible-release-tags) The symbol ""border-block-end-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:207:7 - (ae-incompatible-release-tags) The symbol ""border-block-end-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:208:7 - (ae-incompatible-release-tags) The symbol ""border-block-end-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:209:7 - (ae-incompatible-release-tags) The symbol ""border-block-start-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:210:7 - (ae-incompatible-release-tags) The symbol ""border-block-start-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:211:7 - (ae-incompatible-release-tags) The symbol ""border-block-start-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:212:7 - (ae-incompatible-release-tags) The symbol ""border-bottom-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:213:7 - (ae-incompatible-release-tags) The symbol ""border-bottom-left-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:214:7 - (ae-incompatible-release-tags) The symbol ""border-bottom-right-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:215:7 - (ae-incompatible-release-tags) The symbol ""border-bottom-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:216:7 - (ae-incompatible-release-tags) The symbol ""border-bottom-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:217:7 - (ae-incompatible-release-tags) The symbol ""border-collapse"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:218:7 - (ae-incompatible-release-tags) The symbol ""border-end-end-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:219:7 - (ae-incompatible-release-tags) The symbol ""border-end-start-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:220:7 - (ae-incompatible-release-tags) The symbol ""border-image-outset"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:221:7 - (ae-incompatible-release-tags) The symbol ""border-image-repeat"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:222:7 - (ae-incompatible-release-tags) The symbol ""border-image-slice"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:223:7 - (ae-incompatible-release-tags) The symbol ""border-image-source"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:224:7 - (ae-incompatible-release-tags) The symbol ""border-image-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:225:7 - (ae-incompatible-release-tags) The symbol ""border-inline-end-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:226:7 - (ae-incompatible-release-tags) The symbol ""border-inline-end-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:227:7 - (ae-incompatible-release-tags) The symbol ""border-inline-end-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:228:7 - (ae-incompatible-release-tags) The symbol ""border-inline-start-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:229:7 - (ae-incompatible-release-tags) The symbol ""border-inline-start-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:230:7 - (ae-incompatible-release-tags) The symbol ""border-inline-start-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:231:7 - (ae-incompatible-release-tags) The symbol ""border-left-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:232:7 - (ae-incompatible-release-tags) The symbol ""border-left-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:233:7 - (ae-incompatible-release-tags) The symbol ""border-left-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:234:7 - (ae-incompatible-release-tags) The symbol ""border-right-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:235:7 - (ae-incompatible-release-tags) The symbol ""border-right-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:236:7 - (ae-incompatible-release-tags) The symbol ""border-right-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:237:7 - (ae-incompatible-release-tags) The symbol ""border-start-end-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:238:7 - (ae-incompatible-release-tags) The symbol ""border-start-start-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:239:7 - (ae-incompatible-release-tags) The symbol ""border-top-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:240:7 - (ae-incompatible-release-tags) The symbol ""border-top-left-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:241:7 - (ae-incompatible-release-tags) The symbol ""border-top-right-radius"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:242:7 - (ae-incompatible-release-tags) The symbol ""border-top-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:243:7 - (ae-incompatible-release-tags) The symbol ""border-top-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:244:7 - (ae-incompatible-release-tags) The symbol "bottom" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:245:7 - (ae-incompatible-release-tags) The symbol ""box-shadow"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:246:7 - (ae-incompatible-release-tags) The symbol ""clip-path"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:247:7 - (ae-incompatible-release-tags) The symbol "clip" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:248:7 - (ae-incompatible-release-tags) The symbol "color" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:249:7 - (ae-incompatible-release-tags) The symbol "contain" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:250:7 - (ae-incompatible-release-tags) The symbol ""container-type"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:251:7 - (ae-incompatible-release-tags) The symbol "cursor" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:252:7 - (ae-incompatible-release-tags) The symbol "display" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:253:7 - (ae-incompatible-release-tags) The symbol ""flex-direction"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:254:7 - (ae-incompatible-release-tags) The symbol ""flex-wrap"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:255:7 - (ae-incompatible-release-tags) The symbol "float" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:256:7 - (ae-incompatible-release-tags) The symbol ""font-family"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:257:7 - (ae-incompatible-release-tags) The symbol ""font-size"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:258:7 - (ae-incompatible-release-tags) The symbol ""font-stretch"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:259:7 - (ae-incompatible-release-tags) The symbol ""font-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:260:7 - (ae-incompatible-release-tags) The symbol ""font-variant-caps"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:261:7 - (ae-incompatible-release-tags) The symbol ""font-variant-east-asian"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:262:7 - (ae-incompatible-release-tags) The symbol ""font-variant-ligatures"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:263:7 - (ae-incompatible-release-tags) The symbol ""font-variant-numeric"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:264:7 - (ae-incompatible-release-tags) The symbol ""font-variant-position"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:265:7 - (ae-incompatible-release-tags) The symbol ""font-weight"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:266:7 - (ae-incompatible-release-tags) The symbol "height" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:267:7 - (ae-incompatible-release-tags) The symbol ""inset-block-end"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:268:7 - (ae-incompatible-release-tags) The symbol ""inset-block-start"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:269:7 - (ae-incompatible-release-tags) The symbol ""inset-inline-end"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:270:7 - (ae-incompatible-release-tags) The symbol ""inset-inline-start"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:271:7 - (ae-incompatible-release-tags) The symbol "isolation" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:272:7 - (ae-incompatible-release-tags) The symbol "left" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:273:7 - (ae-incompatible-release-tags) The symbol ""letter-spacing"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:274:7 - (ae-incompatible-release-tags) The symbol ""line-height"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:275:7 - (ae-incompatible-release-tags) The symbol ""margin-bottom"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:276:7 - (ae-incompatible-release-tags) The symbol ""margin-left"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:277:7 - (ae-incompatible-release-tags) The symbol ""margin-right"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:278:7 - (ae-incompatible-release-tags) The symbol ""margin-top"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:279:7 - (ae-incompatible-release-tags) The symbol ""mask-clip"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:280:7 - (ae-incompatible-release-tags) The symbol ""mask-composite"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:281:7 - (ae-incompatible-release-tags) The symbol ""mask-image"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:282:7 - (ae-incompatible-release-tags) The symbol ""mask-mode"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:283:7 - (ae-incompatible-release-tags) The symbol ""mask-origin"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:284:7 - (ae-incompatible-release-tags) The symbol ""mask-position"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:285:7 - (ae-incompatible-release-tags) The symbol ""mask-repeat"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:286:7 - (ae-incompatible-release-tags) The symbol ""mask-size"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:287:7 - (ae-incompatible-release-tags) The symbol ""min-height"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:288:7 - (ae-incompatible-release-tags) The symbol ""min-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:289:7 - (ae-incompatible-release-tags) The symbol ""mix-blend-mode"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:290:7 - (ae-incompatible-release-tags) The symbol "opacity" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:291:7 - (ae-incompatible-release-tags) The symbol ""outline-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:292:7 - (ae-incompatible-release-tags) The symbol ""outline-offset"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:293:7 - (ae-incompatible-release-tags) The symbol ""outline-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:294:7 - (ae-incompatible-release-tags) The symbol ""outline-width"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:295:7 - (ae-incompatible-release-tags) The symbol ""overflow-x"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:296:7 - (ae-incompatible-release-tags) The symbol ""overflow-y"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:297:7 - (ae-incompatible-release-tags) The symbol "perspective" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:298:7 - (ae-incompatible-release-tags) The symbol ""pointer-events"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:299:7 - (ae-incompatible-release-tags) The symbol "position" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:300:7 - (ae-incompatible-release-tags) The symbol "right" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:301:7 - (ae-incompatible-release-tags) The symbol "rotate" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:302:7 - (ae-incompatible-release-tags) The symbol "scale" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:303:7 - (ae-incompatible-release-tags) The symbol ""text-align"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:304:7 - (ae-incompatible-release-tags) The symbol ""text-decoration-color"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:305:7 - (ae-incompatible-release-tags) The symbol ""text-decoration-line"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:306:7 - (ae-incompatible-release-tags) The symbol ""text-decoration-style"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:307:7 - (ae-incompatible-release-tags) The symbol ""text-decoration-thickness"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:308:7 - (ae-incompatible-release-tags) The symbol ""text-indent"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:309:7 - (ae-incompatible-release-tags) The symbol ""text-overflow"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:310:7 - (ae-incompatible-release-tags) The symbol ""text-shadow"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:311:7 - (ae-incompatible-release-tags) The symbol ""text-transform"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:312:7 - (ae-incompatible-release-tags) The symbol "top" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:313:7 - (ae-incompatible-release-tags) The symbol "transform" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:314:7 - (ae-incompatible-release-tags) The symbol "translate" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:315:7 - (ae-incompatible-release-tags) The symbol ""vertical-align"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:316:7 - (ae-incompatible-release-tags) The symbol "visibility" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:317:7 - (ae-incompatible-release-tags) The symbol ""white-space"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:318:7 - (ae-incompatible-release-tags) The symbol "width" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:319:7 - (ae-incompatible-release-tags) The symbol ""will-change"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:320:7 - (ae-incompatible-release-tags) The symbol ""word-spacing"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/longhands.ts:321:7 - (ae-incompatible-release-tags) The symbol ""z-index"" is marked as @public, but its signature references "Longhand" which is marked as @internal +// src/shorthands.ts:48:14 - (ae-incompatible-release-tags) The symbol "background" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:49:14 - (ae-incompatible-release-tags) The symbol ""background-position"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:50:14 - (ae-incompatible-release-tags) The symbol ""background-repeat"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:51:14 - (ae-incompatible-release-tags) The symbol ""border-block-color"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:52:14 - (ae-incompatible-release-tags) The symbol ""border-block-end"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:53:14 - (ae-incompatible-release-tags) The symbol ""border-block-start"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:54:14 - (ae-incompatible-release-tags) The symbol ""border-block-style"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:55:14 - (ae-incompatible-release-tags) The symbol ""border-block"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:56:14 - (ae-incompatible-release-tags) The symbol ""border-block-width"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:57:14 - (ae-incompatible-release-tags) The symbol ""border-bottom"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:58:14 - (ae-incompatible-release-tags) The symbol ""border-color"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:59:14 - (ae-incompatible-release-tags) The symbol ""border-image"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:60:14 - (ae-incompatible-release-tags) The symbol ""border-inline-color"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:61:14 - (ae-incompatible-release-tags) The symbol ""border-inline-end"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:62:14 - (ae-incompatible-release-tags) The symbol ""border-inline-start"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:63:14 - (ae-incompatible-release-tags) The symbol ""border-inline-style"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:64:14 - (ae-incompatible-release-tags) The symbol ""border-inline"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:65:14 - (ae-incompatible-release-tags) The symbol ""border-inline-width"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:66:14 - (ae-incompatible-release-tags) The symbol ""border-left"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:67:14 - (ae-incompatible-release-tags) The symbol ""border-radius"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:68:14 - (ae-incompatible-release-tags) The symbol ""border-right"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:69:14 - (ae-incompatible-release-tags) The symbol ""border-style"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:70:14 - (ae-incompatible-release-tags) The symbol ""border-top"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:71:14 - (ae-incompatible-release-tags) The symbol "border" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:72:14 - (ae-incompatible-release-tags) The symbol ""border-width"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:73:14 - (ae-incompatible-release-tags) The symbol ""flex-flow"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:74:14 - (ae-incompatible-release-tags) The symbol "font" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:75:14 - (ae-incompatible-release-tags) The symbol ""font-variant"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:76:14 - (ae-incompatible-release-tags) The symbol ""inset-block"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:77:14 - (ae-incompatible-release-tags) The symbol ""inset-inline"" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:78:14 - (ae-incompatible-release-tags) The symbol "inset" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:79:14 - (ae-incompatible-release-tags) The symbol "margin" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:80:14 - (ae-incompatible-release-tags) The symbol "mask" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:81:14 - (ae-incompatible-release-tags) The symbol "outline" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:82:14 - (ae-incompatible-release-tags) The symbol "overflow" is marked as @public, but its signature references "Shorthand" which is marked as @internal +// src/shorthands.ts:83:14 - (ae-incompatible-release-tags) The symbol ""text-decoration"" is marked as @public, but its signature references "Shorthand" which is marked as @internal // (No @packageDocumentation comment for this package) diff --git a/packages/alfa-css/src/value/box.ts b/packages/alfa-css/src/value/box.ts index c370ac60f7..dc539fa215 100644 --- a/packages/alfa-css/src/value/box.ts +++ b/packages/alfa-css/src/value/box.ts @@ -66,4 +66,62 @@ export namespace Box { parseShape, Keyword.parse("fill-box", "stroke-box", "view-box"), ); + + /** + * {@link https://www.w3.org/TR/css-box-4/#typedef-visual-box} + */ + export type VisualBox = + | Keyword<"content-box"> + | Keyword<"padding-box"> + | Keyword<"border-box">; + + namespace VisualBox { + export type JSON = + | Keyword.JSON<"content-box"> + | Keyword.JSON<"padding-box"> + | Keyword.JSON<"border-box">; + } + + export const parseVisualBox: CSSParser = Keyword.parse( + "content-box", + "padding-box", + "border-box", + ); + + /** + * {@link https://www.w3.org/TR/css-box-4/#typedef-paint-box} + */ + export type PaintBox = + | VisualBox + | Keyword<"fill-box"> + | Keyword<"stroke-box">; + + namespace PaintBox { + export type JSON = + | VisualBox.JSON + | Keyword.JSON<"fill-box"> + | Keyword.JSON<"stroke-box">; + } + + export const parsePaintBox: CSSParser = either( + parseVisualBox, + Keyword.parse("fill-box", "stroke-box"), + ); + + /** + * {@link https://www.w3.org/TR/css-box-4/#typedef-coord-box} + * + * @privateRemarks + * This is not the same type as `Geometry`. The only difference is that this type does not contain `margin-box`. + */ + export type CoordBox = PaintBox | Keyword<"view-box">; + + export namespace CoordBox { + export type JSON = PaintBox.JSON | Keyword.JSON<"view-box">; + } + + export const parseCoordBox: CSSParser = either( + parsePaintBox, + Keyword.parse("view-box"), + ); } diff --git a/packages/alfa-css/src/value/collection/list.ts b/packages/alfa-css/src/value/collection/list.ts index 3a75b1f48d..4f42c570ab 100644 --- a/packages/alfa-css/src/value/collection/list.ts +++ b/packages/alfa-css/src/value/collection/list.ts @@ -44,6 +44,10 @@ export class List return this._values; } + public get size(): number { + return this._values.length; + } + public resolve( resolver?: Resolvable.Resolver, ): List> { @@ -65,6 +69,33 @@ export class List return new List(this._values.map(mapper), this._separator); } + /** + * Returns a copy of the current instance cut off or extended with repeated values to match the given `length`. + * + * @example + * List.of([1, 2, 3]).cutOrExtend(2); // returns a new List with values [1, 2] + * + * @example + * List.of([1, 2, 3]).cutOrExtend(5); // returns a new List with values [1, 2, 3, 1, 2] + */ + public cutOrExtend(length: number): List { + if (this.size === length) { + return new List(this._values, this._separator); + } + + if (length < this.size) { + return new List(this._values.slice(0, length), this._separator); + } + + const extended: Array = []; + for (let i = 0; i < length; ++i) { + // Cyclically repeat the values until the result has the desired length. + extended.push(this._values[i % this.size]); + } + + return new List(extended, this._separator); + } + public equals(value: List): boolean; public equals(value: unknown): value is this; diff --git a/packages/alfa-css/test/value/collection/list.spec.ts b/packages/alfa-css/test/value/collection/list.spec.ts index f175a85847..af8bb1bbac 100644 --- a/packages/alfa-css/test/value/collection/list.spec.ts +++ b/packages/alfa-css/test/value/collection/list.spec.ts @@ -2,15 +2,13 @@ import type { Parser } from "@siteimprove/alfa-parser"; import type { Slice } from "@siteimprove/alfa-slice"; import { test } from "@siteimprove/alfa-test"; -import type { - Token, - Value} from "../../../dist/index.js"; +import type { Token, Value } from "../../../dist/index.js"; import { Length, LengthPercentage, Lexer, List, - Number + Number, } from "../../../dist/index.js"; function parse( @@ -68,3 +66,40 @@ test("resolve() resolves all values in a list", (t) => { separator: ", ", }); }); + +test("#cutOrExtend returns identical copy if list has the same length as the given length", (t) => { + t.deepEqual(parse("1, 2, 3", Number.parse).cutOrExtend(3).toJSON(), { + type: "list", + values: [ + { type: "number", value: 1 }, + { type: "number", value: 2 }, + { type: "number", value: 3 }, + ], + separator: ", ", + }); +}); + +test("#cutOrExtend cuts a list longer than the given length", (t) => { + t.deepEqual(parse("1, 2, 3", Number.parse).cutOrExtend(2).toJSON(), { + type: "list", + values: [ + { type: "number", value: 1 }, + { type: "number", value: 2 }, + ], + separator: ", ", + }); +}); + +test("#cutOrExtend repeats a list shorter than the given length", (t) => { + t.deepEqual(parse("1, 2, 3", Number.parse).cutOrExtend(5).toJSON(), { + type: "list", + values: [ + { type: "number", value: 1 }, + { type: "number", value: 2 }, + { type: "number", value: 3 }, + { type: "number", value: 1 }, + { type: "number", value: 2 }, + ], + separator: ", ", + }); +}); diff --git a/packages/alfa-style/src/longhands.ts b/packages/alfa-style/src/longhands.ts index 266561512e..148d3869f2 100644 --- a/packages/alfa-style/src/longhands.ts +++ b/packages/alfa-style/src/longhands.ts @@ -83,6 +83,14 @@ import MarginBottom from "./property/margin-bottom.js"; import MarginLeft from "./property/margin-left.js"; import MarginRight from "./property/margin-right.js"; import MarginTop from "./property/margin-top.js"; +import MaskClip from "./property/mask-clip.js"; +import MaskComposite from "./property/mask-composite.js"; +import MaskImage from "./property/mask-image.js"; +import MaskMode from "./property/mask-mode.js"; +import MaskOrigin from "./property/mask-origin.js"; +import MaskPosition from "./property/mask-position.js"; +import MaskRepeat from "./property/mask-repeat.js"; +import MaskSize from "./property/mask-size.js"; import MinHeight from "./property/min-height.js"; import MinWidth from "./property/min-width.js"; import MixBlendMode from "./property/mix-blend-mode.js"; @@ -268,6 +276,14 @@ export namespace Longhands { "margin-left": MarginLeft, "margin-right": MarginRight, "margin-top": MarginTop, + "mask-clip": MaskClip, + "mask-composite": MaskComposite, + "mask-image": MaskImage, + "mask-mode": MaskMode, + "mask-origin": MaskOrigin, + "mask-position": MaskPosition, + "mask-repeat": MaskRepeat, + "mask-size": MaskSize, "min-height": MinHeight, "min-width": MinWidth, "mix-blend-mode": MixBlendMode, diff --git a/packages/alfa-style/src/property/mask-clip.ts b/packages/alfa-style/src/property/mask-clip.ts new file mode 100644 index 0000000000..525c97724b --- /dev/null +++ b/packages/alfa-style/src/property/mask-clip.ts @@ -0,0 +1,41 @@ +import { Parser } from "@siteimprove/alfa-parser"; +import { Box, Keyword, List } from "@siteimprove/alfa-css"; + +import { Longhand } from "../longhand.js"; +import { Resolver } from "../resolver.js"; + +const { either } = Parser; + +type Specified = List; + +/** + * @internal + */ +export namespace Specified { + export type Item = Box.CoordBox | Keyword<"no-clip">; +} + +type Computed = Specified; + +/** + * @internal + */ +export const parse = either(Box.parseCoordBox, Keyword.parse("no-clip")); + +const parseList = List.parseCommaSeparated(parse); + +/** + * @internal + */ +export const initialItem = Keyword.of("border-box"); + +/** + * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/mask-clip} + * + * @internal + */ +export default Longhand.of( + List.of([initialItem]), + parseList, + (value, style) => value.map(Resolver.layers(style, "mask-image")), +); diff --git a/packages/alfa-style/src/property/mask-composite.ts b/packages/alfa-style/src/property/mask-composite.ts new file mode 100644 index 0000000000..ff9c29b8a4 --- /dev/null +++ b/packages/alfa-style/src/property/mask-composite.ts @@ -0,0 +1,42 @@ +import { Keyword, List } from "@siteimprove/alfa-css"; + +import { Longhand } from "../longhand.js"; +import { Resolver } from "../resolver.js"; + +type Specified = List; + +/** + * @internal + */ +export namespace Specified { + export type Item = + | Keyword<"add"> + | Keyword<"subtract"> + | Keyword<"intersect"> + | Keyword<"exclude">; +} + +type Computed = Specified; + +/** + * @internal + */ +export const parse = Keyword.parse("add", "subtract", "intersect", "exclude"); + +const parseList = List.parseCommaSeparated(parse); + +/** + * @internal + */ +export const initialItem = Keyword.of("add"); + +/** + * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/mask-composite} + * + * @internal + */ +export default Longhand.of( + List.of([initialItem], ", "), + parseList, + (value, style) => value.map(Resolver.layers(style, "mask-image")), +); diff --git a/packages/alfa-style/src/property/mask-image.ts b/packages/alfa-style/src/property/mask-image.ts new file mode 100644 index 0000000000..845585bbf5 --- /dev/null +++ b/packages/alfa-style/src/property/mask-image.ts @@ -0,0 +1,54 @@ +import { Parser } from "@siteimprove/alfa-parser"; +import { Image, Keyword, List, URL } from "@siteimprove/alfa-css"; +import { Selective } from "@siteimprove/alfa-selective"; + +import { Longhand } from "../longhand.js"; +import { Resolver } from "../resolver.js"; + +const { either } = Parser; + +type Specified = List; + +/** + * @internal + */ +export namespace Specified { + export type Item = Keyword<"none"> | Image | URL; +} + +type Computed = Specified; + +/** + * @internal + */ +export const parse = either( + Keyword.parse("none"), + either(Image.parse, URL.parse), +); + +const parseList = List.parseCommaSeparated(parse); + +/** + * @internal + */ +export const initialItem = Keyword.of("none"); + +/** + * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/mask-image} + * + * @internal + */ +export default Longhand.of( + List.of([initialItem], ", "), + parseList, + (value, style) => + value.map((images) => + images.map((image) => + Selective.of(image) + .if(Image.isImage, (image) => + image.partiallyResolve(Resolver.length(style)), + ) + .get(), + ), + ), +); diff --git a/packages/alfa-style/src/property/mask-mode.ts b/packages/alfa-style/src/property/mask-mode.ts new file mode 100644 index 0000000000..76d5d88282 --- /dev/null +++ b/packages/alfa-style/src/property/mask-mode.ts @@ -0,0 +1,41 @@ +import { Keyword, List } from "@siteimprove/alfa-css"; + +import { Longhand } from "../longhand.js"; +import { Resolver } from "../resolver.js"; + +type Specified = List; + +/** + * @internal + */ +export namespace Specified { + export type Item = + | Keyword<"alpha"> + | Keyword<"luminance"> + | Keyword<"match-source">; +} + +type Computed = Specified; + +/** + * @internal + */ +export const parse = Keyword.parse("alpha", "luminance", "match-source"); + +const parseList = List.parseCommaSeparated(parse); + +/** + * @internal + */ +export const initialItem = Keyword.of("match-source"); + +/** + * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/mask-mode} + * + * @internal + */ +export default Longhand.of( + List.of([initialItem], ", "), + parseList, + (value, style) => value.map(Resolver.layers(style, "mask-image")), +); diff --git a/packages/alfa-style/src/property/mask-origin.ts b/packages/alfa-style/src/property/mask-origin.ts new file mode 100644 index 0000000000..d968516f52 --- /dev/null +++ b/packages/alfa-style/src/property/mask-origin.ts @@ -0,0 +1,38 @@ +import { Box, Keyword, List } from "@siteimprove/alfa-css"; + +import { Longhand } from "../longhand.js"; +import { Resolver } from "../resolver.js"; + +type Specified = List; + +/** + * @internal + */ +export namespace Specified { + export type Item = Box.CoordBox; +} + +type Computed = Specified; + +/** + * @internal + */ +export const parse = Box.parseCoordBox; + +const parseList = List.parseCommaSeparated(parse); + +/** + * @internal + */ +export const initialItem = Keyword.of("border-box"); + +/** + * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/mask-origin} + * + * @internal + */ +export default Longhand.of( + List.of([initialItem], ", "), + parseList, + (value, style) => value.map(Resolver.layers(style, "mask-image")), +); diff --git a/packages/alfa-style/src/property/mask-position.ts b/packages/alfa-style/src/property/mask-position.ts new file mode 100644 index 0000000000..7bbd69d4b1 --- /dev/null +++ b/packages/alfa-style/src/property/mask-position.ts @@ -0,0 +1,63 @@ +import { + Keyword, + LengthPercentage, + List, + Position, +} from "@siteimprove/alfa-css"; + +import { Longhand } from "../longhand.js"; +import { Resolver } from "../resolver.js"; + +type Specified = List; + +/** + * @internal + */ +export namespace Specified { + export type Item = Position; +} + +type Computed = Specified; + +/** + * @internal + */ +export const parse = Position.parse(/* legacySyntax */ true); + +const parseList = List.parseCommaSeparated(parse); + +/** + * @internal + */ +export const initialItem = Position.of( + Position.Side.of(Keyword.of("left"), LengthPercentage.of(0)), + Position.Side.of(Keyword.of("top"), LengthPercentage.of(0)), +); + +/** + * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/mask-position} + * + * @remarks + * We do not currently fully follow the definition of computed value given in the specification. + * Accordingly the computed value should consist of two keywords and two offsets. + * E.g specifying a single keyword `right` would compute to `top 50% left 100%` or similar. + * But in the current implementation keyword based values are not resolved into keywords with offsets. + * So the single keyword `right` will just compute unaltered to `right`. + * + * @internal + */ +export default Longhand.of( + List.of([initialItem], ", "), + parseList, + (value, style) => { + const layers = Resolver.layers(style, "mask-image"); + + return value.map((positions) => + layers( + positions.map((position) => + position.partiallyResolve(Resolver.length(style)), + ), + ), + ); + }, +); diff --git a/packages/alfa-style/src/property/mask-repeat.ts b/packages/alfa-style/src/property/mask-repeat.ts new file mode 100644 index 0000000000..5711ac37f7 --- /dev/null +++ b/packages/alfa-style/src/property/mask-repeat.ts @@ -0,0 +1,76 @@ +import { Keyword, List, Tuple } from "@siteimprove/alfa-css"; +import { Parser } from "@siteimprove/alfa-parser"; +import { Selective } from "@siteimprove/alfa-selective"; + +import { Longhand } from "../longhand.js"; +import { Resolver } from "../resolver.js"; + +const { either, map } = Parser; + +type Specified = List; + +type LonghandValue = + | Keyword<"repeat"> + | Keyword<"space"> + | Keyword<"round"> + | Keyword<"no-repeat">; + +/** + * @internal + */ +export namespace Specified { + export type Item = + | Keyword<"repeat-x"> + | Keyword<"repeat-y"> + | Tuple<[LonghandValue, LonghandValue]>; +} + +type Computed = List>; + +/** + * @internal + */ +export const parse = either( + Keyword.parse("repeat-x", "repeat-y"), + map( + List.parseSpaceSeparated( + Keyword.parse("repeat", "space", "round", "no-repeat"), + 1, + 2, + ), + ([horizontal, vertical = horizontal]) => Tuple.of(horizontal, vertical), + ), +); + +const parseList = List.parseCommaSeparated(parse); + +/** + * @internal + */ +export const initialItem = Tuple.of(Keyword.of("repeat"), Keyword.of("repeat")); + +/** + * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/mask-repeat} + * + * @internal + */ +export default Longhand.of( + List.of([initialItem], ", "), + parseList, + (value, style) => { + const layers = Resolver.layers(style, "mask-image"); + return value.map((values) => + layers( + values.map((value) => + Selective.of(value) + .if(Keyword.isKeyword, (keyword) => + keyword.is("repeat-x") + ? Tuple.of(Keyword.of("repeat"), Keyword.of("no-repeat")) + : Tuple.of(Keyword.of("no-repeat"), Keyword.of("repeat")), + ) + .get(), + ), + ), + ); + }, +); diff --git a/packages/alfa-style/src/property/mask-size.ts b/packages/alfa-style/src/property/mask-size.ts new file mode 100644 index 0000000000..8d5482f7f9 --- /dev/null +++ b/packages/alfa-style/src/property/mask-size.ts @@ -0,0 +1,78 @@ +import { Keyword, LengthPercentage, List, Tuple } from "@siteimprove/alfa-css"; +import { Parser } from "@siteimprove/alfa-parser"; +import { Selective } from "@siteimprove/alfa-selective"; + +import { Longhand } from "../longhand.js"; +import { Resolver } from "../resolver.js"; + +const { either, map } = Parser; + +type Specified = List; + +/** + * @internal + */ +export namespace Specified { + export type Item = + | Tuple< + [LengthPercentage | Keyword<"auto">, LengthPercentage | Keyword<"auto">] + > + | Keyword<"cover"> + | Keyword<"contain">; +} + +type Computed = Specified; + +/** + * @internal + */ +export const parse = either( + map( + List.parseSpaceSeparated( + either(LengthPercentage.parse, Keyword.parse("auto")), + 1, + 2, + ), + ([horizontal, vertical = horizontal]) => Tuple.of(horizontal, vertical), + ), + Keyword.parse("cover", "contain"), +); + +const parseList = List.parseCommaSeparated(parse); + +/** + * @internal + */ +export const initialItem = Tuple.of(Keyword.of("auto"), Keyword.of("auto")); + +/** + * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/mask-size} + * + * @internal + */ +export default Longhand.of( + List.of([initialItem], ", "), + parseList, + (value, style) => { + const layers = Resolver.layers(style, "mask-image"); + const lengthResolver = LengthPercentage.partiallyResolve( + Resolver.length(style), + ); + + return value.map((sizes) => + layers( + sizes.map((size) => + Selective.of(size) + .if(Tuple.isTuple, (tuple) => { + const [h, v] = tuple.values; + return Tuple.of( + Keyword.isKeyword(h) ? h : lengthResolver(h), + Keyword.isKeyword(v) ? v : lengthResolver(v), + ); + }) + .get(), + ), + ), + ); + }, +); diff --git a/packages/alfa-style/src/property/mask.ts b/packages/alfa-style/src/property/mask.ts new file mode 100644 index 0000000000..15410b2c15 --- /dev/null +++ b/packages/alfa-style/src/property/mask.ts @@ -0,0 +1,128 @@ +import { + Token, + List, +} from "@siteimprove/alfa-css"; +import { Parser } from "@siteimprove/alfa-parser"; +import type { Slice } from "@siteimprove/alfa-slice"; +import { Option } from "@siteimprove/alfa-option"; + +import { Shorthand } from "../shorthand.js"; + +import * as Reference from "./mask-image.js"; +import * as Size from "./mask-size.js"; +import * as Repeat from "./mask-repeat.js"; +import * as Mode from "./mask-mode.js"; +import * as Position from "./mask-position.js"; +import * as Origin from "./mask-origin.js"; +import * as Clip from "./mask-clip.js"; +import * as Composite from "./mask-composite.js"; + +const { doubleBar, map, option, pair, right, delimited, separatedList } = + Parser; + +const slash = delimited(option(Token.parseWhitespace), Token.parseDelim("/")); + +const parsePosAndSize = pair(Position.parse, option(right(slash, Size.parse))); + +/** + * {@link https://drafts.fxtf.org/css-masking/#typedef-mask-layer} + * + * @privateRemarks + * As of December 2024 the specification uses the type in the shorthand defintion + * whereas the longhands `mask-clip` and `mask-origin` uses . + * These are not the same types - does not have `margin-box`. + * There is an open PR to fix that, which we follow. + * {@link https://github.com/w3c/fxtf-drafts/pull/552} + */ +const parse = map( + doubleBar< + Slice, + [ + Reference.Specified.Item, + [Position.Specified.Item, Option], + Repeat.Specified.Item, + Origin.Specified.Item, + Clip.Specified.Item, + Composite.Specified.Item, + Mode.Specified.Item, + ], + string + >( + Token.parseWhitespace, + Reference.parse, + parsePosAndSize, + Repeat.parse, + Origin.parse, + Clip.parse, + Composite.parse, + Mode.parse, + ), + ([image, posAndSize, repeat, box1, box2, composite, mode]) => { + const [pos, size] = + posAndSize !== undefined + ? [posAndSize[0], posAndSize[1].getOr(undefined)] + : [undefined, undefined]; + + const origin = box1; + const clip = box2 ?? box1; + + return [image, pos, size, repeat, origin, clip, composite, mode] as const; + }, +); + +// List.parseCommaSeparated(parse); +const parseList = separatedList( + parse, + delimited(option(Token.parseWhitespace), Token.parseComma), +); + +/** + * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/mask} + * + * @internal + */ +export default Shorthand.of( + [ + "mask-image", + "mask-position", + "mask-size", + "mask-repeat", + "mask-origin", + "mask-clip", + "mask-composite", + "mask-mode", + ], + map(parseList, (layers) => { + const images: Array = []; + const positions: Array = []; + const sizes: Array = []; + const repeats: Array = []; + const origins: Array = []; + const clips: Array = []; + const composites: Array = []; + const modes: Array = []; + + for (const layer of layers) { + const [image, pos, size, repeat, origin, clip, composite, mode] = layer; + images.push(image ?? Reference.initialItem); + positions.push(pos ?? Position.initialItem); + sizes.push(size ?? Size.initialItem); + repeats.push(repeat ?? Repeat.initialItem); + origins.push(origin ?? Origin.initialItem); + clips.push(clip ?? Clip.initialItem); + composites.push(composite ?? Composite.initialItem); + modes.push(mode ?? Mode.initialItem); + } + + return [ + ["mask-image", List.of(images, ", ")], + ["mask-position", List.of(positions, ", ")], + ["mask-size", List.of(sizes, ", ")], + ["mask-repeat", List.of(repeats, ", ")], + ["mask-origin", List.of(origins, ", ")], + ["mask-clip", List.of(clips, ", ")], + ["mask-composite", List.of(composites, ", ")], + ["mask-mode", List.of(modes, ", ")], + ]; + }), +); diff --git a/packages/alfa-style/src/resolver.ts b/packages/alfa-style/src/resolver.ts index 8172734a46..f529c24186 100644 --- a/packages/alfa-style/src/resolver.ts +++ b/packages/alfa-style/src/resolver.ts @@ -1,5 +1,5 @@ -import type { LengthPercentage, Unit } from "@siteimprove/alfa-css"; -import { Length } from "@siteimprove/alfa-css"; +import type { LengthPercentage, Unit, Value } from "@siteimprove/alfa-css"; +import { Length, List } from "@siteimprove/alfa-css"; import type { Mapper } from "@siteimprove/alfa-mapper"; import type { Style } from "./style.js"; @@ -50,4 +50,26 @@ export namespace Resolver { ): LengthPercentage.Resolver { return { percentageBase: base, length: lengthResolver(style) }; } + + /** + * Resolve layers for properties that uses layering like background and mask. + * + * The number of layers is determined by the number of comma separated values + * in the property where the image is specified, i.e. `background-image` or `mask-image`. + * + * If there are more values than layers, the excess values are discarded. + * Otherwise, the values must be repeated until the number of values matches the number of layers. + * + * {@link https://www.w3.org/TR/css-backgrounds-3/#layering} + * {@link https://drafts.fxtf.org/css-masking/#layering}. + * + * @internal + */ + export function layers( + style: Style, + name: "mask-image" | "background-image", + ) { + return (value: List): List => + value.cutOrExtend(Math.max(style.computed(name).value.size, 1)); + } } diff --git a/packages/alfa-style/src/shorthands.ts b/packages/alfa-style/src/shorthands.ts index 30555c7219..b214b58975 100644 --- a/packages/alfa-style/src/shorthands.ts +++ b/packages/alfa-style/src/shorthands.ts @@ -30,6 +30,7 @@ import InsetBlock from "./property/inset-block.js"; import InsetInline from "./property/inset-inline.js"; import Inset from "./property/inset.js"; import Margin from "./property/margin.js"; +import Mask from "./property/mask.js"; import Outline from "./property/outline.js"; import Overflow from "./property/overflow.js"; import TextDecoration from "./property/text-decoration.js"; @@ -76,6 +77,7 @@ export namespace Shorthands { "inset-inline": InsetInline, inset: Inset, margin: Margin, + mask: Mask, outline: Outline, overflow: Overflow, "text-decoration": TextDecoration, diff --git a/packages/alfa-style/src/tsconfig.json b/packages/alfa-style/src/tsconfig.json index 9afb97ca5a..80e803580f 100644 --- a/packages/alfa-style/src/tsconfig.json +++ b/packages/alfa-style/src/tsconfig.json @@ -150,6 +150,15 @@ "./property/letter-spacing.ts", "./property/line-height.ts", "./property/margin.ts", + "./property/mask-clip.ts", + "./property/mask-composite.ts", + "./property/mask-image.ts", + "./property/mask-mode.ts", + "./property/mask-origin.ts", + "./property/mask-position.ts", + "./property/mask-repeat.ts", + "./property/mask-size.ts", + "./property/mask.ts", "./property/margin-bottom.ts", "./property/margin-left.ts", "./property/margin-right.ts", diff --git a/packages/alfa-style/test/common.ts b/packages/alfa-style/test/common.ts index e4c9283347..60a8a43413 100755 --- a/packages/alfa-style/test/common.ts +++ b/packages/alfa-style/test/common.ts @@ -32,6 +32,17 @@ export function specified( return Style.from(element, device, context).specified(name).toJSON(); } +/** + * @internal + */ +export function computed( + element: Element, + name: N, + context: Context = Context.empty(), +): Value.JSON> { + return Style.from(element, device, context).computed(name).toJSON(); +} + /** * @internal */ diff --git a/packages/alfa-style/test/property/mask-clip.spec.tsx b/packages/alfa-style/test/property/mask-clip.spec.tsx new file mode 100644 index 0000000000..3f64d8dc0e --- /dev/null +++ b/packages/alfa-style/test/property/mask-clip.spec.tsx @@ -0,0 +1,114 @@ +import { test } from "@siteimprove/alfa-test"; +import { h } from "@siteimprove/alfa-dom"; + +import { computed } from "../common.js"; + +test("initial value is border-box", (t) => { + t.deepEqual(computed(
, "mask-clip"), { + value: { + type: "list", + separator: " ", + values: [{ type: "keyword", value: "border-box" }], + }, + source: null, + }); +}); + +test("#computed parses single keywords", (t) => { + for (const kw of [ + "content-box", + "padding-box", + "border-box", + "fill-box", + "stroke-box", + "view-box", + "no-clip", + ] as const) { + t.deepEqual(computed(
, "mask-clip"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: kw }], + }, + source: h.declaration("mask-clip", kw).toJSON(), + }); + } +}); + +test("#computed parses multiple layers", (t) => { + t.deepEqual( + computed( +
, + "mask-clip", + ), + { + value: { + type: "list", + separator: ", ", + values: [ + { type: "keyword", value: "padding-box" }, + { type: "keyword", value: "no-clip" }, + ], + }, + source: h.declaration("mask-clip", "padding-box, no-clip").toJSON(), + }, + ); +}); + +test("#computed discards excess values when there are more values than layers", (t) => { + t.deepEqual( + computed( +
, + "mask-clip", + ), + { + value: { + type: "list", + separator: ", ", + values: [ + { type: "keyword", value: "view-box" }, + { type: "keyword", value: "fill-box" }, + ], + }, + source: h + .declaration("mask-clip", "view-box, fill-box, border-box") + .toJSON(), + }, + ); +}); + +test("#computed repeats values when there are more layers than values", (t) => { + t.deepEqual( + computed( +
, + "mask-clip", + ), + { + value: { + type: "list", + separator: ", ", + values: [ + { type: "keyword", value: "view-box" }, + { type: "keyword", value: "fill-box" }, + { type: "keyword", value: "view-box" }, + ], + }, + source: h.declaration("mask-clip", "view-box, fill-box").toJSON(), + }, + ); +}); diff --git a/packages/alfa-style/test/property/mask-composite.spec.tsx b/packages/alfa-style/test/property/mask-composite.spec.tsx new file mode 100644 index 0000000000..66072abec8 --- /dev/null +++ b/packages/alfa-style/test/property/mask-composite.spec.tsx @@ -0,0 +1,31 @@ +import { test } from "@siteimprove/alfa-test"; +import { h } from "@siteimprove/alfa-dom"; + +import { computed } from "../common.js"; + +test("initial value is add", (t) => { + t.deepEqual(computed(
, "mask-composite"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "add" }], + }, + source: null, + }); +}); + +test("#computed parses single keywords", (t) => { + for (const kw of ["add", "subtract", "intersect", "exclude"] as const) { + t.deepEqual( + computed(
, "mask-composite"), + { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: kw }], + }, + source: h.declaration("mask-composite", kw).toJSON(), + }, + ); + } +}); diff --git a/packages/alfa-style/test/property/mask-image.spec.tsx b/packages/alfa-style/test/property/mask-image.spec.tsx new file mode 100644 index 0000000000..2182d1b7a1 --- /dev/null +++ b/packages/alfa-style/test/property/mask-image.spec.tsx @@ -0,0 +1,89 @@ +import { test } from "@siteimprove/alfa-test"; +import { h } from "@siteimprove/alfa-dom"; + +import { computed } from "../common.js"; + +test("initial value is none", (t) => { + t.deepEqual(computed(
, "mask-image"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "none" }], + }, + source: null, + }); +}); + +test("#computed parses url value", (t) => { + t.deepEqual( + computed( +
, + "mask-image", + ), + { + value: { + type: "list", + separator: ", ", + values: [ + { type: "image", image: { type: "url", url: "masks.svg#mask1" } }, + ], + }, + source: h.declaration("mask-image", "url(masks.svg#mask1)").toJSON(), + }, + ); +}); + +test("#computed parses linear-gradient value", (t) => { + t.deepEqual( + computed( +
, + "mask-image", + ), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "image", + image: { + type: "gradient", + kind: "linear", + direction: { type: "side", side: "bottom" }, + items: [ + { + color: { + type: "color", + format: "rgb", + alpha: { type: "percentage", value: 1 }, + red: { type: "percentage", value: 1 }, + green: { type: "percentage", value: 0 }, + blue: { type: "percentage", value: 0 }, + }, + position: null, + type: "stop", + }, + { + color: { + type: "color", + format: "rgb", + alpha: { type: "percentage", value: 1 }, + red: { type: "percentage", value: 0 }, + green: { type: "percentage", value: 0 }, + blue: { type: "percentage", value: 1 }, + }, + position: null, + type: "stop", + }, + ], + repeats: false, + }, + }, + ], + }, + source: h + .declaration("mask-image", "linear-gradient(red, blue)") + .toJSON(), + }, + ); +}); diff --git a/packages/alfa-style/test/property/mask-mode.spec.tsx b/packages/alfa-style/test/property/mask-mode.spec.tsx new file mode 100644 index 0000000000..ac33c1767b --- /dev/null +++ b/packages/alfa-style/test/property/mask-mode.spec.tsx @@ -0,0 +1,28 @@ +import { test } from "@siteimprove/alfa-test"; +import { h } from "@siteimprove/alfa-dom"; + +import { computed } from "../common.js"; + +test("initial value is match-source", (t) => { + t.deepEqual(computed(
, "mask-mode"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "match-source" }], + }, + source: null, + }); +}); + +test("#computed parses single keywords", (t) => { + for (const kw of ["alpha", "luminance", "match-source"] as const) { + t.deepEqual(computed(
, "mask-mode"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: kw }], + }, + source: h.declaration("mask-mode", kw).toJSON(), + }); + } +}); diff --git a/packages/alfa-style/test/property/mask-origin.spec.tsx b/packages/alfa-style/test/property/mask-origin.spec.tsx new file mode 100644 index 0000000000..6456902afa --- /dev/null +++ b/packages/alfa-style/test/property/mask-origin.spec.tsx @@ -0,0 +1,38 @@ +import { test } from "@siteimprove/alfa-test"; +import { h } from "@siteimprove/alfa-dom"; + +import { computed } from "../common.js"; + +test("initial value is border-box", (t) => { + t.deepEqual(computed(
, "mask-origin"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "border-box" }], + }, + source: null, + }); +}); + +test("#computed parses single keywords", (t) => { + for (const kw of [ + "content-box", + "padding-box", + "border-box", + "fill-box", + "stroke-box", + "view-box", + ] as const) { + t.deepEqual( + computed(
, "mask-origin"), + { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: kw }], + }, + source: h.declaration("mask-origin", kw).toJSON(), + }, + ); + } +}); diff --git a/packages/alfa-style/test/property/mask-position.spec.tsx b/packages/alfa-style/test/property/mask-position.spec.tsx new file mode 100644 index 0000000000..d3ca08803a --- /dev/null +++ b/packages/alfa-style/test/property/mask-position.spec.tsx @@ -0,0 +1,125 @@ +import { test } from "@siteimprove/alfa-test"; +import { h } from "@siteimprove/alfa-dom"; + +import { computed } from "../common.js"; + +test("initial value is 0% 0%", (t) => { + t.deepEqual(computed(
, "mask-position"), { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "position", + horizontal: { + type: "side", + side: { type: "keyword", value: "left" }, + offset: { type: "percentage", value: 0 }, + }, + vertical: { + type: "side", + side: { type: "keyword", value: "top" }, + offset: { type: "percentage", value: 0 }, + }, + }, + ], + }, + source: null, + }); +}); + +test("#computed parses single keywords", (t) => { + for (const kw of ["top", "bottom"] as const) { + t.deepEqual( + computed(
, "mask-position"), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "position", + horizontal: { type: "keyword", value: "center" }, + vertical: { + type: "side", + offset: null, + side: { type: "keyword", value: kw }, + }, + }, + ], + }, + source: h.declaration("mask-position", kw).toJSON(), + }, + ); + } + + for (const kw of ["left", "right"] as const) { + t.deepEqual( + computed(
, "mask-position"), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "position", + vertical: { type: "keyword", value: "center" }, + horizontal: { + type: "side", + offset: null, + side: { type: "keyword", value: kw }, + }, + }, + ], + }, + source: h.declaration("mask-position", kw).toJSON(), + }, + ); + } + + t.deepEqual( + computed(
, "mask-position"), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "position", + vertical: { type: "keyword", value: "center" }, + horizontal: { type: "keyword", value: "center" }, + }, + ], + }, + source: h.declaration("mask-position", "center").toJSON(), + }, + ); +}); + +test("#computed parses lengths and percentages", (t) => { + t.deepEqual( + computed(
, "mask-position"), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "position", + horizontal: { + type: "side", + offset: { type: "percentage", value: 0.1 }, + side: { type: "keyword", value: "left" }, + }, + vertical: { + type: "side", + offset: { type: "length", unit: "px", value: 48 }, + side: { type: "keyword", value: "top" }, + }, + }, + ], + }, + source: h.declaration("mask-position", "10% 3em").toJSON(), + }, + ); +}); diff --git a/packages/alfa-style/test/property/mask-repeat.spec.tsx b/packages/alfa-style/test/property/mask-repeat.spec.tsx new file mode 100644 index 0000000000..08df2306cb --- /dev/null +++ b/packages/alfa-style/test/property/mask-repeat.spec.tsx @@ -0,0 +1,132 @@ +import { test } from "@siteimprove/alfa-test"; +import { h } from "@siteimprove/alfa-dom"; + +import { computed } from "../common.js"; + +test("initial value is repeat", (t) => { + t.deepEqual(computed(
, "mask-repeat"), { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "keyword", value: "repeat" }, + { type: "keyword", value: "repeat" }, + ], + }, + ], + }, + source: null, + }); +}); + +test("#computed parses single keywords", (t) => { + t.deepEqual( + computed(
, "mask-repeat"), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "keyword", value: "repeat" }, + { type: "keyword", value: "no-repeat" }, + ], + }, + ], + }, + source: h.declaration("mask-repeat", "repeat-x").toJSON(), + }, + ); + + t.deepEqual( + computed(
, "mask-repeat"), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "keyword", value: "no-repeat" }, + { type: "keyword", value: "repeat" }, + ], + }, + ], + }, + source: h.declaration("mask-repeat", "repeat-y").toJSON(), + }, + ); + + for (const kw of ["repeat", "space", "round", "no-repeat"] as const) { + t.deepEqual( + computed(
, "mask-repeat"), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "keyword", value: kw }, + { type: "keyword", value: kw }, + ], + }, + ], + }, + source: h.declaration("mask-repeat", kw).toJSON(), + }, + ); + } +}); + +test("#computed parses at most two space separated values", (t) => { + t.deepEqual( + computed(
, "mask-repeat"), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "keyword", value: "repeat" }, + { type: "keyword", value: "space" }, + ], + }, + ], + }, + source: h.declaration("mask-repeat", "repeat space").toJSON(), + }, + ); + + t.deepEqual( + computed( +
, + "mask-repeat", + ), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "keyword", value: "repeat" }, + { type: "keyword", value: "repeat" }, + ], + }, + ], + }, + source: null, + }, + ); +}); diff --git a/packages/alfa-style/test/property/mask-size.spec.tsx b/packages/alfa-style/test/property/mask-size.spec.tsx new file mode 100644 index 0000000000..e7b37221f5 --- /dev/null +++ b/packages/alfa-style/test/property/mask-size.spec.tsx @@ -0,0 +1,128 @@ +import { test } from "@siteimprove/alfa-test"; +import { h } from "@siteimprove/alfa-dom"; + +import { computed } from "../common.js"; + +test("initial value is auto", (t) => { + t.deepEqual( + computed( +
, + "mask-size", + ), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "keyword", value: "auto" }, + { type: "keyword", value: "auto" }, + ], + }, + { + type: "tuple", + values: [ + { type: "keyword", value: "auto" }, + { type: "keyword", value: "auto" }, + ], + }, + ], + }, + source: null, + }, + ); +}); + +test("#computed parses single keywords", (t) => { + for (const kw of ["cover", "contain"] as const) { + t.deepEqual(computed(
, "mask-size"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: kw }], + }, + source: h.declaration("mask-size", kw).toJSON(), + }); + } +}); + +test("#computed parses percentage width", (t) => { + t.deepEqual(computed(
, "mask-size"), { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "percentage", value: 0.5 }, + { type: "percentage", value: 0.5 }, + ], + }, + ], + }, + source: h.declaration("mask-size", "50%").toJSON(), + }); +}); + +test("#computed resolves em width", (t) => { + t.deepEqual(computed(
, "mask-size"), { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "length", unit: "px", value: 48 }, + { type: "length", unit: "px", value: 48 }, + ], + }, + ], + }, + source: h.declaration("mask-size", "3em").toJSON(), + }); +}); + +test("#computed parses pixel width", (t) => { + t.deepEqual(computed(
, "mask-size"), { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "length", unit: "px", value: 12 }, + { type: "length", unit: "px", value: 12 }, + ], + }, + ], + }, + source: h.declaration("mask-size", "12px").toJSON(), + }); +}); + +test("#computed parses width and height", (t) => { + t.deepEqual( + computed(
, "mask-size"), + { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "length", unit: "px", value: 48 }, + { type: "percentage", value: 0.25 }, + ], + }, + ], + }, + source: h.declaration("mask-size", "3em 25%").toJSON(), + }, + ); +}); diff --git a/packages/alfa-style/test/property/mask.spec.tsx b/packages/alfa-style/test/property/mask.spec.tsx new file mode 100644 index 0000000000..ca70af7073 --- /dev/null +++ b/packages/alfa-style/test/property/mask.spec.tsx @@ -0,0 +1,239 @@ +import { test } from "@siteimprove/alfa-test"; +import { h } from "@siteimprove/alfa-dom"; + +import { computed } from "../common.js"; + +test("longhands resolve correctly from shorthand", (t) => { + const mask = + "url(foo.svg) 50% 0% / 12px repeat-x view-box padding-box subtract luminance"; + const decl = h.declaration("mask", mask); + const element =
; + + t.deepEqual(computed(element, "mask-image"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "image", image: { type: "url", url: "foo.svg" } }], + }, + source: decl.toJSON(), + }); + + t.deepEqual(computed(element, "mask-position"), { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "position", + horizontal: { + type: "side", + offset: { type: "percentage", value: 0.5 }, + side: { type: "keyword", value: "left" }, + }, + vertical: { + type: "side", + offset: { type: "percentage", value: 0 }, + side: { type: "keyword", value: "top" }, + }, + }, + ], + }, + source: decl.toJSON(), + }); + + t.deepEqual(computed(element, "mask-size"), { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "length", unit: "px", value: 12 }, + { type: "length", unit: "px", value: 12 }, + ], + }, + ], + }, + source: decl.toJSON(), + }); + + t.deepEqual(computed(element, "mask-repeat"), { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "keyword", value: "repeat" }, + { type: "keyword", value: "no-repeat" }, + ], + }, + ], + }, + source: decl.toJSON(), + }); + + t.deepEqual(computed(element, "mask-origin"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "view-box" }], + }, + source: decl.toJSON(), + }); + + t.deepEqual(computed(element, "mask-clip"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "padding-box" }], + }, + source: decl.toJSON(), + }); + + t.deepEqual(computed(element, "mask-composite"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "subtract" }], + }, + source: decl.toJSON(), + }); + + t.deepEqual(computed(element, "mask-mode"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "luminance" }], + }, + source: decl.toJSON(), + }); +}); + +test("if one `` value and the `no-clip` keyword are present then `` sets `mask-origin` and `no-clip` sets `mask-clip`", (t) => { + const mask = "url(foo.svg) view-box no-clip"; + const decl = h.declaration("mask", mask); + const element =
; + + t.deepEqual(computed(element, "mask-origin"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "view-box" }], + }, + source: decl.toJSON(), + }); + + t.deepEqual(computed(element, "mask-clip"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "no-clip" }], + }, + source: decl.toJSON(), + }); +}); + +test("if one `` value and no `no-clip` keyword are present then `` sets both `mask-origin` and `mask-clip`", (t) => { + const mask = "url(foo.svg) view-box"; + const decl = h.declaration("mask", mask); + const element =
; + + t.deepEqual(computed(element, "mask-origin"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "view-box" }], + }, + source: decl.toJSON(), + }); + + t.deepEqual(computed(element, "mask-clip"), { + value: { + type: "list", + separator: ", ", + values: [{ type: "keyword", value: "view-box" }], + }, + source: decl.toJSON(), + }); +}); + +test("longhands resolves correctly from shorthand with layers", (t) => { + const mask = "url(foo.svg) 50% 0% / 12px, url(bar.svg) 0% 50%"; + const decl = h.declaration("mask", mask); + const element =
; + + t.deepEqual(computed(element, "mask-image"), { + value: { + type: "list", + separator: ", ", + values: [ + { type: "image", image: { type: "url", url: "foo.svg" } }, + { type: "image", image: { type: "url", url: "bar.svg" } }, + ], + }, + source: decl.toJSON(), + }); + + t.deepEqual(computed(element, "mask-position"), { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "position", + horizontal: { + type: "side", + offset: { type: "percentage", value: 0.5 }, + side: { type: "keyword", value: "left" }, + }, + vertical: { + type: "side", + offset: { type: "percentage", value: 0 }, + side: { type: "keyword", value: "top" }, + }, + }, + { + type: "position", + horizontal: { + type: "side", + offset: { type: "percentage", value: 0 }, + side: { type: "keyword", value: "left" }, + }, + vertical: { + type: "side", + offset: { type: "percentage", value: 0.5 }, + side: { type: "keyword", value: "top" }, + }, + }, + ], + }, + source: decl.toJSON(), + }); + + t.deepEqual(computed(element, "mask-size"), { + value: { + type: "list", + separator: ", ", + values: [ + { + type: "tuple", + values: [ + { type: "length", unit: "px", value: 12 }, + { type: "length", unit: "px", value: 12 }, + ], + }, + { + type: "tuple", + values: [ + { type: "keyword", value: "auto" }, + { type: "keyword", value: "auto" }, + ], + }, + ], + }, + source: decl.toJSON(), + }); +}); diff --git a/packages/alfa-style/test/tsconfig.json b/packages/alfa-style/test/tsconfig.json index 118d1b5f56..40bb05d75e 100644 --- a/packages/alfa-style/test/tsconfig.json +++ b/packages/alfa-style/test/tsconfig.json @@ -54,6 +54,15 @@ "./property/isolation.spec.tsx", "./property/line-height.spec.tsx", "./property/margin.spec.tsx", + "./property/mask-clip.spec.tsx", + "./property/mask-composite.spec.tsx", + "./property/mask-image.spec.tsx", + "./property/mask-mode.spec.tsx", + "./property/mask-origin.spec.tsx", + "./property/mask-position.spec.tsx", + "./property/mask-repeat.spec.tsx", + "./property/mask-size.spec.tsx", + "./property/mask.spec.tsx", "./property/mix-blend-mode.spec.tsx", "./property/opacity.spec.tsx", "./property/outline.spec.tsx",