From 84f7b8218580bee882fb9f6fdd203597b0eeb5d5 Mon Sep 17 00:00:00 2001 From: Florent Bonomo Date: Mon, 30 Sep 2024 09:07:15 -0700 Subject: [PATCH] feat(hv-navigator): Support for behaviors with `on-event` trigger (#946) Add the ability to install event listener on the `` tag, for example to allow reloading the navigator document upon certain event occurring. --------- Co-authored-by: flochtililoch --- docs/reference_navigator.md | 3 +- src/core/components/hv-navigator/index.tsx | 64 ++++++++++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/docs/reference_navigator.md b/docs/reference_navigator.md index a79e91b63..d3c41d5cf 100644 --- a/docs/reference_navigator.md +++ b/docs/reference_navigator.md @@ -18,13 +18,14 @@ An example stack navigator. ## Structure -A `` element can only appear as a direct and only child of a `` element. A `` must contain at least one `` child. A `` may contain one ore more `` children. `` elements can handle can only handle the `load` trigger. +A `` element can only appear as a direct and only child of a `` element. A `` must contain at least one `` child. A `` may contain one ore more `` children. `` elements can handle can only handle the `load` and `on-event` triggers. An example navigator with behavior. ```xml + ``` diff --git a/src/core/components/hv-navigator/index.tsx b/src/core/components/hv-navigator/index.tsx index 059434ced..5613d05f1 100644 --- a/src/core/components/hv-navigator/index.tsx +++ b/src/core/components/hv-navigator/index.tsx @@ -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'; @@ -43,8 +44,13 @@ export default class HvNavigator extends PureComponent { componentDidMount() { this.triggerLoadBehaviors(); + Events.subscribe(this.onEventDispatch); } + componentWillUnmout = () => { + Events.unsubscribe(this.onEventDispatch); + }; + componentDidUpdate(prevProps: Props) { if (prevProps.element === this.props.element) { return; @@ -54,18 +60,63 @@ export default class HvNavigator extends PureComponent { 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; } @@ -75,10 +126,13 @@ export default class HvNavigator extends PureComponent { }; 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, ); }