reblend-ui
Version:
Utilities for creating robust overlay components
133 lines (132 loc) • 5.02 kB
JavaScript
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _querySelectorAll = require("dom-helpers/querySelectorAll");
var _reblendjs = require("reblendjs");
var Reblend = _reblendjs;
var _reblendHooks = require("reblend-hooks");
var _SelectableContext = require("./SelectableContext");
var _TabContext = require("./TabContext");
var _DataKey = require("./DataKey");
var _NavItem = require("./NavItem");
const noop = () => {};
const EVENT_KEY_ATTR = (0, _DataKey.dataAttr)('event-key');
const Nav = class
/* @Reblend: Transformed from function to class */
extends Reblend.Reblend {
static ELEMENT_NAME = "Nav";
constructor() {
super();
}
async initState() {
// A ref and forceUpdate for refocus, b/c we only want to trigger when needed
// and don't want to reset the set in the effect
const forceUpdate = _reblendHooks.useForceUpdate.bind(this)();
this.state.forceUpdate = forceUpdate;
const needsRefocusRef = _reblendjs.useRef.bind(this)(false);
this.state.needsRefocusRef = needsRefocusRef;
const [parentOnSelect] = _reblendjs.useContext.bind(this)(_SelectableContext.default, "parentOnSelect");
this.state.parentOnSelect = parentOnSelect;
const [tabContext] = _reblendjs.useContext.bind(this)(_TabContext.default, "tabContext");
this.state.tabContext = tabContext;
let getControlledId, getControllerId;
this.state.getControlledId = getControlledId;
this.state.getControllerId = getControllerId;
if (this.state.tabContext) {
this.props.role = this.props.role || 'tablist';
this.props.activeKey = this.state.tabContext.activeKey;
// TODO: do we need to duplicate these?
this.state.getControlledId = this.state.tabContext.getControlledId;
this.state.getControllerId = this.state.tabContext.getControllerId;
}
const listNode = _reblendjs.useRef.bind(this)(null);
this.state.listNode = listNode;
const getNextActiveTab = offset => {
const currentListNode = this.state.listNode.current;
if (!currentListNode) return null;
const items = (0, _querySelectorAll.default)(currentListNode, `[${EVENT_KEY_ATTR}]:not([aria-disabled=true])`);
const activeChild = currentListNode.querySelector('[aria-selected=true]');
if (!activeChild || activeChild !== document.activeElement) return null;
const index = items.indexOf(activeChild);
if (index === -1) return null;
let nextIndex = index + offset;
if (nextIndex >= items.length) nextIndex = 0;
if (nextIndex < 0) nextIndex = items.length - 1;
return items[nextIndex];
};
this.state.getNextActiveTab = getNextActiveTab;
const handleSelect = (key, event) => {
if (key == null) return;
this.props.onSelect?.(key, event);
this.state.parentOnSelect?.(key, event);
};
this.state.handleSelect = handleSelect;
const handleKeyDown = event => {
this.props.onKeyDown?.(event);
if (!this.state.tabContext) {
return;
}
let nextActiveChild;
switch (event.key) {
case 'ArrowLeft':
case 'ArrowUp':
nextActiveChild = this.state.getNextActiveTab(-1);
break;
case 'ArrowRight':
case 'ArrowDown':
nextActiveChild = this.state.getNextActiveTab(1);
break;
default:
return;
}
if (!nextActiveChild) return;
event.preventDefault();
this.state.handleSelect(nextActiveChild.dataset[(0, _DataKey.dataProp)('EventKey')] || null, event);
this.state.needsRefocusRef.current = true;
this.state.forceUpdate();
};
this.state.handleKeyDown = handleKeyDown;
_reblendjs.useEffect.bind(this)(() => {
if (this.state.listNode.current && this.state.needsRefocusRef.current) {
const activeChild = this.state.listNode.current.querySelector(`[${EVENT_KEY_ATTR}][aria-selected=true]`);
activeChild?.focus();
}
this.state.needsRefocusRef.current = false;
});
const mergedRef = _reblendHooks.useMergedRefs.bind(this)(ref, this.state.listNode);
this.state.mergedRef = mergedRef;
}
async initProps({
// Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
as: Component = 'div',
onSelect,
activeKey,
role,
onKeyDown,
ref,
...props
}) {
this.props = {};
this.props.Component = Component;
this.props.onSelect = onSelect;
this.props.activeKey = activeKey;
this.props.role = role;
this.props.onKeyDown = onKeyDown;
this.props.ref = ref;
this.props = {
...this.props,
...props
};
}
async html() {
return Reblend.Reblend.construct.bind(this)(this.props.Component, {
...this.props,
onKeyDown: this.state.handleKeyDown,
ref: this.state.mergedRef,
role: this.props.role
});
}
};
var _default = exports.default = Object.assign(Nav, {
Item: _NavItem.default
});