Make disabled SearchSelect read as one element
The disabled widget showed two clashing surfaces in dark mode: the wrapper
(faded via has-[:disabled]) plus the inner search input, which picked up the
global disabled-input fill from common/input.css
(`form input:disabled { background: neutral-secondary-strong }`). That rule is
unlayered, so it beat any utility override on the input.
Exclude the SearchSelect's inner search box from that global rule
(`:not([data-search-select-search])`) so it stays transparent — the wrapper is
then the single faded surface. Standalone inputs (e.g. the Name field) keep
their distinct disabled surface, unchanged.
e2e: assert the disabled inner input computes transparent background (one
element), alongside the existing wrapper-opacity check.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -13,8 +13,11 @@ This module imports only from ``common.components`` — it has no Django-forms o
|
|||||||
``<div>``, which has no ``disabled`` state of its own. To disable it, set
|
``<div>``, which has no ``disabled`` state of its own. To disable it, set
|
||||||
``disabled`` on the inner search ``<input>`` (``[data-search-select-search]``);
|
``disabled`` on the inner search ``<input>`` (``[data-search-select-search]``);
|
||||||
the wrapper then greys itself via the ``has-[:disabled]:`` utilities in
|
the wrapper then greys itself via the ``has-[:disabled]:`` utilities in
|
||||||
``_CONTAINER_CLASS``. Callers toggle only the control's ``disabled`` — never
|
``_CONTAINER_CLASS``. The inner input is excluded from the global
|
||||||
styles. (See ``ts/add_purchase.ts`` gating ``related_game`` on the type field.)
|
disabled-input surface (``common/input.css``) so it stays transparent — the
|
||||||
|
widget reads as one faded element, not a nested box. Callers toggle only the
|
||||||
|
control's ``disabled`` — never styles. (See ``ts/add_purchase.ts`` gating
|
||||||
|
``related_game`` on the type field.)
|
||||||
|
|
||||||
Option sourcing follows two axes. *Population*: options are either rendered
|
Option sourcing follows two axes. *Population*: options are either rendered
|
||||||
inline up front (``options=``, no ``search_url``) or fetched from ``search_url``.
|
inline up front (``options=``, no ``search_url``) or fetched from ``search_url``.
|
||||||
|
|||||||
+5
-2
@@ -127,11 +127,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
form input:disabled,
|
/* Standalone form controls get a distinct disabled surface. The SearchSelect's
|
||||||
|
inner search box is excluded: it's a composite widget that owns its disabled
|
||||||
|
look on the wrapper (has-[:disabled] in _CONTAINER_CLASS), so painting the
|
||||||
|
inner input here would render a nested box inside the wrapper. */
|
||||||
|
form input:disabled:not([data-search-select-search]),
|
||||||
select:disabled,
|
select:disabled,
|
||||||
textarea:disabled {
|
textarea:disabled {
|
||||||
@apply cursor-not-allowed bg-neutral-secondary-strong text-fg-disabled;
|
@apply cursor-not-allowed bg-neutral-secondary-strong text-fg-disabled;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.errorlist {
|
.errorlist {
|
||||||
|
|||||||
@@ -174,6 +174,10 @@ def test_add_purchase_type_game_disables_related_game_search(
|
|||||||
expect(search).to_be_disabled()
|
expect(search).to_be_disabled()
|
||||||
# The component greys itself via has-[:disabled] when the input is disabled.
|
# The component greys itself via has-[:disabled] when the input is disabled.
|
||||||
assert wrapper.evaluate("el => getComputedStyle(el).opacity") == "0.5"
|
assert wrapper.evaluate("el => getComputedStyle(el).opacity") == "0.5"
|
||||||
|
# The disabled inner input stays transparent (excluded from the global
|
||||||
|
# disabled-input surface) so the widget reads as one element, not a nested
|
||||||
|
# box. transparent is mode-independent, so this holds in light and dark.
|
||||||
|
assert search.evaluate("el => getComputedStyle(el).backgroundColor") == "rgba(0, 0, 0, 0)"
|
||||||
|
|
||||||
page.select_option("#id_type", "dlc")
|
page.select_option("#id_type", "dlc")
|
||||||
expect(search).to_be_enabled()
|
expect(search).to_be_enabled()
|
||||||
|
|||||||
@@ -4400,7 +4400,7 @@
|
|||||||
border-left-color: var(--color-slate-500);
|
border-left-color: var(--color-slate-500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
form input:disabled, select:disabled, textarea:disabled {
|
form input:disabled:not([data-search-select-search]), select:disabled, textarea:disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
background-color: var(--color-neutral-secondary-strong);
|
background-color: var(--color-neutral-secondary-strong);
|
||||||
color: var(--color-fg-disabled);
|
color: var(--color-fg-disabled);
|
||||||
|
|||||||
Reference in New Issue
Block a user