ReviewOS

stacks/stx

toast resolves dark mode from the OS media query only, ignoring the app theme — the #1875 bug, unfixed for the third surface

#1912
Closed glennmichael123 opened this 11 days ago ·
11 days ago

#1875 fixed theme resolution for stxConfirm/stxAlert. toast has the same bug and was not covered.

addToast, signals.ts:5721:

var isDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
var bg = isDark ? '#1f2937' : '#ffffff';

_createDialog, signals.ts:5839 — what #1875 changed it to:

// Resolve dark from what the APP decided, not only from the OS. stx's own
// color-mode boot writes a class (default 'dark') and/or an attribute
// (e.g. data-theme) onto <html>, so an app pinned to light on a dark OS used
// to get a dark dialog over a light page. An explicit opts.dark wins over
// both, and the media query stays as the last resort. See #1875.
var _root = document.documentElement;
var _attrTheme = _root.getAttribute('data-theme') || _root.getAttribute('data-color-mode');
var isDark = opts.dark != null
  ? !!opts.dark
  : _root.classList.contains('dark')
    ? true
    : _attrTheme === 'dark'
      ? true
      : _attrTheme === 'light'
        ? false
        : !!(window.matchMedia && ...);

The failure is the one #1875 describes, verbatim: an app pinned to light on a dark OS gets a dark toast over a light page. Apps that offer a light | dark | system setting — the common case, and what stx's own color-mode boot writes — are affected on every toast.

Toast also has no opts.dark escape hatch, so there is no way to correct it from the call site.

Fix

Same resolution as _createDialog. Worth lifting the ~10 lines into one helper both call, so the next surface that needs a theme cannot drift again — toast drifted precisely because the fix was applied at the two dialog call sites rather than in something shared.

10 days ago

Fixed in f4c8a51dbc.

Done the way you suggested — one _resolveDark helper that both toast and the dialogs call, rather than a third copy of the ten lines. That was the right call and worth stating plainly: toast drifted because #1875 was applied at the two dialog call sites instead of somewhere shared, so pasting the resolution a third time would have set the fourth surface up to drift identically.

Toast also gains the opts.dark escape hatch it had no equivalent of:

toast.info('hello', { dark: true })

5 tests, executing the real runtime rather than inspecting the string: dark class, data-theme="light" (your reported failure — pinned light, dark OS), data-color-mode, the call-site override, and the media-query fallback. Reverting the resolution fails 3 of them.

No OS-only resolution remains in the runtime.

Sign in to comment on this issue.