Skip to content

Commit

Permalink
feat(hv-navigator): Support for behaviors with on-event trigger (#946)
Browse files Browse the repository at this point in the history
Add the ability to install event listener on the `<navigator>` tag, for
example to allow reloading the navigator document upon certain event
occurring.

---------

Co-authored-by: flochtililoch <[email protected]>
  • Loading branch information
flochtililoch and flochtililoch authored Sep 30, 2024
1 parent 19a6b32 commit 84f7b82
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 6 deletions.
3 changes: 2 additions & 1 deletion docs/reference_navigator.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ An example stack navigator.

## Structure

A `<navigator>` element can only appear as a direct and only child of a `<doc>` element. A `<navigator>` must contain at least one `<nav-route>` child. A `<navigator>` may contain one ore more `<behavior>` children. `<navigator>` elements can handle can only handle the `load` trigger.
A `<navigator>` element can only appear as a direct and only child of a `<doc>` element. A `<navigator>` must contain at least one `<nav-route>` child. A `<navigator>` may contain one ore more `<behavior>` children. `<navigator>` elements can handle can only handle the `load` and `on-event` triggers.

An example navigator with behavior.

```xml
<navigator id="root" type="stack">
<behavior trigger="load" ... />
<behavior trigger="on-event" ... />
<nav-route ... />
</navigator>
```
Expand Down
64 changes: 59 additions & 5 deletions src/core/components/hv-navigator/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as Behaviors from 'hyperview/src/services/behaviors';
import * as Contexts from 'hyperview/src/contexts';
import * as Dom from 'hyperview/src/services/dom';
import * as Events from 'hyperview/src/services/events';
import * as Logging from 'hyperview/src/services/logging';
import * as Namespaces from 'hyperview/src/services/namespaces';
import * as NavigationContext from 'hyperview/src/contexts/navigation';
Expand Down Expand Up @@ -43,8 +44,13 @@ export default class HvNavigator extends PureComponent<Props> {

componentDidMount() {
this.triggerLoadBehaviors();
Events.subscribe(this.onEventDispatch);
}

componentWillUnmout = () => {
Events.unsubscribe(this.onEventDispatch);
};

componentDidUpdate(prevProps: Props) {
if (prevProps.element === this.props.element) {
return;
Expand All @@ -54,18 +60,63 @@ export default class HvNavigator extends PureComponent<Props> {
this.triggerLoadBehaviors();
}

onEventDispatch = (eventName: string) => {
const onEventBehaviors = this.behaviorElements.filter(e => {
if (e.getAttribute(BEHAVIOR_ATTRIBUTES.TRIGGER) === TRIGGERS.ON_EVENT) {
const currentAttributeEventName:
| string
| null
| undefined = e.getAttribute('event-name');
const currentAttributeAction:
| string
| null
| undefined = e.getAttribute('action');
if (currentAttributeAction === 'dispatch-event') {
Logging.error(
new Error(
'trigger="on-event" and action="dispatch-event" cannot be used on the same element',
),
);
return false;
}
if (!currentAttributeEventName) {
Logging.error(
new Error('on-event trigger requires an event-name attribute'),
);
return false;
}
return currentAttributeEventName === eventName;
}
return false;
});
onEventBehaviors.forEach(behaviorElement => {
const handler = Behaviors.createActionHandler(
behaviorElement,
this.props.onUpdate,
);
if (!this.props.element) {
return;
}
handler(this.props.element);
});
};

/**
* Cache all behaviors with a `load` trigger
*/
updateBehaviorElements = () => {
const supportedTriggers: string[] = [TRIGGERS.LOAD, TRIGGERS.ON_EVENT];
if (this.props.element) {
this.behaviorElements = Dom.getBehaviorElements(
this.props.element,
).filter(e => {
const triggerAttr = e.getAttribute(BEHAVIOR_ATTRIBUTES.TRIGGER);
if (triggerAttr !== TRIGGERS.LOAD) {
const triggerAttr =
e.getAttribute(BEHAVIOR_ATTRIBUTES.TRIGGER) || 'press';
if (!supportedTriggers.includes(triggerAttr)) {
Logging.warn(
`Unsupported trigger '${triggerAttr}'. Only "load" is supported`,
`Unsupported trigger '${triggerAttr}'. Only "${supportedTriggers.join(
',',
)}" are supported`,
);
return false;
}
Expand All @@ -75,10 +126,13 @@ export default class HvNavigator extends PureComponent<Props> {
};

triggerLoadBehaviors = () => {
if (this.behaviorElements.length > 0 && this.props.element) {
const loadBehaviors = this.behaviorElements.filter(
e => e.getAttribute(BEHAVIOR_ATTRIBUTES.TRIGGER) === TRIGGERS.LOAD,
);
if (loadBehaviors.length > 0 && this.props.element) {
Behaviors.triggerBehaviors(
this.props.element,
this.behaviorElements,
loadBehaviors,
this.props.onUpdate,
);
}
Expand Down

0 comments on commit 84f7b82

Please sign in to comment.