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

Update FloatingUI package and add is-dragging logic #667

Closed
wants to merge 2 commits into from
Closed
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
19 changes: 17 additions & 2 deletions web/app/components/floating-u-i/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ interface FloatingUIContentSignature {
renderOut?: boolean;
offset?: OffsetOptions;
matchAnchorWidth?: MatchAnchorWidthOptions;
hide: () => void;
};
Blocks: {
default: [];
Expand Down Expand Up @@ -65,7 +66,7 @@ export default class FloatingUIContent extends Component<FloatingUIContentSignat
@action didInsert(e: HTMLElement) {
this._content = e;

const { matchAnchorWidth, anchor, placement } = this.args;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unused variable

const { anchor, placement } = this.args;
const { content } = this;

this.maybeMatchAnchorWidth();
Expand All @@ -79,6 +80,17 @@ export default class FloatingUIContent extends Component<FloatingUIContentSignat

let updatePosition = async () => {
let _placement = placement || "bottom-start";
/**
* If anchor exists within a div that's being dragged, hide the content
* to prevent the dropdown from remaining open after its parent is dragged.
* The `is-dragging` class is added by Pragmatic Drag and Drop.
*/
const elementBeingDragged = document.querySelector(".is-dragging");

if (elementBeingDragged && elementBeingDragged.contains(anchor)) {
this.args.hide();
return;
}

computePosition(anchor, content, {
platform,
Expand All @@ -95,7 +107,10 @@ export default class FloatingUIContent extends Component<FloatingUIContentSignat
});
};

this.cleanup = autoUpdate(anchor, content, updatePosition);
this.cleanup = autoUpdate(anchor, content, updatePosition, {
// Recompute on layout shifts such as drag and drop.
layoutShift: true,
});
}

private maybeMatchAnchorWidth() {
Expand Down
1 change: 1 addition & 0 deletions web/app/components/floating-u-i/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
@anchor={{this.anchor}}
@id={{this.contentID}}
@matchAnchorWidth={{@matchAnchorWidth}}
@hide={{this.hideContent}}
...attributes
>
{{yield
Expand Down
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
},
"dependencies": {
"@csstools/postcss-sass": "^5.0.1",
"@floating-ui/dom": "^1.2.4",
"@floating-ui/dom": "^1.6.3",
"@hashicorp/design-system-components": "^3.1.0",
"@hashicorp/ember-flight-icons": "^4.0.2",
"@types/sinon": "^10.0.13",
Expand Down
85 changes: 73 additions & 12 deletions web/tests/integration/components/floating-u-i/content-test.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
import { module, test, todo } from "qunit";
import { setupRenderingTest } from "ember-qunit";
import { TestContext, render } from "@ember/test-helpers";
import { TestContext, find, render, waitUntil } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import htmlElement from "hermes/utils/html-element";
import { OffsetOptions } from "@floating-ui/dom";

const DEFAULT_CONTENT_OFFSET = 5;
const CONTENT_SELECTOR = ".hermes-floating-ui-content";

interface FloatingUIComponentTestContext extends TestContext {
interface Context extends TestContext {
renderOut?: boolean;
offset?: OffsetOptions;
class: string;
isShown: boolean;
spacerIsShown: boolean;
hide: () => void;
}

module("Integration | Component | floating-u-i/content", function (hooks) {
setupRenderingTest(hooks);

test("it can be rendered inline or outside", async function (this: FloatingUIComponentTestContext, assert) {
hooks.beforeEach(function (this: Context) {
this.set("hide", () => {});
});

test("it can be rendered inline or outside", async function (this: Context, assert) {
this.set("renderOut", false);

await render<FloatingUIComponentTestContext>(hbs`
await render<Context>(hbs`
<div class="anchor">
Attach here
</div>
Expand All @@ -29,6 +37,7 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
@id="1"
@anchor={{html-element '.anchor'}}
@renderOut={{this.renderOut}}
@hide={{this.hide}}
>
Content
</FloatingUI::Content>
Expand All @@ -51,7 +60,7 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
});

test("it will render out to a dialog if one is present", async function (assert) {
await render<FloatingUIComponentTestContext>(hbs`
await render<Context>(hbs`

<dialog>
Dialog
Expand All @@ -66,6 +75,7 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
@id="1"
@anchor={{html-element '.anchor'}}
@renderOut={{true}}
@hide={{this.hide}}
>
Content
</FloatingUI::Content>
Expand All @@ -81,7 +91,7 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
.exists("content is rendered in the dialog");
});

test("it is positioned by floating-ui", async function (this: FloatingUIComponentTestContext, assert) {
test("it is positioned by floating-ui", async function (this: Context, assert) {
let contentWidth = 0;
let anchorWidth = 0;
let contentLeft = 0;
Expand All @@ -101,7 +111,7 @@ module("Integration | Component | floating-u-i/content", function (hooks) {

// Center the anchor so the content can be flexibly positioned

await render<FloatingUIComponentTestContext>(hbs`
await render<Context>(hbs`
<div class="grid place-items-center w-full h-full">
<div>
<div class="anchor" style="width: 100px">
Expand All @@ -112,6 +122,7 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
@id="1"
@anchor={{html-element '.anchor'}}
@placement="left"
@hide={{this.hide}}
>
Content
</FloatingUI::Content>
Expand All @@ -138,7 +149,7 @@ module("Integration | Component | floating-u-i/content", function (hooks) {

this.clearRender();

await render<FloatingUIComponentTestContext>(hbs`
await render<Context>(hbs`
<div class="grid place-items-center w-full h-full">
<div>
<div class="anchor" style="width: 100px">
Expand All @@ -149,6 +160,7 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
@id="1"
@anchor={{html-element '.anchor'}}
@placement="right"
@hide={{this.hide}}
>
Content
</FloatingUI::Content>
Expand All @@ -168,8 +180,8 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
);
});

test("it can use a custom offset", async function (this: FloatingUIComponentTestContext, assert) {
await render(hbs`
test("it can use a custom offset", async function (this: Context, assert) {
await render<Context>(hbs`
<div class="grid place-items-center w-full h-full">
<div>
<div class="anchor" style="width: 100px">
Expand All @@ -180,6 +192,7 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
@id="1"
@anchor={{html-element '.anchor'}}
@placement="left"
@hide={{this.hide}}
>
Content
</FloatingUI::Content>
Expand All @@ -203,7 +216,7 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
this.clearRender();
this.set("offset", 10);

await render<FloatingUIComponentTestContext>(hbs`
await render<Context>(hbs`
<div class="grid place-items-center w-full h-full">
<div>
<div class="anchor" style="width: 100px">
Expand All @@ -215,6 +228,7 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
@anchor={{html-element '.anchor'}}
@placement="left"
@offset={{this.offset}}
@hide={{this.hide}}
>
Content
</FloatingUI::Content>
Expand All @@ -236,14 +250,15 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
});

test("it can ignore dynamic positioning", async function (assert) {
await render(hbs`
await render<Context>(hbs`
<div class="anchor">
Attach
</div>
<FloatingUI::Content
@id="1"
@anchor={{html-element '.anchor'}}
@placement={{null}}
@hide={{this.hide}}
>
Content
</FloatingUI::Content>
Expand Down Expand Up @@ -274,6 +289,52 @@ module("Integration | Component | floating-u-i/content", function (hooks) {
);
});

test("it runs the passed-in hide action when the anchor is dragged", async function (assert) {
this.set("class", "");
this.set("isShown", true);
this.set("spacerIsShown", true);
this.set("hide", () => {
this.set("isShown", false);
});

await render<Context>(hbs`
<div class={{this.class}}>
{{#if this.spacerIsShown}}
<div>
Space
</div>
{{/if}}
{{#if this.isShown}}
<div class="anchor">
<FloatingUI::Content
@id="1"
@anchor={{html-element '.anchor'}}
@placement="bottom-start"
@hide={{this.hide}}
>
</FloatingUI::Content>
</div>
{{/if}}
</div>
`);

assert.dom(CONTENT_SELECTOR).exists();

this.set("class", "is-dragging");

assert
.dom(CONTENT_SELECTOR)
.exists("content is visible because the layout hasn't shifted");

// Trigger a layout shift
this.set("spacerIsShown", false);

// Confirm that the content is hidden
await waitUntil(() => {
return !find(CONTENT_SELECTOR);
});
});

todo("it runs a cleanup function on teardown", async function (assert) {
assert.ok(false);
});
Expand Down
30 changes: 20 additions & 10 deletions web/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3422,19 +3422,29 @@ __metadata:
languageName: node
linkType: hard

"@floating-ui/core@npm:^1.2.3":
version: 1.2.4
resolution: "@floating-ui/core@npm:1.2.4"
checksum: 1c163ea1804e2b0a28fda6e32efed0e242d0db8081fd24aab9d1cbb100f94a558709231c483bf74bf09a9204ea6e7845813d43b5322ceb6ee63285308f68f65b
"@floating-ui/core@npm:^1.0.0":
version: 1.6.0
resolution: "@floating-ui/core@npm:1.6.0"
dependencies:
"@floating-ui/utils": ^0.2.1
checksum: 2e25c53b0c124c5c9577972f8ae21d081f2f7895e6695836a53074463e8c65b47722744d6d2b5a993164936da006a268bcfe87fe68fd24dc235b1cb86bed3127
languageName: node
linkType: hard

"@floating-ui/dom@npm:^1.2.4":
version: 1.2.4
resolution: "@floating-ui/dom@npm:1.2.4"
"@floating-ui/dom@npm:^1.6.3":
version: 1.6.3
resolution: "@floating-ui/dom@npm:1.6.3"
dependencies:
"@floating-ui/core": ^1.2.3
checksum: 5c24a2e8f04e436390646c8a4431c6cb79e03711fbb0f818b87d613a6be8971bc560a830b702aaa51a0ebc4d0c45deb06f3140c14125dc1ac770365bf66ee903
"@floating-ui/core": ^1.0.0
"@floating-ui/utils": ^0.2.0
checksum: 81cbb18ece3afc37992f436e469e7fabab2e433248e46fff4302d12493a175b0c64310f8a971e6e1eda7218df28ace6b70237b0f3c22fe12a21bba05b5579555
languageName: node
linkType: hard

"@floating-ui/utils@npm:^0.2.0, @floating-ui/utils@npm:^0.2.1":
version: 0.2.1
resolution: "@floating-ui/utils@npm:0.2.1"
checksum: 9ed4380653c7c217cd6f66ae51f20fdce433730dbc77f95b5abfb5a808f5fdb029c6ae249b4e0490a816f2453aa6e586d9a873cd157fdba4690f65628efc6e06
languageName: node
linkType: hard

Expand Down Expand Up @@ -13465,7 +13475,7 @@ __metadata:
"@csstools/postcss-sass": ^5.0.1
"@ember/optional-features": ^2.0.0
"@ember/test-helpers": ^2.6.0
"@floating-ui/dom": ^1.2.4
"@floating-ui/dom": ^1.6.3
"@gavant/glint-template-types": ^0.3.6
"@glimmer/component": ^1.0.4
"@glimmer/tracking": ^1.0.4
Expand Down
Loading