Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(css/prefixer): any-link fallback #6696

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 1 addition & 9 deletions crates/swc_atoms/words.txt
@@ -1,5 +1,4 @@
*
*
-infinity
-moz-activehyperlinktext
-moz-animation
Expand All @@ -12,8 +11,6 @@
-moz-animation-play-state
-moz-animation-timing-function
-moz-any
-moz-any
-moz-any
-moz-appearance
-moz-backface-visibility
-moz-background-origin
Expand All @@ -38,8 +35,6 @@
-moz-buttonhoverface
-moz-buttonhovertext
-moz-calc
-moz-calc
-moz-calc
-moz-cellhighlight
-moz-cellhighlighttext
-moz-column-count
Expand All @@ -59,8 +54,6 @@
-moz-dialog
-moz-dialogtext
-moz-document
-moz-document
-moz-document
-moz-dragtargetzone
-moz-eventreerow
-moz-font-feature-settings
Expand All @@ -71,8 +64,6 @@
-moz-hyperlinktext
-moz-hyphens
-moz-keyframes
-moz-keyframes
-moz-keyframes
-moz-mac-accentdarkestshadow
-moz-mac-accentdarkshadow
-moz-mac-accentface
Expand Down Expand Up @@ -936,6 +927,7 @@ annotation-xml
anonymous
antiquewhite
any
any-link
appWorkspace
appearance
apple-touch-icon
Expand Down
24 changes: 24 additions & 0 deletions crates/swc_css_prefixer/data/prefixes_and_browsers.json
Expand Up @@ -101,6 +101,30 @@
"firefox": "49"
}
],
":any-link-fallback": [
{
"chrome": "4",
"edge": "12",
"safari": "3",
"firefox": "2",
"opera": "10",
"ie": "6",
"ios": "3.2",
"samsung": "4",
"android": "2.1"
},
{
"chrome": "14",
"edge": "17",
"safari": "6",
"firefox": "2",
"opera": "21.1",
"ie": "11",
"ios": "5.1",
"samsung": "4",
"android": "4.3"
}
],

":-webkit-full-screen": [
{
Expand Down
90 changes: 89 additions & 1 deletion crates/swc_css_prefixer/src/prefixer.rs
Expand Up @@ -669,6 +669,70 @@ where
node.visit_mut_with(&mut FontFaceFormatOldSyntax {});
}

pub struct PseudoClassSearcher<'a> {
found: &'a mut bool,
}

impl VisitMut for PseudoClassSearcher<'_> {
fn visit_mut_pseudo_class_selector(&mut self, n: &mut PseudoClassSelector) {
n.visit_mut_children_with(self);

if n.name.value == js_word!("any-link") {
*self.found = true;
}
}
}

pub struct PseudoClassAnyLinkFallback {}

impl VisitMut for PseudoClassAnyLinkFallback {
fn visit_mut_selector_list(&mut self, n: &mut SelectorList) {
n.visit_mut_children_with(self);

let mut found = false;

n.visit_mut_with(&mut PseudoClassSearcher { found: &mut found });

if !found {
return;
}

let mut new_children: Vec<ComplexSelector> = vec![];

for complex_selector in &n.children {
let mut link_complex_selector = complex_selector.clone();

replace_pseudo_class_selector_name(&mut link_complex_selector, "any-link", "link");

if link_complex_selector.eq_ignore_span(complex_selector) {
new_children.push(complex_selector.clone());

continue;
}

let mut visited_complex_selectors = complex_selector.clone();

replace_pseudo_class_selector_name(
&mut visited_complex_selectors,
"any-link",
"visited",
);

new_children.push(link_complex_selector);
new_children.push(visited_complex_selectors);
}

n.children = new_children;
}
}

pub fn pseudo_class_any_link_fallback<N>(node: &mut N)
where
N: VisitMutWith<PseudoClassAnyLinkFallback>,
{
node.visit_mut_with(&mut PseudoClassAnyLinkFallback {});
}

macro_rules! to_ident {
($val:expr) => {{
ComponentValue::Ident(Box::new(Ident {
Expand Down Expand Up @@ -875,7 +939,6 @@ impl VisitMut for Prefixer {
fn visit_mut_import_conditions(&mut self, import_conditions: &mut ImportConditions) {
import_conditions.visit_mut_children_with(self);

// ComponentValue::Declaration(declaration)
if !self.added_declarations.is_empty() {
if let Some(supports) = import_conditions.supports.take() {
let mut conditions = Vec::with_capacity(1 + self.added_declarations.len());
Expand Down Expand Up @@ -1036,6 +1099,31 @@ impl VisitMut for Prefixer {

n.visit_mut_children_with(self);

// `:any-link` fallback generates only for old browsers, which doesn't support
// `-webkit and `-moz` prefixes
if should_prefix(":any-link-fallback", self.env, false) {
let mut new_prelude = n.prelude.clone();

pseudo_class_any_link_fallback(&mut new_prelude);

if !n.prelude.eq_ignore_span(&new_prelude) {
let qualified_rule = Box::new(QualifiedRule {
span: DUMMY_SP,
prelude: new_prelude,
block: original_simple_block.clone(),
});

// TODO refactor and avoid using prefix
if self.simple_block.is_none() {
self.added_top_rules
.push((Prefix::Webkit, Rule::QualifiedRule(qualified_rule)));
} else {
self.added_qualified_rules
.push((Prefix::Webkit, qualified_rule));
}
}
}

if self.rule_prefix == Some(Prefix::Webkit) || self.rule_prefix.is_none() {
let mut new_webkit_prelude = n.prelude.clone();

Expand Down
120 changes: 120 additions & 0 deletions crates/swc_css_prefixer/tests/fixture/any-link/input.css
@@ -1,3 +1,123 @@
a:any-link {
color: red;
}

nav :any-link > span, foo > bar {
background-color: yellow;
}

:any-link {
order: 1;
}

:aNy-LiNK {
order: 1.1;
}

:any-link,
ul a:any-link > span {
order: 2;
}

:any-link :any-link {
order: 3;
}

:any-link(.ignore) {
order: 4;
}

.foo :any-link {
order: 5;
}

.foo:any-link {
order: 6;
}

.foo:is(:any-link) {
order: 7;
}

:any-link::before,
:any-link:before {
order: 8;
}

::before:any-link,
:before:any-link {
order: 8.1;
}

a:any-link {
order: 9;
}

area:any-link {
order: 10;
}

[hidden]area:any-link {
order: 10.1;
}

AREA:any-link {
order: 10.2;
}

area :any-link {
order: 11;
}

area > :any-link {
order: 12;
}

div:any-link {
order: 13;
}

:any-link + input[type=file]:hover::file-selector-button {
order: 14;
}

:any-link + input[type=file]::file-selector-button:hover {
order: 15;
}

a:any-link,
b {
order: 16;
}

.any > .class:any-link[attr]::before:focus {
order: 100.1;
}

.any > .class[attr]:any-link::before:focus {
order: 100.2;
}

.any > .class[attr]:any-link::before:focus {
order: 100.3;
}

.any > .class:any-link[attr]:focus::before {
order: 101.1;
}

.any > .class[attr]:any-link:focus::before {
order: 101.2;
}

.any > .class[attr]:any-link:focus::before {
order: 101.3;
}

.any > .class[attr]:focus:any-link::before {
order: 101.3;
}

.any + :any-link + .other {
order: 101.4;
}