From 80cbc6b2a166255a9fdc33d8411b4aa935f23523 Mon Sep 17 00:00:00 2001 From: Bartek Date: Thu, 10 Sep 2026 13:03:29 +0200 Subject: [PATCH] Fix SCSS test timeout, layer mapping comments and vendor cursor guard --- UPGRADE.md | 6 ++++-- core/scss/layout/_accessibility.scss | 2 ++ core/scss/layout/_core.scss | 2 ++ core/scss/layout/_footer.scss | 1 + core/scss/layout/_page.scss | 3 +++ core/scss/ui/_forms.scss | 3 +++ core/scss/ui/_images.scss | 2 ++ core/scss/vendor/_wysiwyg.scss | 6 ++++-- core/vitest.scss.config.mjs | 3 +++ docs/content/ui/getting-started/customize.mdx | 4 ++-- 10 files changed, 26 insertions(+), 6 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 3ec581d12..908d5c17b 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -56,8 +56,10 @@ If you need a rule to beat components but still lose to utilities, put it in the } ``` -`@keyframes`, `@property`, `@font-face` and the whole of `tabler-vendors.css` stay -outside the layers on purpose. +`@keyframes`, `@property`, `@font-face` and `tabler-vendors.css` stay outside the +layers on purpose, so Tabler's plugin overrides keep beating each plugin's own +stylesheet. The exception is a few seed color declarations in `tabler-vendors.css`, +layered so a `.text-*` utility can still recolor the widget. ## Upgrading to Tabler 1.5 diff --git a/core/scss/layout/_accessibility.scss b/core/scss/layout/_accessibility.scss index 6a89245a5..b2ddfd398 100644 --- a/core/scss/layout/_accessibility.scss +++ b/core/scss/layout/_accessibility.scss @@ -1,5 +1,7 @@ @use '../config' as *; +// `components`, with the rest of the page chrome. The `!important` below still +// wins over the component rules it disables, and loses to unlayered project CSS. @layer components { // Forced-colors (Windows High Contrast) support: the UA strips box-shadow there, // and Tabler's focus indicator is shadow-based, so restore an outline-drawn one. diff --git a/core/scss/layout/_core.scss b/core/scss/layout/_core.scss index 805103e98..faca22fe1 100644 --- a/core/scss/layout/_core.scss +++ b/core/scss/layout/_core.scss @@ -2,6 +2,8 @@ @use '../config' as *; +// `components`, not `layout`: the page shell restyles component-layer rules +// (`> .navbar:first-child`), and a layer decides before specificity does. @layer components { html { scrollbar-gutter: stable; diff --git a/core/scss/layout/_footer.scss b/core/scss/layout/_footer.scss index 856a8a14d..882e7615f 100644 --- a/core/scss/layout/_footer.scss +++ b/core/scss/layout/_footer.scss @@ -1,5 +1,6 @@ @use '../config' as *; +// `components`, with the rest of the page chrome. @layer components { .footer { padding: $footer-padding-y 0; diff --git a/core/scss/layout/_page.scss b/core/scss/layout/_page.scss index 0a58495ba..88bc22735 100644 --- a/core/scss/layout/_page.scss +++ b/core/scss/layout/_page.scss @@ -1,5 +1,8 @@ @use '../config' as *; +// `components`, not `layout`: the page chrome restyles component-layer rules +// (`.nav-bordered`, `.page-title` against the `h1` rule in `ui/_type.scss`), and +// a layer decides before specificity does. @layer components { // Skip-to-content link: hidden via .visually-hidden-focusable until keyboard focus reveals it .skip-link { diff --git a/core/scss/ui/_forms.scss b/core/scss/ui/_forms.scss index 9d978d4ba..e68e949bc 100644 --- a/core/scss/ui/_forms.scss +++ b/core/scss/ui/_forms.scss @@ -1,5 +1,8 @@ @use '../config' as *; +// `components`, not `forms`: Tabler's form components restyle `.input-group` and +// `.btn`, and `bootstrap/forms/_input-group.scss` is itself hoisted to +// `components`. @layer components { textarea { &[cols] { diff --git a/core/scss/ui/_images.scss b/core/scss/ui/_images.scss index cedc9beab..7fc8f2c9a 100644 --- a/core/scss/ui/_images.scss +++ b/core/scss/ui/_images.scss @@ -2,6 +2,8 @@ @use '../config' as *; +// `components`, not `content`: these are Tabler's image components, not the +// element rules `bootstrap/_images.scss` puts in `content`. @layer components { .img-responsive { --img-responsive-ratio: #{math.percentage(0.75)}; diff --git a/core/scss/vendor/_wysiwyg.scss b/core/scss/vendor/_wysiwyg.scss index a876c7d44..253c5d48a 100644 --- a/core/scss/vendor/_wysiwyg.scss +++ b/core/scss/vendor/_wysiwyg.scss @@ -36,8 +36,10 @@ // `.tox :not(svg):not(rect) { cursor: inherit }` outweighs it, and an unlayered // third-party stylesheet now beats every layer. Disabled buttons keep the // editor's `not-allowed`. -.tox button:not(:disabled):not([aria-disabled='true']) { - cursor: pointer; +@if $enable-button-pointers { + .tox button:not(:disabled):not([aria-disabled='true']) { + cursor: pointer; + } } .tox-edit-area { diff --git a/core/vitest.scss.config.mjs b/core/vitest.scss.config.mjs index 3bf81f74c..d4b646f59 100644 --- a/core/vitest.scss.config.mjs +++ b/core/vitest.scss.config.mjs @@ -6,5 +6,8 @@ import { defineConfig } from 'vitest/config' export default defineConfig({ test: { include: ['scss/tests/**/*.test.mjs'], + // A few cases compile every entry stylesheet through Sass; with the cascade + // layers in place that is slower than the 5s default on CI runners. + testTimeout: 20000, }, }) diff --git a/docs/content/ui/getting-started/customize.mdx b/docs/content/ui/getting-started/customize.mdx index 20c9e02ad..cbcbfb6b1 100644 --- a/docs/content/ui/getting-started/customize.mdx +++ b/docs/content/ui/getting-started/customize.mdx @@ -45,11 +45,11 @@ Use the empty `custom` layer when you want your rules to beat Tabler's component Inside layers, `!important` reverses the order: an important declaration in an earlier layer beats an important one in a later layer. Two rules follow from that: - An `!important` in your unlayered CSS still beats every `!important` Tabler ships. -- An `!important` you add no longer guarantees a win over an important declaration in one of Tabler's early layers, such as the reduced-motion rules. Drop the `!important` and the normal layer order applies again. +- An `!important` you add inside a layer no longer guarantees a win over an important declaration in an earlier layer. `[hidden] { display: none !important }` sits in `reboot`, so it beats `.d-block` and an `!important` of your own in a later layer. Move the rule out of the layer, or drop the `!important` and let the normal layer order apply. ### Third party CSS -A stylesheet you load from a library is unlayered too, so it beats Tabler's layers - including the utilities. `tabler-vendors.css`, which restyles the supported plugins, is deliberately left out of the layers for the same reason. If a `.text-*` or `.bg-*` utility no longer changes a plugin's widget, write the override in your own unlayered CSS instead. +A stylesheet you load from a library is unlayered too, so it beats Tabler's layers - including the utilities. `tabler-vendors.css`, which restyles the supported plugins, is left out of the layers for the same reason: it has to keep winning over the plugin's own CSS. The exception is a handful of seed color declarations there, which are layered on purpose so a `.text-*` utility can still recolor a slider or a star rating. If a utility no longer changes some other plugin's widget, write the override in your own unlayered CSS instead. ## Custom Google font