@codegouvfr/react-dsfr
Version:
French State Design System React integration library
147 lines (120 loc) • 4.3 kB
JavaScript
/*! 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