state-pseudo-class.html (4699B)
1 <!DOCTYPE html> 2 <link rel=help href="https://html.spec.whatwg.org/multipage/custom-elements.html#custom-state-pseudo-class"> 3 <script src="/resources/testharness.js"></script> 4 <script src="/resources/testharnessreport.js"></script> 5 <style> 6 #state-and-part::part(inner) { 7 opacity: 0; 8 } 9 #state-and-part::part(inner):state(innerFoo) { 10 opacity: 0.5; 11 } 12 #state-and-part:state(outerFoo)::part(inner) { 13 opacity: 0.25; 14 } 15 :state( \(escaped\ state ) {} 16 </style> 17 <body> 18 <script> 19 class TestElement extends HTMLElement { 20 constructor() { 21 super(); 22 this._internals = this.attachInternals(); 23 } 24 25 get i() { 26 return this._internals; 27 } 28 } 29 customElements.define('test-element', TestElement); 30 31 class ContainerElement extends HTMLElement { 32 constructor() { 33 super(); 34 this._internals = this.attachInternals(); 35 this._shadow = this.attachShadow({mode:'open'}); 36 this._shadow.innerHTML = ` 37 <style> 38 :host { 39 border-style: solid; 40 } 41 :host(:state(dotted)) { 42 border-style: dotted; 43 } 44 </style> 45 <test-element part="inner"></test-element>`; 46 } 47 48 get i() { 49 return this._internals; 50 } 51 get innerElement() { 52 return this._shadow.querySelector('test-element'); 53 } 54 } 55 customElements.define('container-element', ContainerElement); 56 57 test(() => { 58 document.querySelector(':state(foo)'); 59 document.querySelector(':state(--foo)'); 60 document.querySelector(':state(--)'); 61 document.querySelector(':state(--16px)'); 62 }, ':state() parsing passes'); 63 64 test(() => { 65 assert_throws_dom('SyntaxError', () => { document.querySelector(':state'); }); 66 assert_throws_dom('SyntaxError', () => { document.querySelector(':state('); }); 67 assert_throws_dom('SyntaxError', () => { document.querySelector(':state()'); }); 68 assert_throws_dom('SyntaxError', () => { document.querySelector(':state(=)'); }); 69 assert_throws_dom('SyntaxError', () => { document.querySelector(':state(name=value)'); }); 70 assert_throws_dom('SyntaxError', () => { document.querySelector(':state( foo bar)'); }); 71 assert_throws_dom('SyntaxError', () => { document.querySelector(':state(16px)'); }); 72 }, ':state() parsing failures'); 73 74 test(() => { 75 assert_throws_dom('SyntaxError', () => { document.querySelector(':--('); }); 76 assert_throws_dom('SyntaxError', () => { document.querySelector(':--()'); }); 77 assert_throws_dom('SyntaxError', () => { document.querySelector(':--)'); }); 78 assert_throws_dom('SyntaxError', () => { document.querySelector(':--='); }); 79 assert_throws_dom('SyntaxError', () => { document.querySelector(':--name=value'); }); 80 }, 'deprecated :--state parsing failures'); 81 82 test(() => { 83 assert_equals(document.styleSheets[0].cssRules[1].cssText, 84 '#state-and-part::part(inner):state(innerFoo) { opacity: 0.5; }'); 85 assert_equals(document.styleSheets[0].cssRules[3].selectorText, 86 ':state(\\(escaped\\ state)'); 87 }, ':state(foo) serialization'); 88 89 test(() => { 90 let element = new TestElement(); 91 let states = element.i.states; 92 93 assert_false(element.matches(':state(foo)')); 94 assert_true(element.matches(':not(:state(foo))')); 95 states.add('foo'); 96 assert_true(element.matches(':state(foo)')); 97 assert_true(element.matches(':is(:state(foo))')); 98 element.classList.add('c1', 'c2'); 99 assert_true(element.matches('.c1:state(foo)')); 100 assert_true(element.matches(':state(foo).c1')); 101 assert_true(element.matches('.c2:state(foo).c1')); 102 }, ':state(foo) in simple cases'); 103 104 test(() => { 105 let element = new TestElement(); 106 element.tabIndex = 0; 107 document.body.appendChild(element); 108 element.focus(); 109 let states = element.i.states; 110 111 states.add('foo'); 112 assert_true(element.matches(':focus:state(foo)')); 113 assert_true(element.matches(':state(foo):focus')); 114 }, ':state(foo) and other pseudo classes'); 115 116 test(() => { 117 let outer = new ContainerElement(); 118 outer.id = 'state-and-part'; 119 document.body.appendChild(outer); 120 let inner = outer.innerElement; 121 let innerStates = inner.i.states; 122 123 innerStates.add('innerFoo'); 124 assert_equals(getComputedStyle(inner).opacity, '0.5', 125 '::part() followed by :state()'); 126 innerStates.delete('innerFoo'); 127 innerStates.add('innerfoo'); 128 assert_equals(getComputedStyle(inner).opacity, '0', 129 ':state() matching should be case-sensitive'); 130 innerStates.delete('innerfoo'); 131 132 outer.i.states.add('outerFoo'); 133 assert_equals(getComputedStyle(inner).opacity, '0.25', 134 ':state(foo) followed by ::part()'); 135 }, ':state(foo) and ::part()'); 136 137 test(() => { 138 let outer = new ContainerElement(); 139 document.body.appendChild(outer); 140 141 assert_equals(getComputedStyle(outer).borderStyle, 'solid'); 142 outer.i.states.add('dotted'); 143 assert_equals(getComputedStyle(outer).borderStyle, 'dotted'); 144 }, ':state(foo) and :host()'); 145 </script> 146 </body>