Skip to content

Commit 7725ed7

Browse files
committed
refactor(command): track open dialog via static instance ref
Replace querySelector + hardcoded selector with a static `openInstance` reference set in connect() and cleared in disconnect(). Removes the `data-ruby-ui--command-dialog` marker attribute and per-controller DOM lookups, so renaming the controller or restructuring dialog markup no longer silently breaks single-instance behavior. Addresses review feedback on #386.
1 parent dda391d commit 7725ed7

4 files changed

Lines changed: 30 additions & 18 deletions

File tree

docs/app/javascript/controllers/ruby_ui/command_controller.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { Controller } from "@hotwired/stimulus";
22
import Fuse from "fuse.js";
33

4-
const OPEN_DIALOG_SELECTOR = "[data-ruby-ui--command-dialog]";
5-
64
// Connects to data-controller="ruby-ui--command"
75
export default class extends Controller {
86
static targets = ["input", "group", "item", "empty", "content"];
@@ -14,13 +12,16 @@ export default class extends Controller {
1412
},
1513
};
1614

15+
static openInstance = null;
16+
1717
connect() {
1818
this.selectedIndex = -1;
1919

2020
if (!this.hasInputTarget) {
2121
return;
2222
}
2323

24+
this.constructor.openInstance = this;
2425
this.inputTarget.focus();
2526
this.searchIndex = this.buildSearchIndex();
2627
this.toggleVisibility(this.emptyTargets, false);
@@ -30,6 +31,12 @@ export default class extends Controller {
3031
}
3132
}
3233

34+
disconnect() {
35+
if (this.constructor.openInstance === this) {
36+
this.constructor.openInstance = null;
37+
}
38+
}
39+
3340
open(e) {
3441
if (e) {
3542
e.preventDefault();
@@ -39,9 +46,9 @@ export default class extends Controller {
3946
return;
4047
}
4148

42-
const openDialog = document.querySelector(OPEN_DIALOG_SELECTOR);
43-
if (openDialog) {
44-
this.focusDialogInput(openDialog);
49+
const openInstance = this.constructor.openInstance;
50+
if (openInstance) {
51+
openInstance.focusInput();
4552
return;
4653
}
4754

@@ -153,8 +160,7 @@ export default class extends Controller {
153160
this.selectedIndex = -1;
154161
}
155162

156-
focusDialogInput(dialog) {
157-
const input = dialog.querySelector("[data-ruby-ui--command-target='input']");
158-
input?.focus();
163+
focusInput() {
164+
this.inputTarget?.focus();
159165
}
160166
}

gem/lib/ruby_ui/command/command_controller.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { Controller } from "@hotwired/stimulus";
22
import Fuse from "fuse.js";
33

4-
const OPEN_DIALOG_SELECTOR = "[data-ruby-ui--command-dialog]";
5-
64
// Connects to data-controller="ruby-ui--command"
75
export default class extends Controller {
86
static targets = ["input", "group", "item", "empty", "content"];
@@ -14,13 +12,16 @@ export default class extends Controller {
1412
},
1513
};
1614

15+
static openInstance = null;
16+
1717
connect() {
1818
this.selectedIndex = -1;
1919

2020
if (!this.hasInputTarget) {
2121
return;
2222
}
2323

24+
this.constructor.openInstance = this;
2425
this.inputTarget.focus();
2526
this.searchIndex = this.buildSearchIndex();
2627
this.toggleVisibility(this.emptyTargets, false);
@@ -30,6 +31,12 @@ export default class extends Controller {
3031
}
3132
}
3233

34+
disconnect() {
35+
if (this.constructor.openInstance === this) {
36+
this.constructor.openInstance = null;
37+
}
38+
}
39+
3340
open(e) {
3441
if (e) {
3542
e.preventDefault();
@@ -39,9 +46,9 @@ export default class extends Controller {
3946
return;
4047
}
4148

42-
const openDialog = document.querySelector(OPEN_DIALOG_SELECTOR);
43-
if (openDialog) {
44-
this.focusDialogInput(openDialog);
49+
const openInstance = this.constructor.openInstance;
50+
if (openInstance) {
51+
openInstance.focusInput();
4552
return;
4653
}
4754

@@ -153,8 +160,7 @@ export default class extends Controller {
153160
this.selectedIndex = -1;
154161
}
155162

156-
focusDialogInput(dialog) {
157-
const input = dialog.querySelector("[data-ruby-ui--command-target='input']");
158-
input?.focus();
163+
focusInput() {
164+
this.inputTarget?.focus();
159165
}
160166
}

gem/lib/ruby_ui/command/command_dialog_content.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def initialize(size: :md, **attrs)
1818

1919
def view_template(&block)
2020
template(data: {ruby_ui__command_target: "content"}) do
21-
div(data: {controller: "ruby-ui--command", ruby_ui__command_dialog: true}) do
21+
div(data: {controller: "ruby-ui--command"}) do
2222
backdrop
2323
div(**attrs, &block)
2424
end

gem/test/ruby_ui/command_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,6 @@ def test_render_with_all_items
6060
end
6161

6262
assert_match(/Search/, output)
63-
assert_match(/data-ruby-ui--command-dialog/, output)
63+
assert_match(/data-controller="ruby-ui--command"/, output)
6464
end
6565
end

0 commit comments

Comments
 (0)