From 4560e3728cf8bb93f3fffb576ff65ac2492854d1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 22 Nov 2023 13:20:47 +1100 Subject: [PATCH] Show popout on click or down key It looks like a select drop-down, so it can behave like one too. --- app/views/admin/products_v3/_table.html.haml | 6 +-- .../controllers/popout_controller.js | 26 ++++++++++ app/webpacker/css/admin/products_v3.scss | 1 - .../stimulus/popout_controller_test.js | 49 +++++++++++++++++++ 4 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 app/webpacker/controllers/popout_controller.js create mode 100644 spec/javascripts/stimulus/popout_controller_test.js diff --git a/app/views/admin/products_v3/_table.html.haml b/app/views/admin/products_v3/_table.html.haml index 31e8e27a24..0570f22e63 100644 --- a/app/views/admin/products_v3/_table.html.haml +++ b/app/views/admin/products_v3/_table.html.haml @@ -85,10 +85,10 @@ %td.field = variant_form.text_field :price, 'aria-label': t('admin.products_page.columns.price'), value: number_to_currency(variant.price, unit: '')&.strip # TODO: add a spec to prove that this formatting is necessary. If so, it should be in a shared form helper for currency inputs = error_message_on variant, :price - %td.field.on-hand__wrapper - %button.on-hand__button + %td.field.on-hand__wrapper{'data-controller': "popout"} + %button.on-hand__button{'data-popout-target': "button"} = variant.on_demand ? t(:on_demand) : variant.on_hand - %div.on-hand__popout + %div.on-hand__popout{ style: 'display: none;', 'data-popout-target': "dialog"} .field = variant_form.number_field :on_hand, 'aria-label': t('admin.products_page.columns.on_hand') = error_message_on variant, :on_hand diff --git a/app/webpacker/controllers/popout_controller.js b/app/webpacker/controllers/popout_controller.js new file mode 100644 index 0000000000..06c5156ce4 --- /dev/null +++ b/app/webpacker/controllers/popout_controller.js @@ -0,0 +1,26 @@ +import { Controller } from "stimulus"; + +// Allows a form section to "pop out" and show additional options +export default class PopoutController extends Controller { + static targets = ["button", "dialog"]; + + connect() { + this.first_input = this.dialogTarget.querySelector("input"); + + // Show when click or down-arrow on button + this.buttonTarget.addEventListener("click", this.show.bind(this)); + this.buttonTarget.addEventListener("keydown", this.showIfDownArrow.bind(this)); + } + + show(e) { + this.dialogTarget.style.display = "block"; + this.first_input.focus(); + e.preventDefault(); + } + + showIfDownArrow(e) { + if (e.keyCode == 40) { + this.show(e); + } + } +} diff --git a/app/webpacker/css/admin/products_v3.scss b/app/webpacker/css/admin/products_v3.scss index 4dbbaf39b0..99f9612c20 100644 --- a/app/webpacker/css/admin/products_v3.scss +++ b/app/webpacker/css/admin/products_v3.scss @@ -327,7 +327,6 @@ } &__popout { - display: none; position: absolute; top: -1em; left: -1em; diff --git a/spec/javascripts/stimulus/popout_controller_test.js b/spec/javascripts/stimulus/popout_controller_test.js new file mode 100644 index 0000000000..f3f332143d --- /dev/null +++ b/spec/javascripts/stimulus/popout_controller_test.js @@ -0,0 +1,49 @@ +/** + * @jest-environment jsdom + */ + +import { Application } from "stimulus"; +import popout_controller from "../../../app/webpacker/controllers/popout_controller"; + +describe("PopoutController", () => { + beforeAll(() => { + const application = Application.start(); + application.register("popout", popout_controller); + }); + + beforeEach(() => { + document.body.innerHTML = ` +
+ + +
+ `; + + const button = document.getElementById("button"); + const input1 = document.getElementById("input1"); + const input2 = document.getElementById("input2"); + }); + + describe("Show", () => { + it("shows the dialog on click", () => { + button.click(); + + expect(dialog.style.display).toBe("block"); // visible + }); + + it("shows the dialog on keyboard down arrow", () => { + button.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 40 })); + + expect(dialog.style.display).toBe("block"); // visible + }); + + it("doesn't show the dialog on other key press (tab)", () => { + button.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 9 })); + + expect(dialog.style.display).toBe("none"); // not visible + }); + }); +});