Show which filter segment or chip is selected and focused without :has()
CI / full-gate (push) Failing after 1m3s
CI / full-gate (push) Failing after 1m3s
This commit is contained in:
@@ -6,6 +6,12 @@ at boot. Entries start at 0.3.0.
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### A filter shows its selected and focused choice in browsers without `:has()`
|
||||||
|
|
||||||
|
On Firefox 115, Chromium below 105 and Safari below 15.4, a filter's segments and chips now show
|
||||||
|
their native radio or checkbox, which marks the selected choice and takes the keyboard focus ring.
|
||||||
|
Before, they showed neither. Newer browsers look as before.
|
||||||
|
|
||||||
### The tests fail on a stylesheet feature the browser floor lacks
|
### The tests fail on a stylesheet feature the browser floor lacks
|
||||||
|
|
||||||
`npm test` checks every stylesheet in `public/`, `examples/` and `plugins/` against Chromium 87,
|
`npm test` checks every stylesheet in `public/`, `examples/` and `plugins/` against Chromium 87,
|
||||||
|
|||||||
@@ -226,3 +226,20 @@ Read most (opens and searches):
|
|||||||
- `release-tooling/dockerhub-overview.test.ts` 1
|
- `release-tooling/dockerhub-overview.test.ts` 1
|
||||||
- `release-tooling/dockerhub-overview.ts` 1
|
- `release-tooling/dockerhub-overview.ts` 1
|
||||||
- `src/ci-gate.test.ts` 1
|
- `src/ci-gate.test.ts` 1
|
||||||
|
|
||||||
|
## Reading cost, chunk 984f4d4c8a76, finished 2026-10-31T11:18:20Z
|
||||||
|
|
||||||
|
209334 new input tokens before the first commit.
|
||||||
|
|
||||||
|
Read most (opens and searches):
|
||||||
|
|
||||||
|
- `README.md` 6
|
||||||
|
- `todo.md` 6
|
||||||
|
- `src/ui/stylesheet-floor.test.ts` 4
|
||||||
|
- `src/ui/stylesheet-floor.ts` 4
|
||||||
|
- `CHANGELOG.md` 3
|
||||||
|
- `AGENTS.md` 2
|
||||||
|
- `examples/plugins/scheduling/public/scheduling.css` 2
|
||||||
|
- `package.json` 2
|
||||||
|
- `public/css/styles.css` 2
|
||||||
|
- `ci.sh` 1
|
||||||
|
|||||||
@@ -294,13 +294,6 @@ span.nav-self { cursor: default; } /* static / non-clickable */
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Without :has() every branch is open and every theme rule is inert: neither control does anything.
|
|
||||||
After the base rules, since @supports adds no specificity. */
|
|
||||||
@supports not selector(:has(a)) {
|
|
||||||
.nav-disc { visibility: hidden; } /* keeps its width, so the labels stay aligned */
|
|
||||||
.theme-switch { display: none; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-actions { display: flex; align-items: center; gap: 4px; }
|
.footer-actions { display: flex; align-items: center; gap: 4px; }
|
||||||
.profile {
|
.profile {
|
||||||
display: flex; align-items: center; gap: 9px; flex: 1 1 auto;
|
display: flex; align-items: center; gap: 9px; flex: 1 1 auto;
|
||||||
@@ -485,6 +478,15 @@ span.nav-self { cursor: default; } /* static / non-clickable */
|
|||||||
.chip:has(input:focus-visible) { outline: 2px solid var(--focus); outline-offset: 1px; }
|
.chip:has(input:focus-visible) { outline: 2px solid var(--focus); outline-offset: 1px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Without :has() every branch is open and every theme rule is inert: neither control does anything.
|
||||||
|
The filter inputs stay visible, since the native control is then the only sign of a choice or of
|
||||||
|
focus. After the base rules, since @supports adds no specificity. */
|
||||||
|
@supports not selector(:has(a)) {
|
||||||
|
.nav-disc { visibility: hidden; } /* keeps its width, so the labels stay aligned */
|
||||||
|
.theme-switch { display: none; }
|
||||||
|
.segmented input, .chip input { position: static; opacity: 1; margin: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
/* date range */
|
/* date range */
|
||||||
.daterange {
|
.daterange {
|
||||||
display: inline-flex; align-items: center; gap: 6px;
|
display: inline-flex; align-items: center; gap: 6px;
|
||||||
|
|||||||
@@ -153,6 +153,18 @@ test("styles.css hides the theme switch and the nav toggles where :has() is miss
|
|||||||
assert.match(block, /\.nav-disc\s*\{\s*visibility:\s*hidden/);
|
assert.match(block, /\.nav-disc\s*\{\s*visibility:\s*hidden/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Both inputs are invisible in the base rules and only a `:has()` rule marks the choice, so without
|
||||||
|
// `:has()` the native control is the only sign of what is selected or focused.
|
||||||
|
test("styles.css shows the segmented and chip inputs where :has() is missing, after their base rules", () => {
|
||||||
|
const guard = stylesheet.indexOf("@supports not selector(:has(a)) {");
|
||||||
|
assert.ok(guard >= 0, "no @supports not selector(:has(a)) block");
|
||||||
|
const block = stylesheet.slice(guard, blockEnd(guard));
|
||||||
|
for (const input of [".segmented input", ".chip input"]) {
|
||||||
|
assert.ok(stylesheet.indexOf(`${input} {`) < guard, `the base ${input} rule comes after the guard`);
|
||||||
|
}
|
||||||
|
assert.match(block, /\.segmented input,\s*\.chip input\s*\{[^}]*position:\s*static[^}]*opacity:\s*1/);
|
||||||
|
});
|
||||||
|
|
||||||
// Without `:has()` nothing reads #nav-toggle, so an off-canvas sidebar there is unreachable and the
|
// Without `:has()` nothing reads #nav-toggle, so an off-canvas sidebar there is unreachable and the
|
||||||
// hamburger does nothing: the sidebar has to stay in the flow, with the hamburger hidden.
|
// hamburger does nothing: the sidebar has to stay in the flow, with the hamburger hidden.
|
||||||
test("styles.css moves the sidebar off-canvas at 860px only inside @supports selector(:has(a))", () => {
|
test("styles.css moves the sidebar off-canvas at 860px only inside @supports selector(:has(a))", () => {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
| ID | Release | Blocked by | Exempt | Item | L | E | I | R | S | Moves | Score |
|
| ID | Release | Blocked by | Exempt | Item | L | E | I | R | S | Moves | Score |
|
||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
| 44 | 0.4.21 | | defect | **Show which filter segment or chip is selected and focused on a browser without `:has()`.** | 1 | 2 | 2 | 3 | 2 | 4 by 4 | 23.9 |
|
|
||||||
| 13 | 0.4.21 | | | **Accept a verification code pasted with surrounding whitespace.** | 4 | 2 | 3 | 7 | 7 | 2 by 8 | 1.0 |
|
| 13 | 0.4.21 | | | **Accept a verification code pasted with surrounding whitespace.** | 4 | 2 | 3 | 7 | 7 | 2 by 8 | 1.0 |
|
||||||
| 19 | 0.5.0 | | question | **Run the documented Docker commands on macOS and fix whatever misbehaves.** | 2 | 2 | 1 | 3 | 3 | 1 by 3 | 3.3 |
|
| 19 | 0.5.0 | | question | **Run the documented Docker commands on macOS and fix whatever misbehaves.** | 2 | 2 | 1 | 3 | 3 | 1 by 3 | 3.3 |
|
||||||
| 16 | 0.5.0 | | question | **Decide whether the single Keto `Resource` namespace splits into per-domain namespaces.** | 3 | 2 | 3 | 6 | 6 | 7 by 2 | 0.5 |
|
| 16 | 0.5.0 | | question | **Decide whether the single Keto `Resource` namespace splits into per-domain namespaces.** | 3 | 2 | 3 | 6 | 6 | 7 by 2 | 0.5 |
|
||||||
@@ -27,14 +26,6 @@
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
### 44. Show which filter segment or chip is selected and focused on a browser without `:has()`.
|
|
||||||
|
|
||||||
`.segmented input` and `.chip input` are `opacity: 0`, and only `:has(input:checked)` and
|
|
||||||
`:has(input:focus-visible)` rules mark the choice. On Firefox 115, Chromium 87–104 and Safari
|
|
||||||
15.0–15.3 a filter shows no selected state and no keyboard focus, which README → "Two browser
|
|
||||||
floors" forbids. Show the native inputs in `public/css/styles.css`'s `@supports not selector(:has(a))`
|
|
||||||
block.
|
|
||||||
|
|
||||||
### 13. Accept a verification code pasted with surrounding whitespace.
|
### 13. Accept a verification code pasted with surrounding whitespace.
|
||||||
|
|
||||||
A pasted code fails the browser's `pattern` check. No zero-JS fix exists: `pattern`
|
A pasted code fails the browser's `pattern` check. No zero-JS fix exists: `pattern`
|
||||||
|
|||||||
Reference in New Issue
Block a user