Skip to content

Commit

Permalink
Feat(modules-event-event): create hook for observing events (#1076)
Browse files Browse the repository at this point in the history
* fix(module-event): expose event stream

expose event stream from `IEventModuleProvider`

* feat(react-module-event): create hook for observing events

* docs: update event module docs
  • Loading branch information
odinr committed Jul 28, 2023
1 parent bc8ac3d commit 7aee3cf
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 69 deletions.
5 changes: 5 additions & 0 deletions .changeset/dry-parents-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@equinor/fusion-framework-module-event': patch
---

expose event stream from `IEventModuleProvider`
22 changes: 22 additions & 0 deletions .changeset/light-cows-play.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
'@equinor/fusion-framework-react-module-event': minor
---

Add hook for observing event streams

```ts
/* observe stream of events */
const someEvent$ = useEventStream(
'some_event',
useCallback(
(event$) => event$.pipe(
// only some events
filter(e => e.detail.foo === dep.foo),
// mutate data
map(e => e.detail)
)
), [dep]
);
/* use state of stream */
const someEvent = useObservableState(someEvent$);
```
6 changes: 6 additions & 0 deletions packages/modules/event/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
} from './event';

export interface IEventModuleProvider {
readonly event$: Observable<IFrameworkEvent>;

/** subscribe to a known mapped event @see {@link FrameworkEventMap} */
addEventListener<TKey extends keyof FrameworkEventMap>(
type: TKey,
Expand Down Expand Up @@ -69,6 +71,10 @@ export class EventModuleProvider

private __dispatcher: FrameworkEventDispatcher<FrameworkEvent>;

get event$(): Observable<IFrameworkEvent> {
return this.__event$.asObservable();
}

get closed() {
return this.__event$.closed;
}
Expand Down
1 change: 1 addition & 0 deletions packages/react/modules/event/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export { EventConsumer, EventProvider } from './eventContext';
export { useEventProvider } from './useEventProvider';
export { useModulesEventProvider } from './useModulesEventProvider';
export { useEventHandler } from './useEventHandler';
export { useEventStream, type EventStream } from './useEventStream';
30 changes: 30 additions & 0 deletions packages/react/modules/event/src/useEventStream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useMemo } from 'react';

import { Observable, OperatorFunction } from 'rxjs';

import { FrameworkEventMap, filterEvent } from '@equinor/fusion-framework-module-event';
import { useEventProvider } from 'EventProvider';

export type EventStream<TKey extends keyof FrameworkEventMap = keyof FrameworkEventMap> =
Observable<FrameworkEventMap[TKey]>;

/**
* Hook for observing events
*
* @param key name of the event to filter out
* @param operator [optional] {@link OperatorFunction} for transforming the stream __must be memorized!__
*/
export const useEventStream = <
TKey extends keyof FrameworkEventMap = keyof FrameworkEventMap,
TData = FrameworkEventMap[TKey]
>(
key: TKey,
operator?: OperatorFunction<FrameworkEventMap[TKey], TData>
): Observable<TData> => {
const provider = useEventProvider();
return useMemo(() => {
return provider.event$.pipe(filterEvent(key), operator ?? ((x) => x as Observable<TData>));
}, [provider, key, operator]);
};

export default useEventStream;
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {

/**
* Hook for using the event module from the closes ModuleProvider
* @see {@link useModule}
*/
export const useModulesEventProvider = (): IEventModuleProvider | undefined =>
useModule<EventModule>(eventModuleKey);
17 changes: 16 additions & 1 deletion vue-press/src/.vuepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,22 @@ export default sidebar({
link: 'context/',
},
'app/',
'event/',
{
text: 'Event',
prefix: 'event/',
link: 'event/',
children: [
{
text: 'module',
link: 'README.md',
},
{
text: 'React',
link: 'react.md',
},
]

},
'navigation/',
'bookmark/',
'ag-grid/',
Expand Down
70 changes: 2 additions & 68 deletions vue-press/src/modules/event/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
title: Events
title: Event Module
category: Module
tag:
- event
- core
---

<ModuleBadge module="module-event" />
<ModuleBadge module="modules/event" package="@equinor/fusion-framework-module-event" />

## Concept

Expand Down Expand Up @@ -164,69 +164,3 @@ config.event.onBubble = (e) => {
ref.event.dispatch(e);
}
```

## React

<ModuleBadge module="/react/modules/event" package="@equinor/fusion-framework-react-module-event"/>

### EventProvider

example app:
```tsx
import { EventProvider } = from '@equinor/fusion-framework-react-module-event';
import { useFramework } = from '@equinor/fusion-framework-react-app/framework';
const Content = () => {
const framework = useFramework().modules.event;
return (
<EventProvider value={framework.modules.event}>
<InnerContent>
<EventProvider>
);
};
```
```tsx
const InnerContent = () => {
const eventProvider = useEventProvider();
useEventHandler('some_event', useCallback((event) => {
console.log('FRAMEWORK_EVENT', event.detail);
}, [eventProvider]));

const appEventProvider = useEventModuleProvider();
useEventHandler('some_event', useCallback((event) => {
console.log('APP_EVENT', event.detail);
}, [appEventProvider]));
}
```

### Hooks

#### useEventProvider

use `IEventModuleProvider` from current context see [EventProvider](#EventProvider)
```ts
import { useEventHandler } from '@equinor/fusion-framework-react-module-event';
```

#### useEventModuleProvider

use `IEventModuleProvider` from closes module provider

```ts
import { useEventModuleProvider } from '@equinor/fusion-framework-react-module-event';
```


#### useEventHandler
```ts
import { useEventHandler } from '@equinor/fusion-framework-react-module-event';

const MyHook = () => {
useEventHandler(
'onContextChange',
/** note that callback must be memorized */
useCallback((e) => {
console.log(e.detail);
}, [deps]);
);
}
```
118 changes: 118 additions & 0 deletions vue-press/src/modules/event/react.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
title: Event Module - React
category: Module
tag:
- react
- event
---

<ModuleBadge module="/react/modules/event" package="@equinor/fusion-framework-react-module-event"/>

```ts
import { useEventProvider } from '@equinor/fusion-framework-react-module-event';

/* fetch the `ÌEventModuleProvider` from the closes module provder */
const eventProvider = useEventProvider();
```

## EventProvider

if needed, the resolving of which `ÌEventModuleProvider` the `useEventProvider` will provide can be altered by using
the `EventProvider` component

**example app:**
```tsx
import { EventProvider, EventConsumer } = from '@equinor/fusion-framework-react-module-event';
import { useFramework } = from '@equinor/fusion-framework-react-app/framework';
const Content = () => {
const framework = useFramework().modules.event;
return (
<EventProvider value={framework.modules.event}>
<EventLogger />
<InlineEventConsumer />
<EventProvider>
);
};
```
```tsx
import { useEventHandler } = from '@equinor/fusion-framework-react-module-event';

const eventHandler = (event: FrameworkEventMap['some_event']) => {
console.log(event.detail);
};

const EventLogger = () => useEventHandler('some_event', eventHandler);
```

```tsx
import { EventConsumer } = from '@equinor/fusion-framework-react-module-event';

const InlineEventConsumer = () => (
<EventConsumer>
{
(provider) => provider.dispatch(
'some_event'),
{ detail: { foo: 'bar' } }
}
</EventConsumer>
)
``````

## Hooks

### useEventProvider

use `IEventModuleProvider` from current context see [EventProvider](#EventProvider)
```ts
import { useEventProvider } from '@equinor/fusion-framework-react-module-event';
```

### useEventModuleProvider

use `IEventModuleProvider` from closes module provider

```ts
import { useEventModuleProvider } from '@equinor/fusion-framework-react-module-event';
```


### useEventHandler
```ts
import { useEventHandler } from '@equinor/fusion-framework-react-module-event';

useEventHandler(
'onContextChange',
/** note that callback must be memorized */
useCallback((e) => {
console.log(e.detail);
}, [deps]);
);
```

### useEventStream

```ts
import { useEventStream, EventStream } from '@equinor/fusion-framework-react-module-event';

/* simple usage */
const { value: someEvent } = useObservableState(useEventStream('some_event'));

/* observe stream of events */
const someEvent$ = useEventStream(
'some_event',
/* note that callback must be memorized */
useCallback(
/* note react.useCallback cannot resolve source input */
(event$: EventStream<'some_event'>) => event$.pipe(
/* only some events */
filter(e => e.detail.foo === dep.foo),
/* mutate data */
map(e => e.detail)
),
[dep]
)
);
/* use state of stream */
const { value: foo } = useObservableState(someEvent$);

```

0 comments on commit 7aee3cf

Please sign in to comment.