UNPKG

reblend-ui

Version:

Utilities for creating robust overlay components

133 lines (132 loc) 5.02 kB
"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 });