From 92c62754e1cb3e04fc5d873643c4f8b2bccd3bee Mon Sep 17 00:00:00 2001 From: Prathamesh Kurunkar <59260326+prathameshkurunkar7@users.noreply.github.com> Date: Sun, 8 Feb 2026 11:04:15 +0530 Subject: [PATCH] fix(ux): add currency symbol handling in editable grid rows (#36818) --- frappe/public/js/frappe/form/grid_row.js | 52 ++++++++++++++++++++++++ frappe/public/scss/common/grid.scss | 44 ++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js index a5735ad359..a36a41d918 100644 --- a/frappe/public/js/frappe/form/grid_row.js +++ b/frappe/public/js/frappe/form/grid_row.js @@ -1239,6 +1239,12 @@ export default class GridRow { } else if (this.columns_list && this.columns_list.slice(0)[0] === column) { field.$input.attr("data-first-input", 1); } + if (df.fieldtype === "Currency") { + this.update_currency_symbol_in_grid_input(field, df); + field.$input.off("input.grid-currency").on("input.grid-currency", () => { + this.update_currency_symbol_in_grid_input(field, df); + }); + } } this.set_arrow_keys(field); @@ -1565,6 +1571,9 @@ export default class GridRow { // - after row removals via customize_form.js on links, actions and states child-tables if (this.doc) field.docname = this.doc.name; field.refresh(); + if (df && df.fieldtype === "Currency") { + this.update_currency_symbol_in_grid_input(field, df); + } } // in form @@ -1572,6 +1581,49 @@ export default class GridRow { this.grid_form.refresh_field(fieldname); } } + + update_currency_symbol_in_grid_input(field, df) { + if (!field?.$input || !this.grid?.is_editable?.()) return; + + const currency = frappe.meta.get_field_currency(df, this.doc); + const symbol = window.get_currency_symbol(currency); + const show_on_right = + cint(frappe.model.get_value(":Currency", currency, "symbol_on_right")) === 1; + + let $wrapper = field.$input.parent(); + if (!$wrapper.hasClass("grid-currency-input")) { + field.$input.wrap('
'); + } + + $wrapper.toggleClass("grid-currency-symbol-right", show_on_right); + + let $prefix = $wrapper.find(".grid-currency-prefix"); + let $suffix = $wrapper.find(".grid-currency-suffix"); + + if (!symbol) { + $prefix.remove(); + $suffix.remove(); + $wrapper.removeClass("grid-currency-has-value"); + return; + } + + if (show_on_right) { + if (!$suffix.length) { + $suffix = $('').appendTo($wrapper); + } + $suffix.text(symbol); + $prefix.remove(); + } else { + if (!$prefix.length) { + $prefix = $('').prependTo($wrapper); + } + $prefix.text(symbol); + $suffix.remove(); + } + + const has_value = /\d/.test(field.$input.val() || ""); + $wrapper.toggleClass("grid-currency-has-value", has_value); + } get_field(fieldname) { let field = this.on_grid_fields_dict[fieldname]; if (field) { diff --git a/frappe/public/scss/common/grid.scss b/frappe/public/scss/common/grid.scss index 45cb682ede..08eb3edcfd 100644 --- a/frappe/public/scss/common/grid.scss +++ b/frappe/public/scss/common/grid.scss @@ -449,6 +449,50 @@ z-index: 1; } } + + .grid-currency-input { + position: relative; + display: flex; + align-items: center; + width: 100%; + } + + .grid-currency-prefix, + .grid-currency-suffix { + position: absolute; + color: var(--text-muted); + pointer-events: none; + z-index: 2; + display: none; + } + + .grid-currency-prefix { + left: 8px; + } + + .grid-currency-suffix { + right: 8px; + } + + // for left aligned currency symbol + .grid-currency-input.grid-currency-has-value:not(.grid-currency-symbol-right) .form-control { + padding-left: calc(4px + 1em); + position: relative; + z-index: 1; + text-align: left; + } + + // for right aligned currency symbol + .grid-currency-input.grid-currency-has-value.grid-currency-symbol-right .form-control { + padding-right: calc(4px + 1em); + position: relative; + z-index: 1; + } + + .grid-currency-input.grid-currency-has-value .grid-currency-prefix, + .grid-currency-input.grid-currency-has-value .grid-currency-suffix { + display: block; + } } @mixin base-grid() {