diff --git a/.changeset/focus-ring-mixin.md b/.changeset/focus-ring-mixin.md index 7dce5c2e9..86cc610ec 100644 --- a/.changeset/focus-ring-mixin.md +++ b/.changeset/focus-ring-mixin.md @@ -2,4 +2,4 @@ "@tabler/core": patch --- -Updated `focus-ring()` to be the single focus mixin and added a runtime `--focus-ring-box-shadow` token. +Updated `focus-ring()` to be the single focus-indicator mixin; the `$*-focus-box-shadow` variables stay as aliases. diff --git a/BOOTSTRAP-V6-MIGRATION.md b/BOOTSTRAP-V6-MIGRATION.md index 458d3b667..32534fe3e 100644 --- a/BOOTSTRAP-V6-MIGRATION.md +++ b/BOOTSTRAP-V6-MIGRATION.md @@ -253,15 +253,12 @@ of `color-scheme`, the token-dump verification harness) but not its code. - Decide on `$spacers`: adopting the v6 0–9 scale silently changes every `.p-3` / `.m-4` in every Tabler template. Recommendation: keep the v5 scale, add finer steps at new keys. - Replace all `$*-focus-box-shadow` with one `focus-ring()` mixin over `--focus-ring*` tokens. - Done (#2972). Step 1: `focus-ring()` is the one implementation and every focus consumer calls it; - the `$*-focus-box-shadow` variables stay as `!default` aliases; CSS byte-identical. Step 2: `:root` - emits `--focus-ring-inner-width` and `--focus-ring-box-shadow`, the mixin reads the token so the - ring retunes at runtime and per theme, and the `.focus-ring` helper stops referencing the phantom - `--focus-ring-x/-y/-blur`; the Step 2 CSS diff is limited to focus declarations and the `:root` - tokens. Tabler keeps the two-layer `box-shadow` look, not v6's `outline`, and the `forced-colors` - fallback in `layout/_accessibility.scss` stays. `.form-select` stays a single-layer exception, and - the three `outline: 2px solid` rules (`.btn-action`, `.date-item`, `.switch-icon`) are not - converted — both are follow-ups. + Step 1 done (#2972): `focus-ring()` reads `$focus-ring-box-shadow` and every focus consumer calls + it; the `$*-focus-box-shadow` variables stay as `!default` aliases; CSS byte-identical. Tabler + keeps the two-layer `box-shadow` look, not v6's `outline`, and the `forced-colors` fallback in + `layout/_accessibility.scss` stays. `.form-select` is still a single-layer exception. Step 2 + (emit `--focus-ring-box-shadow` on `:root`, fix the `.focus-ring` helper, decide the + `.form-select` ring) is a follow-up. - Consider the layered shadow scale (`.shadow-xs`…`.shadow-xl`) and `.border-keyline`. - Skip the `.fs-*` renaming — it inverts the scale direction and breaks every page. diff --git a/core/scss/_variables.scss b/core/scss/_variables.scss index 747cf18d7..9dd885397 100644 --- a/core/scss/_variables.scss +++ b/core/scss/_variables.scss @@ -1017,12 +1017,11 @@ $focus-ring-width: 0.25rem !default; $focus-ring-opacity: 0.25 !default; $focus-ring-color: color-mix(in srgb, var(--primary) #{math.percentage($focus-ring-opacity)}, transparent) !default; $focus-ring-blur: 0 !default; -$focus-ring-inner-width: 2px !default; -// The literal, emitted once as `--focus-ring-box-shadow` (`bootstrap/_root.scss`). -$focus-ring-box-shadow-value: - 0 0 0 var(--focus-ring-inner-width) var(--primary), - 0 0 $focus-ring-blur var(--focus-ring-width) var(--focus-ring-color) !default; -$focus-ring-box-shadow: var(--focus-ring-box-shadow) !default; +// Inner 2px solid ring keeps the indicator above the 3:1 non-text contrast minimum; +// the translucent halo preserves the soft look +$focus-ring-box-shadow: + 0 0 0 2px var(--primary), + 0 0 $focus-ring-blur $focus-ring-width $focus-ring-color !default; // Transitions $transition-base: all 0.2s ease-in-out !default; diff --git a/core/scss/bootstrap/_root.scss b/core/scss/bootstrap/_root.scss index 1a7a26fc8..0e9e2e16a 100644 --- a/core/scss/bootstrap/_root.scss +++ b/core/scss/bootstrap/_root.scss @@ -142,8 +142,6 @@ --focus-ring-width: #{$focus-ring-width}; --focus-ring-opacity: #{$focus-ring-opacity}; --focus-ring-color: #{$focus-ring-color}; - --focus-ring-inner-width: #{$focus-ring-inner-width}; - --focus-ring-box-shadow: #{$focus-ring-box-shadow-value}; // scss-docs-end root-focus-variables // scss-docs-start root-form-validation-variables diff --git a/core/scss/helpers/_index.scss b/core/scss/helpers/_index.scss index 85759cf30..2e27153e1 100644 --- a/core/scss/helpers/_index.scss +++ b/core/scss/helpers/_index.scss @@ -141,5 +141,6 @@ // .focus-ring:focus { outline: 0; - box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color); + // By default, there is no `--bs-focus-ring-x`, `--bs-focus-ring-y`, or `--bs-focus-ring-blur`, but we provide CSS variables with fallbacks to initial `0` values + box-shadow: var(--focus-ring-x, 0) var(--focus-ring-y, 0) var(--focus-ring-blur, 0) var(--focus-ring-width) var(--focus-ring-color); } diff --git a/core/scss/mixins/_mixins.scss b/core/scss/mixins/_mixins.scss index 63b24cce7..01a52ed33 100644 --- a/core/scss/mixins/_mixins.scss +++ b/core/scss/mixins/_mixins.scss @@ -85,7 +85,7 @@ box-shadow: $shadow; @if $show-border { - border-color: var(--focus-ring-color); + border-color: $focus-ring-color; } } diff --git a/core/scss/tests/__snapshots__/css-var-prefix.test.mjs.snap b/core/scss/tests/__snapshots__/css-var-prefix.test.mjs.snap index ce76818e0..924931fbe 100644 --- a/core/scss/tests/__snapshots__/css-var-prefix.test.mjs.snap +++ b/core/scss/tests/__snapshots__/css-var-prefix.test.mjs.snap @@ -55,8 +55,6 @@ exports[`css custom-property prefixing > leaves vendor-owned names alone and pre "--tblr-chart-3", "--tblr-chart-4", "--tblr-chart-5", - "--tblr-focus-ring-box-shadow", - "--tblr-focus-ring-color", "--tblr-font-sans-serif", "--tblr-font-size-h3", "--tblr-font-size-h5", diff --git a/core/scss/tests/_mixins.test.scss b/core/scss/tests/_mixins.test.scss index 126231f86..bdc66816b 100644 --- a/core/scss/tests/_mixins.test.scss +++ b/core/scss/tests/_mixins.test.scss @@ -104,7 +104,7 @@ } @include describe('focus-ring mixin') { - @include it('outputs the ring token without a border by default') { + @include it('outputs the ring without a border by default') { @include assert() { @include output() { .t { @@ -114,7 +114,9 @@ @include expect() { .t { outline: 0; - box-shadow: var(--focus-ring-box-shadow); + box-shadow: + 0 0 0 2px var(--primary), + 0 0 0 0.25rem color-mix(in srgb, var(--primary) 25%, transparent); } } } @@ -130,8 +132,10 @@ @include expect() { .t { outline: 0; - box-shadow: var(--focus-ring-box-shadow); - border-color: var(--focus-ring-color); + box-shadow: + 0 0 0 2px var(--primary), + 0 0 0 0.25rem color-mix(in srgb, var(--primary) 25%, transparent); + border-color: color-mix(in srgb, var(--primary) 25%, transparent); } } }