fix(jobs): v3 wizard — chrome on wrapper, not <input> (v19.0.8.16.2)
Root cause user kept seeing inputs as bare/borderless text:
Odoo's <list editable="bottom"> renders each cell as a read-mode
<span> inside .o_field_widget UNTIL the user clicks the cell.
Only then does an <input> swap in. My CSS was targeting
`td.o_fp_iw_value input { ... }` so the chrome only appeared on
focus. Every other (unclicked) cell looked like dead text.
Fix:
Move all input chrome (border, bg, padding, min-height) to the
.o_field_widget wrapper which is ALWAYS in the DOM. Then make
the inner <input> / <span> transparent so they inherit. Effect:
the cell looks like an input box from first paint, regardless
of focus state. Focus ring travels up via :focus-within.
Special widgets (boolean toggle, photo upload, multi-point,
bath panel) opt OUT of the wrapper chrome via :has() so they
keep their own visual treatment.
Same fix applied to .o_fp_iw_extra cells (composite types).
User reproduction: WH/JOB/00339 → Record on Masking step. After
hard-refresh + this build, every value cell should read as an
obvious input box even before the operator clicks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
{
|
{
|
||||||
'name': 'Fusion Plating — Native Jobs',
|
'name': 'Fusion Plating — Native Jobs',
|
||||||
'version': '19.0.8.16.1',
|
'version': '19.0.8.16.2',
|
||||||
'category': 'Manufacturing/Plating',
|
'category': 'Manufacturing/Plating',
|
||||||
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
|
'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.',
|
||||||
'author': 'Nexa Systems Inc.',
|
'author': 'Nexa Systems Inc.',
|
||||||
|
|||||||
@@ -269,51 +269,82 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---------- Value — the live widget for this row's type --------
|
// ---------- Value — the live widget for this row's type --------
|
||||||
|
//
|
||||||
|
// KEY INSIGHT: Odoo's editable list shows each cell as a
|
||||||
|
// read-mode span/text until the user clicks it (then a real
|
||||||
|
// <input> swaps in). Targeting `input { ... }` only styles
|
||||||
|
// the focused state, leaving every other cell looking like
|
||||||
|
// bare un-clickable text. So we put the input chrome on
|
||||||
|
// the .o_field_widget wrapper (always in DOM, both modes)
|
||||||
|
// and make the inner <input> transparent so it inherits.
|
||||||
|
// ---------------------------------------------------------------
|
||||||
td.o_fp_iw_value {
|
td.o_fp_iw_value {
|
||||||
grid-area: value;
|
grid-area: value;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
// Make the value widget container fill the available
|
// The wrapper IS the visible "input box" — both in
|
||||||
// grid area, no centering, no shrinking.
|
// display mode (showing a span) and in edit mode
|
||||||
.o_field_widget {
|
// (showing an actual input).
|
||||||
display: block;
|
> .o_field_widget,
|
||||||
|
> div.o_field_widget {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 420px;
|
max-width: 420px;
|
||||||
|
min-height: 48px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
background-color: $fp-iw-page;
|
||||||
|
color: $fp-iw-ink;
|
||||||
|
border: 1px solid $fp-iw-ink-faint;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 1.125rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: text;
|
||||||
|
transition: border-color 120ms ease,
|
||||||
|
background-color 120ms ease,
|
||||||
|
box-shadow 120ms ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: $fp-iw-ink-mute;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inputs — number/text/date/etc. all share the same
|
// Focus ring travels up from the inner input to the
|
||||||
// chrome. Brighter border + slight surface tint so
|
// wrapper via :focus-within so the visible chrome
|
||||||
// empty inputs are obviously interactive in dark mode.
|
// glows when the user clicks in.
|
||||||
|
> .o_field_widget:focus-within,
|
||||||
|
> div.o_field_widget:focus-within {
|
||||||
|
border-color: $fp-iw-border-focus !important;
|
||||||
|
background-color: $fp-iw-card !important;
|
||||||
|
box-shadow: 0 0 0 3px
|
||||||
|
color-mix(in srgb,
|
||||||
|
#{$fp-iw-border-focus} 25%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inner inputs / spans inherit from wrapper — fully
|
||||||
|
// transparent so they don't double-up on chrome.
|
||||||
|
input,
|
||||||
input[type="text"],
|
input[type="text"],
|
||||||
input[type="number"],
|
input[type="number"],
|
||||||
input[type="datetime-local"],
|
input[type="datetime-local"],
|
||||||
input.o_input,
|
input.o_input,
|
||||||
input:not([type]) {
|
.o_field_widget > span,
|
||||||
|
.o_field_widget > div {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
|
background: transparent !important;
|
||||||
|
color: inherit !important;
|
||||||
|
border: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
font-size: 1.125rem;
|
font-size: inherit !important;
|
||||||
font-weight: 500;
|
font-weight: inherit !important;
|
||||||
padding: 10px 14px !important;
|
line-height: 1.4 !important;
|
||||||
min-height: 48px;
|
min-height: 0 !important;
|
||||||
background-color: $fp-iw-page !important;
|
height: auto !important;
|
||||||
color: $fp-iw-ink !important;
|
|
||||||
border: 1px solid $fp-iw-ink-faint !important;
|
|
||||||
border-radius: 8px !important;
|
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
transition: border-color 120ms ease,
|
outline: none !important;
|
||||||
box-shadow 120ms ease,
|
|
||||||
background-color 120ms ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: $fp-iw-ink-mute !important;
|
|
||||||
}
|
|
||||||
&:focus {
|
|
||||||
border-color: $fp-iw-border-focus !important;
|
|
||||||
background-color: $fp-iw-card !important;
|
|
||||||
box-shadow: 0 0 0 3px
|
|
||||||
color-mix(in srgb,
|
|
||||||
#{$fp-iw-border-focus} 25%, transparent) !important;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: $fp-iw-ink-faint;
|
color: $fp-iw-ink-faint;
|
||||||
@@ -321,6 +352,28 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- Special widgets — opt out of the input chrome ----
|
||||||
|
//
|
||||||
|
// Boolean toggle, photo upload, multi-point and panel
|
||||||
|
// widgets each have their own visual treatment. They
|
||||||
|
// shouldn't sit inside an "input box" — they should
|
||||||
|
// render bare with their own chrome.
|
||||||
|
> .o_field_widget:has(.o_boolean_toggle),
|
||||||
|
> .o_field_widget:has(.form-switch),
|
||||||
|
> .o_field_widget.o_field_image,
|
||||||
|
> .o_field_widget:has(.o_form_image_controls) {
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
min-height: 0 !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
background: transparent !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Boolean toggle — bigger pill for fat fingers
|
// Boolean toggle — bigger pill for fat fingers
|
||||||
.o_boolean_toggle,
|
.o_boolean_toggle,
|
||||||
.form-switch {
|
.form-switch {
|
||||||
@@ -330,8 +383,7 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Image / photo widget — constrain the WHOLE field
|
// Image / photo widget — constrain the WHOLE field
|
||||||
// (upload area + preview) so it doesn't blow up to
|
// (upload area + preview) so it doesn't blow up.
|
||||||
// fill the whole card width.
|
|
||||||
.o_field_image {
|
.o_field_image {
|
||||||
max-width: 240px;
|
max-width: 240px;
|
||||||
|
|
||||||
@@ -348,6 +400,8 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---------- Extras — composite types (multi-point, panel) ----
|
// ---------- Extras — composite types (multi-point, panel) ----
|
||||||
|
// Same display/edit-mode trick as the value cell: chrome
|
||||||
|
// on the wrapper, transparent input inside.
|
||||||
td.o_fp_iw_extra {
|
td.o_fp_iw_extra {
|
||||||
grid-area: extras;
|
grid-area: extras;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -355,7 +409,6 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
|
|
||||||
// Compact label-before-input grouping
|
|
||||||
&::before {
|
&::before {
|
||||||
content: attr(data-label);
|
content: attr(data-label);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -364,18 +417,35 @@ $fp-iw-pill-bg : var(--fp-pill-bg, #{$_fp-iw-pill-bg-hex});
|
|||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input,
|
> .o_field_widget,
|
||||||
input.o_input {
|
> div.o_field_widget {
|
||||||
width: 80px !important;
|
display: inline-flex;
|
||||||
text-align: left !important;
|
align-items: center;
|
||||||
font-size: 1rem;
|
width: 80px;
|
||||||
padding: 6px 10px !important;
|
|
||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
background-color: $fp-iw-page !important;
|
padding: 6px 10px;
|
||||||
color: $fp-iw-ink !important;
|
background-color: $fp-iw-page;
|
||||||
border: 1px solid $fp-iw-ink-faint !important;
|
color: $fp-iw-ink;
|
||||||
border-radius: 6px !important;
|
border: 1px solid $fp-iw-ink-faint;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: text;
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
border-color: $fp-iw-border-focus;
|
||||||
|
background-color: $fp-iw-card;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100% !important;
|
||||||
|
background: transparent !important;
|
||||||
|
color: inherit !important;
|
||||||
|
border: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
text-align: left !important;
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
|
outline: none !important;
|
||||||
|
min-height: 0 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user