Skip to content

Commit

Permalink
feat: usePosition (#259)
Browse files Browse the repository at this point in the history
  • Loading branch information
ggazzo committed Jul 14, 2020
1 parent f586722 commit b395d8c
Show file tree
Hide file tree
Showing 30 changed files with 790 additions and 140 deletions.
26 changes: 20 additions & 6 deletions packages/fuselage-hooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,20 @@ yarn add @rocket.chat/fuselage-hooks
- [Parameters](#parameters-9)
- [useMutableCallback](#usemutablecallback)
- [Parameters](#parameters-10)
- [useResizeObserver](#useresizeobserver)
- [usePosition](#useposition)
- [Parameters](#parameters-11)
- [useSafely](#usesafely)
- [useResizeObserver](#useresizeobserver)
- [Parameters](#parameters-12)
- [useStableArray](#usestablearray)
- [useSafely](#usesafely)
- [Parameters](#parameters-13)
- [useLocalStorage](#uselocalstorage)
- [useStableArray](#usestablearray)
- [Parameters](#parameters-14)
- [useSessionStorage](#usesessionstorage)
- [useLocalStorage](#uselocalstorage)
- [Parameters](#parameters-15)
- [useToggle](#usetoggle)
- [useSessionStorage](#usesessionstorage)
- [Parameters](#parameters-16)
- [useToggle](#usetoggle)
- [Parameters](#parameters-17)
- [useUniqueId](#useuniqueid)

### useAutoFocus
Expand Down Expand Up @@ -211,6 +213,18 @@ Hook to create a stable callback from a mutable one.

Returns **function (...args: P): T** a stable callback

### usePosition

Hook to deal with sessionStorage

#### Parameters

- `reference` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** the anchor
- `targetEl` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** the element to be positioned
- `options` **PostionOptions** options to position

Returns **(PositionStyle | null)** a state and a setter function

### useResizeObserver

Hook to track dimension changes in a DOM element using the ResizeObserver API.
Expand Down
17 changes: 17 additions & 0 deletions packages/fuselage-hooks/docs/fuselage-hooks.getpositionstyle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@rocket.chat/fuselage-hooks](./fuselage-hooks.md) &gt; [getPositionStyle](./fuselage-hooks.getpositionstyle.md)

## getPositionStyle variable

<b>Signature:</b>

```typescript
getPositionStyle: ({ placement, container, targetBoundaries, variantStore, target }: {
placement: Placements;
target: DOMRect;
container: DOMRect;
targetBoundaries: Boundaries;
variantStore: VariantBoundaries;
}) => PositionStyle | null
```
15 changes: 15 additions & 0 deletions packages/fuselage-hooks/docs/fuselage-hooks.gettargetboundaries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@rocket.chat/fuselage-hooks](./fuselage-hooks.md) &gt; [getTargetBoundaries](./fuselage-hooks.gettargetboundaries.md)

## getTargetBoundaries variable

<b>Signature:</b>

```typescript
getTargetBoundaries: ({ referenceBox, target, margin }: {
referenceBox: DOMRect;
target: DOMRect;
margin?: number;
}) => Boundaries
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@rocket.chat/fuselage-hooks](./fuselage-hooks.md) &gt; [getVariantBoundaries](./fuselage-hooks.getvariantboundaries.md)

## getVariantBoundaries variable

<b>Signature:</b>

```typescript
getVariantBoundaries: ({ referenceBox, target }: {
referenceBox: DOMRect;
target: DOMRect;
}) => VariantBoundaries
```
13 changes: 13 additions & 0 deletions packages/fuselage-hooks/docs/fuselage-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

| Variable | Description |
| --- | --- |
| [getPositionStyle](./fuselage-hooks.getpositionstyle.md) | |
| [getTargetBoundaries](./fuselage-hooks.gettargetboundaries.md) | |
| [getVariantBoundaries](./fuselage-hooks.getvariantboundaries.md) | |
| [useAutoFocus](./fuselage-hooks.useautofocus.md) | Hook to automatically request focus for an DOM element. |
| [useBreakpoints](./fuselage-hooks.usebreakpoints.md) | Hook to catch which responsive design' breakpoints are active. |
| [useDebouncedCallback](./fuselage-hooks.usedebouncedcallback.md) | Hook to memoize a debounced version of a callback. |
Expand All @@ -30,10 +33,20 @@
| [useMediaQuery](./fuselage-hooks.usemediaquery.md) | Hook to listen to a media query. |
| [useMergedRefs](./fuselage-hooks.usemergedrefs.md) | Hook to merge refs and callbacks refs into a single callback ref. Useful when your component need a internal ref while receiving a forwared ref. |
| [useMutableCallback](./fuselage-hooks.usemutablecallback.md) | Hook to create a stable callback from a mutable one. |
| [usePosition](./fuselage-hooks.useposition.md) | Hook to deal with sessionStorage |
| [useResizeObserver](./fuselage-hooks.useresizeobserver.md) | Hook to track dimension changes in a DOM element using the ResizeObserver API. |
| [useSafely](./fuselage-hooks.usesafely.md) | Hook that wraps pairs of state and dispatcher to provide a new dispatcher which can be safe and asynchronically called even after the component unmounted. |
| [useSessionStorage](./fuselage-hooks.usesessionstorage.md) | Hook to deal with sessionStorage |
| [useStableArray](./fuselage-hooks.usestablearray.md) | Hook to create an array with stable identity if its elements are equal. |
| [useToggle](./fuselage-hooks.usetoggle.md) | Hook to create a toggleable boolean state. |
| [useUniqueId](./fuselage-hooks.useuniqueid.md) | Hook to keep a unique ID string. |

## Type Aliases

| Type Alias | Description |
| --- | --- |
| [Placements](./fuselage-hooks.placements.md) | |
| [PositionFlipOrder](./fuselage-hooks.positionfliporder.md) | |
| [Positions](./fuselage-hooks.positions.md) | |
| [PostionOptions](./fuselage-hooks.postionoptions.md) | |

11 changes: 11 additions & 0 deletions packages/fuselage-hooks/docs/fuselage-hooks.placements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@rocket.chat/fuselage-hooks](./fuselage-hooks.md) &gt; [Placements](./fuselage-hooks.placements.md)

## Placements type

<b>Signature:</b>

```typescript
export declare type Placements = 'top-start' | 'top-middle' | 'top-end' | 'bottom-start' | 'bottom-middle' | 'bottom-end' | 'left-start' | 'left-middle' | 'left-end' | 'right-start' | 'right-middle' | 'right-end' | Positions;
```
16 changes: 16 additions & 0 deletions packages/fuselage-hooks/docs/fuselage-hooks.positionfliporder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@rocket.chat/fuselage-hooks](./fuselage-hooks.md) &gt; [PositionFlipOrder](./fuselage-hooks.positionfliporder.md)

## PositionFlipOrder type

<b>Signature:</b>

```typescript
export declare type PositionFlipOrder = {
top: string;
right: string;
bottom: string;
left: string;
};
```
11 changes: 11 additions & 0 deletions packages/fuselage-hooks/docs/fuselage-hooks.positions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@rocket.chat/fuselage-hooks](./fuselage-hooks.md) &gt; [Positions](./fuselage-hooks.positions.md)

## Positions type

<b>Signature:</b>

```typescript
export declare type Positions = 'top' | 'left' | 'bottom' | 'right';
```
16 changes: 16 additions & 0 deletions packages/fuselage-hooks/docs/fuselage-hooks.postionoptions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@rocket.chat/fuselage-hooks](./fuselage-hooks.md) &gt; [PostionOptions](./fuselage-hooks.postionoptions.md)

## PostionOptions type

<b>Signature:</b>

```typescript
export declare type PostionOptions = {
margin?: number;
container?: Element;
placement?: Placements;
watch?: boolean;
};
```
13 changes: 13 additions & 0 deletions packages/fuselage-hooks/docs/fuselage-hooks.useposition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@rocket.chat/fuselage-hooks](./fuselage-hooks.md) &gt; [usePosition](./fuselage-hooks.useposition.md)

## usePosition variable

Hook to deal with sessionStorage

<b>Signature:</b>

```typescript
usePosition: (reference: Element, targetEl: Element, options: PostionOptions) => PositionStyle | null
```
1 change: 1 addition & 0 deletions packages/fuselage-hooks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './useMediaQueries';
export * from './useMediaQuery';
export * from './useMergedRefs';
export * from './useMutableCallback';
export * from './usePosition';
export * from './useResizeObserver';
export * from './useSafely';
export * from './useStableArray';
Expand Down
176 changes: 176 additions & 0 deletions packages/fuselage-hooks/src/usePosition.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { getPositionStyle, getTargetBoundaries, getVariantBoundaries } from './usePosition';
// TODO: add tests targeting the hook itself

const container = {
bottom: 1000,
height: 1000,
left: 0,
right: 1024,
top: 0,
width: 1024,
x: 0,
y: 0,
} as DOMRect;

const referenceBox = {
bottom: 300,
height: 100,
left: 0,
right: 100,
top: 200,
width: 100,
x: 0,
y: 200,
} as DOMRect;

const target = {
bottom: 50,
height: 50,
left: 0,
right: 50,
top: 0,
width: 50,
x: 0,
y: 0,
} as DOMRect;

describe('usePosition hook', () => {
describe('getTargetBoundaries', () => {
it('...', () => {
const targetBoundaries = getTargetBoundaries({ referenceBox, target });
expect(targetBoundaries.t).toEqual(150);
expect(targetBoundaries.b).toEqual(300);
expect(targetBoundaries.r).toEqual(100);
expect(targetBoundaries.l).toEqual(-50);
});
});
describe('getPositionStyle function', () => {
it('returns a style for placement bottom-start', () => {
const targetBoundaries = getTargetBoundaries({ referenceBox, target });
const variantStore = getVariantBoundaries({ referenceBox, target });
const style = getPositionStyle({ placement: 'bottom-start', container, targetBoundaries, variantStore, target });
expect(style.left).toEqual('0px');
expect(style.top).toEqual('300px');
});
it('returns a style for placement bottom-start if the element height does not fit', () => {
const targetBoundaries = getTargetBoundaries({ referenceBox, target });
const variantStore = getVariantBoundaries({ referenceBox, target });
const style = getPositionStyle({ placement: 'bottom-start',
container: {
...container,
bottom: 300,
height: 300,
},
targetBoundaries,
variantStore,
target });
expect(style.left).toEqual('0px');
expect(style.top).toEqual('150px');
});

it('returns a style for placement bottom-middle', () => {
const targetBoundaries = getTargetBoundaries({ referenceBox, target });

const variantStore = getVariantBoundaries({ referenceBox, target });

const style = getPositionStyle({ placement: 'bottom-middle', container, targetBoundaries, variantStore, target });

expect(style.left).toEqual('25px');
expect(style.top).toEqual('300px');
});
it('returns a style for placement bottom-middle if the element height does not fit', () => {
const targetBoundaries = getTargetBoundaries({ referenceBox, target });
const variantStore = getVariantBoundaries({ referenceBox, target });
const style = getPositionStyle({ placement: 'bottom-middle',
container: {
...container,
bottom: 300,
height: 300,
},
targetBoundaries,
variantStore,
target });
expect(style.left).toEqual('25px');
expect(style.top).toEqual('150px');
});

it('returns a style for placement bottom-end', () => {
const targetBoundaries = getTargetBoundaries({ referenceBox, target });

const variantStore = getVariantBoundaries({ referenceBox, target });

const style = getPositionStyle({ placement: 'bottom-end', container, targetBoundaries, variantStore, target });

expect(style.left).toEqual('50px');
expect(style.top).toEqual('300px');
});
it('returns a style for placement bottom-end if the element height does not fit', () => {
const targetBoundaries = getTargetBoundaries({ referenceBox, target });
const variantStore = getVariantBoundaries({ referenceBox, target });
const style = getPositionStyle({ placement: 'bottom-end',
container: {
...container,
bottom: 300,
height: 300,
},
targetBoundaries,
variantStore,
target });
expect(style.left).toEqual('50px');
expect(style.top).toEqual('150px');
});


it('returns a style for placement top-start', () => {
const targetBoundaries = getTargetBoundaries({ referenceBox, target });
const variantStore = getVariantBoundaries({ referenceBox, target });
const style = getPositionStyle({ placement: 'top-start', container, targetBoundaries, variantStore, target });
expect(style.left).toEqual('0px');
expect(style.top).toEqual('150px');
});
it('returns a style for placement top-start if the element height does not fit', () => {
const box = { ...referenceBox, top: 10, y: 10, bottom: 110 };
const targetBoundaries = getTargetBoundaries({ referenceBox: box, target });
const variantStore = getVariantBoundaries({ referenceBox: box, target });
const style = getPositionStyle({ placement: 'top-start', container, targetBoundaries, variantStore, target });
expect(style.left).toEqual('0px');
expect(style.top).toEqual('110px');
});
it('returns a style for placement top-middle', () => {
const targetBoundaries = getTargetBoundaries({ referenceBox, target });

const variantStore = getVariantBoundaries({ referenceBox, target });

const style = getPositionStyle({ placement: 'top-middle', container, targetBoundaries, variantStore, target });

expect(style.left).toEqual('25px');
expect(style.top).toEqual('150px');
});
it('returns a style for placement top-middle if the element height does not fit', () => {
const box = { ...referenceBox, top: 10, y: 10, bottom: 110 };
const targetBoundaries = getTargetBoundaries({ referenceBox: box, target });
const variantStore = getVariantBoundaries({ referenceBox: box, target });
const style = getPositionStyle({ placement: 'top-middle', container, targetBoundaries, variantStore, target });
expect(style.left).toEqual('25px');
expect(style.top).toEqual('110px');
});
it('returns a style for placement top-end', () => {
const targetBoundaries = getTargetBoundaries({ referenceBox, target });

const variantStore = getVariantBoundaries({ referenceBox, target });

const style = getPositionStyle({ placement: 'top-end', container, targetBoundaries, variantStore, target });

expect(style.left).toEqual('50px');
expect(style.top).toEqual('150px');
});
it('returns a style for placement top-end if the element height does not fit', () => {
const box = { ...referenceBox, top: 10, y: 10, bottom: 110 };
const targetBoundaries = getTargetBoundaries({ referenceBox: box, target });
const variantStore = getVariantBoundaries({ referenceBox: box, target });
const style = getPositionStyle({ placement: 'top-end', container, targetBoundaries, variantStore, target });
expect(style.left).toEqual('50px');
expect(style.top).toEqual('110px');
});
});
});
Loading

0 comments on commit b395d8c

Please sign in to comment.