@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
90 lines • 12.3 kB
JavaScript
import { BehaviorSubject, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
export class FocusIndicator {
/** Apply a class when the item is focused */
set isFocused(isFocused) {
// update the class on the element
isFocused
? this._renderer.addClass(this._element, 'ux-focus-indicator-active')
: this._renderer.removeClass(this._element, 'ux-focus-indicator-active');
// emit the focus state
this.isFocused$.next(isFocused);
}
/** Provide a convenience getter to allow access to focus state without a subscription */
get isFocused() {
return this.isFocused$.value;
}
constructor(_element, _focusMonitor, _renderer, _options, _focusIndicatorOrigin) {
this._element = _element;
this._focusMonitor = _focusMonitor;
this._renderer = _renderer;
this._options = _options;
this._focusIndicatorOrigin = _focusIndicatorOrigin;
/** An observable to monitor the focus state */
this.isFocused$ = new BehaviorSubject(false);
/** An observable to monitor the focus origin */
this.origin$ = new Subject();
/** Remove all subscriptions on destroy */
this._onDestroy = new Subject();
// check if the element is already being monitored
if (!_element.classList.contains('ux-focus-indicator')) {
this.initialise();
}
}
/** Setup the focus monitoring */
initialise() {
// add a class to the element to specify we are controlling the focus
this._renderer.addClass(this._element, 'ux-focus-indicator');
// watch for any changes to the focus state
this._focusMonitor
.monitor(this._element, this._options.checkChildren)
.pipe(takeUntil(this._onDestroy))
.subscribe(this.onFocusChange.bind(this));
}
/** Focus the element with a specific origin */
focus(origin, options) {
this._focusIndicatorOrigin.setOrigin(origin);
this._element.focus(options);
}
/** Tear down the subscriptions */
destroy() {
this._onDestroy.next();
this._onDestroy.complete();
this.isFocused$.complete();
this._focusMonitor.stopMonitoring(this._element);
}
/** Allow the options to be updates */
setOptions(options) {
this._options = { ...this._options, ...options };
}
/** Monitor changes to an elements focus state */
onFocusChange(origin) {
// if the origin is null then we blurred
if (origin === null) {
this.isFocused = false;
this.origin$.next(null);
return;
}
// get the origin if there is one
const syntheticOrigin = this._focusIndicatorOrigin.getOrigin();
// emit the origin
this.origin$.next(syntheticOrigin || origin);
switch (syntheticOrigin || origin) {
case 'mouse':
this.isFocused = this._options.mouseFocusIndicator;
break;
case 'touch':
this.isFocused = this._options.touchFocusIndicator;
break;
case 'keyboard':
this.isFocused = this._options.keyboardFocusIndicator;
break;
case 'program':
this.isFocused = this._options.programmaticFocusIndicator;
break;
default:
this.isFocused = false;
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9jdXMtaW5kaWNhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2RpcmVjdGl2ZXMvYWNjZXNzaWJpbGl0eS9mb2N1cy1pbmRpY2F0b3IvZm9jdXMtaW5kaWNhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxlQUFlLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ2hELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUkzQyxNQUFNLE9BQU8sY0FBYztJQUN6Qiw2Q0FBNkM7SUFDN0MsSUFBSSxTQUFTLENBQUMsU0FBa0I7UUFDOUIsa0NBQWtDO1FBQ2xDLFNBQVM7WUFDUCxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSwyQkFBMkIsQ0FBQztZQUNyRSxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSwyQkFBMkIsQ0FBQyxDQUFDO1FBRTNFLHVCQUF1QjtRQUN2QixJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBRUQseUZBQXlGO0lBQ3pGLElBQUksU0FBUztRQUNYLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUM7SUFDL0IsQ0FBQztJQVdELFlBQ21CLFFBQXFCLEVBQ3JCLGFBQTJCLEVBQzNCLFNBQW9CLEVBQzdCLFFBQStCLEVBQ3RCLHFCQUFrRDtRQUpsRCxhQUFRLEdBQVIsUUFBUSxDQUFhO1FBQ3JCLGtCQUFhLEdBQWIsYUFBYSxDQUFjO1FBQzNCLGNBQVMsR0FBVCxTQUFTLENBQVc7UUFDN0IsYUFBUSxHQUFSLFFBQVEsQ0FBdUI7UUFDdEIsMEJBQXFCLEdBQXJCLHFCQUFxQixDQUE2QjtRQWRyRSwrQ0FBK0M7UUFDdEMsZUFBVSxHQUFHLElBQUksZUFBZSxDQUFVLEtBQUssQ0FBQyxDQUFDO1FBRTFELGdEQUFnRDtRQUN2QyxZQUFPLEdBQUcsSUFBSSxPQUFPLEVBQWUsQ0FBQztRQUU5QywwQ0FBMEM7UUFDekIsZUFBVSxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7UUFTaEQsa0RBQWtEO1FBQ2xELElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQyxFQUFFLENBQUM7WUFDdkQsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ3BCLENBQUM7SUFDSCxDQUFDO0lBRUQsaUNBQWlDO0lBQ3pCLFVBQVU7UUFDaEIscUVBQXFFO1FBQ3JFLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztRQUU3RCwyQ0FBMkM7UUFDM0MsSUFBSSxDQUFDLGFBQWE7YUFDZixPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQzthQUNuRCxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQzthQUNoQyxTQUFTLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUM5QyxDQUFDO0lBRUQsK0NBQStDO0lBQy9DLEtBQUssQ0FBQyxNQUFvQixFQUFFLE9BQXFDO1FBQy9ELElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDN0MsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDL0IsQ0FBQztJQUVELGtDQUFrQztJQUNsQyxPQUFPO1FBQ0wsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDM0IsSUFBSSxDQUFDLGFBQWEsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFRCxzQ0FBc0M7SUFDdEMsVUFBVSxDQUFDLE9BQThCO1FBQ3ZDLElBQUksQ0FBQyxRQUFRLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsR0FBRyxPQUFPLEVBQUUsQ0FBQztJQUNuRCxDQUFDO0lBRUQsaURBQWlEO0lBQ3pDLGFBQWEsQ0FBQyxNQUFtQjtRQUN2Qyx3Q0FBd0M7UUFDeEMsSUFBSSxNQUFNLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDcEIsSUFBSSxDQUFDLFNBQVMsR0FBRyxLQUFLLENBQUM7WUFDdkIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDeEIsT0FBTztRQUNULENBQUM7UUFFRCxpQ0FBaUM7UUFDakMsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFNBQVMsRUFBRSxDQUFDO1FBRS9ELGtCQUFrQjtRQUNsQixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxlQUFlLElBQUksTUFBTSxDQUFDLENBQUM7UUFFN0MsUUFBUSxlQUFlLElBQUksTUFBTSxFQUFFLENBQUM7WUFDbEMsS0FBSyxPQUFPO2dCQUNWLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQztnQkFDbkQsTUFBTTtZQUVSLEtBQUssT0FBTztnQkFDVixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsbUJBQW1CLENBQUM7Z0JBQ25ELE1BQU07WUFFUixLQUFLLFVBQVU7Z0JBQ2IsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLHNCQUFzQixDQUFDO2dCQUN0RCxNQUFNO1lBRVIsS0FBSyxTQUFTO2dCQUNaLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQywwQkFBMEIsQ0FBQztnQkFDMUQsTUFBTTtZQUVSO2dCQUNFLElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO1FBQzNCLENBQUM7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBGb2N1c01vbml0b3IsIEZvY3VzT3JpZ2luIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2ExMXknO1xuaW1wb3J0IHsgUmVuZGVyZXIyIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IEZvY3VzSW5kaWNhdG9yT3B0aW9ucyB9IGZyb20gJy4vZm9jdXMtaW5kaWNhdG9yLW9wdGlvbnMuaW50ZXJmYWNlJztcbmltcG9ydCB7IEZvY3VzSW5kaWNhdG9yT3JpZ2luU2VydmljZSB9IGZyb20gJy4vZm9jdXMtaW5kaWNhdG9yLW9yaWdpbi9mb2N1cy1pbmRpY2F0b3Itb3JpZ2luLnNlcnZpY2UnO1xuXG5leHBvcnQgY2xhc3MgRm9jdXNJbmRpY2F0b3Ige1xuICAvKiogQXBwbHkgYSBjbGFzcyB3aGVuIHRoZSBpdGVtIGlzIGZvY3VzZWQgKi9cbiAgc2V0IGlzRm9jdXNlZChpc0ZvY3VzZWQ6IGJvb2xlYW4pIHtcbiAgICAvLyB1cGRhdGUgdGhlIGNsYXNzIG9uIHRoZSBlbGVtZW50XG4gICAgaXNGb2N1c2VkXG4gICAgICA/IHRoaXMuX3JlbmRlcmVyLmFkZENsYXNzKHRoaXMuX2VsZW1lbnQsICd1eC1mb2N1cy1pbmRpY2F0b3ItYWN0aXZlJylcbiAgICAgIDogdGhpcy5fcmVuZGVyZXIucmVtb3ZlQ2xhc3ModGhpcy5fZWxlbWVudCwgJ3V4LWZvY3VzLWluZGljYXRvci1hY3RpdmUnKTtcblxuICAgIC8vIGVtaXQgdGhlIGZvY3VzIHN0YXRlXG4gICAgdGhpcy5pc0ZvY3VzZWQkLm5leHQoaXNGb2N1c2VkKTtcbiAgfVxuXG4gIC8qKiBQcm92aWRlIGEgY29udmVuaWVuY2UgZ2V0dGVyIHRvIGFsbG93IGFjY2VzcyB0byBmb2N1cyBzdGF0ZSB3aXRob3V0IGEgc3Vic2NyaXB0aW9uICovXG4gIGdldCBpc0ZvY3VzZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNGb2N1c2VkJC52YWx1ZTtcbiAgfVxuXG4gIC8qKiBBbiBvYnNlcnZhYmxlIHRvIG1vbml0b3IgdGhlIGZvY3VzIHN0YXRlICovXG4gIHJlYWRvbmx5IGlzRm9jdXNlZCQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcblxuICAvKiogQW4gb2JzZXJ2YWJsZSB0byBtb25pdG9yIHRoZSBmb2N1cyBvcmlnaW4gKi9cbiAgcmVhZG9ubHkgb3JpZ2luJCA9IG5ldyBTdWJqZWN0PEZvY3VzT3JpZ2luPigpO1xuXG4gIC8qKiBSZW1vdmUgYWxsIHN1YnNjcmlwdGlvbnMgb24gZGVzdHJveSAqL1xuICBwcml2YXRlIHJlYWRvbmx5IF9vbkRlc3Ryb3kgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgX2VsZW1lbnQ6IEhUTUxFbGVtZW50LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgX2ZvY3VzTW9uaXRvcjogRm9jdXNNb25pdG9yLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgX3JlbmRlcmVyOiBSZW5kZXJlcjIsXG4gICAgcHJpdmF0ZSBfb3B0aW9uczogRm9jdXNJbmRpY2F0b3JPcHRpb25zLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgX2ZvY3VzSW5kaWNhdG9yT3JpZ2luOiBGb2N1c0luZGljYXRvck9yaWdpblNlcnZpY2VcbiAgKSB7XG4gICAgLy8gY2hlY2sgaWYgdGhlIGVsZW1lbnQgaXMgYWxyZWFkeSBiZWluZyBtb25pdG9yZWRcbiAgICBpZiAoIV9lbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygndXgtZm9jdXMtaW5kaWNhdG9yJykpIHtcbiAgICAgIHRoaXMuaW5pdGlhbGlzZSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBTZXR1cCB0aGUgZm9jdXMgbW9uaXRvcmluZyAqL1xuICBwcml2YXRlIGluaXRpYWxpc2UoKTogdm9pZCB7XG4gICAgLy8gYWRkIGEgY2xhc3MgdG8gdGhlIGVsZW1lbnQgdG8gc3BlY2lmeSB3ZSBhcmUgY29udHJvbGxpbmcgdGhlIGZvY3VzXG4gICAgdGhpcy5fcmVuZGVyZXIuYWRkQ2xhc3ModGhpcy5fZWxlbWVudCwgJ3V4LWZvY3VzLWluZGljYXRvcicpO1xuXG4gICAgLy8gd2F0Y2ggZm9yIGFueSBjaGFuZ2VzIHRvIHRoZSBmb2N1cyBzdGF0ZVxuICAgIHRoaXMuX2ZvY3VzTW9uaXRvclxuICAgICAgLm1vbml0b3IodGhpcy5fZWxlbWVudCwgdGhpcy5fb3B0aW9ucy5jaGVja0NoaWxkcmVuKVxuICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSkpXG4gICAgICAuc3Vic2NyaWJlKHRoaXMub25Gb2N1c0NoYW5nZS5iaW5kKHRoaXMpKTtcbiAgfVxuXG4gIC8qKiBGb2N1cyB0aGUgZWxlbWVudCB3aXRoIGEgc3BlY2lmaWMgb3JpZ2luICovXG4gIGZvY3VzKG9yaWdpbj86IEZvY3VzT3JpZ2luLCBvcHRpb25zPzogeyBwcmV2ZW50U2Nyb2xsPzogYm9vbGVhbiB9KTogdm9pZCB7XG4gICAgdGhpcy5fZm9jdXNJbmRpY2F0b3JPcmlnaW4uc2V0T3JpZ2luKG9yaWdpbik7XG4gICAgdGhpcy5fZWxlbWVudC5mb2N1cyhvcHRpb25zKTtcbiAgfVxuXG4gIC8qKiBUZWFyIGRvd24gdGhlIHN1YnNjcmlwdGlvbnMgKi9cbiAgZGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLl9vbkRlc3Ryb3kubmV4dCgpO1xuICAgIHRoaXMuX29uRGVzdHJveS5jb21wbGV0ZSgpO1xuICAgIHRoaXMuaXNGb2N1c2VkJC5jb21wbGV0ZSgpO1xuICAgIHRoaXMuX2ZvY3VzTW9uaXRvci5zdG9wTW9uaXRvcmluZyh0aGlzLl9lbGVtZW50KTtcbiAgfVxuXG4gIC8qKiBBbGxvdyB0aGUgb3B0aW9ucyB0byBiZSB1cGRhdGVzICovXG4gIHNldE9wdGlvbnMob3B0aW9uczogRm9jdXNJbmRpY2F0b3JPcHRpb25zKTogdm9pZCB7XG4gICAgdGhpcy5fb3B0aW9ucyA9IHsgLi4udGhpcy5fb3B0aW9ucywgLi4ub3B0aW9ucyB9O1xuICB9XG5cbiAgLyoqIE1vbml0b3IgY2hhbmdlcyB0byBhbiBlbGVtZW50cyBmb2N1cyBzdGF0ZSAqL1xuICBwcml2YXRlIG9uRm9jdXNDaGFuZ2Uob3JpZ2luOiBGb2N1c09yaWdpbik6IHZvaWQge1xuICAgIC8vIGlmIHRoZSBvcmlnaW4gaXMgbnVsbCB0aGVuIHdlIGJsdXJyZWRcbiAgICBpZiAob3JpZ2luID09PSBudWxsKSB7XG4gICAgICB0aGlzLmlzRm9jdXNlZCA9IGZhbHNlO1xuICAgICAgdGhpcy5vcmlnaW4kLm5leHQobnVsbCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gZ2V0IHRoZSBvcmlnaW4gaWYgdGhlcmUgaXMgb25lXG4gICAgY29uc3Qgc3ludGhldGljT3JpZ2luID0gdGhpcy5fZm9jdXNJbmRpY2F0b3JPcmlnaW4uZ2V0T3JpZ2luKCk7XG5cbiAgICAvLyBlbWl0IHRoZSBvcmlnaW5cbiAgICB0aGlzLm9yaWdpbiQubmV4dChzeW50aGV0aWNPcmlnaW4gfHwgb3JpZ2luKTtcblxuICAgIHN3aXRjaCAoc3ludGhldGljT3JpZ2luIHx8IG9yaWdpbikge1xuICAgICAgY2FzZSAnbW91c2UnOlxuICAgICAgICB0aGlzLmlzRm9jdXNlZCA9IHRoaXMuX29wdGlvbnMubW91c2VGb2N1c0luZGljYXRvcjtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ3RvdWNoJzpcbiAgICAgICAgdGhpcy5pc0ZvY3VzZWQgPSB0aGlzLl9vcHRpb25zLnRvdWNoRm9jdXNJbmRpY2F0b3I7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdrZXlib2FyZCc6XG4gICAgICAgIHRoaXMuaXNGb2N1c2VkID0gdGhpcy5fb3B0aW9ucy5rZXlib2FyZEZvY3VzSW5kaWNhdG9yO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAncHJvZ3JhbSc6XG4gICAgICAgIHRoaXMuaXNGb2N1c2VkID0gdGhpcy5fb3B0aW9ucy5wcm9ncmFtbWF0aWNGb2N1c0luZGljYXRvcjtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRoaXMuaXNGb2N1c2VkID0gZmFsc2U7XG4gICAgfVxuICB9XG59XG4iXX0=