Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autofocus PeopleSelects in the sidebar #333

Merged
merged 2 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions web/app/components/custom-editable-field.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
</:default>
<:editing as |F|>
<Inputs::PeopleSelect
{{autofocus targetChildren=true}}
class="multiselect--narrow"
@selected={{this.people}}
@onChange={{this.updateEmails}}
Expand Down
2 changes: 2 additions & 0 deletions web/app/components/document/sidebar.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@
</:default>
<:editing as |F|>
<Inputs::PeopleSelect
{{autofocus targetChildren=true}}
data-test-document-contributors-editable
class="multiselect--narrow"
@selected={{this.contributors}}
Expand Down Expand Up @@ -273,6 +274,7 @@
</:default>
<:editing as |F|>
<Inputs::PeopleSelect
{{autofocus targetChildren=true}}
data-test-document-approvers-editable
class="multiselect--narrow"
@selected={{this.approvers}}
Expand Down
2 changes: 2 additions & 0 deletions web/app/components/inputs/people-select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ interface InputsPeopleSelectComponentSignature {
Args: {
selected: HermesUser[];
onChange: (people: HermesUser[]) => void;
renderInPlace?: boolean;
disabled?: boolean;
Comment on lines +20 to +21
Copy link
Contributor Author

@jeffdaley jeffdaley Sep 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happened to come across these missing types. SORRY

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

};
}

Expand Down
55 changes: 55 additions & 0 deletions web/app/modifiers/autofocus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { assert } from "@ember/debug";
import { action } from "@ember/object";
import { tracked } from "@glimmer/tracking";
import Modifier from "ember-modifier";
import { FOCUSABLE } from "hermes/components/editable-field";

interface AutofocusModifierSignature {
Args: {
Element: Element;
Positional: [];
Named: {
targetChildren?: boolean;
};
};
}

export default class AutofocusModifier extends Modifier<AutofocusModifierSignature> {
@tracked private _element: Element | null = null;
@tracked private targetChildren = false;

private get element(): Element {
assert("element must exist", this._element);
return this._element;
}

@action private maybeAutofocus() {
if (this.targetChildren) {
const target = this.element.querySelector(FOCUSABLE);
if (target instanceof HTMLElement) {
target.focus();
}
} else {
if (this.element instanceof HTMLElement) {
this.element.focus();
}
}
}

modify(
element: Element,
_positional: [],
named: AutofocusModifierSignature["Args"]["Named"]
) {
this._element = element;
this.targetChildren = named.targetChildren ?? false;

this.maybeAutofocus();
}
}

declare module "@glint/environment-ember-loose/registry" {
export default interface Registry {
autofocus: typeof AutofocusModifier;
}
}
34 changes: 34 additions & 0 deletions web/tests/acceptance/authenticated/document-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -524,4 +524,38 @@ module("Acceptance | authenticated/document", function (hooks) {

assert.dom(SUMMARY_SELECTOR).hasText("Enter a summary");
});

test('"people" inputs receive focus on click', async function (this: AuthenticatedDocumentRouteTestContext, assert) {
this.server.create("document", {
objectID: 1,
title: "Test Document",
isDraft: true,
customEditableFields: {
Stakeholders: {
displayName: "Stakeholders",
type: "PEOPLE",
},
},
});

await visit("/document/1?draft=true");

await click(`${CONTRIBUTORS_SELECTOR} .field-toggle`);

assert.true(
document.activeElement === find(`${CONTRIBUTORS_SELECTOR} input`)
);

await click(`${APPROVERS_SELECTOR} .field-toggle`);

assert.true(document.activeElement === find(`${APPROVERS_SELECTOR} input`));

const stakeholdersSelector = "[data-test-custom-people-field]";

await click(`${stakeholdersSelector} .field-toggle`);

assert.true(
document.activeElement === find(`${stakeholdersSelector} input`)
);
});
});
44 changes: 44 additions & 0 deletions web/tests/integration/modifiers/autofocus-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { TestContext, find, render } from "@ember/test-helpers";
import { module, test } from "qunit";
import { hbs } from "ember-cli-htmlbars";
import { setupRenderingTest } from "ember-qunit";

interface AutofocusModifierTestContext extends TestContext {
buttonIsShown: boolean;
}
module("Integration | Modifier | autofocus", function (hooks) {
setupRenderingTest(hooks);

test("it autofocuses a focusable element", async function (this: AutofocusModifierTestContext, assert) {
this.set("buttonIsShown", false);

await render<AutofocusModifierTestContext>(hbs`
<input {{autofocus}} />

{{#if this.buttonIsShown}}
<button {{autofocus}}>Button</button>
{{/if}}
`);

assert.true(find("input") === document.activeElement);

this.set("buttonIsShown", true);

assert.true(find("button") === document.activeElement);
});

test("it can target focusable children of an element", async function (this: AutofocusModifierTestContext, assert) {
await render<AutofocusModifierTestContext>(hbs`
<div {{autofocus targetChildren=true}}>
<span/>
<input />
<button />
</div>
`);

assert.true(
find("input") === document.activeElement,
"the first focusable child is focused"
);
});
});