-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
656b523
commit 9d49141
Showing
6 changed files
with
281 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import { | ||
Keyword, | ||
Number, | ||
Percentage, | ||
Token, | ||
Tuple, | ||
} from "@siteimprove/alfa-css"; | ||
import { Parser } from "@siteimprove/alfa-parser"; | ||
import { Slice } from "@siteimprove/alfa-slice"; | ||
|
||
import { Longhand } from "../longhand.js"; | ||
import { Resolver } from "../resolver.js"; | ||
|
||
const { doubleBar, either, filter, map } = Parser; | ||
|
||
type NumberPercentage = Number | Percentage; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export type Specified = | ||
| Tuple< | ||
[NumberPercentage, NumberPercentage, NumberPercentage, NumberPercentage] | ||
> | ||
| Tuple< | ||
[ | ||
NumberPercentage, | ||
NumberPercentage, | ||
NumberPercentage, | ||
NumberPercentage, | ||
Keyword<"fill">, | ||
] | ||
>; | ||
|
||
const parseNumberPercentage = either(Number.parse, Percentage.parse); | ||
|
||
/** | ||
* @internal | ||
* | ||
* @privateRemarks | ||
* The `doubleBar` parser is used because the `fill` keyword may appear at any position. | ||
*/ | ||
export const parse = map( | ||
filter( | ||
doubleBar< | ||
Slice<Token>, | ||
[ | ||
NumberPercentage, | ||
NumberPercentage, | ||
NumberPercentage, | ||
NumberPercentage, | ||
Keyword<"fill">, | ||
], | ||
string | ||
>( | ||
Token.parseWhitespace, | ||
parseNumberPercentage, | ||
parseNumberPercentage, | ||
parseNumberPercentage, | ||
parseNumberPercentage, | ||
Keyword.parse("fill"), | ||
), | ||
(values) => | ||
values.some((value) => value !== undefined && !Keyword.isKeyword(value)), | ||
() => "At least one non-keyword value must be present.", | ||
), | ||
([p1, p2, p3, p4, fill]) => { | ||
// At least one number is guaranteed to be defined by the filter above | ||
// and we assume that `doubleBar` is implemented such that the defined values appears first. | ||
p1 = p1 as NumberPercentage; | ||
|
||
// Represents the postions in order of [top, right, bottom, left] | ||
let positions: [ | ||
NumberPercentage, | ||
NumberPercentage, | ||
NumberPercentage, | ||
NumberPercentage, | ||
]; | ||
if (p2 === undefined) { | ||
positions = [p1, p1, p1, p1]; | ||
} else if (p3 === undefined) { | ||
// when two positions are specified, the first creates slices measured from the **top and bottom**, | ||
// the second creates slices measured from the **left and right**. | ||
positions = [p1, p2, p1, p2]; | ||
} else if (p4 === undefined) { | ||
// when three positions are specified, the first creates a slice measured from the **top**, | ||
// the second creates slices measured from the **left and right**, | ||
// the third creates a slice measured from the **bottom**. | ||
positions = [p1, p2, p3, p2]; | ||
} else { | ||
positions = [p1, p2, p3, p4]; | ||
} | ||
|
||
return fill !== undefined | ||
? Tuple.of(...positions, fill) | ||
: Tuple.of(...positions); | ||
}, | ||
); | ||
|
||
/** | ||
* @internal | ||
*/ | ||
export const initialItem = Tuple.of( | ||
Number.of(0), | ||
Number.of(0), | ||
Number.of(0), | ||
Number.of(0), | ||
); | ||
|
||
type Computed = Specified; | ||
|
||
/** | ||
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/mask-border-slice} | ||
* | ||
* @internal | ||
*/ | ||
export default Longhand.of<Specified, Computed>( | ||
initialItem, | ||
parse, | ||
(value, style) => | ||
value.map((tuple) => { | ||
const [p1, p2, p3, p4, fill] = tuple.values; | ||
const positions = [ | ||
p1.resolve(Resolver.length(style)), | ||
p2.resolve(Resolver.length(style)), | ||
p3.resolve(Resolver.length(style)), | ||
p4.resolve(Resolver.length(style)), | ||
] as const; | ||
|
||
return fill !== undefined | ||
? Tuple.of(...positions, fill) | ||
: Tuple.of(...positions); | ||
}), | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
packages/alfa-style/test/property/mask-border-slice.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 none", (t) => { | ||
t.deepEqual(computed(<div></div>, "mask-border-slice"), { | ||
value: { | ||
type: "tuple", | ||
values: [ | ||
{ type: "number", value: 0 }, | ||
{ type: "number", value: 0 }, | ||
{ type: "number", value: 0 }, | ||
{ type: "number", value: 0 }, | ||
], | ||
}, | ||
source: null, | ||
}); | ||
}); | ||
|
||
test("#computed parses one value", (t) => { | ||
t.deepEqual( | ||
computed( | ||
<div style={{ maskBorderSlice: "30%" }}></div>, | ||
"mask-border-slice", | ||
), | ||
{ | ||
value: { | ||
type: "tuple", | ||
values: [ | ||
{ type: "percentage", value: 0.3 }, | ||
{ type: "percentage", value: 0.3 }, | ||
{ type: "percentage", value: 0.3 }, | ||
{ type: "percentage", value: 0.3 }, | ||
], | ||
}, | ||
source: h.declaration("mask-border-slice", "30%").toJSON(), | ||
}, | ||
); | ||
}); | ||
|
||
test("#computed parses two values", (t) => { | ||
t.deepEqual( | ||
computed( | ||
<div style={{ maskBorderSlice: "10% 30%" }}></div>, | ||
"mask-border-slice", | ||
), | ||
{ | ||
value: { | ||
type: "tuple", | ||
values: [ | ||
{ type: "percentage", value: 0.1 }, | ||
{ type: "percentage", value: 0.3 }, | ||
{ type: "percentage", value: 0.1 }, | ||
{ type: "percentage", value: 0.3 }, | ||
], | ||
}, | ||
source: h.declaration("mask-border-slice", "10% 30%").toJSON(), | ||
}, | ||
); | ||
}); | ||
|
||
test("#computed parses three values", (t) => { | ||
t.deepEqual( | ||
computed( | ||
<div style={{ maskBorderSlice: "30 30% 45" }}></div>, | ||
"mask-border-slice", | ||
), | ||
{ | ||
value: { | ||
type: "tuple", | ||
values: [ | ||
{ type: "number", value: 30 }, | ||
{ type: "percentage", value: 0.3 }, | ||
{ type: "number", value: 45 }, | ||
{ type: "percentage", value: 0.3 }, | ||
], | ||
}, | ||
source: h.declaration("mask-border-slice", "30 30% 45").toJSON(), | ||
}, | ||
); | ||
}); | ||
|
||
test("#computed parses four values", (t) => { | ||
t.deepEqual( | ||
computed( | ||
<div style={{ maskBorderSlice: "7 12 14 5" }}></div>, | ||
"mask-border-slice", | ||
), | ||
{ | ||
value: { | ||
type: "tuple", | ||
values: [ | ||
{ type: "number", value: 7 }, | ||
{ type: "number", value: 12 }, | ||
{ type: "number", value: 14 }, | ||
{ type: "number", value: 5 }, | ||
], | ||
}, | ||
source: h.declaration("mask-border-slice", "7 12 14 5").toJSON(), | ||
}, | ||
); | ||
}); | ||
|
||
test("#computed parses the `fill` keyword", (t) => { | ||
t.deepEqual( | ||
computed( | ||
<div style={{ maskBorderSlice: "10 fill 7 12" }}></div>, | ||
"mask-border-slice", | ||
), | ||
{ | ||
value: { | ||
type: "tuple", | ||
values: [ | ||
{ type: "number", value: 10 }, | ||
{ type: "number", value: 7 }, | ||
{ type: "number", value: 12 }, | ||
{ type: "number", value: 7 }, | ||
{ type: "keyword", value: "fill" }, | ||
], | ||
}, | ||
source: h.declaration("mask-border-slice", "10 fill 7 12").toJSON(), | ||
}, | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters