Skip to content

Commit

Permalink
feat: setHook, merge pull request #186 from miguelcobain/set-hook
Browse files Browse the repository at this point in the history
yield setHook function
  • Loading branch information
nicolechung authored Apr 9, 2024
2 parents 46a8bdf + 6bdf51b commit 42333b4
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/nasty-steaks-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ember-velcro": minor
---

Yields a `setHook` function back to consumers.
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,46 @@ The `Velcro` component yields a single hash - 2 modifiers and 'velcro data':

See [MiddlewareArguments](https://floating-ui.com/docs/middleware#middlewarearguments) for a description of each.

<details>
<summary>You can also use `velcro.setHook` yielded function for more complex composibility scenarios. Expand to read more.</summary>

## `setHook`

Imagine you're writing a dropdown component with ember-velcro. You want to yield a `trigger` modifier that does two things:
1. sets an element as the "hook" for ember-velcro
2. attaches a click handler to toggle between the open/closed states

Without the yielded `setHook` function, this would not be possible. With `setHook` however, we can pass that function to the modifier, and the modifier can call that function with the element.

Such a dropdown component might look something like this:

```gjs
let myModifier = modifier((element, [setHook, handler]) => {
// call ember-velcro's setHook
setHook(element);
// other custom logic
element.addEventListener('click', handler);
return () => {
element.removeEventListener('click', handler);
};
});
<template>
<Velcro as |velcro|>
{{yield (hash
trigger=(modifier myModifier velcro.setHook onClick)
)}}
</Velcro>
</template>
```

This is needed because, at the time of writing, there's no way in ember to combine two existing modifiers into a single one. You can check the relevant [pull request](https://github.com/CrowdStrike/ember-velcro/pull/186) for more information.


</details>

Compatibility
------------------------------------------------------------------------------

Expand Down
1 change: 1 addition & 0 deletions ember-velcro/src/components/velcro/index.hbs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{{yield (hash
hook=this.velcroHook
setHook=this.setHook
loop=(if this.hook (modifier this.velcroLoop
this.hook
flipOptions=@flipOptions
Expand Down
9 changes: 7 additions & 2 deletions ember-velcro/src/components/velcro/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ interface Signature {
default: [
velcro: {
hook: ModifierLike<HookSignature>;
setHook: (element: HTMLElement | SVGElement) => void;
loop: ModifierLike<{
Element: HTMLElement;
}>;
Expand All @@ -46,9 +47,13 @@ export default class Velcro extends Component<Signature> {

setVelcroData = (data: MiddlewareArguments) => (this.velcroData = data);

setHook = (element: HTMLElement | SVGElement) => {
this.hook = element;
};

velcroHook = modifier<HookSignature>(
(element) => {
this.hook = element;
(element: HTMLElement | SVGElement) => {
this.setHook(element);
},
{ eager: false }
);
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "^2.26.0"
"@changesets/cli": "^2.26.0",
"@glint/core": "^1.3.0"
},
"pnpm": {
"overrides": {
Expand Down
27 changes: 27 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions test-app/tests/integration/components/velcro-test.gts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { render } from '@ember/test-helpers';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { modifier } from 'ember-modifier';

import { findElement, resetTestingContainerDimensions, styleFor } from '../velcro-test-helpers';

Expand Down Expand Up @@ -37,6 +38,35 @@ module('Integration | Component | velcro', function (hooks) {
});
});

test('it renders with setHook', async function (assert) {
let hookModifier = modifier((element: HTMLElement | SVGElement, [setHook]: [(element: HTMLElement | SVGElement) => void]) => {
setHook(element);
});


await render(<template>
<Velcro as |velcro|>
<div id="hook" {{hookModifier velcro.setHook}} style="width: 200px; height: 40px">
{{velcro.data.rects.reference.width}}
{{velcro.data.rects.reference.height}}
</div>
<div id="loop" {{velcro.loop}} style="width: 200px; height: 400px">
{{velcro.data.rects.floating.width}}
{{velcro.data.rects.floating.height}}
</div>
</Velcro>
</template>);

assert.dom('#hook').hasText('200 40', 'reference element has expected dimensions');
assert.dom('#loop').hasText('200 400', 'floating element has expected dimensions');
assert.dom('#loop').hasAttribute('style');
assert.dom('#loop').hasStyle({
position: 'fixed',
top: '40px',
left: '0px',
});
});

module('@middleware', function () {
test('it yields the MiddlewareArguments', async function (assert) {
await render(<template>
Expand Down

0 comments on commit 42333b4

Please sign in to comment.