Repository: sveltejs/svelte (JavaScript) — Bug Fix

Issue:
`details bind:open` should count as `[open]` for styling
```svelte
<script>
	let open = false;
</script>

<details bind:open>Hello</details>

<style>
	details[open] {
		color: red;
	}
</style>
```

`details[open]` is getting removed because the compiler doesn't think that `<details bind:open>` indicates an `open` attribute that might be present.


Discussion:
I had assumed there was some precedent for handling this with other bindings, but thinking about it more, I'm not sure what bindings those would be. We might just need a weird one-off check for this when determining whether an element can match a selector.
```diff
diff --git a/src/compiler/compile/css/Selector.ts b/src/compiler/compile/css/Selector.ts
index ef54f789..e70b2986 100644
--- a/src/compiler/compile/css/Selector.ts
+++ b/src/compiler/compile/css/Selector.ts
@@ -219,6 +219,8 @@ function attribute_matches(node: Node, name: string, expected_value: string, ope
 	const spread = node.attributes.find(attr => attr.type === 'Spread');
 	if (spread) return true;
 
+	if (name === 'open' && node.bindings.some((binding: Node) => binding.name === 'open')) return true;
+
 	const attr = node.attributes.find((attr: Node) => attr.name === name);
 	if (!attr) return false;
 	if (attr.is_true) return operator === null;
```

This seems to do it. I don't know whether there is a more elegant way. It _might_ make sense to always also search `node.bindings`, and if we find a binding, assume that it's always possible for this selector to match this element. I.e.:

```diff
diff --git a/src/compiler/compile/css/Selector.ts b/src/compiler/compile/css/Selector.ts
index ef54f789..0d4ea82b 100644
--- a/src/compiler/compile/css/Selector.ts
+++ b/src/compiler/compile/css/Selector.ts
@@ -219,6 +219,8 @@ function attribute_matches(node: Node, name: string, expected_value: string, ope
 	const spread = node.attributes.find(attr => attr.type === 'Spread');
 	if (spread) return true;
 
+	if (node.bindings.some((binding: Node) => binding.name === name)) return true;
+
 	const attr = node.attributes.find((attr: Node) => attr.name === name);
 	if (!attr) return false;
 	if (attr.is_true) return operator === null;
```

Resolving patch:
diff --git a/src/compiler/compile/css/Selector.ts b/src/compiler/compile/css/Selector.ts
--- a/src/compiler/compile/css/Selector.ts
+++ b/src/compiler/compile/css/Selector.ts
@@ -219,6 +219,8 @@ function attribute_matches(node: Node, name: string, expected_value: string, ope
 	const spread = node.attributes.find(attr => attr.type === 'Spread');
 	if (spread) return true;
 
+	if (node.bindings.some((binding: Node) => binding.name === name)) return true;
+
 	const attr = node.attributes.find((attr: Node) => attr.name === name);
 	if (!attr) return false;
 	if (attr.is_true) return operator === null;


Test patch:
diff --git a/test/css/samples/attribute-selector-bind/expected.css b/test/css/samples/attribute-selector-bind/expected.css
new file mode 100644
--- /dev/null
+++ b/test/css/samples/attribute-selector-bind/expected.css
@@ -0,0 +1 @@
+details[open].svelte-xyz{color:red}
\ No newline at end of file
diff --git a/test/css/samples/attribute-selector-bind/input.svelte b/test/css/samples/attribute-selector-bind/input.svelte
new file mode 100644
--- /dev/null
+++ b/test/css/samples/attribute-selector-bind/input.svelte
@@ -0,0 +1,11 @@
+<script>
+	let open = false;
+</script>
+
+<details bind:open>Hello</details>
+
+<style>
+	details[open] {
+		color: red;
+	}
+</style>