UNPKG

@codegouvfr/react-dsfr

Version:

French State Design System React integration library

147 lines (120 loc) 4.3 kB
/*! DSFR v1.8.5 | SPDX-License-Identifier: MIT | License-Filename: LICENSE.md | restricted use (see terms and conditions) */ const config = { prefix: 'fr', namespace: 'dsfr', organisation: '@gouvfr', version: '1.8.5' }; const api = window[config.namespace]; const NavigationSelector = { NAVIGATION: api.internals.ns.selector('nav'), COLLAPSE: `${api.internals.ns.selector('nav__item')} > ${api.internals.ns.selector('collapse')}`, ITEM: api.internals.ns.selector('nav__item'), ITEM_RIGHT: api.internals.ns('nav__item--align-right'), MENU: api.internals.ns.selector('menu') }; class NavigationItem extends api.core.Instance { constructor () { super(); this._isRightAligned = false; } static get instanceClassName () { return 'NavigationItem'; } init () { this.addAscent(api.core.DisclosureEmission.ADDED, this.calculate.bind(this)); this.addAscent(api.core.DisclosureEmission.REMOVED, this.calculate.bind(this)); this.isResizing = true; this.calculate(); } resize () { this.calculate(); } calculate () { const collapse = this.element.getDescendantInstances(api.core.Collapse.instanceClassName, null, true)[0]; if (collapse && this.isBreakpoint(api.core.Breakpoints.LG) && collapse.element.node.matches(NavigationSelector.MENU)) { const right = this.element.node.parentElement.getBoundingClientRect().right; // todo: ne fonctionne que si la nav fait 100% du container const width = collapse.element.node.getBoundingClientRect().width; const left = this.element.node.getBoundingClientRect().left; this.isRightAligned = left + width > right; } else this.isRightAligned = false; } get isRightAligned () { return this._isRightAligned; } set isRightAligned (value) { if (this._isRightAligned === value) return; this._isRightAligned = value; if (value) api.internals.dom.addClass(this.element.node, NavigationSelector.ITEM_RIGHT); else api.internals.dom.removeClass(this.element.node, NavigationSelector.ITEM_RIGHT); } } const NavigationMousePosition = { NONE: -1, INSIDE: 0, OUTSIDE: 1 }; class Navigation extends api.core.CollapsesGroup { static get instanceClassName () { return 'Navigation'; } init () { super.init(); this.clicked = false; this.out = false; this.listen('focusout', this.focusOut.bind(this)); this.listen('mousedown', this.down.bind(this)); } validate (member) { return member.element.node.matches(NavigationSelector.COLLAPSE); } down (e) { if (!this.isBreakpoint(api.core.Breakpoints.LG) || this.index === -1 || !this.current) return; this.position = this.current.node.contains(e.target) ? NavigationMousePosition.INSIDE : NavigationMousePosition.OUTSIDE; this.requestPosition(); } focusOut (e) { if (!this.isBreakpoint(api.core.Breakpoints.LG)) return; this.out = true; this.requestPosition(); } requestPosition () { if (this.isRequesting) return; this.isRequesting = true; this.request(this.getPosition.bind(this)); } getPosition () { if (this.out) { switch (this.position) { case NavigationMousePosition.OUTSIDE: this.index = -1; break; case NavigationMousePosition.INSIDE: if (this.current && !this.current.node.contains(document.activeElement)) this.current.focus(); break; default: if (this.index > -1 && !this.current.hasFocus) this.index = -1; } } this.request(this.requested.bind(this)); } requested () { this.position = NavigationMousePosition.NONE; this.out = false; this.isRequesting = false; } get index () { return super.index; } set index (value) { if (value === -1 && this.current !== null && this.current.hasFocus) this.current.focus(); super.index = value; } } api.navigation = { Navigation: Navigation, NavigationItem: NavigationItem, NavigationMousePosition: NavigationMousePosition, NavigationSelector: NavigationSelector }; api.internals.register(api.navigation.NavigationSelector.NAVIGATION, api.navigation.Navigation); api.internals.register(api.navigation.NavigationSelector.ITEM, api.navigation.NavigationItem); //# sourceMappingURL=navigation.module.js.map