PageSourceSearch

https://www.georisques.gouv.fr/libraries/dsfr/dist/dsfr.module.js?tlugul

js georisques.gouv.fr collected 2026-09-24 09:02:59 UTC 170,261 bytes, 6,536 lines download raw bytes

vendor: 8,009 bytes, lines 1-371
1/*! DSFR v1.12.1 | SPDX-License-Identifier: MIT | License-Filename: LICENSE.md | restricted use (see terms and conditions) */
2
3class State {
4  constructor () {
5    this.modules = {};
6  }
7
8  create (ModuleClass) {
9    const module = new ModuleClass();
10    this.modules[module.type] = module;
11  }
12
13  getModule (type) {
14    return this.modules[type];
15  }
16
17  add (type, item) {
18    this.modules[type].add(item);
19  }
20
21  remove (type, item) {
22    this.modules[type].remove(item);
23  }
24
25  get isActive () {
26    return this._isActive;
27  }
28
29  set isActive (value) {
30    if (value === this._isActive) return;
31    this._isActive = value;
32    const values = Object.keys(this.modules).map((e) => {
33      return this.modules[e];
34    });
35    if (value) {
36      for (const module of values) {
37        module.activate();
38      }
39    } else {
40      for (const module of values) {
41        module.deactivate();
42      }
43    }
44  }
45
46  get isLegacy () {
47    return this._isLegacy;
48  }
49
50  set isLegacy (value) {
51    if (value === this._isLegacy) return;
52    this._isLegacy = value;
53  }
54}
55
56const state = new State();
57
58const config = {
59  prefix: 'fr',
60  namespace: 'dsfr',
61  organisation: '@gouvfr',
62  version: '1.12.1'
63};
64
65class LogLevel {
66  constructor (level, light, dark, logger) {
67    this.level = level;
68    this.light = light;
69    this.dark = dark;
70
71    switch (logger) {
72      case 'warn':
73        this.logger = console.warn;
74        break;
75
76      case 'error':
77        this.logger = console.error;
78        break;
79
80      default:
81        this.logger = console.log;
82    }
83  }
84
85  log (...values) {
86    const message = new Message(config.namespace);
87    for (const value of values) message.add(value);
88    this.print(message);
89  }
90
91  print (message) {
92    message.setColor(this.color);
93    this.logger.apply(console, message.getMessage());
94  }
95
96  get color () {
97    return window.matchMedia('(prefers-color-scheme: dark)').matches ? this.dark : this.light;
98  }
99}
100
101class Message {
102  constructor (domain) {
103    this.inputs = ['%c'];
104    this.styles = ['font-family:Marianne', 'line-height: 1.5'];
105    this.objects = [];
106
107    if (domain) this.add(`${domain} :`);
108  }
109
110  add (value) {
111    switch (typeof value) {
112      case 'object':
113      case 'function':
114        this.inputs.push('%o ');
115        this.objects.push(value);
116        break;
117
118      default:
119        this.inputs.push(`${value} `);
120    }
121  }
122
123  setColor (color) {
124    this.styles.push(`color:${color}`);
125  }
126
127  getMessage () {
128    return [this.inputs.join(''), this.styles.join(';'), ...this.objects];
129  }
130}
131
132const LEVELS = {
133  log: new LogLevel(0, '#616161', '#989898'),
134  debug: new LogLevel(1, '#000091', '#8B8BFF'),
135  info: new LogLevel(2, '#007c3b', '#00ed70'),
136  warn: new LogLevel(3, '#ba4500', '#fa5c00', 'warn'),
137  error: new LogLevel(4, '#D80600', '#FF4641', 'error')
138};
139
140class Inspector {
141  constructor () {
142    this.level = 2;
143
144    for (const id in LEVELS) {
145      const level = LEVELS[id];
146      this[id] = (...msgs) => {
147        if (this.level <= level.level) level.log.apply(level, msgs);
148      };
149      this[id].print = level.print.bind(level);
150    }
151  }
152
153  state () {
154    const message = new Message();
155    message.add(state);
156    this.log.print(message);
157  }
158
159  tree () {
160    const stage = state.getModule('stage');
161    if (!stage) return;
162    const message = new Message();
163    this._branch(stage.root, 0, message);
164    this.log.print(message);
165  }
166
167  _branch (element, space, message) {
168    let branch = '';
169    if (space > 0) {
170      let indent = '';
171      for (let i = 0; i < space; i++) indent += '    ';
172      // branch += indent + '|\n';
173      branch += indent + '└─ ';
174    }
175    branch += `[${element.id}] ${element.html}`;
176    message.add(branch);
177    message.add({ '@': element });
178    message.add('\n');
179    for (const child of element.children) branch += this._branch(child, space + 1, message);
180  }
181}
182
183const inspector = new Inspector();
184
185const startAtDomContentLoaded = (callback) => {
186  if (document.readyState !== 'loading') window.requestAnimationFrame(callback);
187  else document.addEventListener('DOMContentLoaded', callback);
188};
189
190const startAuto = (callback) => {
191  // detect
192  startAtDomContentLoaded(callback);
193};
194
195const Modes = {
196  AUTO: 'auto',
197  MANUAL: 'manual',
198  RUNTIME: 'runtime',
199  LOADED: 'loaded',
200  VUE: 'vue',
201  ANGULAR: 'angular',
202  REACT: 'react'
203};
204
205class Options {
206  constructor () {
207    this._mode = Modes.AUTO;
208    this.isStarted = false;
209    this.starting = this.start.bind(this);
210    this.preventManipulation = false;
211  }
212
213  configure (settings = {}, start, query) {
214    this.startCallback = start;
215    const isProduction = settings.production && (!query || query.production !== 'false');
216    switch (true) {
217      case query && !isNaN(query.level):
218        inspector.level = Number(query.level);
219        break;
220
221      case query && query.verbose && (query.verbose === 'true' || query.verbose === 1):
222        inspector.level = 0;
223        break;
224
225      case isProduction:
226        inspector.level = 999;
227        break;
228
229      case settings.verbose:
230        inspector.level = 0;
231        break;
232    }
233    inspector.info(`version ${config.version}`);
234    this.mode = settings.mode || Modes.AUTO;
235  }
236
237  set mode (value) {
238    switch (value) {
239      case Modes.AUTO:
240        this.preventManipulation = false;
241        startAuto(this.starting);
242        break;
243
244      case Modes.LOADED:
245        this.preventManipulation = false;
246        startAtDomContentLoaded(this.starting);
247        break;
248
249      case Modes.RUNTIME:
250        this.preventManipulation = false;
251        this.start();
252        break;
253
254      case Modes.MANUAL:
255        this.preventManipulation = false;
256        break;
257
258      case Modes.VUE:
259        this.preventManipulation = true;
260        break;
261
262      case Modes.ANGULAR:
263        this.preventManipulation = true;
264        break;
265
266      case Modes.REACT:
267        this.preventManipulation = true;
268        break;
269
270      default:
271        inspector.error('Illegal mode');
272        return;
273    }
274
275    this._mode = value;
276    inspector.info(`mode set to ${value}`);
277  }
278
279  get mode () {
280    return this._mode;
281  }
282
283  start () {
284    inspector.info('start');
285    this.startCallback();
286  }
287}
288
289const options = new Options();
290
291class Collection {
292  constructor () {
293    this._collection = [];
294  }
295
296  forEach (callback) {
297    this._collection.forEach(callback);
298  }
299
300  map (callback) {
301    return this._collection.map(callback);
302  }
303
304  get length () {
305    return this._collection.length;
306  }
307
308  add (collectable) {
309    if (this._collection.indexOf(collectable) > -1) return false;
310    this._collection.push(collectable);
311    if (this.onAdd) this.onAdd();
312    if (this.onPopulate && this._collection.length === 1) this.onPopulate();
313    return true;
314  }
315
316  remove (collectable) {
317    const index = this._collection.indexOf(collectable);
318    if (index === -1) return false;
319    this._collection.splice(index, 1);
320    if (this.onRemove) this.onRemove();
321    if (this.onEmpty && this._collection.length === 0) this.onEmpty();
322  }
323
324  execute (...args) {
325    for (const collectable of this._collection) if (collectable) collectable.apply(null, args);
326  }
327
328  clear () {
329    this._collection.length = 0;
330  }
331
332  clone () {
333    const clone = new Collection();
334    clone._collection = this._collection.slice();
335    return clone;
336  }
337
338  get collection () {
339    return this._collection;
340  }
341}
342
343class Module extends Collection {
344  constructor (type) {
345    super();
346    this.type = type;
347    this.isActive = false;
348  }
349
350  activate () {}
351  deactivate () {}
352}
353
354const ns = name => `${config.prefix}-${name}`;
355
356ns.selector = (name, notation) => {
357  if (notation === undefined) notation = '.';
358  return `${notation}${ns(name)}`;
359};
360
361ns.attr = (name) => `data-${ns(name)}`;
362
363ns.attr.selector = (name, value) => {
364  let result = ns.attr(name);
365  if (value !== undefined) result += `="${value}"`;
366  return `[${result}]`;
367};
368
369ns.event = (type) => `${config.namespace}.${type}`;
370
371ns.emission = (domain, type) => `emission:${domain}.${type}`;
vendor: 9,408 bytes, lines 371-679
371
372
373const querySelectorAllArray = (element, selectors) => Array.prototype.slice.call(element.querySelectorAll(selectors));
374
375const queryParentSelector = (element, selectors) => {
376  const parent = element.parentElement;
377  if (parent.matches(selectors)) return parent;
378  if (parent === document.documentElement) return null;
379  return queryParentSelector(parent, selectors);
380};
381
382class Registration {
383  constructor (selector, InstanceClass, creator) {
384    this.selector = selector;
385    this.InstanceClass = InstanceClass;
386    this.creator = creator;
387    this.instances = new Collection();
388    this.isIntroduced = false;
389    this._instanceClassName = this.InstanceClass.instanceClassName;
390    this._instanceClassNames = this.getInstanceClassNames(this.InstanceClass);
391    this._property = this._instanceClassName.substring(0, 1).toLowerCase() + this._instanceClassName.substring(1);
392    const dashed = this._instanceClassName
393      .replace(/[^a-zA-Z0-9]+/g, '-')
394      .replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
395      .replace(/([a-z])([A-Z])/g, '$1-$2')
396      .replace(/([0-9])([^0-9])/g, '$1-$2')
397      .replace(/([^0-9])([0-9])/g, '$1-$2')
398      .toLowerCase();
399    this._attribute = ns.attr(`js-${dashed}`);
400  }
401
402  getInstanceClassNames (InstanceClass) {
403    const prototype = Object.getPrototypeOf(InstanceClass);
404    if (!prototype || prototype.instanceClassName === 'Instance') return [InstanceClass.instanceClassName];
405    return [...this.getInstanceClassNames(prototype), InstanceClass.instanceClassName];
406  }
407
408  hasInstanceClassName (instanceClassName) {
409    return this._instanceClassNames.indexOf(instanceClassName) > -1;
410  }
411
412  introduce () {
413    if (this.isIntroduced) return;
414    this.isIntroduced = true;
415    state.getModule('stage').parse(document.documentElement, this);
416  }
417
418  parse (node, nonRecursive) {
419    const nodes = [];
420    if (node.matches && node.matches(this.selector)) nodes.push(node);
421    // eslint-disable-next-line no-useless-call
422    if (!nonRecursive && node.querySelectorAll && node.querySelector(this.selector)) nodes.push.apply(nodes, querySelectorAllArray(node, this.selector));
423    return nodes;
424  }
425
426  create (element) {
427    if (!element.node.matches(this.selector)) return;
428    const instance = new this.InstanceClass();
429    this.instances.add(instance);
430    return instance;
431  }
432
433  remove (instance) {
434    this.instances.remove(instance);
435  }
436
437  dispose () {
438    const instances = this.instances.collection;
439    for (let i = instances.length - 1; i > -1; i--) instances[i]._dispose();
440    this.creator = null;
441  }
442
443  get instanceClassName () {
444    return this._instanceClassName;
445  }
446
447  get instanceClassNames () {
448    return this._instanceClassNames;
449  }
450
451  get property () {
452    return this._property;
453  }
454
455  get attribute () {
456    return this._attribute;
457  }
458}
459
460class Register extends Module {
461  constructor () {
462    super('register');
463  }
464
465  register (selector, InstanceClass, creator) {
466    const registration = new Registration(selector, InstanceClass, creator);
467    this.add(registration);
468    if (state.isActive) registration.introduce();
469    return registration;
470  }
471
472  activate () {
473    for (const registration of this.collection) registration.introduce();
474  }
475
476  remove (registration) {
477    registration.dispose();
478    super.remove(registration);
479  }
480}
481
482let count = 0;
483
484class Element$1 {
485  constructor (node, id) {
486    if (!id) {
487      count++;
488      this.id = count;
489    } else this.id = id;
490    this.node = node;
491    this.attributeNames = [];
492    this.instances = [];
493    this._children = [];
494    this._parent = null;
495    this._projects = [];
496  }
497
498  get proxy () {
499    const scope = this;
500    if (!this._proxy) {
501      this._proxy = {
502        id: this.id,
503        get parent () {
504          return scope.parent ? scope.parent.proxy : null;
505        },
506        get children () {
507          return scope.children.map((child) => child.proxy);
508        }
509      };
510
511      for (const instance of this.instances) this._proxy[instance.registration.property] = instance.proxy;
512    }
513    return this._proxy;
514  }
515
516  get html () {
517    if (!this.node || !this.node.outerHTML) return '';
518    const end = this.node.outerHTML.indexOf('>');
519    return this.node.outerHTML.substring(0, end + 1);
520  }
521
522  project (registration) {
523    if (this._projects.indexOf(registration) === -1) this._projects.push(registration);
524  }
525
526  populate () {
527    const projects = this._projects.slice();
528    this._projects.length = 0;
529    for (const registration of projects) this.create(registration);
530  }
531
532  create (registration) {
533    if (this.hasInstance(registration.instanceClassName)) {
534      // inspector.debug(`failed creation, instance of ${registration.instanceClassName} already exists on element [${this.id}]`);
535      return;
536    }
537    inspector.debug(`create instance of ${registration.instanceClassName} on element [${this.id}]`);
538    const instance = registration.create(this);
539    this.instances.push(instance);
540    instance._config(this, registration);
541    if (this._proxy) this._proxy[registration.property] = instance.proxy;
542  }
543
544  remove (instance) {
545    const index = this.instances.indexOf(instance);
546    if (index > -1) this.instances.splice(index, 1);
547    if (this._proxy) delete this._proxy[instance.registration.property];
548  }
549
550  get parent () {
551    return this._parent;
552  }
553
554  get ascendants () {
555    return [this.parent, ...this.parent.ascendants];
556  }
557
558  get children () {
559    return this._children;
560  }
561
562  get descendants () {
563    const descendants = [...this._children];
564    this._children.forEach(child => descendants.push(...child.descendants));
565    return descendants;
566  }
567
568  // TODO : emit ascendant et descendant de changement ?
569
570  addChild (child, index) {
571    if (this._children.indexOf(child) > -1) return null;
572    child._parent = this;
573    if (!isNaN(index) && index > -1 && index < this._children.length) this._children.splice(index, 0, child);
574    else this._children.push(child);
575    return child;
576  }
577
578  removeChild (child) {
579    const index = this._children.indexOf(child);
580    if (index === -1) return null;
581    child._parent = null;
582    this._children.splice(index, 1);
583  }
584
585  emit (type, data) {
586    const elements = state.getModule('stage').collection;
587    const response = [];
588    for (const element of elements) response.push(...element._emit(type, data));
589    return response;
590  }
591
592  _emit (type, data) {
593    const response = [];
594    for (const instance of this.instances) response.push(...instance._emitter.emit(type, data));
595    return response;
596  }
597
598  ascend (type, data) {
599    if (this._parent) return this._parent._ascend(type, data);
600    return [];
601  }
602
603  _ascend (type, data) {
604    const response = [];
605    for (const instance of this.instances) response.push(...instance._ascent.emit(type, data));
606    if (this._parent) response.push(...this._parent._ascend(type, data));
607    return response;
608  }
609
610  descend (type, data) {
611    const response = [];
612    for (const child of this._children) response.push(...child._descend(type, data));
613    return response;
614  }
615
616  _descend (type, data) {
617    const response = [];
618    for (const instance of this.instances) response.push(...instance._descent.emit(type, data));
619    for (const child of this._children) response.push(...child._descend(type, data));
620    return response;
621  }
622
623  getInstance (instanceClassName) {
624    for (const instance of this.instances) if (instance.registration.hasInstanceClassName(instanceClassName)) return instance;
625    return null;
626  }
627
628  hasInstance (instanceClassName) {
629    return this.getInstance(instanceClassName) !== null;
630  }
631
632  getDescendantInstances (instanceClassName, stopAtInstanceClassName, stopAtFirstInstance) {
633    if (!instanceClassName) return [];
634    const instances = [];
635    for (const child of this._children) {
636      const instance = child.getInstance(instanceClassName);
637      if (instance) {
638        instances.push(instance);
639        if (stopAtFirstInstance) continue;
640      }
641      if ((!stopAtInstanceClassName || !child.hasInstance(stopAtInstanceClassName)) && child.children.length) instances.push.apply(instances, child.getDescendantInstances(instanceClassName, stopAtInstanceClassName, stopAtFirstInstance));
642    }
643    return instances;
644  }
645
646  getAscendantInstance (instanceClassName, stopAtInstanceClassName) {
647    if (!instanceClassName || !this._parent) return null;
648    const instance = this._parent.getInstance(instanceClassName);
649    if (instance) return instance;
650    if (stopAtInstanceClassName && this._parent.hasInstance(stopAtInstanceClassName)) return null;
651    return this._parent.getAscendantInstance(instanceClassName, stopAtInstanceClassName);
652  }
653
654  dispose () {
655    for (let i = this.instances.length - 1; i >= 0; i--) {
656      const instance = this.instances[i];
657      if (instance) instance._dispose();
658    }
659    this.instances.length = 0;
660    state.remove('stage', this);
661    this.parent.removeChild(this);
662    this._children.length = 0;
663    inspector.debug(`remove element [${this.id}] ${this.html}`);
664  }
665
666  prepare (attributeName) {
667    if (this.attributeNames.indexOf(attributeName) === -1) this.attributeNames.push(attributeName);
668  }
669
670  examine () {
671    const attributeNames = this.attributeNames.slice();
672    this.attributeNames.length = 0;
673    for (let i = this.instances.length - 1; i > -1; i--) this.instances[i].examine(attributeNames);
674  }
675}
676
677const RootEmission = {
678  CLICK: ns.emission('root', 'click'),
679  
679KEYDOWN: ns.emission('root', 'keydown'),
680  KEYUP: ns.emission('root', 'keyup')
681};
682
683const KeyCodes = {
684  TAB: {
685    id: 'tab',
686    value: 9
687  },
688  ESCAPE: {
689    id: 'escape',
690    value: 27
691  },
692  END: {
693    id: 'end',
694    value: 35
695  },
696  HOME: {
697    id: 'home',
698    value: 36
699  },
700  LEFT: {
701    id: 'left',
702    value: 37
703  },
704  UP: {
705    id: 'up',
706    value: 38
707  },
708  RIGHT: {
709    id: 'right',
710    value: 39
711  },
712  DOWN: {
713    id: 'down',
714    value: 40
715  }
716};
717
718const getKeyCode = (keyCode) => Object.values(KeyCodes).filter(entry => entry.value === keyCode)[0];
719
vendor: 46,617 bytes, lines 720-2596
720class Root extends Element$1 {
721  constructor () {
722    super(document.documentElement, 'root');
723    this.node.setAttribute(ns.attr('js'), true);
724    this.listen();
725  }
726
727  listen () {
728    // TODO v2 => listener au niveau des éléments qui redistribuent aux instances.
729    document.documentElement.addEventListener('click', this.click.bind(this), { capture: true });
730    document.documentElement.addEventListener('keydown', this.keydown.bind(this), { capture: true });
731    document.documentElement.addEventListener('keyup', this.keyup.bind(this), { capture: true });
732  }
733
734  click (e) {
735    this.emit(RootEmission.CLICK, e.target);
736  }
737
738  keydown (e) {
739    this.emit(RootEmission.KEYDOWN, getKeyCode(e.keyCode));
740  }
741
742  keyup (e) {
743    this.emit(RootEmission.KEYUP, getKeyCode(e.keyCode));
744  }
745}
746
747class Stage extends Module {
748  constructor () {
749    super('stage');
750    this.root = new Root();
751    super.add(this.root);
752    this.observer = new MutationObserver(this.mutate.bind(this));
753    this.modifications = [];
754    this.willModify = false;
755    this.modifying = this.modify.bind(this);
756  }
757
758  hasElement (node) {
759    for (const element of this.collection) if (element.node === node) return true;
760    return false;
761  }
762
763  getElement (node) {
764    for (const element of this.collection) if (element.node === node) return element;
765    const element = new Element$1(node);
766    this.add(element);
767    inspector.debug(`add element [${element.id}] ${element.html}`);
768    return element;
769  }
770
771  getProxy (node) {
772    if (!this.hasElement(node)) return null;
773    const element = this.getElement(node);
774    return element.proxy;
775  }
776
777  add (element) {
778    super.add(element);
779    this.put(element, this.root);
780  }
781
782  put (element, branch) {
783    let index = 0;
784    for (let i = branch.children.length - 1; i > -1; i--) {
785      const child = branch.children[i];
786      const position = element.node.compareDocumentPosition(child.node);
787      if (position & Node.DOCUMENT_POSITION_CONTAINS) {
788        this.put(element, child);
789        return;
790      } else if (position & Node.DOCUMENT_POSITION_CONTAINED_BY) {
791        branch.removeChild(child);
792        element.addChild(child, 0);
793      } else if (position & Node.DOCUMENT_POSITION_PRECEDING) {
794        index = i + 1;
795        break;
796      }
797    }
798
799    branch.addChild(element, index);
800  }
801
802  activate () {
803    this.observer.observe(document.documentElement, { childList: true, subtree: true, attributes: true });
804  }
805
806  deactivate () {
807    this.observer.disconnect();
808  }
809
810  mutate (mutations) {
811    const examinations = [];
812    mutations.forEach((mutation) => {
813      switch (mutation.type) {
814        case 'childList':
815          mutation.removedNodes.forEach((node) => this.dispose(node));
816          mutation.addedNodes.forEach((node) => this.parse(node));
817          break;
818
819        case 'attributes':
820          if (this.hasElement(mutation.target)) {
821            const element = this.getElement(mutation.target);
822            element.prepare(mutation.attributeName);
823            if (examinations.indexOf(element) === -1) examinations.push(element);
824            for (const descendant of element.descendants) if (examinations.indexOf(descendant) === -1) examinations.push(descendant);
825          }
826          if (this.modifications.indexOf(mutation.target) === -1) this.modifications.push(mutation.target);
827          break;
828      }
829    });
830
831    examinations.forEach(element => element.examine());
832    if (this.modifications.length && !this.willModify) {
833      this.willModify = true;
834      window.requestAnimationFrame(this.modifying);
835    }
836  }
837
838  modify () {
839    this.willModify = false;
840    const targets = this.modifications.slice();
841    this.modifications.length = 0;
842    for (const target of targets) if (document.documentElement.contains(target)) this.parse(target);
843  }
844
845  dispose (node) {
846    const disposables = [];
847    this.forEach((element) => {
848      if (node.contains(element.node)) disposables.push(element);
849    });
850
851    for (const disposable of disposables) {
852      disposable.dispose();
853      this.remove(disposable);
854    }
855  }
856
857  parse (node, registration, nonRecursive) {
858    const registrations = registration ? [registration] : state.getModule('register').collection;
859    const creations = [];
860
861    for (const registration of registrations) {
862      const nodes = registration.parse(node, nonRecursive);
863
864      for (const n of nodes) {
865        const element = this.getElement(n);
866        element.project(registration);
867        if (creations.indexOf(element) === -1) creations.push(element);
868      }
869    }
870
871    for (const element of creations) element.populate();
872  }
873}
874
875class Renderer extends Module {
876  constructor () {
877    super('render');
878    this.rendering = this.render.bind(this);
879    this.nexts = new Collection();
880  }
881
882  activate () {
883    window.requestAnimationFrame(this.rendering);
884  }
885
886  request (instance) {
887    this.nexts.add(instance);
888  }
889
890  render () {
891    if (!state.isActive) return;
892    window.requestAnimationFrame(this.rendering);
893    this.forEach((instance) => instance.render());
894    if (!this.nexts.length) return;
895    const nexts = this.nexts.clone();
896    this.nexts.clear();
897    nexts.forEach((instance) => instance.next());
898  }
899}
900
901class Resizer extends Module {
902  constructor () {
903    super('resize');
904    this.requireResize = false;
905    this.resizing = this.resize.bind(this);
906    const requesting = this.request.bind(this);
907    if (document.fonts) {
908      document.fonts.ready.then(requesting);
909    }
910    window.addEventListener('resize', requesting);
911    window.addEventListener('orientationchange', requesting);
912  }
913
914  activate () {
915    this.request();
916  }
917
918  request () {
919    if (this.requireResize) return;
920    this.requireResize = true;
921    window.requestAnimationFrame(this.resizing);
922  }
923
924  resize () {
925    if (!this.requireResize) return;
926    this.forEach((instance) => instance.resize());
927    this.requireResize = false;
928  }
929}
930
931class ScrollLocker extends Module {
932  constructor () {
933    super('lock');
934    this._isLocked = false;
935    this._scrollY = 0;
936    this.onPopulate = this.lock.bind(this);
937    this.onEmpty = this.unlock.bind(this);
938  }
939
940  get isLocked () {
941    return this._isLocked;
942  }
943
944  lock () {
945    if (!this._isLocked) {
946      this._isLocked = true;
947      this._scrollY = window.scrollY;
948      const scrollBarGap = window.innerWidth - document.documentElement.clientWidth;
949      document.documentElement.setAttribute(ns.attr('scrolling'), 'false');
950      document.body.style.top = `${-this._scrollY}px`;
951      this.behavior = getComputedStyle(document.documentElement).getPropertyValue('scroll-behavior');
952      if (this.behavior === 'smooth') document.documentElement.style.scrollBehavior = 'auto';
953      if (scrollBarGap > 0) {
954        document.documentElement.style.setProperty('--scrollbar-width', `${scrollBarGap}px`);
955      }
956    }
957  }
958
959  unlock () {
960    if (this._isLocked) {
961      this._isLocked = false;
962      document.documentElement.removeAttribute(ns.attr('scrolling'));
963      document.body.style.top = '';
964      window.scrollTo(0, this._scrollY);
965      if (this.behavior === 'smooth') document.documentElement.style.removeProperty('scroll-behavior');
966      document.documentElement.style.removeProperty('--scrollbar-width');
967    }
968  }
969
970  move (value) {
971    if (this._isLocked) {
972      this._scrollY += value;
973      document.body.style.top = `${-this._scrollY}px`;
974    } else {
975      window.scrollTo(0, window.scrollY + value);
976    }
977  }
978}
979
980class Load extends Module {
981  constructor () {
982    super('load');
983    this.loading = this.load.bind(this);
984  }
985
986  activate () {
987    window.addEventListener('load', this.loading);
988  }
989
990  load () {
991    this.forEach((instance) => instance.load());
992  }
993}
994
995const FONT_FAMILIES = ['Marianne', 'Spectral'];
996
997class FontSwap extends Module {
998  constructor () {
999    super('font-swap');
1000    this.swapping = this.swap.bind(this);
1001  }
1002
1003  activate () {
1004    if (document.fonts) {
1005      document.fonts.addEventListener('loadingdone', this.swapping);
1006    }
1007  }
1008
1009  swap () {
1010    const families = FONT_FAMILIES.filter(family => document.fonts.check(`16px ${family}`));
1011
1012    this.forEach((instance) => instance.swapFont(families));
1013  }
1014}
1015
1016class MouseMove extends Module {
1017  constructor () {
1018    super('mouse-move');
1019    this.requireMove = false;
1020    this._isMoving = false;
1021    this.moving = this.move.bind(this);
1022    this.requesting = this.request.bind(this);
1023    this.onPopulate = this.listen.bind(this);
1024    this.onEmpty = this.unlisten.bind(this);
1025  }
1026
1027  listen () {
1028    if (this._isMoving) return;
1029    this._isMoving = true;
1030    this.requireMove = false;
1031    document.documentElement.addEventListener('mousemove', this.requesting);
1032  }
1033
1034  unlisten () {
1035    if (!this._isMoving) return;
1036    this._isMoving = false;
1037    this.requireMove = false;
1038    document.documentElement.removeEventListener('mousemove', this.requesting);
1039  }
1040
1041  request (e) {
1042    if (!this._isMoving) return;
1043    this.point = { x: e.clientX, y: e.clientY };
1044    if (this.requireMove) return;
1045    this.requireMove = true;
1046    window.requestAnimationFrame(this.moving);
1047  }
1048
1049  move () {
1050    if (!this.requireMove) return;
1051    this.forEach((instance) => instance.mouseMove(this.point));
1052    this.requireMove = false;
1053  }
1054}
1055
1056class Hash extends Module {
1057  constructor () {
1058    super('hash');
1059    this.handling = this.handle.bind(this);
1060    this.getLocationHash();
1061  }
1062
1063  activate () {
1064    window.addEventListener('hashchange', this.handling);
1065  }
1066
1067  deactivate () {
1068    window.removeEventListener('hashchange', this.handling);
1069  }
1070
1071  _sanitize (hash) {
1072    if (hash.charAt(0) === '#') return hash.substring(1);
1073    return hash;
1074  }
1075
1076  set hash (value) {
1077    const hash = this._sanitize(value);
1078    if (this._hash !== hash) window.location.hash = hash;
1079  }
1080
1081  get hash () {
1082    return this._hash;
1083  }
1084
1085  getLocationHash () {
1086    const hash = window.location.hash;
1087    this._hash = this._sanitize(hash);
1088  }
1089
1090  handle (e) {
1091    this.getLocationHash();
1092    this.forEach((instance) => instance.handleHash(this._hash, e));
1093  }
1094}
1095
1096class Engine {
1097  constructor () {
1098    state.create(Register);
1099    state.create(Stage);
1100    state.create(Renderer);
1101    state.create(Resizer);
1102    state.create(ScrollLocker);
1103    state.create(Load);
1104    state.create(FontSwap);
1105    state.create(MouseMove);
1106    state.create(Hash);
1107
1108    const registerModule = state.getModule('register');
1109    this.register = registerModule.register.bind(registerModule);
1110  }
1111
1112  get isActive () {
1113    return state.isActive;
1114  }
1115
1116  start () {
1117    inspector.debug('START');
1118    state.isActive = true;
1119  }
1120
1121  stop () {
1122    inspector.debug('STOP');
1123    state.isActive = false;
1124  }
1125}
1126
1127const engine = new Engine();
1128
1129class Colors {
1130  getColor (context, use, tint, options = {}) {
1131    const option = getOption(options);
1132    const decision = `--${context}-${use}-${tint}${option}`;
1133    return getComputedStyle(document.documentElement).getPropertyValue(decision).trim() || null;
1134  }
1135}
1136
1137const getOption = (options) => {
1138  switch (true) {
1139    case options.hover:
1140      return '-hover';
1141    case options.active:
1142      return '-active';
1143    default:
1144      return '';
1145  }
1146};
1147
1148const colors = new Colors();
1149
1150const sanitize = (className) => className.charAt(0) === '.' ? className.substr(1) : className;
1151
1152const getClassNames = (element) => {
1153  switch (true) {
1154    case !element.className:
1155      return [];
1156
1157    case typeof element.className === 'string':
1158      return element.className.split(' ');
1159
1160    case typeof element.className.baseVal === 'string':
1161      return element.className.baseVal.split(' ');
1162  }
1163
1164  return [];
1165};
1166
1167const modifyClass = (element, className, remove) => {
1168  className = sanitize(className);
1169  const classNames = getClassNames(element);
1170  const index = classNames.indexOf(className);
1171  if (remove === true) {
1172    if (index > -1) classNames.splice(index, 1);
1173  } else if (index === -1) classNames.push(className);
1174  element.className = classNames.join(' ');
1175};
1176
1177const addClass = (element, className) => modifyClass(element, className);
1178
1179const removeClass = (element, className) => modifyClass(element, className, true);
1180
1181const hasClass = (element, className) => getClassNames(element).indexOf(sanitize(className)) > -1;
1182
1183const ACTIONS = [
1184  '[tabindex]:not([tabindex="-1"])',
1185  'a[href]',
1186  'button:not([disabled])',
1187  'input:not([disabled])',
1188  'select:not([disabled])',
1189  'textarea:not([disabled])',
1190  'audio[controls]',
1191  'video[controls]',
1192  '[contenteditable]:not([contenteditable="false"])',
1193  'details>summary:first-of-type',
1194  'details',
1195  'iframe'
1196];
1197
1198const ACTIONS_SELECTOR = ACTIONS.join();
1199
1200const queryActions = (element) => {
1201  return element.querySelectorAll(ACTIONS_SELECTOR);
1202};
1203
1204let counter = 0;
1205
1206const uniqueId = (id) => {
1207  if (!document.getElementById(id)) return id;
1208  let element = true;
1209  const base = id;
1210  while (element) {
1211    counter++;
1212    id = `${base}-${counter}`;
1213    element = document.getElementById(id);
1214  }
1215  return id;
1216};
1217
1218const dom = {
1219  addClass: addClass,
1220  hasClass: hasClass,
1221  removeClass: removeClass,
1222  queryParentSelector: queryParentSelector,
1223  querySelectorAllArray: querySelectorAllArray,
1224  queryActions: queryActions,
1225  uniqueId: uniqueId
1226};
1227
1228class DataURISVG {
1229  constructor (width = 0, height = 0) {
1230    this._width = width;
1231    this._height = height;
1232    this._content = '';
1233  }
1234
1235  get width () {
1236    return this._width;
1237  }
1238
1239  set width (value) {
1240    this._width = value;
1241  }
1242
1243  get height () {
1244    return this._height;
1245  }
1246
1247  set height (value) {
1248    this._height = value;
1249  }
1250
1251  get content () {
1252    return this._content;
1253  }
1254
1255  set content (value) {
1256    this._content = value;
1257  }
1258
1259  getDataURI (isLegacy = false) {
1260    let svg = `<svg xmlns='http://www.w3.org/2000/svg' viewbox='0 0 ${this._width} ${this._height}' width='${this._width}px' height='${this._height}px'>${this._content}</svg>`;
1261
1262    svg = svg.replace(/#/gi, '%23');
1263    if (isLegacy) {
1264      svg = svg.replace(/</gi, '%3C');
1265      svg = svg.replace(/>/gi, '%3E');
1266      svg = svg.replace(/"/gi, '\'');
1267      svg = svg.replace(/{/gi, '%7B');
1268      svg = svg.replace(/}/gi, '%7D');
1269    }
1270    return `data:image/svg+xml;charset=utf8,${svg}`;
1271  }
1272}
1273
1274const image = {
1275  DataURISVG: DataURISVG
1276};
1277
1278const supportLocalStorage = () => {
1279  try {
1280    return 'localStorage' in window && window.localStorage !== null;
1281  } catch (e) {
1282    return false;
1283  }
1284};
1285
1286const supportAspectRatio = () => {
1287  if (!window.CSS) return false;
1288  return CSS.supports('aspect-ratio: 16 / 9');
1289};
1290
1291const support = {
1292  supportLocalStorage: supportLocalStorage,
1293  supportAspectRatio: supportAspectRatio
1294};
1295
1296const TransitionSelector = {
1297  NONE: ns.selector('transition-none')
1298};
1299
1300const selector = {
1301  TransitionSelector: TransitionSelector
1302};
1303
1304/**
1305 * Copy properties from multiple sources including accessors.
1306 * source : https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#copier_des_accesseurs
1307 *
1308 * @param {object} [target] - Target object to copy into
1309 * @param {...objects} [sources] - Multiple objects
1310 * @return {object} A new object
1311 *
1312 * @example
1313 *
1314 *     const obj1 = {
1315 *        key: 'value'
1316 *     };
1317 *     const obj2 = {
1318 *        get function01 () {
1319 *          return a-value;
1320 *        }
1321 *        set function01 () {
1322 *          return a-value;
1323 *        }
1324 *     };
1325 *     completeAssign(obj1, obj2)
1326 */
1327const completeAssign = (target, ...sources) => {
1328  sources.forEach(source => {
1329    const descriptors = Object.keys(source).reduce((descriptors, key) => {
1330      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
1331      return descriptors;
1332    }, {});
1333
1334    Object.getOwnPropertySymbols(source).forEach(sym => {
1335      const descriptor = Object.getOwnPropertyDescriptor(source, sym);
1336      if (descriptor.enumerable) {
1337        descriptors[sym] = descriptor;
1338      }
1339    });
1340    Object.defineProperties(target, descriptors);
1341  });
1342  return target;
1343};
1344
1345const property = {
1346  completeAssign: completeAssign
1347};
1348
1349/**
1350 * Return an object of query params or null
1351 *
1352 * @method
1353 * @name searchParams
1354 * @param {string} url - an url
1355 * @returns {Object} object of query params or null
1356 */
1357
1358const searchParams = (url) => {
1359  if (url && url.search) {
1360    const params = new URLSearchParams(window.location.search);
1361    const entries = params.entries();
1362    return Object.fromEntries(entries);
1363  }
1364  return null;
1365};
1366
1367const internals = {};
1368const legacy = {};
1369
1370Object.defineProperty(legacy, 'isLegacy', {
1371  get: () => state.isLegacy
1372});
1373
1374legacy.setLegacy = () => {
1375  state.isLegacy = true;
1376};
1377
1378internals.legacy = legacy;
1379internals.dom = dom;
1380internals.image = image;
1381internals.support = support;
1382internals.motion = selector;
1383internals.property = property;
1384internals.ns = ns;
1385internals.register = engine.register;
1386internals.state = state;
1387internals.query = searchParams(window.location);
1388
1389Object.defineProperty(internals, 'preventManipulation', {
1390  get: () => options.preventManipulation
1391});
1392Object.defineProperty(internals, 'stage', {
1393  get: () => state.getModule('stage')
1394});
1395
1396const api$1 = (node) => {
1397  const stage = state.getModule('stage');
1398  return stage.getProxy(node);
1399};
1400
1401api$1.version = config.version;
1402api$1.prefix = config.prefix;
1403api$1.organisation = config.organisation;
1404api$1.Modes = Modes;
1405
1406Object.defineProperty(api$1, 'mode', {
1407  set: (value) => { options.mode = value; },
1408  get: () => options.mode
1409});
1410
1411api$1.internals = internals;
1412api$1.version = config.version;
1413
1414api$1.start = engine.start;
1415api$1.stop = engine.stop;
1416
1417api$1.inspector = inspector;
1418api$1.colors = colors;
1419
1420const configuration = window[config.namespace];
1421api$1.internals.configuration = configuration;
1422
1423options.configure(configuration, api$1.start, api$1.internals.query);
1424
1425window[config.namespace] = api$1;
1426
1427class Emitter {
1428  constructor () {
1429    this.emissions = {};
1430  }
1431
1432  add (type, closure) {
1433    if (typeof closure !== 'function') throw new Error('closure must be a function');
1434    if (!this.emissions[type]) this.emissions[type] = [];
1435    this.emissions[type].push(closure);
1436  }
1437
1438  remove (type, closure) {
1439    if (!this.emissions[type]) return;
1440    if (!closure) delete this.emissions[type];
1441    else {
1442      const index = this.emissions[type].indexOf(closure);
1443      if (index > -1) this.emissions[type].splice(index);
1444    }
1445  }
1446
1447  emit (type, data) {
1448    if (!this.emissions[type]) return [];
1449    const response = [];
1450    for (const closure of this.emissions[type]) if (closure) response.push(closure(data));
1451    return response;
1452  }
1453
1454  dispose () {
1455    this.emissions = null;
1456  }
1457}
1458
1459class Breakpoint {
1460  constructor (id, minWidth) {
1461    this.id = id;
1462    this.minWidth = minWidth;
1463  }
1464
1465  test () {
1466    return window.matchMedia(`(min-width: ${this.minWidth}em)`).matches;
1467  }
1468}
1469
1470const Breakpoints = {
1471  XS: new Breakpoint('xs', 0),
1472  SM: new Breakpoint('sm', 36),
1473  MD: new Breakpoint('md', 48),
1474  LG: new Breakpoint('lg', 62),
1475  XL: new Breakpoint('xl', 78)
1476};
1477
1478class Instance {
1479  constructor (jsAttribute = true) {
1480    this.jsAttribute = jsAttribute;
1481    this._isRendering = false;
1482    this._isResizing = false;
1483    this._isScrollLocked = false;
1484    this._isLoading = false;
1485    this._isSwappingFont = false;
1486    this._isEnabled = true;
1487    this._isDisposed = false;
1488    this._listeners = {};
1489    this._handlingClick = this.handleClick.bind(this);
1490    this._hashes = [];
1491    this._hash = '';
1492    this._keyListenerTypes = [];
1493    this._keys = [];
1494    this.handlingKey = this.handleKey.bind(this);
1495    this._emitter = new Emitter();
1496    this._ascent = new Emitter();
1497    this._descent = new Emitter();
1498    this._registrations = [];
1499    this._nexts = [];
1500  }
1501
1502  static get instanceClassName () {
1503    return 'Instance';
1504  }
1505
1506  _config (element, registration) {
1507    this.element = element;
1508    this.registration = registration;
1509    this.node = element.node;
1510    this.id = element.node.id;
1511    if (this.jsAttribute) this.setAttribute(registration.attribute, true);
1512    this.init();
1513  }
1514
1515  init () {}
1516
1517  get proxy () {
1518    const scope = this;
1519    const proxy = {
1520      render: () => scope.render(),
1521      resize: () => scope.resize()
1522    };
1523
1524    const proxyAccessors = {
1525      get node () {
1526        return this.node;
1527      },
1528      get isEnabled () {
1529        return scope.isEnabled;
1530      },
1531      set isEnabled (value) {
1532        scope.isEnabled = value;
1533      }
1534    };
1535
1536    return completeAssign(proxy, proxyAccessors);
1537  }
1538
1539  log (...values) {
1540    values.unshift(`${this.registration.instanceClassName} #${this.id} - `);
1541    inspector.log.apply(inspector, values);
1542  }
1543
1544  debug (...values) {
1545    values.unshift(`${this.registration.instanceClassName} #${this.id} - `);
1546    inspector.debug.apply(inspector, values);
1547  }
1548
1549  info (...values) {
1550    values.unshift(`${this.registration.instanceClassName} #${this.id} - `);
1551    inspector.info.apply(inspector, values);
1552  }
1553
1554  warn (...values) {
1555    values.unshift(`${this.registration.instanceClassName} #${this.id} - `);
1556    inspector.warn.apply(inspector, values);
1557  }
1558
1559  error (...values) {
1560    values.unshift(`${this.registration.instanceClassName} #${this.id} - `);
1561    inspector.error.apply(inspector, values);
1562  }
1563
1564  register (selector, InstanceClass) {
1565    const registration = state.getModule('register').register(selector, InstanceClass, this);
1566    this._registrations.push(registration);
1567  }
1568
1569  getRegisteredInstances (instanceClassName) {
1570    for (const registration of this._registrations) if (registration.hasInstanceClassName(instanceClassName)) return registration.instances.collection;
1571    return [];
1572  }
1573
1574  dispatch (type, detail, bubbles, cancelable) {
1575    const event = new CustomEvent(type, { detail: detail, bubble: bubbles === true, cancelable: cancelable === true });
1576    this.node.dispatchEvent(event);
1577  }
1578
1579  // TODO v2 => listener au niveau des éléments qui redistribuent aux instances.
1580  listen (type, closure, options) {
1581    if (!this._listeners[type]) this._listeners[type] = [];
1582    const listeners = this._listeners[type];
1583    // if (listeners.some(listener => listener.closure === closure)) return;
1584    const listener = new Listener(this.node, type, closure, options);
1585    listeners.push(listener);
1586    listener.listen();
1587  }
1588
1589  unlisten (type, closure, options) {
1590    if (!type) {
1591      for (const type in this._listeners) this.unlisten(type);
1592      return;
1593    }
1594
1595    const listeners = this._listeners[type];
1596
1597    if (!listeners) return;
1598
1599    if (!closure) {
1600      listeners.forEach(listener => this.unlisten(type, listener.closure));
1601      return;
1602    }
1603
1604    const removal = listeners.filter(listener => listener.closure === closure && listener.matchOptions(options));
1605    removal.forEach(listener => listener.unlisten());
1606    this._listeners[type] = listeners.filter(listener => removal.indexOf(listener) === -1);
1607  }
1608
1609  listenClick (options) {
1610    this.listen('click', this._handlingClick, options);
1611  }
1612
1613  unlistenClick (options) {
1614    this.unlisten('click', this._handlingClick, options);
1615  }
1616
1617  handleClick (e) {}
1618
1619  set hash (value) {
1620    state.getModule('hash').hash = value;
1621  }
1622
1623  get hash () {
1624    return state.getModule('hash').hash;
1625  }
1626
1627  listenHash (hash, add) {
1628    if (!this._hashes) return;
1629    if (this._hashes.length === 0) state.add('hash', this);
1630    const action = new HashAction(hash, add);
1631    this._hashes = this._hashes.filter(action => action.hash !== hash);
1632    this._hashes.push(action);
1633  }
1634
1635  unlistenHash (hash) {
1636    if (!this._hashes) return;
1637    this._hashes = this._hashes.filter(action => action.hash !== hash);
1638    if (this._hashes.length === 0) state.remove('hash', this);
1639  }
1640
1641  handleHash (hash, e) {
1642    if (!this._hashes) return;
1643    for (const action of this._hashes) action.handle(hash, e);
1644  }
1645
1646  listenKey (keyCode, closure, preventDefault = false, stopPropagation = false, type = 'down') {
1647    if (this._keyListenerTypes.indexOf(type) === -1) {
1648      this.listen(`key${type}`, this.handlingKey);
1649      this._keyListenerTypes.push(type);
1650    }
1651
1652    this._keys.push(new KeyAction(type, keyCode, closure, preventDefault, stopPropagation));
1653  }
1654
1655  unlistenKey (code, closure) {
1656    this._keys = this._keys.filter((key) => key.code !== code || key.closure !== closure);
1657
1658    this._keyListenerTypes.forEach(type => {
1659      if (!this._keys.some(key => key.type === type)) this.unlisten(`key${type}`, this.handlingKey);
1660    });
1661  }
1662
1663  handleKey (e) {
1664    for (const key of this._keys) key.handle(e);
1665  }
1666
1667  get isEnabled () { return this._isEnabled; }
1668
1669  set isEnabled (value) {
1670    this._isEnabled = value;
1671  }
1672
1673  get isRendering () { return this._isRendering; }
1674
1675  set isRendering (value) {
1676    if (this._isRendering === value) return;
1677    if (value) state.add('render', this);
1678    else state.remove('render', this);
1679    this._isRendering = value;
1680  }
1681
1682  render () {}
1683
1684  request (closure) {
1685    this._nexts.push(closure);
1686    state.getModule('render').request(this);
1687  }
1688
1689  next () {
1690    const nexts = this._nexts.slice();
1691    this._nexts.length = 0;
1692    for (const closure of nexts) if (closure) closure();
1693  }
1694
1695  get isResizing () { return this._isResizing; }
1696
1697  set isResizing (value) {
1698    if (this._isResizing === value) return;
1699    if (value) {
1700      state.add('resize', this);
1701      this.resize();
1702    } else state.remove('resize', this);
1703    this._isResizing = value;
1704  }
1705
1706  resize () {}
1707
1708  isBreakpoint (breakpoint) {
1709    switch (true) {
1710      case typeof breakpoint === 'string':
1711        return Breakpoints[breakpoint.toUpperCase()].test();
1712
1713      default:
1714        return breakpoint.test();
1715    }
1716  }
1717
1718  get isScrollLocked () {
1719    return this._isScrollLocked;
1720  }
1721
1722  set isScrollLocked (value) {
1723    if (this._isScrollLocked === value) return;
1724    if (value) state.add('lock', this);
1725    else state.remove('lock', this);
1726    this._isScrollLocked = value;
1727  }
1728
1729  get isLoading () {
1730    return this._isLoading;
1731  }
1732
1733  set isLoading (value) {
1734    if (this._isLoading === value) return;
1735    if (value) state.add('load', this);
1736    else state.remove('load', this);
1737    this._isLoading = value;
1738  }
1739
1740  load () {}
1741
1742  get isSwappingFont () {
1743    return this._isSwappingFont;
1744  }
1745
1746  set isSwappingFont (value) {
1747    if (this._isSwappingFont === value) return;
1748    if (value) state.add('font-swap', this);
1749    else state.remove('font-swap', this);
1750    this._isSwappingFont = value;
1751  }
1752
1753  swapFont () {}
1754
1755  get isMouseMoving () { return this._isMouseMoving; }
1756
1757  set isMouseMoving (value) {
1758    if (this._isMouseMoving === value) return;
1759    if (value) {
1760      state.add('mouse-move', this);
1761    } else {
1762      state.remove('mouse-move', this);
1763    }
1764    this._isMouseMoving = value;
1765  }
1766
1767  mouseMove (point) {}
1768
1769  examine (attributeNames) {
1770    if (!this.node.matches(this.registration.selector)) {
1771      this._dispose();
1772      return;
1773    }
1774
1775    this.mutate(attributeNames);
1776  }
1777
1778  mutate (attributeNames) {}
1779
1780  retrieveNodeId (node, append) {
1781    if (node.id) return node.id;
1782    const id = uniqueId(`${this.id}-${append}`);
1783    this.warn(`add id '${id}' to ${append}`);
1784    node.setAttribute('id', id);
1785    return id;
1786  }
1787
1788  get isDisposed () {
1789    return this._isDisposed;
1790  }
1791
1792  _dispose () {
1793    this.debug(`dispose instance of ${this.registration.instanceClassName} on element [${this.element.id}]`);
1794    this.removeAttribute(this.registration.attribute);
1795    this.unlisten();
1796    state.remove('hash', this);
1797    this._hashes = null;
1798    this._keys = null;
1799    this.isRendering = false;
1800    this.isResizing = false;
1801    this._nexts = null;
1802    state.getModule('render').nexts.remove(this);
1803    this.isScrollLocked = false;
1804    this.isLoading = false;
1805    this.isSwappingFont = false;
1806    this.isMouseMoving = false;
1807    this._emitter.dispose();
1808    this._emitter = null;
1809    this._ascent.dispose();
1810    this._ascent = null;
1811    this._descent.dispose();
1812    this._descent = null;
1813    this.element.remove(this);
1814    for (const registration of this._registrations) state.remove('register', registration);
1815    this._registrations = null;
1816    this.registration.remove(this);
1817    this._isDisposed = true;
1818    this.dispose();
1819  }
1820
1821  dispose () {}
1822
1823  emit (type, data) {
1824    return this.element.emit(type, data);
1825  }
1826
1827  addEmission (type, closure) {
1828    this._emitter.add(type, closure);
1829  }
1830
1831  removeEmission (type, closure) {
1832    this._emitter.remove(type, closure);
1833  }
1834
1835  ascend (type, data) {
1836    return this.element.ascend(type, data);
1837  }
1838
1839  addAscent (type, closure) {
1840    this._ascent.add(type, closure);
1841  }
1842
1843  removeAscent (type, closure) {
1844    this._ascent.remove(type, closure);
1845  }
1846
1847  descend (type, data) {
1848    return this.element.descend(type, data);
1849  }
1850
1851  addDescent (type, closure) {
1852    this._descent.add(type, closure);
1853  }
1854
1855  removeDescent (type, closure) {
1856    this._descent.remove(type, closure);
1857  }
1858
1859  get style () {
1860    return this.node.style;
1861  }
1862
1863  addClass (className) {
1864    addClass(this.node, className);
1865  }
1866
1867  removeClass (className) {
1868    removeClass(this.node, className);
1869  }
1870
1871  hasClass (className) {
1872    return hasClass(this.node, className);
1873  }
1874
1875  get classNames () {
1876    return getClassNames(this.node);
1877  }
1878
1879  remove () {
1880    this.node.parentNode.removeChild(this.node);
1881  }
1882
1883  setAttribute (attributeName, value) {
1884    this.node.setAttribute(attributeName, value);
1885  }
1886
1887  getAttribute (attributeName) {
1888    return this.node.getAttribute(attributeName);
1889  }
1890
1891  hasAttribute (attributeName) {
1892    return this.node.hasAttribute(attributeName);
1893  }
1894
1895  removeAttribute (attributeName) {
1896    this.node.removeAttribute(attributeName);
1897  }
1898
1899  setProperty (propertyName, value) {
1900    this.node.style.setProperty(propertyName, value);
1901  }
1902
1903  removeProperty (propertyName) {
1904    this.node.style.removeProperty(propertyName);
1905  }
1906
1907  focus () {
1908    this.node.focus();
1909  }
1910
1911  blur () {
1912    this.node.blur();
1913  }
1914
1915  focusClosest () {
1916    const closest = this._focusClosest(this.node.parentNode);
1917    if (closest) closest.focus();
1918  }
1919
1920  _focusClosest (parent) {
1921    if (!parent) return null;
1922    const actions = [...queryActions(parent)];
1923    if (actions.length <= 1) {
1924      return this._focusClosest(parent.parentNode);
1925    } else {
1926      const index = actions.indexOf(this.node);
1927      return actions[index + (index < actions.length - 1 ? 1 : -1)];
1928    }
1929  }
1930
1931  get hasFocus () {
1932    return this.node === document.activeElement;
1933  }
1934
1935  scrollIntoView () {
1936    const rect = this.getRect();
1937
1938    const scroll = state.getModule('lock');
1939
1940    if (rect.top < 0) {
1941      scroll.move(rect.top - 50);
1942    }
1943
1944    if (rect.bottom > window.innerHeight) {
1945      scroll.move(rect.bottom - window.innerHeight + 50);
1946    }
1947  }
1948
1949  matches (selectors) {
1950    return this.node.matches(selectors);
1951  }
1952
1953  querySelector (selectors) {
1954    return this.node.querySelector(selectors);
1955  }
1956
1957  querySelectorAll (selectors) {
1958    return querySelectorAllArray(this.node, selectors);
1959  }
1960
1961  queryParentSelector (selectors) {
1962    return queryParentSelector(this.node, selectors);
1963  }
1964
1965  getRect () {
1966    const rect = this.node.getBoundingClientRect();
1967    rect.center = rect.left + rect.width * 0.5;
1968    rect.middle = rect.top + rect.height * 0.5;
1969    return rect;
1970  }
1971
1972  get isLegacy () {
1973    return state.isLegacy;
1974  }
1975}
1976
1977class KeyAction {
1978  constructor (type, keyCode, closure, preventDefault, stopPropagation) {
1979    this.type = type;
1980    this.eventType = `key${type}`;
1981    this.keyCode = keyCode;
1982    this.closure = closure;
1983    this.preventDefault = preventDefault === true;
1984    this.stopPropagation = stopPropagation === true;
1985  }
1986
1987  handle (e) {
1988    if (e.type !== this.eventType) return;
1989    if (e.keyCode === this.keyCode.value) {
1990      this.closure(e);
1991      if (this.preventDefault) {
1992        e.preventDefault();
1993      }
1994      if (this.stopPropagation) {
1995        e.stopPropagation();
1996      }
1997    }
1998  }
1999}
2000
2001class Listener {
2002  constructor (node, type, closure, options) {
2003    this._node = node;
2004    this._type = type;
2005    this._closure = closure;
2006    this._options = options;
2007  }
2008
2009  get closure () {
2010    return this._closure;
2011  }
2012
2013  listen () {
2014    this._node.addEventListener(this._type, this._closure, this._options);
2015  }
2016
2017  matchOptions (options = null) {
2018    switch (true) {
2019      case options === null:
2020      case typeof this._options === 'boolean' && typeof options === 'boolean' && this._options === options:
2021        return true;
2022
2023      case Object.keys(this._options).length !== Object.keys(options).length:
2024        return false;
2025
2026      case Object.keys(options).every(key => this._options[key] === options[key]):
2027        return true;
2028    }
2029
2030    return false;
2031  }
2032
2033  unlisten () {
2034    this._node.removeEventListener(this._type, this._closure, this._options);
2035  }
2036}
2037
2038class HashAction {
2039  constructor (hash, add) {
2040    this.hash = hash;
2041    this.add = add;
2042  }
2043
2044  handle (hash, e) {
2045    if (this.hash === hash) this.add(e);
2046  }
2047}
2048
2049const DisclosureEvent = {
2050  DISCLOSE: ns.event('disclose'),
2051  CONCEAL: ns.event('conceal')
2052};
2053
2054const DisclosureEmission = {
2055  RESET: ns.emission('disclosure', 'reset'),
2056  ADDED: ns.emission('disclosure', 'added'),
2057  RETRIEVE: ns.emission('disclosure', 'retrieve'),
2058  REMOVED: ns.emission('disclosure', 'removed'),
2059  GROUP: ns.emission('disclosure', 'group'),
2060  UNGROUP: ns.emission('disclosure', 'ungroup'),
2061  SPOTLIGHT: ns.emission('disclosure', 'spotlight')
2062};
2063
2064class Disclosure extends Instance {
2065  constructor (type, selector, DisclosureButtonInstanceClass, disclosuresGroupInstanceClassName) {
2066    super();
2067    this.type = type;
2068    this._selector = selector;
2069    this.DisclosureButtonInstanceClass = DisclosureButtonInstanceClass;
2070    this.disclosuresGroupInstanceClassName = disclosuresGroupInstanceClassName;
2071    this.modifier = this._selector + '--' + this.type.id;
2072    this._isPristine = true;
2073    this._isRetrievingPrimaries = false;
2074    this._hasRetrieved = false;
2075    this._primaryButtons = [];
2076  }
2077
2078  static get instanceClassName () {
2079    return 'Disclosure';
2080  }
2081
2082  init () {
2083    this.addDescent(DisclosureEmission.RESET, this.reset.bind(this));
2084    this.addDescent(DisclosureEmission.GROUP, this.update.bind(this));
2085    this.addDescent(DisclosureEmission.UNGROUP, this.update.bind(this));
2086    this.addAscent(DisclosureEmission.SPOTLIGHT, this.disclose.bind(this));
2087    this.register(`[aria-controls="${this.id}"]`, this.DisclosureButtonInstanceClass);
2088    this.ascend(DisclosureEmission.ADDED);
2089    this.listenHash(this.id, this._spotlight.bind(this));
2090    this.update();
2091  }
2092
2093  get isEnabled () { return super.isEnabled; }
2094
2095  set isEnabled (value) {
2096    if (this.isEnabled === value) return;
2097    super.isEnabled = value;
2098    if (value) this.ascend(DisclosureEmission.ADDED);
2099    else this.ascend(DisclosureEmission.REMOVED);
2100  }
2101
2102  get isPristine () {
2103    return this._isPristine;
2104  }
2105
2106  get proxy () {
2107    const scope = this;
2108    const proxy = Object.assign(super.proxy, {
2109      disclose: scope.disclose.bind(scope),
2110      focus: scope.focus.bind(scope)
2111    });
2112
2113    if (this.type.canConceal) proxy.conceal = scope.conceal.bind(scope);
2114
2115    const proxyAccessors = {
2116      get buttons () {
2117        return scope.buttons.map((button) => button.proxy);
2118      },
2119      get group () {
2120        const group = scope.group;
2121        return group ? group.proxy : null;
2122      },
2123      get isDisclosed () {
2124        return scope.isDisclosed;
2125      }
2126    };
2127
2128    return completeAssign(proxy, proxyAccessors);
2129  }
2130
2131  get buttons () {
2132    return this.getRegisteredInstances(this.DisclosureButtonInstanceClass.instanceClassName);
2133  }
2134
2135  update () {
2136    this.getGroup();
2137    this.retrievePrimaries();
2138  }
2139
2140  getGroup () {
2141    if (!this.disclosuresGroupInstanceClassName) {
2142      this._group = null;
2143      return;
2144    }
2145
2146    const group = this.element.getAscendantInstance(this.disclosuresGroupInstanceClassName, this.constructor.instanceClassName);
2147    if (!group || !group.validate(this)) {
2148      this._group = null;
2149      return;
2150    }
2151
2152    this._group = group;
2153  }
2154
2155  get group () {
2156    return this._group;
2157  }
2158
2159  disclose (withhold) {
2160    if (this.isDisclosed === true || !this.isEnabled) return false;
2161    this._isPristine = false;
2162    this.isDisclosed = true;
2163    if (!withhold && this.group) this.group.current = this;
2164    return true;
2165  }
2166
2167  conceal (withhold, preventFocus = true) {
2168    if (this.isDisclosed === false) return false;
2169    if (!this.type.canConceal && this.group && this.group.current === this) return false;
2170    this.isDisclosed = false;
2171    if (!withhold && this.group && this.group.current === this) this.group.current = null;
2172    if (!preventFocus) this.focus();
2173    if (!this._isPristine) this.descend(DisclosureEmission.RESET);
2174    return true;
2175  }
2176
2177  get isDisclosed () {
2178    return this._isDisclosed;
2179  }
2180
2181  set isDisclosed (value) {
2182    if (this._isDisclosed === value || (!this.isEnabled && value === true)) return;
2183    this.dispatch(value ? DisclosureEvent.DISCLOSE : DisclosureEvent.CONCEAL, this.type);
2184    this._isDisclosed = value;
2185    if (value) this.addClass(this.modifier);
2186    else this.removeClass(this.modifier);
2187    for (let i = 0; i < this.buttons.length; i++) this.buttons[i].apply(value);
2188  }
2189
2190  get isInitiallyDisclosed () {
2191    return this.primaryButtons.some(button => button.isInitiallyDisclosed);
2192  }
2193
2194  hasRetrieved () {
2195    return this._hasRetrieved;
2196  }
2197
2198  reset () {}
2199
2200  toggle (canDisclose) {
2201    if (!this.type.canConceal) this.disclose();
2202    else {
2203      switch (true) {
2204        case !canDisclose:
2205        case this.isDisclosed:
2206          this.conceal(false, false);
2207          break;
2208
2209        default:
2210          this.disclose();
2211      }
2212    }
2213  }
2214
2215  get buttonHasFocus () {
2216    return this.buttons.some((button) => { return button.hasFocus; });
2217  }
2218
2219  get hasFocus () {
2220    if (super.hasFocus) return true;
2221    if (this.buttonHasFocus) return true;
2222    return this.querySelectorAll(':focus').length > 0;
2223  }
2224
2225  focus () {
2226    if (this._primaryButtons.length > 0) this._primaryButtons[0].focus();
2227  }
2228
2229  get primaryButtons () {
2230    return this._primaryButtons;
2231  }
2232
2233  retrievePrimaries () {
2234    if (this._isRetrievingPrimaries) return;
2235    this._isRetrievingPrimaries = true;
2236    this.request(this._retrievePrimaries.bind(this));
2237  }
2238
2239  _retrievePrimaries () {
2240    this._isRetrievingPrimaries = false;
2241    this._primaryButtons = this._electPrimaries(this.buttons);
2242
2243    if (this._hasRetrieved || this._primaryButtons.length === 0) return;
2244    this.retrieved();
2245    this._hasRetrieved = true;
2246
2247    this.applyAbility(true);
2248
2249    if (this.group) {
2250      this.group.retrieve();
2251      return;
2252    }
2253
2254    if (this._isPristine && this.isEnabled && !this.group) {
2255      switch (true) {
2256        case this.hash === this.id:
2257          this._spotlight();
2258          break;
2259
2260        case this.isInitiallyDisclosed:
2261          this.disclose();
2262          break;
2263      }
2264    }
2265  }
2266
2267  retrieved () {}
2268
2269  _spotlight () {
2270    this.disclose();
2271    this.request(() => { this.ascend(DisclosureEmission.SPOTLIGHT); });
2272  }
2273
2274  _electPrimaries (candidates) {
2275    return candidates.filter(button => button.canDisclose && !this.node.contains(button.node));
2276  }
2277
2278  applyAbility (withhold = false) {
2279    const isEnabled = !this._primaryButtons.every(button => button.isDisabled);
2280
2281    if (this.isEnabled === isEnabled) return;
2282
2283    this.isEnabled = isEnabled;
2284
2285    if (withhold) return;
2286
2287    if (!this.isEnabled && this.isDisclosed) {
2288      if (this.group) this.ascend(DisclosureEmission.REMOVED);
2289      else if (this.type.canConceal) this.conceal();
2290    }
2291
2292    if (this.isEnabled) {
2293      if (this.group) this.ascend(DisclosureEmission.ADDED);
2294      if (this.hash === this.id) {
2295        this._spotlight();
2296      }
2297    }
2298  }
2299
2300  dispose () {
2301    this._group = null;
2302    this._primaryButtons = null;
2303    super.dispose();
2304    this.ascend(DisclosureEmission.REMOVED);
2305  }
2306}
2307
2308class DisclosureButton extends Instance {
2309  constructor (type) {
2310    super();
2311    this.type = type;
2312    this.attributeName = type.ariaState ? 'aria-' + type.id : ns.attr(type.id);
2313    this._canDisclose = false;
2314  }
2315
2316  static get instanceClassName () {
2317    return 'DisclosureButton';
2318  }
2319
2320  get isPrimary () {
2321    return this.registration.creator.primaryButtons.includes(this);
2322  }
2323
2324  get canDisclose () {
2325    return this._canDisclose;
2326  }
2327
2328  get isDisabled () {
2329    return this.type.canDisable && this.hasAttribute('disabled');
2330  }
2331
2332  init () {
2333    this._canDisclose = this.hasAttribute(this.attributeName);
2334    this._isInitiallyDisclosed = this.isDisclosed;
2335    this._isContained = this.registration.creator.node.contains(this.node);
2336    this.controlsId = this.getAttribute('aria-controls');
2337    this.registration.creator.retrievePrimaries();
2338    this.listenClick();
2339  }
2340
2341  get proxy () {
2342    const scope = this;
2343    return Object.assign(super.proxy, {
2344      focus: scope.focus.bind(scope)
2345    });
2346  }
2347
2348  handleClick (e) {
2349    if (this.registration.creator) this.registration.creator.toggle(this.canDisclose);
2350  }
2351
2352  mutate (attributeNames) {
2353    this._canDisclose = this.hasAttribute(this.attributeName);
2354    this.registration.creator.applyAbility();
2355    if (!this._isApplying && this.isPrimary && attributeNames.indexOf(this.attributeName) > -1 && this.registration.creator) {
2356      if (this.isDisclosed) this.registration.creator.disclose();
2357      else if (this.type.canConceal) this.registration.creator.conceal();
2358    }
2359  }
2360
2361  apply (value) {
2362    if (!this.canDisclose) return;
2363    this._isApplying = true;
2364    this.setAttribute(this.attributeName, value);
2365    this.request(() => { this._isApplying = false; });
2366  }
2367
2368  get isDisclosed () {
2369    return this.getAttribute(this.attributeName) === 'true';
2370  }
2371
2372  get isInitiallyDisclosed () {
2373    return this._isInitiallyDisclosed;
2374  }
2375
2376  focus () {
2377    super.focus();
2378    this.scrollIntoView();
2379  }
2380
2381  measure (rect) {
2382    const buttonRect = this.rect;
2383    this._dx = rect.x - buttonRect.x;
2384    this._dy = rect.y - buttonRect.y;
2385  }
2386
2387  get dx () {
2388    return this._dx;
2389  }
2390
2391  get dy () {
2392    return this._dy;
2393  }
2394}
2395
2396const DisclosureSelector = {
2397  PREVENT_CONCEAL: ns.attr.selector('prevent-conceal'),
2398  GROUP: ns.attr('group')
2399};
2400
2401class DisclosuresGroup extends Instance {
2402  constructor (disclosureInstanceClassName, jsAttribute) {
2403    super(jsAttribute);
2404    this.disclosureInstanceClassName = disclosureInstanceClassName;
2405    this._members = [];
2406    this._index = -1;
2407    this._isRetrieving = false;
2408    this._hasRetrieved = false;
2409    this._isGrouped = true;
2410  }
2411
2412  static get instanceClassName () {
2413    return 'DisclosuresGroup';
2414  }
2415
2416  init () {
2417    this.addAscent(DisclosureEmission.ADDED, this.update.bind(this));
2418    this.addAscent(DisclosureEmission.RETRIEVE, this.retrieve.bind(this));
2419    this.addAscent(DisclosureEmission.REMOVED, this.update.bind(this));
2420    this.descend(DisclosureEmission.GROUP);
2421    this._isGrouped = this.getAttribute(DisclosureSelector.GROUP) !== 'false';
2422    this.update();
2423  }
2424
2425  get proxy () {
2426    const scope = this;
2427
2428    const proxyAccessors = {
2429      set index (value) {
2430        scope.index = value;
2431      },
2432      get index () {
2433        return scope.index;
2434      },
2435      get length () {
2436        return scope.length;
2437      },
2438      get current () {
2439        const current = scope.current;
2440        return current ? current.proxy : null;
2441      },
2442      get members () {
2443        return scope.members.map((member) => member.proxy);
2444      },
2445      get hasFocus () {
2446        return scope.hasFocus;
2447      },
2448      set isGrouped (value) {
2449        scope.isGrouped = value;
2450      },
2451      get isGrouped () {
2452        return scope.isGrouped;
2453      }
2454    };
2455
2456    return completeAssign(super.proxy, proxyAccessors);
2457  }
2458
2459  validate (member) {
2460    return true;
2461  }
2462
2463  getMembers () {
2464    const members = this.element.getDescendantInstances(this.disclosureInstanceClassName, this.constructor.instanceClassName, true);
2465    this._members = members.filter(this.validate.bind(this)).filter(member => member.isEnabled);
2466    const invalids = members.filter(member => !this._members.includes(member));
2467    invalids.forEach(invalid => invalid.conceal());
2468  }
2469
2470  retrieve (bypassPrevention = false) {
2471    if (this._isRetrieving || (this._hasRetrieved && !bypassPrevention)) return;
2472    this._isRetrieving = true;
2473    this.request(this._retrieve.bind(this));
2474  }
2475
2476  _retrieve () {
2477    this.getMembers();
2478    this._isRetrieving = false;
2479    this._hasRetrieved = true;
2480    if (this.hash) {
2481      for (let i = 0; i < this.length; i++) {
2482        const member = this.members[i];
2483        if (this.hash === member.id) {
2484          this.index = i;
2485          this.request(() => { this.ascend(DisclosureEmission.SPOTLIGHT); });
2486          return i;
2487        }
2488      }
2489    }
2490
2491    for (let i = 0; i < this.length; i++) {
2492      const member = this.members[i];
2493      if (member.isInitiallyDisclosed) {
2494        this.index = i;
2495        return i;
2496      }
2497    }
2498
2499    return this.getIndex();
2500  }
2501
2502  update () {
2503    this.getMembers();
2504    if (this._hasRetrieved) this.getIndex();
2505  }
2506
2507  get members () {
2508    return this._members;
2509  }
2510
2511  get length () {
2512    return this.members ? this.members.length : 0;
2513  }
2514
2515  getIndex (defaultIndex = -1) {
2516    this._index = undefined;
2517    let index = defaultIndex;
2518    for (let i = 0; i < this.length; i++) {
2519      if (this.members[i].isDisclosed) {
2520        index = i;
2521        break;
2522      }
2523    }
2524
2525    this.index = index;
2526    return index;
2527  }
2528
2529  get index () {
2530    return this._index;
2531  }
2532
2533  set index (value) {
2534    if (value < -1 || value >= this.length || value === this._index) return;
2535    this._index = value;
2536    for (let i = 0; i < this.length; i++) {
2537      const member = this.members[i];
2538      if (value === i) {
2539        if (!member.isDisclosed) member.disclose(true);
2540      } else {
2541        if ((this.isGrouped || !this.canUngroup) && member.isDisclosed) member.conceal(true);
2542      }
2543    }
2544    this.apply();
2545  }
2546
2547  get current () {
2548    if (this._index === -1 || isNaN(this._index)) return null;
2549    return this._members[this._index] || null;
2550  }
2551
2552  set current (member) {
2553    this.index = this.members.indexOf(member);
2554  }
2555
2556  get hasFocus () {
2557    const current = this.current;
2558    if (current) return current.hasFocus;
2559    return false;
2560  }
2561
2562  set isGrouped (value) {
2563    const isGrouped = !!value;
2564    if (this._isGrouped === isGrouped) return;
2565    this._isGrouped = isGrouped;
2566    this.setAttribute(DisclosureSelector.GROUP, !!value);
2567    this.update();
2568  }
2569
2570  get isGrouped () {
2571    return this._isGrouped;
2572  }
2573
2574  get canUngroup () {
2575    return false;
2576  }
2577
2578  mutate (attributesNames) {
2579    if (attributesNames.includes(DisclosureSelector.GROUP)) {
2580      this.isGrouped = this.getAttribute(DisclosureSelector.GROUP) !== 'false';
2581    }
2582  }
2583
2584  apply () {}
2585
2586  dispose () {
2587    super.dispose();
2588    this.descend(DisclosureEmission.UNGROUP);
2589    this._members = null;
2590  }
2591}
2592
2593const DisclosureType = {
2594  EXPAND: {
2595    id: 'expanded',
2596    ariaState: true,
vendor: 13,495 bytes, lines 2597-3137
2597    ariaControls: true,
2598    canConceal: true,
2599    canDisable: true
2600  },
2601  SELECT: {
2602    id: 'selected',
2603    ariaState: true,
2604    ariaControls: true,
2605    canConceal: false,
2606    canDisable: true
2607  },
2608  OPENED: {
2609    id: 'opened',
2610    ariaState: false,
2611    ariaControls: true,
2612    canConceal: true,
2613    canDisable: false
2614  }
2615};
2616
2617class CollapseButton extends DisclosureButton {
2618  constructor () {
2619    super(DisclosureType.EXPAND);
2620  }
2621
2622  static get instanceClassName () {
2623    return 'CollapseButton';
2624  }
2625}
2626
2627const CollapseSelector = {
2628  COLLAPSE: ns.selector('collapse'),
2629  COLLAPSING: ns.selector('collapsing')
2630};
2631
2632/**
2633 * Tab coorespond au panel d'un élement Tabs (tab panel)
2634 * Tab étend disclosure qui ajoute/enleve le modifier --selected,
2635 * et ajoute/eleve l'attribut hidden, sur le panel
2636 */
2637class Collapse extends Disclosure {
2638  constructor () {
2639    super(DisclosureType.EXPAND, CollapseSelector.COLLAPSE, CollapseButton, 'CollapsesGroup');
2640  }
2641
2642  static get instanceClassName () {
2643    return 'Collapse';
2644  }
2645
2646  init () {
2647    super.init();
2648    this.listen('transitionend', this.endCollapsing.bind(this));
2649  }
2650
2651  endCollapsing (e) {
2652    if (!this._isCollpasing) return;
2653    if (this._timeout) clearTimeout(this._timeout);
2654    this._timeout = null;
2655    this._isCollpasing = false;
2656    this.removeClass(CollapseSelector.COLLAPSING);
2657    if (!this.isDisclosed) {
2658      if (this.isLegacy) this.style.maxHeight = '';
2659    }
2660  }
2661
2662  unbound () {
2663    if (this.isLegacy) this.style.maxHeight = 'none';
2664  }
2665
2666  disclose (withhold) {
2667    if (this.isDisclosed === true || !this.isEnabled) return false;
2668    this.unbound();
2669    this.collapsing(() => super.disclose(withhold));
2670  }
2671
2672  conceal (withhold, preventFocus) {
2673    if (this.isDisclosed === false) return false;
2674    this.collapsing(() => super.conceal(withhold, preventFocus));
2675  }
2676
2677  collapsing (request) {
2678    this._isCollpasing = true;
2679    if (this._timeout) clearTimeout(this._timeout);
2680    this.addClass(CollapseSelector.COLLAPSING);
2681    this.adjust();
2682    this.request(() => {
2683      request();
2684      this._timeout = setTimeout(this.endCollapsing.bind(this), 500);
2685    });
2686  }
2687
2688  adjust () {
2689    this.setProperty('--collapser', 'none');
2690    const height = this.node.offsetHeight;
2691    this.setProperty('--collapse', -height + 'px');
2692    this.setProperty('--collapser', '');
2693  }
2694
2695  reset () {
2696    if (!this.isPristine) this.isDisclosed = false;
2697  }
2698
2699  _electPrimaries (candidates) {
2700    const primary = this.element.parent.instances.map(instance => instance.collapsePrimary).filter(button => button !== undefined && candidates.indexOf(button) > -1);
2701    if (primary.length === 1) return primary;
2702    candidates = super._electPrimaries(candidates);
2703    if (candidates.length === 1) return candidates;
2704    const before = candidates.filter(candidate => candidate.dy >= 0);
2705    if (before.length > 0) candidates = before;
2706    if (candidates.length === 1) return candidates;
2707    const min = Math.min(...candidates.map(candidate => candidate.dy));
2708    const mins = candidates.filter(candidate => candidate.dy === min);
2709    if (mins.length > 0) candidates = mins;
2710    if (candidates.length === 1) return candidates;
2711    candidates.sort((a, b) => Math.abs(b.dx) - Math.abs(a.dx));
2712    return candidates;
2713  }
2714}
2715
2716class CollapsesGroup extends DisclosuresGroup {
2717  constructor () {
2718    super('Collapse');
2719  }
2720
2721  static get instanceClassName () {
2722    return 'CollapsesGroup';
2723  }
2724
2725  get canUngroup () {
2726    return true;
2727  }
2728}
2729
2730const EquisizedEmission = {
2731  CHANGE: ns('equisized')
2732};
2733
2734class Equisized extends Instance {
2735  static get instanceClassName () {
2736    return 'Equisized';
2737  }
2738
2739  init () {
2740    this.ascend(EquisizedEmission.CHANGE);
2741  }
2742
2743  measure () {
2744    if (this.isLegacy) this.style.width = 'auto';
2745    return this.getRect().width;
2746  }
2747
2748  adjust (width) {
2749    if (this.isLegacy) this.style.width = `${width}px`;
2750  }
2751
2752  dispose () {
2753    this.ascend(EquisizedEmission.CHANGE);
2754  }
2755}
2756
2757class EquisizedsGroup extends Instance {
2758  static get instanceClassName () {
2759    return 'EquisizedsGroup';
2760  }
2761
2762  init () {
2763    this.isResizing = true;
2764    this.isLoading = true;
2765    this.addAscent(EquisizedEmission.CHANGE, this.resize.bind(this));
2766  }
2767
2768  load () {
2769    this.resize();
2770  }
2771
2772  resize () {
2773    const equisizeds = this.element.getDescendantInstances('Equisized');
2774    if (!this.isLegacy) this.style.setProperty('--equisized-width', 'auto');
2775
2776    const width = Math.max(...equisizeds.map(equisized => equisized.measure()));
2777    if (this.isLegacy) equisizeds.forEach(equisized => equisized.adjust(width));
2778    else this.style.setProperty('--equisized-width', `${width}px`);
2779  }
2780}
2781
2782const ToggleEvent = {
2783  TOGGLE: ns.event('toggle')
2784};
2785
2786class Toggle extends Instance {
2787  static get instanceClassName () {
2788    return 'Toggle';
2789  }
2790
2791  init () {
2792    this.pressed = this.pressed === 'true';
2793    this.listenClick();
2794  }
2795
2796  handleClick () {
2797    this.toggle();
2798  }
2799
2800  toggle () {
2801    this.pressed = this.pressed !== 'true';
2802  }
2803
2804  get pressed () {
2805    return this.getAttribute('aria-pressed');
2806  }
2807
2808  set pressed (value) {
2809    this.setAttribute('aria-pressed', value ? 'true' : 'false');
2810    this.dispatch(ToggleEvent.TOGGLE, value);
2811  }
2812
2813  get proxy () {
2814    const scope = this;
2815    const proxy = Object.assign(super.proxy, {
2816      toggle: scope.toggle.bind(scope)
2817    });
2818
2819    const proxyAccessors = {
2820      get pressed () {
2821        return scope.pressed;
2822      },
2823      set pressed (value) {
2824        scope.pressed = value;
2825      }
2826    };
2827
2828    return completeAssign(proxy, proxyAccessors);
2829  }
2830}
2831
2832const RootSelector = {
2833  ROOT: ':root'
2834};
2835
2836const setAttributes = (el, attrs) => {
2837  Object.keys(attrs).forEach(key => el.setAttribute(key, attrs[key]));
2838};
2839
2840class InjectSvg extends Instance {
2841  static get instanceClassName () {
2842    return 'InjectSvg';
2843  }
2844
2845  init () {
2846    if (this.node) {
2847      this.img = this.node.querySelector('img');
2848    }
2849
2850    if (!this.isLegacy) {
2851      this.replace();
2852    }
2853  }
2854
2855  get proxy () {
2856    const scope = this;
2857    return Object.assign(super.proxy, {
2858      replace: scope.replace.bind(scope),
2859      restore: scope.restore.bind(scope)
2860    });
2861  }
2862
2863  fetch () {
2864    if (this.img) {
2865      this.imgID = this.img.getAttribute('id');
2866      this.imgClass = this.img.getAttribute('class');
2867      this.imgURL = this.img.getAttribute('src');
2868
2869      fetch(this.imgURL)
2870        .then(data => data.text())
2871        .then(response => {
2872          const parser = new DOMParser();
2873          const xmlDoc = parser.parseFromString(response, 'text/html');
2874          this.svg = xmlDoc.querySelector('svg');
2875
2876          if (this.svg) {
2877            this.replace();
2878          }
2879        });
2880    }
2881  }
2882
2883  replace () {
2884    if (!this.svg) {
2885      this.fetch();
2886      return;
2887    }
2888
2889    if (this.imgID && typeof this.imgID !== 'undefined') {
2890      this.svg.setAttribute('id', this.imgID);
2891    }
2892
2893    // gestion de la dépréciation
2894    let name = this.imgURL.match(/[ \w-]+\./)[0];
2895    if (name) {
2896      name = name.slice(0, -1);
2897
2898      if (['dark', 'light', 'system'].includes(name)) {
2899        this.svg.innerHTML = this.svg.innerHTML.replaceAll('id="artwork-', `id="${name}-artwork-`);
2900        this.svg.innerHTML = this.svg.innerHTML.replaceAll('"#artwork-', `"#${name}-artwork-`);
2901      }
2902    }
2903
2904    if (this.imgClass && typeof this.imgClass !== 'undefined') {
2905      this.svg.setAttribute('class', this.imgClass);
2906    }
2907
2908    if (this.svg.hasAttribute('xmlns:a')) {
2909      this.svg.removeAttribute('xmlns:a');
2910    }
2911
2912    this.node.setAttribute('data-fr-inject-svg', true);
2913    const svgAttributes = {
2914      'aria-hidden': true,
2915      focusable: false
2916    };
2917    setAttributes(this.svg, svgAttributes);
2918    this.node.replaceChild(this.svg, this.img);
2919  }
2920
2921  restore () {
2922    if (this.img && this.svg) {
2923      this.node.setAttribute('data-fr-inject-svg', false);
2924      this.node.replaceChild(this.img, this.svg);
2925    }
2926  }
2927}
2928
2929const InjectSvgSelector = {
2930  INJECT_SVG: `[${ns.attr('inject-svg')}]`
2931};
2932
2933class Artwork extends Instance {
2934  static get instanceClassName () {
2935    return 'Artwork';
2936  }
2937
2938  init () {
2939    if (this.isLegacy) {
2940      this.replace();
2941    }
2942  }
2943
2944  get proxy () {
2945    const scope = this;
2946    return Object.assign(super.proxy, {
2947      replace: scope.replace.bind(scope)
2948    });
2949  }
2950
2951  fetch () {
2952    this.xlink = this.node.getAttribute('href');
2953    const splitUrl = this.xlink.split('#');
2954    this.svgUrl = splitUrl[0];
2955    this.svgName = splitUrl[1];
2956
2957    const xhr = new XMLHttpRequest();
2958    xhr.onload = () => {
2959      const parser = new DOMParser();
2960      const xmlDoc = parser.parseFromString(xhr.responseText, 'text/html');
2961      this.realSvgContent = xmlDoc.getElementById(this.svgName);
2962      if (this.realSvgContent) {
2963        if (this.realSvgContent.tagName === 'symbol') {
2964          this.use = xmlDoc.querySelector('use[href="#' + this.svgName + '"]');
2965          if (this.use) this.node.parentNode.insertBefore(this.use, this.node);
2966        } else {
2967          // deprecated svg structure
2968          this.realSvgContent.classList.add(this.node.classList);
2969        }
2970
2971        this.replace();
2972      }
2973    };
2974    xhr.open('GET', this.svgUrl);
2975    xhr.send();
2976  }
2977
2978  replace () {
2979    if (!this.realSvgContent) {
2980      this.fetch();
2981      return;
2982    }
2983
2984    this.node.parentNode.replaceChild(this.realSvgContent, this.node);
2985  }
2986}
2987
2988const ArtworkSelector = {
2989  ARTWORK_USE: `${ns.selector('artwork')} use`
2990};
2991
2992const AssessSelector = {
2993  ASSESS_FILE: `${ns.attr.selector('assess-file')}`,
2994  DETAIL: `${ns.attr.selector('assess-file')} [class$="__detail"], ${ns.attr.selector('assess-file')} [class*="__detail "]`
2995};
2996
2997const AssessEmission = {
2998  UPDATE: ns.emission('assess', 'update'),
2999  ADDED: ns.emission('assess', 'added')
3000};
3001
3002class AssessFile extends Instance {
3003  static get instanceClassName () {
3004    return 'AssessFile';
3005  }
3006
3007  init () {
3008    this.lang = this.getLang(this.node);
3009    this.href = this.getAttribute('href');
3010    this.hreflang = this.getAttribute('hreflang');
3011    this.file = {};
3012    this.gather();
3013    this.addAscent(AssessEmission.ADDED, this.update.bind(this));
3014    this.addDescent(AssessEmission.ADDED, this.update.bind(this));
3015  }
3016
3017  getFileLength () {
3018    if (this.href === undefined) {
3019      this.length = -1;
3020      return;
3021    }
3022
3023    fetch(this.href, { method: 'HEAD', mode: 'cors' }).then(response => {
3024      this.length = response.headers.get('content-length') || -1;
3025      if (this.length === -1) {
3026        inspector.warn('File size unknown: ' + this.href + '\nUnable to get HTTP header: "content-length"');
3027      }
3028      this.gather();
3029    });
3030  }
3031
3032  mutate (attributeNames) {
3033    if (attributeNames.indexOf('href') !== -1) {
3034      this.href = this.getAttribute('href');
3035      this.getFileLength();
3036    }
3037
3038    if (attributeNames.indexOf('hreflang') !== -1) {
3039      this.hreflang = this.getAttribute('hreflang');
3040      this.gather();
3041    }
3042  }
3043
3044  gather () {
3045    // TODO V2: implémenter async
3046    if (this.isLegacy) this.length = -1;
3047
3048    if (!this.length) {
3049      this.getFileLength();
3050      return;
3051    }
3052
3053    this.details = [];
3054
3055    if (this.href) {
3056      const extension = this.parseExtension(this.href);
3057      if (extension) this.details.push(extension.toUpperCase());
3058    }
3059
3060    if (this.length !== -1) {
3061      this.details.push(this.bytesToSize(this.length));
3062    }
3063
3064    if (this.hreflang) {
3065      this.details.push(this.getLangDisplayName(this.hreflang));
3066    }
3067
3068    this.update();
3069  }
3070
3071  update () {
3072    if (!this.details) return;
3073    this.descend(AssessEmission.UPDATE, this.details);
3074    this.ascend(AssessEmission.UPDATE, this.details);
3075  }
3076
3077  getLang (elem) {
3078    // todo: ajouter un listener global de changement de langue
3079    if (elem.lang) return elem.lang;
3080    if (document.documentElement === elem) return window.navigator.language;
3081    return this.getLang(elem.parentElement);
3082  }
3083
3084  parseExtension (url) {
3085    const regexExtension = /\.(\w{1,9})(?:$|[?#])/;
3086    return url.match(regexExtension)[0].replace('.', '');
3087  }
3088
3089  getLangDisplayName (locale) {
3090    if (this.isLegacy) return locale;
3091    const displayNames = new Intl.DisplayNames([this.lang], { type: 'language' });
3092    const name = displayNames.of(locale);
3093    return name.charAt(0).toUpperCase() + name.slice(1);
3094  }
3095
3096  bytesToSize (bytes) {
3097    if (bytes === -1) return null;
3098
3099    let sizeUnits = ['octets', 'ko', 'Mo', 'Go', 'To'];
3100    if (this.getAttribute(ns.attr('assess-file')) === 'bytes') {
3101      sizeUnits = ['bytes', 'KB', 'MB', 'GB', 'TB'];
3102    }
3103
3104    const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1000)), 10);
3105    if (i === 0) return `${bytes} ${sizeUnits[i]}`;
3106
3107    const size = bytes / (1000 ** i);
3108    const roundedSize = Math.round((size + Number.EPSILON) * 100) / 100; // arrondi a 2 décimal
3109    const stringSize = String(roundedSize).replace('.', ',');
3110
3111    return `${stringSize} ${sizeUnits[i]}`;
3112  }
3113}
3114
3115class AssessDetail extends Instance {
3116  static get instanceClassName () {
3117    return 'AssessDetail';
3118  }
3119
3120  init () {
3121    this.addDescent(AssessEmission.UPDATE, this.update.bind(this));
3122    this.ascend(AssessEmission.ADDED);
3123  }
3124
3125  update (details) {
3126    this.node.innerHTML = details.join(' - ');
3127  }
3128}
3129
3130const ratiosImg = ['32x9', '16x9', '3x2', '4x3', '1x1', '3x4', '2x3'];
3131const ratiosVid = ['16x9', '4x3', '1x1'];
3132
3133const ratioSelector = (name, modifiers) => {
3134  return modifiers.map(modifier => ns.selector(`${name}--${modifier}`)).join(',');
3135};
3136
3137const deprecatedRatioSelector = `${ns.selector('responsive-img')}, ${ratioSelector('responsive-img', ratiosImg)}, ${ns.selector('responsive-vid')}
3137, ${ratioSelector('responsive-vid', ratiosVid)}`;
3138
3139const RatioSelector = {
3140  RATIO: `${ns.selector('ratio')}, ${ratioSelector('ratio', ratiosImg)}, ${deprecatedRatioSelector}`
3141};
3142
3143const api = window[config.namespace];
3144
3145class Ratio extends Instance {
3146  static get instanceClassName () {
3147    return 'Ratio';
3148  }
3149
3150  init () {
3151    if (!api.internals.support.supportAspectRatio()) {
3152      this.ratio = 16 / 9;
3153      for (const className in this.classNames) {
3154        if (this.registration.selector.indexOf(this.classNames[className]) > 0) {
3155          const ratio = this.classNames[className].split('ratio-');
3156          if (ratio[1]) {
3157            this.ratio = ratio[1].split('x')[0] / ratio[1].split('x')[1];
3158          }
3159        }
3160      }
3161      this.isRendering = true;
3162      this.update();
3163    }
3164  }
3165
3166  render () {
3167    const width = this.getRect().width;
3168    if (width !== this.currentWidth) this.update();
3169  }
3170
3171  update () {
3172    this.currentWidth = this.getRect().width;
3173    this.style.height = this.currentWidth / this.ratio + 'px';
3174  }
3175}
3176
3177const PlaceSelector = {
3178  TOP: ns.selector('placement--top'),
3179  RIGHT: ns.selector('placement--right'),
3180  BOTTOM: ns.selector('placement--bottom'),
3181  LEFT: ns.selector('placement--left')
3182};
3183
3184const AlignSelector = {
3185  START: ns.selector('placement--start'),
3186  CENTER: ns.selector('placement--center'),
3187  END: ns.selector('placement--end')
3188};
3189
3190const PlacementPosition = {
3191  TOP: 'place_top',
3192  RIGHT: 'place_right',
3193  BOTTOM: 'place_bottom',
3194  LEFT: 'place_left'
3195};
3196
3197const PlacementAlign = {
3198  START: 'align_start',
3199  CENTER: 'align_center',
3200  END: 'align_end'
3201};
3202
3203const PlacementMode = {
3204  AUTO: 'placement_auto',
3205  MANUAL: 'placement_manual'
3206};
3207
3208class Placement extends Instance {
3209  constructor (mode = PlacementMode.AUTO, places = [PlacementPosition.BOTTOM, PlacementPosition.TOP, PlacementPosition.LEFT, PlacementPosition.RIGHT], aligns = [PlacementAlign.CENTER, PlacementAlign.START, PlacementAlign.END], safeAreaMargin = 16) {
3210    super();
3211    this._mode = mode;
3212    this._places = places;
3213    this._aligns = aligns;
3214    this._safeAreaMargin = safeAreaMargin;
3215    this._isShown = false;
3216  }
3217
3218  static get instanceClassName () {
3219    return 'Placement';
3220  }
3221
3222  init () {
3223    this.isResizing = true;
3224  }
3225
3226  get proxy () {
3227    const scope = this;
3228    const proxy = Object.assign(super.proxy, {
3229      show: scope.show.bind(scope),
3230      hide: scope.hide.bind(scope)
3231    });
3232
3233    const proxyAccessors = {
3234      get mode () {
3235        return scope.mode;
3236      },
3237      set mode (value) {
3238        scope.mode = value;
3239      },
3240      get place () {
3241        return scope.place;
3242      },
3243      set place (value) {
3244        scope.place = value;
3245      },
3246      get align () {
3247        return scope.align;
3248      },
3249      set align (value) {
3250        scope.align = value;
3251      },
3252      get isShown () {
3253        return scope.isShown;
3254      },
3255      set isShown (value) {
3256        scope.isShown = value;
3257      }
3258    };
3259
3260    return completeAssign(proxy, proxyAccessors);
3261  }
3262
3263  get mode () {
3264    return this._mode;
3265  }
3266
3267  set mode (value) {
3268    this._mode = value;
3269  }
3270
3271  get place () {
3272    return this._place;
3273  }
3274
3275  set place (value) {
3276    if (this._place === value) return;
3277    switch (this._place) {
3278      case PlacementPosition.TOP:
3279        this.removeClass(PlaceSelector.TOP);
3280        break;
3281
3282      case PlacementPosition.RIGHT:
3283        this.removeClass(PlaceSelector.RIGHT);
3284        break;
3285
3286      case PlacementPosition.BOTTOM:
3287        this.removeClass(PlaceSelector.BOTTOM);
3288        break;
3289
3290      case PlacementPosition.LEFT:
3291        this.removeClass(PlaceSelector.LEFT);
3292        break;
3293    }
3294    this._place = value;
3295    switch (this._place) {
3296      case PlacementPosition.TOP:
3297        this.addClass(PlaceSelector.TOP);
3298        break;
3299
3300      case PlacementPosition.RIGHT:
3301        this.addClass(PlaceSelector.RIGHT);
3302        break;
3303
3304      case PlacementPosition.BOTTOM:
3305        this.addClass(PlaceSelector.BOTTOM);
3306        break;
3307
3308      case PlacementPosition.LEFT:
3309        this.addClass(PlaceSelector.LEFT);
3310        break;
3311    }
3312  }
3313
3314  get align () {
3315    return this._align;
3316  }
3317
3318  set align (value) {
3319    if (this._align === value) return;
3320    switch (this._align) {
3321      case PlacementAlign.START:
3322        this.removeClass(AlignSelector.START);
3323        break;
3324
3325      case PlacementAlign.CENTER:
3326        this.removeClass(AlignSelector.CENTER);
3327        break;
3328
3329      case PlacementAlign.END:
3330        this.removeClass(AlignSelector.END);
3331        break;
3332    }
3333    this._align = value;
3334    switch (this._align) {
3335      case PlacementAlign.START:
3336        this.addClass(AlignSelector.START);
3337        break;
3338
3339      case PlacementAlign.CENTER:
3340        this.addClass(AlignSelector.CENTER);
3341        break;
3342
3343      case PlacementAlign.END:
3344        this.addClass(AlignSelector.END);
3345        break;
3346    }
3347  }
3348
3349  show () {
3350    this.isShown = true;
3351  }
3352
3353  hide () {
3354    this.isShown = false;
3355  }
3356
3357  get isShown () {
3358    return this._isShown;
3359  }
3360
3361  set isShown (value) {
3362    if (this._isShown === value || !this.isEnabled) return;
3363    this.isRendering = value;
3364    this._isShown = value;
3365  }
3366
3367  setReferent (referent) {
3368    this._referent = referent;
3369  }
3370
3371  resize () {
3372    this.safeArea = {
3373      top: this._safeAreaMargin,
3374      right: window.innerWidth - this._safeAreaMargin,
3375      bottom: window.innerHeight - this._safeAreaMargin,
3376      left: this._safeAreaMargin,
3377      center: window.innerWidth * 0.5,
3378      middle: window.innerHeight * 0.5
3379    };
3380  }
3381
3382  render () {
3383    if (!this._referent) return;
3384    this.rect = this.getRect();
3385    this.referentRect = this._referent.getRect();
3386
3387    if (this.mode === PlacementMode.AUTO) {
3388      this.place = this.getPlace();
3389      switch (this.place) {
3390        case PlacementPosition.TOP:
3391        case PlacementPosition.BOTTOM:
3392          this.align = this.getHorizontalAlign();
3393          break;
3394
3395        case PlacementPosition.LEFT:
3396        case PlacementPosition.RIGHT:
3397          this.align = this.getVerticalAlign();
3398      }
3399    }
3400
3401    let x, y;
3402
3403    switch (this.place) {
3404      case PlacementPosition.TOP:
3405        y = this.referentRect.top - this.rect.height;
3406        break;
3407
3408      case PlacementPosition.RIGHT:
3409        x = this.referentRect.right;
3410        break;
3411
3412      case PlacementPosition.BOTTOM:
3413        y = this.referentRect.bottom;
3414        break;
3415
3416      case PlacementPosition.LEFT:
3417        x = this.referentRect.left - this.rect.width;
3418        break;
3419    }
3420
3421    switch (this.place) {
3422      case PlacementPosition.TOP:
3423      case PlacementPosition.BOTTOM:
3424        switch (this.align) {
3425          case PlacementAlign.CENTER:
3426            x = this.referentRect.center - this.rect.width * 0.5;
3427            break;
3428
3429          case PlacementAlign.START:
3430            x = this.referentRect.left;
3431            break;
3432
3433          case PlacementAlign.END:
3434            x = this.referentRect.right - this.rect.width;
3435            break;
3436        }
3437        break;
3438
3439      case PlacementPosition.RIGHT:
3440      case PlacementPosition.LEFT:
3441        switch (this.align) {
3442          case PlacementAlign.CENTER:
3443            y = this.referentRect.middle - this.rect.height * 0.5;
3444            break;
3445
3446          case PlacementAlign.START:
3447            y = this.referentRect.top;
3448            break;
3449
3450          case PlacementAlign.END:
3451            y = this.referentRect.bottom - this.rect.height;
3452            break;
3453        }
3454        break;
3455    }
3456
3457    if (this._x !== x || this._y !== y) {
3458      this._x = (x + 0.5) | 0;
3459      this._y = (y + 0.5) | 0;
3460      this.node.style.transform = `translate(${this._x}px,${this._y}px)`;
3461    }
3462  }
3463
3464  getPlace () {
3465    for (const place of this._places) {
3466      switch (place) {
3467        case PlacementPosition.TOP:
3468          if (this.referentRect.top - this.rect.height > this.safeArea.top) return PlacementPosition.TOP;
3469          break;
3470
3471        case PlacementPosition.RIGHT:
3472          if (this.referentRect.right + this.rect.width < this.safeArea.right) return PlacementPosition.RIGHT;
3473          break;
3474
3475        case PlacementPosition.BOTTOM:
3476          if (this.referentRect.bottom + this.rect.height < this.safeArea.bottom) return PlacementPosition.BOTTOM;
3477          break;
3478
3479        case PlacementPosition.LEFT:
3480          if (this.referentRect.left - this.rect.width > this.safeArea.left) return PlacementPosition.LEFT;
3481          break;
3482      }
3483    }
3484
3485    return this._places[0];
3486  }
3487
3488  getHorizontalAlign () {
3489    for (const align of this._aligns) {
3490      switch (align) {
3491        case PlacementAlign.CENTER:
3492          if (this.referentRect.center - this.rect.width * 0.5 > this.safeArea.left && this.referentRect.center + this.rect.width * 0.5 < this.safeArea.right) return PlacementAlign.CENTER;
3493          break;
3494
3495        case PlacementAlign.START:
3496          if (this.referentRect.left + this.rect.width < this.safeArea.right) return PlacementAlign.START;
3497          break;
3498
3499        case PlacementAlign.END:
3500          if (this.referentRect.right - this.rect.width > this.safeArea.left) return PlacementAlign.END;
3501          break;
3502      }
3503    }
3504
3505    return this._aligns[0];
3506  }
3507
3508  getVerticalAlign () {
vendor: 11,752 bytes, lines 3509-3936
3509    for (const align of this._aligns) {
3510      switch (align) {
3511        case PlacementAlign.CENTER:
3512          if (this.referentRect.middle - this.rect.height * 0.5 > this.safeArea.top && this.referentRect.middle + this.rect.height * 0.5 < this.safeArea.bottom) return PlacementAlign.CENTER;
3513          break;
3514
3515        case PlacementAlign.START:
3516          if (this.referentRect.top + this.rect.height < this.safeArea.bottom) return PlacementAlign.START;
3517          break;
3518
3519        case PlacementAlign.END:
3520          if (this.referentRect.bottom - this.rect.height > this.safeArea.top) return PlacementAlign.END;
3521          break;
3522      }
3523    }
3524
3525    return this._aligns[0];
3526  }
3527
3528  dispose () {
3529    this._referent = null;
3530    super.dispose();
3531  }
3532}
3533
3534class PlacementReferent extends Instance {
3535  constructor () {
3536    super();
3537    this._isShown = false;
3538  }
3539
3540  static get instanceClassName () {
3541    return 'PlacementReferent';
3542  }
3543
3544  init () {
3545    this.registration.creator.setReferent(this);
3546    this._placement = this.registration.creator;
3547  }
3548
3549  get placement () {
3550    return this._placement;
3551  }
3552
3553  get isShown () {
3554    return this._isShown;
3555  }
3556
3557  set isShown (value) {
3558    if (this._isShown === value || !this.isEnabled) return;
3559    this._isShown = value;
3560    if (value) this.registration.creator.show();
3561    else this.registration.creator.hide();
3562  }
3563
3564  show () {
3565    this.isShown = true;
3566  }
3567
3568  hide () {
3569    this.isShown = false;
3570  }
3571}
3572
3573api$1.core = {
3574  Instance: Instance,
3575  Breakpoints: Breakpoints,
3576  KeyCodes: KeyCodes,
3577  Disclosure: Disclosure,
3578  DisclosureButton: DisclosureButton,
3579  DisclosuresGroup: DisclosuresGroup,
3580  DisclosureType: DisclosureType,
3581  DisclosureEvent: DisclosureEvent,
3582  DisclosureSelector: DisclosureSelector,
3583  DisclosureEmission: DisclosureEmission,
3584  Collapse: Collapse,
3585  CollapseButton: CollapseButton,
3586  CollapsesGroup: CollapsesGroup,
3587  CollapseSelector: CollapseSelector,
3588  RootSelector: RootSelector,
3589  RootEmission: RootEmission,
3590  Equisized: Equisized,
3591  EquisizedEmission: EquisizedEmission,
3592  Toggle: Toggle,
3593  EquisizedsGroup: EquisizedsGroup,
3594  InjectSvg: InjectSvg,
3595  InjectSvgSelector: InjectSvgSelector,
3596  Artwork: Artwork,
3597  ArtworkSelector: ArtworkSelector,
3598  AssessFile: AssessFile,
3599  AssessDetail: AssessDetail,
3600  AssessEmission: AssessEmission,
3601  AssessSelector: AssessSelector,
3602  Ratio: Ratio,
3603  RatioSelector: RatioSelector,
3604  Placement: Placement,
3605  PlacementReferent: PlacementReferent,
3606  PlacementAlign: PlacementAlign,
3607  PlacementPosition: PlacementPosition,
3608  PlacementMode: PlacementMode
3609};
3610
3611api$1.internals.register(api$1.core.CollapseSelector.COLLAPSE, api$1.core.Collapse);
3612api$1.internals.register(api$1.core.InjectSvgSelector.INJECT_SVG, api$1.core.InjectSvg);
3613api$1.internals.register(api$1.core.RatioSelector.RATIO, api$1.core.Ratio);
3614api$1.internals.register(api$1.core.AssessSelector.ASSESS_FILE, api$1.core.AssessFile);
3615api$1.internals.register(api$1.core.AssessSelector.DETAIL, api$1.core.AssessDetail);
3616
3617const SchemeValue = {
3618  SYSTEM: 'system',
3619  LIGHT: 'light',
3620  DARK: 'dark'
3621};
3622
3623const SchemeAttribute = {
3624  THEME: api.internals.ns.attr('theme'),
3625  SCHEME: api.internals.ns.attr('scheme'),
3626  TRANSITION: api.internals.ns.attr('transition')
3627};
3628
3629const SchemeTheme = {
3630  LIGHT: 'light',
3631  DARK: 'dark'
3632};
3633
3634const SchemeEmission = {
3635  SCHEME: api.internals.ns.emission('scheme', 'scheme'),
3636  THEME: api.internals.ns.emission('scheme', 'theme'),
3637  ASK: api.internals.ns.emission('scheme', 'ask')
3638};
3639
3640const SchemeEvent = {
3641  SCHEME: api.internals.ns.event('scheme'),
3642  THEME: api.internals.ns.event('theme')
3643};
3644
3645class Scheme extends api.core.Instance {
3646  constructor () {
3647    super(false);
3648  }
3649
3650  static get instanceClassName () {
3651    return 'Scheme';
3652  }
3653
3654  init () {
3655    this.changing = this.change.bind(this);
3656
3657    if (this.hasAttribute(SchemeAttribute.TRANSITION)) {
3658      this.removeAttribute(SchemeAttribute.TRANSITION);
3659      this.request(this.restoreTransition.bind(this));
3660    }
3661
3662    const scheme = api.internals.support.supportLocalStorage() ? localStorage.getItem('scheme') : '';
3663    const schemeAttr = this.getAttribute(SchemeAttribute.SCHEME);
3664
3665    switch (scheme) {
3666      case SchemeValue.DARK:
3667      case SchemeValue.LIGHT:
3668      case SchemeValue.SYSTEM:
3669        this.scheme = scheme;
3670        break;
3671
3672      default:
3673        switch (schemeAttr) {
3674          case SchemeValue.DARK:
3675            this.scheme = SchemeValue.DARK;
3676            break;
3677
3678          case SchemeValue.LIGHT:
3679            this.scheme = SchemeValue.LIGHT;
3680            break;
3681
3682          default:
3683            this.scheme = SchemeValue.SYSTEM;
3684        }
3685    }
3686
3687    this.addAscent(SchemeEmission.ASK, this.ask.bind(this));
3688    this.addAscent(SchemeEmission.SCHEME, this.apply.bind(this));
3689  }
3690
3691  get proxy () {
3692    const scope = this;
3693
3694    const proxyAccessors = {
3695      get scheme () {
3696        return scope.scheme;
3697      },
3698      set scheme (value) {
3699        scope.scheme = value;
3700      }
3701    };
3702
3703    return api.internals.property.completeAssign(super.proxy, proxyAccessors);
3704  }
3705
3706  restoreTransition () {
3707    this.setAttribute(SchemeAttribute.TRANSITION, '');
3708  }
3709
3710  ask () {
3711    this.descend(SchemeEmission.SCHEME, this.scheme);
3712  }
3713
3714  apply (value) {
3715    this.scheme = value;
3716  }
3717
3718  get scheme () {
3719    return this._scheme;
3720  }
3721
3722  set scheme (value) {
3723    if (this._scheme === value) return;
3724    this._scheme = value;
3725    switch (value) {
3726      case SchemeValue.SYSTEM:
3727        this.listenPreferences();
3728        break;
3729
3730      case SchemeValue.DARK:
3731        this.unlistenPreferences();
3732        this.theme = SchemeTheme.DARK;
3733        break;
3734
3735      case SchemeValue.LIGHT:
3736        this.unlistenPreferences();
3737        this.theme = SchemeTheme.LIGHT;
3738        break;
3739
3740      default:
3741        this.scheme = SchemeValue.SYSTEM;
3742        return;
3743    }
3744
3745    this.descend(SchemeEmission.SCHEME, value);
3746    if (api.internals.support.supportLocalStorage()) {
3747      localStorage.setItem('scheme', value);
3748    }
3749    this.setAttribute(SchemeAttribute.SCHEME, value);
3750    this.dispatch(SchemeEvent.SCHEME, { scheme: this._scheme });
3751  }
3752
3753  get theme () {
3754    return this._theme;
3755  }
3756
3757  set theme (value) {
3758    if (this._theme === value) return;
3759    switch (value) {
3760      case SchemeTheme.LIGHT:
3761      case SchemeTheme.DARK:
3762        this._theme = value;
3763        this.setAttribute(SchemeAttribute.THEME, value);
3764        this.descend(SchemeEmission.THEME, value);
3765        this.dispatch(SchemeEvent.THEME, { theme: this._theme });
3766        document.documentElement.style.colorScheme = value === SchemeTheme.DARK ? 'dark' : '';
3767        break;
3768    }
3769  }
3770
3771  listenPreferences () {
3772    if (this.isListening) return;
3773    this.isListening = true;
3774    this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
3775    if (this.mediaQuery.addEventListener) this.mediaQuery.addEventListener('change', this.changing);
3776    this.change();
3777  }
3778
3779  unlistenPreferences () {
3780    if (!this.isListening) return;
3781    this.isListening = false;
3782    this.mediaQuery.removeEventListener('change', this.changing);
3783    this.mediaQuery = null;
3784  }
3785
3786  change () {
3787    if (!this.isListening) return;
3788    this.theme = this.mediaQuery.matches ? SchemeTheme.DARK : SchemeTheme.LIGHT;
3789  }
3790
3791  mutate (attributeNames) {
3792    if (attributeNames.indexOf(SchemeAttribute.SCHEME) > -1) this.scheme = this.getAttribute(SchemeAttribute.SCHEME);
3793    if (attributeNames.indexOf(SchemeAttribute.THEME) > -1) this.theme = this.getAttribute(SchemeAttribute.THEME);
3794  }
3795
3796  dispose () {
3797    this.unlistenPreferences();
3798  }
3799}
3800
3801const SchemeSelector = {
3802  SCHEME: `:root${api.internals.ns.attr.selector('theme')}, :root${api.internals.ns.attr.selector('scheme')}`,
3803  SWITCH_THEME: api.internals.ns.selector('switch-theme'),
3804  RADIO_BUTTONS: `input[name="${api.internals.ns('radios-theme')}"]`
3805};
3806
3807api.scheme = {
3808  Scheme: Scheme,
3809  SchemeValue: SchemeValue,
3810  SchemeSelector: SchemeSelector,
3811  SchemeEmission: SchemeEmission,
3812  SchemeTheme: SchemeTheme,
3813  SchemeEvent: SchemeEvent
3814};
3815
3816api.internals.register(api.scheme.SchemeSelector.SCHEME, api.scheme.Scheme);
3817
3818const ACCORDION = api.internals.ns.selector('accordion');
3819const COLLAPSE$2 = api.internals.ns.selector('collapse');
3820
3821const AccordionSelector = {
3822  GROUP: api.internals.ns.selector('accordions-group'),
3823  ACCORDION: ACCORDION,
3824  COLLAPSE: `${ACCORDION} > ${COLLAPSE$2}, ${ACCORDION} > *:not(${ACCORDION}):not(${COLLAPSE$2}) > ${COLLAPSE$2}, ${ACCORDION} > *:not(${ACCORDION}):not(${COLLAPSE$2}) > *:not(${ACCORDION}):not(${COLLAPSE$2}) > ${COLLAPSE$2}`,
3825  COLLAPSE_LEGACY: `${ACCORDION} ${COLLAPSE$2}`,
3826  BUTTON: `${ACCORDION}__btn`
3827};
3828
3829class Accordion extends api.core.Instance {
3830  static get instanceClassName () {
3831    return 'Accordion';
3832  }
3833
3834  get collapsePrimary () {
3835    const buttons = this.element.children.map(child => child.getInstance('CollapseButton')).filter(button => button !== null && button.hasClass(AccordionSelector.BUTTON));
3836    return buttons[0];
3837  }
3838}
3839
3840class AccordionsGroup extends api.core.CollapsesGroup {
3841  static get instanceClassName () {
3842    return 'AccordionsGroup';
3843  }
3844
3845  validate (member) {
3846    const match = member.node.matches(api.internals.legacy.isLegacy ? AccordionSelector.COLLAPSE_LEGACY : AccordionSelector.COLLAPSE);
3847    return super.validate(member) && match;
3848  }
3849}
3850
3851api.accordion = {
3852  Accordion: Accordion,
3853  AccordionSelector: AccordionSelector,
3854  AccordionsGroup: AccordionsGroup
3855};
3856
3857api.internals.register(api.accordion.AccordionSelector.GROUP, api.accordion.AccordionsGroup);
3858api.internals.register(api.accordion.AccordionSelector.ACCORDION, api.accordion.Accordion);
3859
3860const ButtonSelector = {
3861  EQUISIZED_BUTTON: `${api.internals.ns.selector('btns-group--equisized')} ${api.internals.ns.selector('btn')}`,
3862  EQUISIZED_GROUP: api.internals.ns.selector('btns-group--equisized')
3863};
3864
3865api.button = {
3866  ButtonSelector: ButtonSelector
3867};
3868
3869api.internals.register(api.button.ButtonSelector.EQUISIZED_BUTTON, api.core.Equisized);
3870api.internals.register(api.button.ButtonSelector.EQUISIZED_GROUP, api.core.EquisizedsGroup);
3871
3872class CardDownload extends api.core.Instance {
3873  static get instanceClassName () {
3874    return 'CardDownload';
3875  }
3876
3877  init () {
3878    this.addAscent(api.core.AssessEmission.UPDATE, details => {
3879      this.descend(api.core.AssessEmission.UPDATE, details);
3880    });
3881    this.addAscent(api.core.AssessEmission.ADDED, () => {
3882      this.descend(api.core.AssessEmission.ADDED);
3883    });
3884  }
3885}
3886
3887const CardSelector = {
3888  DOWNLOAD: api.internals.ns.selector('card--download'),
3889  DOWNLOAD_DETAIL: `${api.internals.ns.selector('card--download')} ${api.internals.ns.selector('card__end')} ${api.internals.ns.selector('card__detail')}`
3890};
3891
3892api.card = {
3893  CardSelector: CardSelector,
3894  CardDownload: CardDownload
3895};
3896
3897api.internals.register(api.card.CardSelector.DOWNLOAD, api.card.CardDownload);
3898api.internals.register(api.card.CardSelector.DOWNLOAD_DETAIL, api.core.AssessDetail);
3899
3900const CheckboxSelector = {
3901  INPUT: `${api.internals.ns.selector('checkbox-group')} input[type="checkbox"]`
3902};
3903
3904const CheckboxEmission = {
3905  CHANGE: api.internals.ns.emission('checkbox', 'change'),
3906  RETRIEVE: api.internals.ns.emission('checkbox', 'retrieve')
3907};
3908
3909class CheckboxInput extends api.core.Instance {
3910  static get instanceClassName () {
3911    return 'CheckboxInput';
3912  }
3913
3914  constructor () {
3915    super();
3916    this._handlingChange = this.handleChange.bind(this);
3917  }
3918
3919  init () {
3920    this.node.addEventListener('change', this._handlingChange);
3921    this.addDescent(CheckboxEmission.RETRIEVE, this._handlingChange);
3922    this.handleChange();
3923  }
3924
3925  get isChecked () {
3926    return this.node.checked;
3927  }
3928
3929  handleChange () {
3930    this.ascend(CheckboxEmission.CHANGE, this.node);
3931  }
3932}
3933
3934api.checkbox = {
3935  CheckboxSelector: CheckboxSelector,
3936  CheckboxEmission: CheckboxEmission,
vendor: 4,407 bytes, lines 3937-4094
3937  CheckboxInput: CheckboxInput
3938};
3939
3940api.internals.register(api.checkbox.CheckboxSelector.INPUT, api.checkbox.CheckboxInput);
3941
3942const SegmentedSelector = {
3943  SEGMENTED: api.internals.ns.selector('segmented'),
3944  SEGMENTED_ELEMENTS: api.internals.ns.selector('segmented__elements'),
3945  SEGMENTED_ELEMENT: api.internals.ns.selector('segmented__element input'),
3946  SEGMENTED_LEGEND: api.internals.ns.selector('segmented__legend')
3947};
3948
3949const SegmentedEmission = {
3950  ADDED: api.internals.ns.emission('segmented', 'added'),
3951  REMOVED: api.internals.ns.emission('segmented', 'removed')
3952};
3953
3954class Segmented extends api.core.Instance {
3955  static get instanceClassName () {
3956    return 'Segmented';
3957  }
3958
3959  init () {
3960    this.elements = this.node.querySelector(SegmentedSelector.SEGMENTED_ELEMENTS);
3961    this.legend = this.node.querySelector(SegmentedSelector.SEGMENTED_LEGEND);
3962    this.addAscent(SegmentedEmission.ADDED, this.resize.bind(this));
3963    this.addAscent(SegmentedEmission.REMOVED, this.resize.bind(this));
3964    this._isLegendInline = this.legend && this.legend.classList.contains(`${api.prefix}-segmented__legend--inline`);
3965    this.isResizing = true;
3966  }
3967
3968  resize () {
3969    const SEGMENTED_VERTICAL = `${api.prefix}-segmented--vertical`;
3970    const LEGEND_INLINE = `${api.prefix}-segmented__legend--inline`;
3971    const gapOffset = 16;
3972
3973    this.removeClass(SEGMENTED_VERTICAL);
3974
3975    if (this._isLegendInline) {
3976      this.legend.classList.add(LEGEND_INLINE);
3977
3978      if (this.node.offsetWidth > this.node.parentNode.offsetWidth || (this.elements.scrollWidth + this.legend.offsetWidth + gapOffset) > this.node.parentNode.offsetWidth) {
3979        this.legend.classList.remove(LEGEND_INLINE);
3980      }
3981    }
3982
3983    if (this.elements.offsetWidth > this.node.parentNode.offsetWidth || this.elements.scrollWidth > this.node.parentNode.offsetWidth) {
3984      this.addClass(SEGMENTED_VERTICAL);
3985    } else {
3986      this.removeClass(SEGMENTED_VERTICAL);
3987    }
3988  }
3989}
3990
3991class SegmentedElement extends api.core.Instance {
3992  static get instanceClassName () {
3993    return 'SegmentedElement';
3994  }
3995
3996  init () {
3997    this.ascend(SegmentedEmission.ADDED);
3998  }
3999
4000  dispose () {
4001    this.ascend(SegmentedEmission.REMOVED);
4002  }
4003}
4004
4005api.segmented = {
4006  SegmentedSelector: SegmentedSelector,
4007  SegmentedEmission: SegmentedEmission,
4008  SegmentedElement: SegmentedElement,
4009  Segmented: Segmented
4010};
4011
4012api.internals.register(api.segmented.SegmentedSelector.SEGMENTED, api.segmented.Segmented);
4013api.internals.register(api.segmented.SegmentedSelector.SEGMENTED_ELEMENT, api.segmented.SegmentedElement);
4014
4015const BreadcrumbSelector = {
4016  BREADCRUMB: api.internals.ns.selector('breadcrumb'),
4017  BUTTON: api.internals.ns.selector('breadcrumb__button')
4018};
4019
4020class Breadcrumb extends api.core.Instance {
4021  constructor () {
4022    super();
4023    this.count = 0;
4024    this.focusing = this.focus.bind(this);
4025  }
4026
4027  static get instanceClassName () {
4028    return 'Breadcrumb';
4029  }
4030
4031  init () {
4032    this.getCollapse();
4033    this.isResizing = true;
4034  }
4035
4036  get proxy () {
4037    const scope = this;
4038    return Object.assign(super.proxy, {
4039      focus: scope.focus.bind(scope),
4040      disclose: scope.collapse.disclose.bind(scope.collapse)
4041    });
4042  }
4043
4044  getCollapse () {
4045    const collapse = this.collapse;
4046    if (collapse) {
4047      collapse.listen(api.core.DisclosureEvent.DISCLOSE, this.focusing);
4048    } else {
4049      this.addAscent(api.core.DisclosureEmission.ADDED, this.getCollapse.bind(this));
4050    }
4051  }
4052
4053  resize () {
4054    const collapse = this.collapse;
4055    const links = this.links;
4056    if (!collapse || !links.length) return;
4057
4058    if (this.isBreakpoint(api.core.Breakpoints.MD)) {
4059      if (collapse.buttonHasFocus) links[0].focus();
4060    } else {
4061      if (links.indexOf(document.activeElement) > -1) collapse.focus();
4062    }
4063  }
4064
4065  get links () {
4066    return [...this.querySelectorAll('a[href]')];
4067  }
4068
4069  get collapse () {
4070    return this.element.getDescendantInstances(api.core.Collapse.instanceClassName, null, true)[0];
4071  }
4072
4073  focus () {
4074    this.count = 0;
4075    this._focus();
4076  }
4077
4078  _focus () {
4079    const link = this.links[0];
4080    if (!link) return;
4081    link.focus();
4082    this.request(this.verify.bind(this));
4083  }
4084
4085  verify () {
4086    this.count++;
4087    if (this.count > 100) return;
4088    const link = this.links[0];
4089    if (!link) return;
4090    if (document.activeElement !== link) this._focus();
4091  }
4092
4093  get collapsePrimary () {
4094    const buttons = this.element.children.map(child =>
vendor: 4,524 bytes, lines 4094-4286
4094 child.getInstance('CollapseButton')).filter(button => button !== null && button.hasClass(BreadcrumbSelector.BUTTON));
4095    return buttons[0];
4096  }
4097}
4098
4099api.breadcrumb = {
4100  BreadcrumbSelector: BreadcrumbSelector,
4101  Breadcrumb: Breadcrumb
4102};
4103
4104api.internals.register(api.breadcrumb.BreadcrumbSelector.BREADCRUMB, api.breadcrumb.Breadcrumb);
4105
4106const TooltipSelector = {
4107  TOOLTIP: api.internals.ns.selector('tooltip'),
4108  SHOWN: api.internals.ns.selector('tooltip--shown'),
4109  BUTTON: api.internals.ns.selector('btn--tooltip')
4110};
4111
4112const TooltipReferentState = {
4113  FOCUS: 1 << 0,
4114  HOVER: 1 << 1
4115};
4116
4117class TooltipReferent extends api.core.PlacementReferent {
4118  constructor () {
4119    super();
4120    this._state = 0;
4121  }
4122
4123  static get instanceClassName () {
4124    return 'TooltipReferent';
4125  }
4126
4127  init () {
4128    super.init();
4129    this.listen('focusin', this.focusIn.bind(this));
4130    this.listen('focusout', this.focusOut.bind(this));
4131    if (!this.matches(TooltipSelector.BUTTON)) {
4132      const mouseover = this.mouseover.bind(this);
4133      this.listen('mouseover', mouseover);
4134      this.placement.listen('mouseover', mouseover);
4135      const mouseout = this.mouseout.bind(this);
4136      this.listen('mouseout', mouseout);
4137      this.placement.listen('mouseout', mouseout);
4138    }
4139    this.addEmission(api.core.RootEmission.KEYDOWN, this._keydown.bind(this));
4140    this.listen('click', this._click.bind(this));
4141    this.addEmission(api.core.RootEmission.CLICK, this._clickOut.bind(this));
4142  }
4143
4144  _click () {
4145    this.focus();
4146  }
4147
4148  _clickOut (target) {
4149    if (!this.node.contains(target)) this.blur();
4150  }
4151
4152  _keydown (keyCode) {
4153    switch (keyCode) {
4154      case api.core.KeyCodes.ESCAPE:
4155        this.blur();
4156        this.close();
4157        break;
4158    }
4159  }
4160
4161  close () {
4162    this.state = 0;
4163  }
4164
4165  get state () {
4166    return this._state;
4167  }
4168
4169  set state (value) {
4170    if (this._state === value) return;
4171    this.isShown = value > 0;
4172    this._state = value;
4173  }
4174
4175  focusIn () {
4176    this.state |= TooltipReferentState.FOCUS;
4177  }
4178
4179  focusOut () {
4180    this.state &= ~TooltipReferentState.FOCUS;
4181  }
4182
4183  mouseover () {
4184    this.state |= TooltipReferentState.HOVER;
4185  }
4186
4187  mouseout () {
4188    this.state &= ~TooltipReferentState.HOVER;
4189  }
4190}
4191
4192const TooltipEvent = {
4193  SHOW: ns.event('show'),
4194  HIDE: ns.event('hide')
4195};
4196
4197const TooltipState = {
4198  HIDDEN: 'hidden',
4199  SHOWN: 'shown',
4200  HIDING: 'hiding'
4201};
4202
4203class Tooltip extends api.core.Placement {
4204  constructor () {
4205    super(api.core.PlacementMode.AUTO, [api.core.PlacementPosition.TOP, api.core.PlacementPosition.BOTTOM], [api.core.PlacementAlign.CENTER, api.core.PlacementAlign.START, api.core.PlacementAlign.END]);
4206    this.modifier = '';
4207    this._state = TooltipState.HIDDEN;
4208  }
4209
4210  static get instanceClassName () {
4211    return 'Tooltip';
4212  }
4213
4214  init () {
4215    super.init();
4216    this.register(`[aria-describedby="${this.id}"]`, TooltipReferent);
4217    this.listen('transitionend', this.transitionEnd.bind(this));
4218  }
4219
4220  transitionEnd () {
4221    if (this._state === TooltipState.HIDING) {
4222      this._state = TooltipState.HIDDEN;
4223      this.isShown = false;
4224    }
4225  }
4226
4227  get isShown () {
4228    return super.isShown;
4229  }
4230
4231  set isShown (value) {
4232    if (!this.isEnabled) return;
4233    switch (true) {
4234      case value:
4235        this._state = TooltipState.SHOWN;
4236        this.addClass(TooltipSelector.SHOWN);
4237        this.dispatch(TooltipEvent.SHOW);
4238        super.isShown = true;
4239        break;
4240
4241      case this.isShown && !value && this._state === TooltipState.SHOWN:
4242        this._state = TooltipState.HIDING;
4243        this.removeClass(TooltipSelector.SHOWN);
4244        break;
4245
4246      case this.isShown && !value && this._state === TooltipState.HIDDEN:
4247        this.dispatch(TooltipEvent.HIDE);
4248        super.isShown = false;
4249        break;
4250    }
4251  }
4252
4253  render () {
4254    super.render();
4255    let x = this.referentRect.center - this.rect.center;
4256    const limit = this.rect.width * 0.5 - 8;
4257    if (x < -limit) x = -limit;
4258    if (x > limit) x = limit;
4259    this.setProperty('--arrow-x', `${x.toFixed(2)}px`);
4260  }
4261}
4262
4263api.tooltip = {
4264  Tooltip: Tooltip,
4265  TooltipSelector: TooltipSelector,
4266  TooltipEvent: TooltipEvent
4267};
4268
4269api.internals.register(api.tooltip.TooltipSelector.TOOLTIP, api.tooltip.Tooltip);
4270
4271class ToggleInput extends api.core.Instance {
4272  static get instanceClassName () {
4273    return 'ToggleInput';
4274  }
4275
4276  get isChecked () {
4277    return this.node.checked;
4278  }
4279}
4280
4281class ToggleStatusLabel extends api.core.Instance {
4282  static get instanceClassName () {
4283    return 'ToggleStatusLabel';
4284  }
4285
4286  init () {
vendor: 4,567 bytes, lines 4287-4448
4287    this.register(`input[id="${this.getAttribute('for')}"]`, ToggleInput);
4288    this.update();
4289    this.isSwappingFont = true;
4290  }
4291
4292  get proxy () {
4293    const scope = this;
4294    return Object.assign(super.proxy, {
4295      update: scope.update.bind(scope)
4296    });
4297  }
4298
4299  get input () {
4300    return this.getRegisteredInstances('ToggleInput')[0];
4301  }
4302
4303  update () {
4304    this.node.style.removeProperty('--toggle-status-width');
4305    const checked = this.input.isChecked;
4306
4307    const style = getComputedStyle(this.node, ':before');
4308    let maxWidth = parseFloat(style.width);
4309    this.input.node.checked = !checked;
4310
4311    const style2 = getComputedStyle(this.node, ':before');
4312    const width = parseFloat(style2.width);
4313    if (width > maxWidth) maxWidth = width;
4314    this.input.node.checked = checked;
4315
4316    this.node.style.setProperty('--toggle-status-width', (maxWidth / 16) + 'rem');
4317  }
4318
4319  swapFont (families) {
4320    this.update();
4321  }
4322}
4323
4324const ToggleSelector = {
4325  STATUS_LABEL: `${api.internals.ns.selector('toggle__label')}${api.internals.ns.attr.selector('checked-label')}${api.internals.ns.attr.selector('unchecked-label')}`
4326};
4327
4328// import { ToggleInput } from './script/toggle/toggle-input.js';
4329
4330api.toggle = {
4331  ToggleStatusLabel: ToggleStatusLabel,
4332  ToggleSelector: ToggleSelector
4333};
4334
4335api.internals.register(api.toggle.ToggleSelector.STATUS_LABEL, api.toggle.ToggleStatusLabel);
4336
4337const ITEM$1 = api.internals.ns.selector('sidemenu__item');
4338const COLLAPSE$1 = api.internals.ns.selector('collapse');
4339
4340const SidemenuSelector = {
4341  LIST: api.internals.ns.selector('sidemenu__list'),
4342  COLLAPSE: `${ITEM$1} > ${COLLAPSE$1}, ${ITEM$1} > *:not(${ITEM$1}):not(${COLLAPSE$1}) > ${COLLAPSE$1}, ${ITEM$1} > *:not(${ITEM$1}):not(${COLLAPSE$1}) > *:not(${ITEM$1}):not(${COLLAPSE$1}) > ${COLLAPSE$1}`,
4343  COLLAPSE_LEGACY: `${ITEM$1} ${COLLAPSE$1}`,
4344  ITEM: api.internals.ns.selector('sidemenu__item'),
4345  BUTTON: api.internals.ns.selector('sidemenu__btn')
4346};
4347
4348class SidemenuList extends api.core.CollapsesGroup {
4349  static get instanceClassName () {
4350    return 'SidemenuList';
4351  }
4352
4353  validate (member) {
4354    return super.validate(member) && member.node.matches(api.internals.legacy.isLegacy ? SidemenuSelector.COLLAPSE_LEGACY : SidemenuSelector.COLLAPSE);
4355  }
4356}
4357
4358class SidemenuItem extends api.core.Instance {
4359  static get instanceClassName () {
4360    return 'SidemenuItem';
4361  }
4362
4363  get collapsePrimary () {
4364    const buttons = this.element.children.map(child => child.getInstance('CollapseButton')).filter(button => button !== null && button.hasClass(SidemenuSelector.BUTTON));
4365    return buttons[0];
4366  }
4367}
4368
4369api.sidemenu = {
4370  SidemenuList: SidemenuList,
4371  SidemenuItem: SidemenuItem,
4372  SidemenuSelector: SidemenuSelector
4373};
4374
4375api.internals.register(api.sidemenu.SidemenuSelector.LIST, api.sidemenu.SidemenuList);
4376api.internals.register(api.sidemenu.SidemenuSelector.ITEM, api.sidemenu.SidemenuItem);
4377
4378const ModalSelector = {
4379  MODAL: api.internals.ns.selector('modal'),
4380  SCROLL_DIVIDER: api.internals.ns.selector('scroll-divider'),
4381  BODY: api.internals.ns.selector('modal__body'),
4382  TITLE: api.internals.ns.selector('modal__title')
4383};
4384
4385class ModalButton extends api.core.DisclosureButton {
4386  constructor () {
4387    super(api.core.DisclosureType.OPENED);
4388  }
4389
4390  static get instanceClassName () {
4391    return 'ModalButton';
4392  }
4393}
4394
4395const ModalAttribute = {
4396  CONCEALING_BACKDROP: api.internals.ns.attr('concealing-backdrop')
4397};
4398
4399class Modal extends api.core.Disclosure {
4400  constructor () {
4401    super(api.core.DisclosureType.OPENED, ModalSelector.MODAL, ModalButton, 'ModalsGroup');
4402    this._isActive = false;
4403    this.scrolling = this.resize.bind(this, false);
4404    this.resizing = this.resize.bind(this, true);
4405  }
4406
4407  static get instanceClassName () {
4408    return 'Modal';
4409  }
4410
4411  init () {
4412    super.init();
4413    this._isDialog = this.node.tagName === 'DIALOG';
4414    this.isScrolling = false;
4415    this.listenClick();
4416    this.addEmission(api.core.RootEmission.KEYDOWN, this._keydown.bind(this));
4417  }
4418
4419  _keydown (keyCode) {
4420    switch (keyCode) {
4421      case api.core.KeyCodes.ESCAPE:
4422        this._escape();
4423        break;
4424    }
4425  }
4426
4427  // TODO v2 : passer les tagName d'action en constante
4428  _escape () {
4429    const tagName = document.activeElement ? document.activeElement.tagName : undefined;
4430
4431    switch (tagName) {
4432      case 'INPUT':
4433      case 'LABEL':
4434      case 'TEXTAREA':
4435      case 'SELECT':
4436      case 'AUDIO':
4437      case 'VIDEO':
4438        break;
4439
4440      default:
4441        if (this.isDisclosed) {
4442          this.conceal();
4443          this.focus();
4444        }
4445    }
4446  }
4447
4448  retrieved () {
vendor: 17,945 bytes, lines 4449-5088
4449    this._ensureAccessibleName();
4450  }
4451
4452  get body () {
4453    return this.element.getDescendantInstances('ModalBody', 'Modal')[0];
4454  }
4455
4456  handleClick (e) {
4457    if (e.target === this.node && this.getAttribute(ModalAttribute.CONCEALING_BACKDROP) !== 'false') this.conceal();
4458  }
4459
4460  disclose (withhold) {
4461    if (!super.disclose(withhold)) return false;
4462    if (this.body) this.body.activate();
4463    this.isScrollLocked = true;
4464    this.setAttribute('aria-modal', 'true');
4465    this.setAttribute('open', 'true');
4466    if (!this._isDialog) {
4467      this.activateModal();
4468    }
4469    return true;
4470  }
4471
4472  conceal (withhold, preventFocus) {
4473    if (!super.conceal(withhold, preventFocus)) return false;
4474    this.isScrollLocked = false;
4475    this.removeAttribute('aria-modal');
4476    this.removeAttribute('open');
4477    if (this.body) this.body.deactivate();
4478    if (!this._isDialog) {
4479      this.deactivateModal();
4480    }
4481    return true;
4482  }
4483
4484  get isDialog () {
4485    return this._isDialog;
4486  }
4487
4488  set isDialog (value) {
4489    this._isDialog = value;
4490  }
4491
4492  activateModal () {
4493    if (this._isActive) return;
4494    this._isActive = true;
4495    this._hasDialogRole = this.getAttribute('role') === 'dialog';
4496    if (!this._hasDialogRole) this.setAttribute('role', 'dialog');
4497  }
4498
4499  deactivateModal () {
4500    if (!this._isActive) return;
4501    this._isActive = false;
4502    if (!this._hasDialogRole) this.removeAttribute('role');
4503  }
4504
4505  _setAccessibleName (node, append) {
4506    const id = this.retrieveNodeId(node, append);
4507    this.warn(`add reference to ${append} for accessible name (aria-labelledby)`);
4508    this.setAttribute('aria-labelledby', id);
4509  }
4510
4511  _ensureAccessibleName () {
4512    if (this.hasAttribute('aria-labelledby') || this.hasAttribute('aria-label')) return;
4513    this.warn('missing accessible name');
4514    const title = this.node.querySelector(ModalSelector.TITLE);
4515    const primary = this.primaryButtons[0];
4516
4517    switch (true) {
4518      case title !== null:
4519        this._setAccessibleName(title, 'title');
4520        break;
4521
4522      case primary !== undefined:
4523        this.warn('missing required title, fallback to primary button');
4524        this._setAccessibleName(primary, 'primary');
4525        break;
4526    }
4527  }
4528}
4529
4530const unordereds = [
4531  '[tabindex="0"]',
4532  'a[href]',
4533  'button:not([disabled])',
4534  'input:not([disabled])',
4535  'select:not([disabled])',
4536  'textarea:not([disabled])',
4537  'audio[controls]',
4538  'video[controls]',
4539  '[contenteditable]:not([contenteditable="false"])',
4540  'details>summary:first-of-type',
4541  'details',
4542  'iframe'
4543];
4544
4545const UNORDEREDS = unordereds.join();
4546
4547const ordereds = [
4548  '[tabindex]:not([tabindex="-1"]):not([tabindex="0"])'
4549];
4550
4551const ORDEREDS = ordereds.join();
4552
4553const isFocusable = (element, container) => {
4554  if (!(element instanceof Element)) return false;
4555  const style = window.getComputedStyle(element);
4556  if (!style) return false;
4557  if (style.visibility === 'hidden') return false;
4558  if (container === undefined) container = element;
4559
4560  while (container.contains(element)) {
4561    if (style.display === 'none') return false;
4562    element = element.parentElement;
4563  }
4564
4565  return true;
4566};
4567
4568class FocusTrap {
4569  constructor (onTrap, onUntrap) {
4570    this.element = null;
4571    this.activeElement = null;
4572    this.onTrap = onTrap;
4573    this.onUntrap = onUntrap;
4574    this.waiting = this.wait.bind(this);
4575    this.handling = this.handle.bind(this);
4576    this.focusing = this.maintainFocus.bind(this);
4577    this.current = null;
4578  }
4579
4580  get trapped () { return this.element !== null; }
4581
4582  trap (element) {
4583    if (this.trapped) this.untrap();
4584
4585    this.element = element;
4586    this.isTrapping = true;
4587    this.wait();
4588
4589    if (this.onTrap) this.onTrap();
4590  }
4591
4592  wait () {
4593    if (!isFocusable(this.element)) {
4594      window.requestAnimationFrame(this.waiting);
4595      return;
4596    }
4597
4598    this.trapping();
4599  }
4600
4601  trapping () {
4602    if (!this.isTrapping) return;
4603    this.isTrapping = false;
4604    const focusables = this.focusables;
4605    if (focusables.length && focusables.indexOf(document.activeElement) === -1) focusables[0].focus();
4606    this.element.setAttribute('aria-modal', true);
4607    window.addEventListener('keydown', this.handling);
4608    document.body.addEventListener('focus', this.focusing, true);
4609  }
4610
4611  stun (node) {
4612    for (const child of node.children) {
4613      if (child === this.element) continue;
4614      if (child.contains(this.element)) {
4615        this.stun(child);
4616        continue;
4617      }
4618      this.stunneds.push(new Stunned(child));
4619    }
4620  }
4621
4622  maintainFocus (event) {
4623    if (!this.element.contains(event.target)) {
4624      const focusables = this.focusables;
4625      if (focusables.length === 0) return;
4626      const first = focusables[0];
4627      event.preventDefault();
4628      first.focus();
4629    }
4630  }
4631
4632  handle (e) {
4633    if (e.keyCode !== 9) return;
4634
4635    const focusables = this.focusables;
4636    if (focusables.length === 0) return;
4637
4638    const first = focusables[0];
4639    const last = focusables[focusables.length - 1];
4640
4641    const index = focusables.indexOf(document.activeElement);
4642
4643    if (e.shiftKey) {
4644      if (!this.element.contains(document.activeElement) || index < 1) {
4645        e.preventDefault();
4646        last.focus();
4647      } else if (document.activeElement.tabIndex > 0 || focusables[index - 1].tabIndex > 0) {
4648        e.preventDefault();
4649        focusables[index - 1].focus();
4650      }
4651    } else {
4652      if (!this.element.contains(document.activeElement) || index === focusables.length - 1 || index === -1) {
4653        e.preventDefault();
4654        first.focus();
4655      } else if (document.activeElement.tabIndex > 0) {
4656        e.preventDefault();
4657        focusables[index + 1].focus();
4658      }
4659    }
4660  }
4661
4662  get focusables () {
4663    let unordereds = api.internals.dom.querySelectorAllArray(this.element, UNORDEREDS);
4664
4665    /**
4666     *  filtrage des radiobutttons de même name (la navigations d'un groupe de radio se fait à la flèche et non pas au tab
4667     **/
4668    const radios = api.internals.dom.querySelectorAllArray(document.documentElement, 'input[type="radio"]');
4669
4670    if (radios.length) {
4671      const groups = {};
4672
4673      for (const radio of radios) {
4674        const name = radio.getAttribute('name');
4675        if (groups[name] === undefined) groups[name] = new RadioButtonGroup(name);
4676        groups[name].push(radio);
4677      }
4678
4679      unordereds = unordereds.filter((unordered) => {
4680        if (unordered.tagName.toLowerCase() !== 'input' || unordered.getAttribute('type').toLowerCase() !== 'radio') return true;
4681        const name = unordered.getAttribute('name');
4682        return groups[name].keep(unordered);
4683      });
4684    }
4685
4686    const ordereds = api.internals.dom.querySelectorAllArray(this.element, ORDEREDS);
4687
4688    ordereds.sort((a, b) => a.tabIndex - b.tabIndex);
4689
4690    const noDuplicates = unordereds.filter((element) => ordereds.indexOf(element) === -1);
4691    const concateneds = ordereds.concat(noDuplicates);
4692    return concateneds.filter((element) => element.tabIndex !== '-1' && isFocusable(element, this.element));
4693  }
4694
4695  untrap () {
4696    if (!this.trapped) return;
4697    this.isTrapping = false;
4698
4699    this.element.removeAttribute('aria-modal');
4700    window.removeEventListener('keydown', this.handling);
4701    document.body.removeEventListener('focus', this.focusing, true);
4702
4703    this.element = null;
4704
4705    if (this.onUntrap) this.onUntrap();
4706  }
4707
4708  dispose () {
4709    this.untrap();
4710  }
4711}
4712
4713class Stunned {
4714  constructor (element) {
4715    this.element = element;
4716    // this.hidden = element.getAttribute('aria-hidden');
4717    this.inert = element.getAttribute('inert');
4718
4719    // this.element.setAttribute('aria-hidden', true);
4720    this.element.setAttribute('inert', '');
4721  }
4722
4723  unstun () {
4724    /*
4725    if (this.hidden === null) this.element.removeAttribute('aria-hidden');
4726    else this.element.setAttribute('aria-hidden', this.hidden);
4727     */
4728
4729    if (this.inert === null) this.element.removeAttribute('inert');
4730    else this.element.setAttribute('inert', this.inert);
4731  }
4732}
4733
4734class RadioButtonGroup {
4735  constructor (name) {
4736    this.name = name;
4737    this.buttons = [];
4738  }
4739
4740  push (button) {
4741    this.buttons.push(button);
4742    if (button === document.activeElement || button.checked || this.selected === undefined) this.selected = button;
4743  }
4744
4745  keep (button) {
4746    return this.selected === button;
4747  }
4748}
4749
4750class ModalsGroup extends api.core.DisclosuresGroup {
4751  constructor () {
4752    super('Modal', false);
4753    this.focusTrap = new FocusTrap();
4754  }
4755
4756  static get instanceClassName () {
4757    return 'ModalsGroup';
4758  }
4759
4760  apply (value, initial) {
4761    super.apply(value, initial);
4762    if (this.current === null) this.focusTrap.untrap();
4763    else this.focusTrap.trap(this.current.node);
4764  }
4765}
4766
4767const OFFSET = 32; // 32px => 8v => 2rem
4768
4769class ModalBody extends api.core.Instance {
4770  static get instanceClassName () {
4771    return 'ModalBody';
4772  }
4773
4774  init () {
4775    this.listen('scroll', this.divide.bind(this));
4776  }
4777
4778  activate () {
4779    this.isResizing = true;
4780    this.resize();
4781  }
4782
4783  deactivate () {
4784    this.isResizing = false;
4785  }
4786
4787  divide () {
4788    if (this.node.scrollHeight > this.node.clientHeight) {
4789      if (this.node.offsetHeight + this.node.scrollTop >= this.node.scrollHeight) {
4790        this.removeClass(ModalSelector.SCROLL_DIVIDER);
4791      } else {
4792        this.addClass(ModalSelector.SCROLL_DIVIDER);
4793      }
4794    } else {
4795      this.removeClass(ModalSelector.SCROLL_DIVIDER);
4796    }
4797  }
4798
4799  resize () {
4800    this.adjust();
4801    this.request(this.adjust.bind(this));
4802  }
4803
4804  adjust () {
4805    const offset = OFFSET * (this.isBreakpoint(api.core.Breakpoints.MD) ? 2 : 1);
4806    if (this.isLegacy) this.style.maxHeight = `${window.innerHeight - offset}px`;
4807    else this.style.setProperty('--modal-max-height', `${window.innerHeight - offset}px`);
4808    this.divide();
4809  }
4810}
4811
4812api.modal = {
4813  Modal: Modal,
4814  ModalButton: ModalButton,
4815  ModalBody: ModalBody,
4816  ModalsGroup: ModalsGroup,
4817  ModalSelector: ModalSelector
4818};
4819
4820api.internals.register(api.modal.ModalSelector.MODAL, api.modal.Modal);
4821api.internals.register(api.modal.ModalSelector.BODY, api.modal.ModalBody);
4822api.internals.register(api.core.RootSelector.ROOT, api.modal.ModalsGroup);
4823
4824const PasswordEmission = {
4825  TOGGLE: api.internals.ns.emission('password', 'toggle'),
4826  ADJUST: api.internals.ns.emission('password', 'adjust')
4827};
4828
4829class PasswordToggle extends api.core.Instance {
4830  static get instanceClassName () {
4831    return 'PasswordToggle';
4832  }
4833
4834  init () {
4835    this.listenClick();
4836    this.ascend(PasswordEmission.ADJUST, this.width);
4837    this.isSwappingFont = true;
4838    this._isChecked = this.isChecked;
4839  }
4840
4841  get width () {
4842    const style = getComputedStyle(this.node.parentNode);
4843    return parseInt(style.width);
4844  }
4845
4846  get isChecked () {
4847    return this.node.checked;
4848  }
4849
4850  set isChecked (value) {
4851    this._isChecked = value;
4852    this.ascend(PasswordEmission.TOGGLE, value);
4853  }
4854
4855  handleClick () {
4856    this.isChecked = !this._isChecked;
4857  }
4858
4859  swapFont (families) {
4860    this.ascend(PasswordEmission.ADJUST, this.width);
4861  }
4862}
4863
4864class Password extends api.core.Instance {
4865  static get instanceClassName () {
4866    return 'Password';
4867  }
4868
4869  init () {
4870    this.addAscent(PasswordEmission.TOGGLE, this.toggle.bind(this));
4871    this.addAscent(PasswordEmission.ADJUST, this.adjust.bind(this));
4872  }
4873
4874  toggle (value) {
4875    this.descend(PasswordEmission.TOGGLE, value);
4876  }
4877
4878  adjust (value) {
4879    this.descend(PasswordEmission.ADJUST, value);
4880  }
4881}
4882
4883const PasswordSelector = {
4884  PASSWORD: api.internals.ns.selector('password'),
4885  INPUT: api.internals.ns.selector('password__input'),
4886  LABEL: api.internals.ns.selector('password__label'),
4887  TOOGLE: `${api.internals.ns.selector('password__checkbox')} input[type="checkbox"]`
4888};
4889
4890class PasswordInput extends api.core.Instance {
4891  static get instanceClassName () {
4892    return 'PasswordInput';
4893  }
4894
4895  init () {
4896    this.addDescent(PasswordEmission.TOGGLE, this.toggle.bind(this));
4897    this._isRevealed = this.hasAttribute('type') === 'password';
4898    this.listen('keydown', this.capslock.bind(this)); // for capslock enabled
4899    this.listen('keyup', this.capslock.bind(this)); // for capslock desabled
4900  }
4901
4902  toggle (value) {
4903    this.isRevealed = value;
4904    this.setAttribute('type', value ? 'text' : 'password');
4905  }
4906
4907  get isRevealed () {
4908    return this._isRevealed;
4909  }
4910
4911  capslock (event) {
4912    if (event && typeof event.getModifierState !== 'function') return;
4913    if (event.getModifierState('CapsLock')) {
4914      this.node.parentNode.setAttribute(api.internals.ns.attr('capslock'), '');
4915    } else {
4916      this.node.parentNode.removeAttribute(api.internals.ns.attr('capslock'));
4917    }
4918  }
4919
4920  set isRevealed (value) {
4921    this._isRevealed = value;
4922    this.setAttribute('type', value ? 'text' : 'password');
4923  }
4924}
4925
4926class PasswordLabel extends api.core.Instance {
4927  static get instanceClassName () {
4928    return 'PasswordLabel';
4929  }
4930
4931  init () {
4932    this.addDescent(PasswordEmission.ADJUST, this.adjust.bind(this));
4933  }
4934
4935  adjust (value) {
4936    const valueREM = Math.ceil(value / 16);
4937    this.node.style.paddingRight = valueREM + 'rem';
4938  }
4939}
4940
4941api.password = {
4942  Password: Password,
4943  PasswordToggle: PasswordToggle,
4944  PasswordSelector: PasswordSelector,
4945  PasswordInput: PasswordInput,
4946  PasswordLabel: PasswordLabel
4947};
4948
4949api.internals.register(api.password.PasswordSelector.INPUT, api.password.PasswordInput);
4950api.internals.register(api.password.PasswordSelector.PASSWORD, api.password.Password);
4951api.internals.register(api.password.PasswordSelector.TOOGLE, api.password.PasswordToggle);
4952api.internals.register(api.password.PasswordSelector.LABEL, api.password.PasswordLabel);
4953
4954const ITEM = api.internals.ns.selector('nav__item');
4955const COLLAPSE = api.internals.ns.selector('collapse');
4956
4957const NavigationSelector = {
4958  NAVIGATION: api.internals.ns.selector('nav'),
4959  COLLAPSE: `${ITEM} > ${COLLAPSE}, ${ITEM} > *:not(${ITEM}):not(${COLLAPSE}) > ${COLLAPSE}, ${ITEM} > *:not(${ITEM}):not(${COLLAPSE}) > *:not(${ITEM}):not(${COLLAPSE}) > ${COLLAPSE}`,
4960  COLLAPSE_LEGACY: `${ITEM} ${COLLAPSE}`,
4961  ITEM: ITEM,
4962  ITEM_RIGHT: `${ITEM}--align-right`,
4963  MENU: api.internals.ns.selector('menu'),
4964  BUTTON: api.internals.ns.selector('nav__btn'),
4965  TRANSLATE_BUTTON: api.internals.ns.selector('translate__btn')
4966};
4967
4968class NavigationItem extends api.core.Instance {
4969  constructor () {
4970    super();
4971    this._isRightAligned = false;
4972  }
4973
4974  static get instanceClassName () {
4975    return 'NavigationItem';
4976  }
4977
4978  init () {
4979    this.addAscent(api.core.DisclosureEmission.ADDED, this.calculate.bind(this));
4980    this.addAscent(api.core.DisclosureEmission.REMOVED, this.calculate.bind(this));
4981    this.isResizing = true;
4982    this.calculate();
4983  }
4984
4985  resize () {
4986    this.calculate();
4987  }
4988
4989  calculate () {
4990    const collapse = this.element.getDescendantInstances(api.core.Collapse.instanceClassName, null, true)[0];
4991    if (collapse && this.isBreakpoint(api.core.Breakpoints.LG) && collapse.element.node.matches(NavigationSelector.MENU)) {
4992      const right = this.element.node.parentElement.getBoundingClientRect().right; // todo: ne fonctionne que si la nav fait 100% du container
4993      const width = collapse.element.node.getBoundingClientRect().width;
4994      const left = this.element.node.getBoundingClientRect().left;
4995      this.isRightAligned = left + width > right;
4996    } else this.isRightAligned = false;
4997  }
4998
4999  get isRightAligned () {
5000    return this._isRightAligned;
5001  }
5002
5003  set isRightAligned (value) {
5004    if (this._isRightAligned === value) return;
5005    this._isRightAligned = value;
5006    if (value) api.internals.dom.addClass(this.element.node, NavigationSelector.ITEM_RIGHT);
5007    else api.internals.dom.removeClass(this.element.node, NavigationSelector.ITEM_RIGHT);
5008  }
5009
5010  get collapsePrimary () {
5011    const buttons = this.element.children.map(child => child.getInstance('CollapseButton')).filter(button => button !== null && (button.hasClass(NavigationSelector.BUTTON) || button.hasClass(NavigationSelector.TRANSLATE_BUTTON)));
5012    return buttons[0];
5013  }
5014}
5015
5016const NavigationMousePosition = {
5017  NONE: -1,
5018  INSIDE: 0,
5019  OUTSIDE: 1
5020};
5021
5022class Navigation extends api.core.CollapsesGroup {
5023  static get instanceClassName () {
5024    return 'Navigation';
5025  }
5026
5027  init () {
5028    super.init();
5029    this.clicked = false;
5030    this.out = false;
5031    this.addEmission(api.core.RootEmission.CLICK, this._handleRootClick.bind(this));
5032    this.listen('mousedown', this.handleMouseDown.bind(this));
5033    this.listenClick({ capture: true });
5034    this.isResizing = true;
5035  }
5036
5037  validate (member) {
5038    return super.validate(member) && member.element.node.matches(api.internals.legacy.isLegacy ? NavigationSelector.COLLAPSE_LEGACY : NavigationSelector.COLLAPSE);
5039  }
5040
5041  handleMouseDown (e) {
5042    if (!this.isBreakpoint(api.core.Breakpoints.LG) || this.index === -1 || !this.current) return;
5043    this.position = this.current.node.contains(e.target) ? NavigationMousePosition.INSIDE : NavigationMousePosition.OUTSIDE;
5044    this.requestPosition();
5045  }
5046
5047  handleClick (e) {
5048    if (e.target.matches('a, button') && !e.target.matches('[aria-controls]') && !e.target.matches(api.core.DisclosureSelector.PREVENT_CONCEAL)) {
5049      this.index = -1;
5050    }
5051  }
5052
5053  _handleRootClick (target) {
5054    if (!this.isBreakpoint(api.core.Breakpoints.LG)) return;
5055    if (!this.node.contains(target)) {
5056      this.out = true;
5057      this.requestPosition();
5058    }
5059  }
5060
5061  requestPosition () {
5062    if (this.isRequesting) return;
5063    this.isRequesting = true;
5064    this.request(this.getPosition.bind(this));
5065  }
5066
5067  getPosition () {
5068    if (this.out) {
5069      switch (this.position) {
5070        case NavigationMousePosition.OUTSIDE:
5071          this.index = -1;
5072          break;
5073
5074        case NavigationMousePosition.INSIDE:
5075          if (this.current && !this.current.node.contains(document.activeElement)) this.current.focus();
5076          break;
5077
5078        default:
5079          if (this.index > -1 && !this.current.hasFocus) this.index = -1;
5080      }
5081    }
5082
5083    this.request(this.requested.bind(this));
5084  }
5085
5086  requested () {
5087    this.position = NavigationMousePosition.NONE;
5088    this.out = false;
vendor: 9,981 bytes, lines 5089-5461
5089    this.isRequesting = false;
5090  }
5091
5092  get index () { return super.index; }
5093
5094  set index (value) {
5095    if (value === -1 && this.current && this.current.hasFocus) this.current.focus();
5096    super.index = value;
5097  }
5098
5099  get canUngroup () {
5100    return !this.isBreakpoint(api.core.Breakpoints.LG);
5101  }
5102
5103  resize () {
5104    this.update();
5105  }
5106}
5107
5108api.navigation = {
5109  Navigation: Navigation,
5110  NavigationItem: NavigationItem,
5111  NavigationMousePosition: NavigationMousePosition,
5112  NavigationSelector: NavigationSelector
5113};
5114
5115api.internals.register(api.navigation.NavigationSelector.NAVIGATION, api.navigation.Navigation);
5116api.internals.register(api.navigation.NavigationSelector.ITEM, api.navigation.NavigationItem);
5117
5118/**
5119  * TabButton correspond au bouton cliquable qui change le panel
5120  * TabButton étend de DisclosureButton qui ajoute/enelve l'attribut aria-selected,
5121  * Et change l'attributte tabindex a 0 si le boutton est actif (value=true), -1 s'il n'est pas actif (value=false)
5122 */
5123class TabButton extends api.core.DisclosureButton {
5124  constructor () {
5125    super(api.core.DisclosureType.SELECT);
5126  }
5127
5128  static get instanceClassName () {
5129    return 'TabButton';
5130  }
5131
5132  handleClick (e) {
5133    super.handleClick(e);
5134    this.focus();
5135  }
5136
5137  apply (value) {
5138    super.apply(value);
5139    if (this.isPrimary) {
5140      this.setAttribute('tabindex', value ? '0' : '-1');
5141      if (value) {
5142        if (this.list) this.list.focalize(this);
5143      }
5144    }
5145  }
5146
5147  get list () {
5148    return this.element.getAscendantInstance('TabsList', 'TabsGroup');
5149  }
5150}
5151
5152const TabSelector = {
5153  TAB: api.internals.ns.selector('tabs__tab'),
5154  GROUP: api.internals.ns.selector('tabs'),
5155  PANEL: api.internals.ns.selector('tabs__panel'),
5156  LIST: api.internals.ns.selector('tabs__list'),
5157  SHADOW: api.internals.ns.selector('tabs__shadow'),
5158  SHADOW_LEFT: api.internals.ns.selector('tabs__shadow--left'),
5159  SHADOW_RIGHT: api.internals.ns.selector('tabs__shadow--right'),
5160  PANEL_START: api.internals.ns.selector('tabs__panel--direction-start'),
5161  PANEL_END: api.internals.ns.selector('tabs__panel--direction-end')
5162};
5163
5164const TabPanelDirection = {
5165  START: 'direction-start',
5166  END: 'direction-end',
5167  NONE: 'none'
5168};
5169
5170/**
5171  * Tab coorespond au panel d'un élement Tabs (tab panel)
5172  * Tab étend disclosure qui ajoute/enleve le modifier --selected,
5173  * et ajoute/eleve l'attribut hidden, sur le panel
5174  */
5175class TabPanel extends api.core.Disclosure {
5176  constructor () {
5177    super(api.core.DisclosureType.SELECT, TabSelector.PANEL, TabButton, 'TabsGroup');
5178    this._direction = TabPanelDirection.NONE;
5179    this._isPreventingTransition = false;
5180  }
5181
5182  static get instanceClassName () {
5183    return 'TabPanel';
5184  }
5185
5186  get direction () {
5187    return this._direction;
5188  }
5189
5190  set direction (value) {
5191    if (value === this._direction) return;
5192    switch (this._direction) {
5193      case TabPanelDirection.START:
5194        this.removeClass(TabSelector.PANEL_START);
5195        break;
5196
5197      case TabPanelDirection.END:
5198        this.removeClass(TabSelector.PANEL_END);
5199        break;
5200
5201      case TabPanelDirection.NONE:
5202        break;
5203
5204      default:
5205        return;
5206    }
5207
5208    this._direction = value;
5209
5210    switch (this._direction) {
5211      case TabPanelDirection.START:
5212        this.addClass(TabSelector.PANEL_START);
5213        break;
5214
5215      case TabPanelDirection.END:
5216        this.addClass(TabSelector.PANEL_END);
5217        break;
5218    }
5219  }
5220
5221  get isPreventingTransition () {
5222    return this._isPreventingTransition;
5223  }
5224
5225  set isPreventingTransition (value) {
5226    if (this._isPreventingTransition === value) return;
5227    if (value) this.addClass(api.internals.motion.TransitionSelector.NONE);
5228    else this.removeClass(api.internals.motion.TransitionSelector.NONE);
5229    this._isPreventingTransition = value === true;
5230  }
5231
5232  translate (direction, initial) {
5233    this.isPreventingTransition = initial;
5234    this.direction = direction;
5235  }
5236
5237  reset () {
5238    if (this.group) this.group.retrieve(true);
5239  }
5240
5241  _electPrimaries (candidates) {
5242    if (!this.group || !this.group.list) return [];
5243    return super._electPrimaries(candidates).filter(candidate => this.group.list.node.contains(candidate.node));
5244  }
5245}
5246
5247const TabKeys = {
5248  LEFT: 'tab_keys_left',
5249  RIGHT: 'tab_keys_right',
5250  HOME: 'tab_keys_home',
5251  END: 'tab_keys_end'
5252};
5253
5254const TabEmission = {
5255  PRESS_KEY: api.internals.ns.emission('tab', 'press_key'),
5256  LIST_HEIGHT: api.internals.ns.emission('tab', 'list_height')
5257};
5258
5259/**
5260* TabGroup est la classe étendue de DiscosuresGroup
5261* Correspond à un objet Tabs avec plusieurs tab-button & Tab (panel)
5262*/
5263class TabsGroup extends api.core.DisclosuresGroup {
5264  constructor () {
5265    super('TabPanel');
5266  }
5267
5268  static get instanceClassName () {
5269    return 'TabsGroup';
5270  }
5271
5272  init () {
5273    super.init();
5274
5275    this.listen('transitionend', this.transitionend.bind(this));
5276    this.addAscent(TabEmission.PRESS_KEY, this.pressKey.bind(this));
5277    this.addAscent(TabEmission.LIST_HEIGHT, this.setListHeight.bind(this));
5278    this.isRendering = true;
5279  }
5280
5281  getIndex (defaultIndex = 0) {
5282    super.getIndex(defaultIndex);
5283  }
5284
5285  get list () {
5286    return this.element.getDescendantInstances('TabsList', 'TabsGroup', true)[0];
5287  }
5288
5289  setListHeight (value) {
5290    this.listHeight = value;
5291  }
5292
5293  transitionend (e) {
5294    this.isPreventingTransition = true;
5295  }
5296
5297  get buttonHasFocus () {
5298    return this.members.some(member => member.buttonHasFocus);
5299  }
5300
5301  pressKey (key) {
5302    switch (key) {
5303      case TabKeys.LEFT:
5304        this.pressLeft();
5305        break;
5306
5307      case TabKeys.RIGHT:
5308        this.pressRight();
5309        break;
5310
5311      case TabKeys.HOME:
5312        this.pressHome();
5313        break;
5314
5315      case TabKeys.END:
5316        this.pressEnd();
5317        break;
5318    }
5319  }
5320
5321  /**
5322   * Selectionne l'element suivant de la liste si on est sur un bouton
5323   * Si on est à la fin on retourne au début
5324   */
5325  pressRight () {
5326    if (this.buttonHasFocus) {
5327      if (this.index < this.length - 1) {
5328        this.index++;
5329      } else {
5330        this.index = 0;
5331      }
5332
5333      this.focus();
5334    }
5335  };
5336
5337  /**
5338   * Selectionne l'element précédent de la liste si on est sur un bouton
5339   * Si on est au debut retourne a la fin
5340   */
5341  pressLeft () {
5342    if (this.buttonHasFocus) {
5343      if (this.index > 0) {
5344        this.index--;
5345      } else {
5346        this.index = this.length - 1;
5347      }
5348
5349      this.focus();
5350    }
5351  };
5352
5353  /**
5354   * Selectionne le permier element de la liste si on est sur un bouton
5355   */
5356  pressHome () {
5357    if (this.buttonHasFocus) {
5358      this.index = 0;
5359      this.focus();
5360    }
5361  };
5362
5363  /**
5364   * Selectionne le dernier element de la liste si on est sur un bouton
5365   */
5366  pressEnd () {
5367    if (this.buttonHasFocus) {
5368      this.index = this.length - 1;
5369      this.focus();
5370    }
5371  };
5372
5373  focus () {
5374    if (this.current) {
5375      this.current.focus();
5376    }
5377  }
5378
5379  apply () {
5380    for (let i = 0; i < this._index; i++) this.members[i].translate(TabPanelDirection.START);
5381    if (this.current) this.current.translate(TabPanelDirection.NONE);
5382    for (let i = this._index + 1; i < this.length; i++) this.members[i].translate(TabPanelDirection.END);
5383    this.isPreventingTransition = false;
5384  }
5385
5386  get isPreventingTransition () {
5387    return this._isPreventingTransition;
5388  }
5389
5390  set isPreventingTransition (value) {
5391    if (this._isPreventingTransition === value) return;
5392    if (value) this.addClass(api.internals.motion.TransitionSelector.NONE);
5393    else this.removeClass(api.internals.motion.TransitionSelector.NONE);
5394    this._isPreventingTransition = value === true;
5395  }
5396
5397  render () {
5398    if (this.current === null) return;
5399    this.node.scrollTop = 0;
5400    this.node.scrollLeft = 0;
5401    const paneHeight = Math.round(this.current.node.offsetHeight);
5402    if (this.panelHeight === paneHeight) return;
5403    this.panelHeight = paneHeight;
5404    this.style.setProperty('--tabs-height', (this.panelHeight + this.listHeight) + 'px');
5405  }
5406}
5407
5408const FOCALIZE_OFFSET = 16;
5409const SCROLL_OFFSET$1 = 16; // valeur en px du scroll avant laquelle le shadow s'active ou se desactive
5410
5411class TabsList extends api.core.Instance {
5412  static get instanceClassName () {
5413    return 'TabsList';
5414  }
5415
5416  init () {
5417    this.listen('scroll', this.scroll.bind(this));
5418    this.listenKey(api.core.KeyCodes.RIGHT, this.ascend.bind(this, TabEmission.PRESS_KEY, TabKeys.RIGHT), true, true);
5419    this.listenKey(api.core.KeyCodes.LEFT, this.ascend.bind(this, TabEmission.PRESS_KEY, TabKeys.LEFT), true, true);
5420    this.listenKey(api.core.KeyCodes.HOME, this.ascend.bind(this, TabEmission.PRESS_KEY, TabKeys.HOME), true, true);
5421    this.listenKey(api.core.KeyCodes.END, this.ascend.bind(this, TabEmission.PRESS_KEY, TabKeys.END), true, true);
5422    this.isResizing = true;
5423  }
5424
5425  focalize (btn) {
5426    const btnRect = btn.getRect();
5427    const listRect = this.getRect();
5428    const actualScroll = this.node.scrollLeft;
5429    if (btnRect.left < listRect.left) this.node.scrollTo(actualScroll - listRect.left + btnRect.left - FOCALIZE_OFFSET, 0);
5430    else if (btnRect.right > listRect.right) this.node.scrollTo(actualScroll - listRect.right + btnRect.right + FOCALIZE_OFFSET, 0);
5431  }
5432
5433  get isScrolling () {
5434    return this._isScrolling;
5435  }
5436
5437  set isScrolling (value) {
5438    if (this._isScrolling === value) return;
5439    this._isScrolling = value;
5440    this.apply();
5441  }
5442
5443  apply () {
5444    if (this._isScrolling) {
5445      this.addClass(TabSelector.SHADOW);
5446      this.scroll();
5447    } else {
5448      this.removeClass(TabSelector.SHADOW_RIGHT);
5449      this.removeClass(TabSelector.SHADOW_LEFT);
5450      this.removeClass(TabSelector.SHADOW);
5451    }
5452  }
5453
5454  /* ajoute la classe fr-table__shadow-left ou fr-table__shadow-right sur fr-table en fonction d'une valeur de scroll et du sens (right, left) */
5455  scroll () {
5456    const scrollLeft = this.node.scrollLeft;
5457    const isMin = scrollLeft <= SCROLL_OFFSET$1;
5458    const max = this.node.scrollWidth - this.node.clientWidth - SCROLL_OFFSET$1;
5459
5460    const isMax = Math.abs(scrollLeft) >= max;
5461    const isRtl = document.documentElement.getAttribute('dir')
vendor: 15,059 bytes, lines 5461-6046
5461 === 'rtl';
5462    const minSelector = isRtl ? TabSelector.SHADOW_RIGHT : TabSelector.SHADOW_LEFT;
5463    const maxSelector = isRtl ? TabSelector.SHADOW_LEFT : TabSelector.SHADOW_RIGHT;
5464
5465    if (isMin) {
5466      this.removeClass(minSelector);
5467    } else {
5468      this.addClass(minSelector);
5469    }
5470
5471    if (isMax) {
5472      this.removeClass(maxSelector);
5473    } else {
5474      this.addClass(maxSelector);
5475    }
5476  }
5477
5478  resize () {
5479    this.isScrolling = this.node.scrollWidth > this.node.clientWidth + SCROLL_OFFSET$1;
5480    const height = this.getRect().height;
5481    this.setProperty('--tabs-list-height', `${height}px`);
5482    this.ascend(TabEmission.LIST_HEIGHT, height);
5483  }
5484
5485  dispose () {
5486    this.isScrolling = false;
5487  }
5488}
5489
5490api.tab = {
5491  TabPanel: TabPanel,
5492  TabButton: TabButton,
5493  TabsGroup: TabsGroup,
5494  TabsList: TabsList,
5495  TabSelector: TabSelector,
5496  TabEmission: TabEmission
5497};
5498
5499api.internals.register(api.tab.TabSelector.PANEL, api.tab.TabPanel);
5500api.internals.register(api.tab.TabSelector.GROUP, api.tab.TabsGroup);
5501api.internals.register(api.tab.TabSelector.LIST, api.tab.TabsList);
5502
5503const TagEvent = {
5504  DISMISS: api.internals.ns.event('dismiss')
5505};
5506
5507class TagDismissible extends api.core.Instance {
5508  static get instanceClassName () {
5509    return 'TagDismissible';
5510  }
5511
5512  init () {
5513    this.listenClick();
5514  }
5515
5516  handleClick () {
5517    this.focusClosest();
5518
5519    switch (api.mode) {
5520      case api.Modes.ANGULAR:
5521      case api.Modes.REACT:
5522      case api.Modes.VUE:
5523        this.request(this.verify.bind(this));
5524        break;
5525
5526      default:
5527        this.remove();
5528    }
5529
5530    this.dispatch(TagEvent.DISMISS);
5531  }
5532
5533  verify () {
5534    if (document.body.contains(this.node)) this.warn(`a TagDismissible has just been dismissed and should be removed from the dom. In ${api.mode} mode, the api doesn't handle dom modification. An event ${TagEvent.DISMISS} is dispatched by the element to trigger the removal`);
5535  }
5536}
5537
5538const TagSelector = {
5539  PRESSABLE: `${api.internals.ns.selector('tag')}[aria-pressed]`,
5540  DISMISSIBLE: `${api.internals.ns.selector('tag--dismiss')}`
5541};
5542
5543api.tag = {
5544  TagDismissible: TagDismissible,
5545  TagSelector: TagSelector,
5546  TagEvent: TagEvent
5547};
5548
5549api.internals.register(api.tag.TagSelector.PRESSABLE, api.core.Toggle);
5550api.internals.register(api.tag.TagSelector.DISMISSIBLE, api.tag.TagDismissible);
5551
5552const TRANSCRIPTION = api.internals.ns.selector('transcription');
5553
5554const TranscriptionSelector = {
5555  TRANSCRIPTION: TRANSCRIPTION,
5556  BUTTON: `${TRANSCRIPTION}__btn`
5557};
5558
5559class Transcription extends api.core.Instance {
5560  static get instanceClassName () {
5561    return 'Transcription';
5562  }
5563
5564  get collapsePrimary () {
5565    const buttons = this.element.children.map(child => child.getInstance('CollapseButton')).filter(button => button !== null && button.hasClass(TranscriptionSelector.BUTTON));
5566    return buttons[0];
5567  }
5568}
5569
5570api.transcription = {
5571  Transcription: Transcription,
5572  TranscriptionSelector: TranscriptionSelector
5573};
5574
5575api.internals.register(api.transcription.TranscriptionSelector.TRANSCRIPTION, api.transcription.Transcription);
5576
5577class TileDownload extends api.core.Instance {
5578  static get instanceClassName () {
5579    return 'TileDownload';
5580  }
5581
5582  init () {
5583    this.addAscent(api.core.AssessEmission.UPDATE, details => {
5584      this.descend(api.core.AssessEmission.UPDATE, details);
5585    });
5586    this.addAscent(api.core.AssessEmission.ADDED, () => {
5587      this.descend(api.core.AssessEmission.ADDED);
5588    });
5589  }
5590}
5591
5592const TileSelector = {
5593  DOWNLOAD: api.internals.ns.selector('tile--download'),
5594  DOWNLOAD_DETAIL: `${api.internals.ns.selector('tile--download')} ${api.internals.ns.selector('tile__detail')}`
5595};
5596
5597api.tile = {
5598  TileSelector: TileSelector,
5599  TileDownload: TileDownload
5600};
5601
5602api.internals.register(api.tile.TileSelector.DOWNLOAD, api.tile.TileDownload);
5603api.internals.register(api.tile.TileSelector.DOWNLOAD_DETAIL, api.core.AssessDetail);
5604
5605const RangeSelector = {
5606  RANGE: api.internals.ns.selector('range'),
5607  RANGE_SM: api.internals.ns.selector('range--sm'),
5608  RANGE_STEP: api.internals.ns.selector('range--step'),
5609  RANGE_DOUBLE: api.internals.ns.selector('range--double'),
5610  RANGE_DOUBLE_STEP: api.internals.ns.selector('range--double') + api.internals.ns.selector('range--step'),
5611  RANGE_INPUT: api.internals.ns.selector('range input[type=range]:nth-of-type(1)'),
5612  RANGE_INPUT2: `${api.internals.ns.selector('range--double')} input[type=range]:nth-of-type(2)`,
5613  RANGE_OUTPUT: api.internals.ns.selector('range__output'),
5614  RANGE_MIN: api.internals.ns.selector('range__min'),
5615  RANGE_MAX: api.internals.ns.selector('range__max'),
5616  RANGE_PREFIX: api.internals.ns.attr('prefix'),
5617  RANGE_SUFFIX: api.internals.ns.attr('suffix')
5618};
5619
5620const RangeEmission = {
5621  VALUE: api.internals.ns.emission('range', 'value'),
5622  VALUE2: api.internals.ns.emission('range', 'value2'),
5623  OUTPUT: api.internals.ns.emission('range', 'output'),
5624  CONSTRAINTS: api.internals.ns.emission('range', 'constraints'),
5625  MIN: api.internals.ns.emission('range', 'min'),
5626  MAX: api.internals.ns.emission('range', 'max'),
5627  STEP: api.internals.ns.emission('range', 'step'),
5628  PREFIX: api.internals.ns.emission('range', 'prefix'),
5629  SUFFIX: api.internals.ns.emission('range', 'suffix'),
5630  DISABLED: api.internals.ns.emission('range', 'disabled'),
5631  ENABLE_POINTER: api.internals.ns.emission('range', 'enable_pointer')
5632};
5633
5634class RangeModel {
5635  constructor () {
5636    this._width = 0;
5637    this._min = 0;
5638    this._max = 0;
5639    this._value = 0;
5640    this._thumbSize = 24;
5641    this._innerWidth = 0;
5642    this._prefix = '';
5643    this._suffix = '';
5644    this._background = {};
5645  }
5646
5647  configure (model) {
5648    if (!model) return;
5649    this._prefix = model._prefix;
5650    this._suffix = model._suffix;
5651    this._width = model.width;
5652    this.setConstraints(model._constraints);
5653    this.value = model.value;
5654    this.update();
5655  }
5656
5657  setPrefix (value) {
5658    this._prefix = value !== null ? value : '';
5659  }
5660
5661  setSuffix (value) {
5662    this._suffix = value !== null ? value : '';
5663  }
5664
5665  _decorate (value) {
5666    return `${this._prefix}${value}${this._suffix}`;
5667  }
5668
5669  get width () {
5670    return this._width;
5671  }
5672
5673  set width (value) {
5674    this._width = value;
5675  }
5676
5677  get isSm () {
5678    return this._isSm;
5679  }
5680
5681  set isSm (value) {
5682    if (this._isSm === value) return;
5683    this._isSm = value;
5684    this.setThumbSize(value ? 16 : 24);
5685    this.update();
5686  }
5687
5688  setThumbSize (value, mult = 1) {
5689    this._thumbSize = value;
5690    this._innerPadding = value * mult;
5691  }
5692
5693  get textValue () {
5694    return this._decorate(this._value);
5695  }
5696
5697  get value () {
5698    return this._value;
5699  }
5700
5701  set value (value) {
5702    this._value = value;
5703  }
5704
5705  get outputX () {
5706    return this._outputX;
5707  }
5708
5709  setConstraints (constraints) {
5710    this._constraints = constraints;
5711    this._min = constraints.min;
5712    this._max = constraints.max;
5713    this._step = constraints.step;
5714    this._rangeWidth = constraints.rangeWidth;
5715  }
5716
5717  get min () {
5718    return this._min;
5719  }
5720
5721  get textMin () {
5722    return this._decorate(this._min);
5723  }
5724
5725  get max () {
5726    return this._max;
5727  }
5728
5729  get textMax () {
5730    return this._decorate(this._max);
5731  }
5732
5733  get step () {
5734    return this._step;
5735  }
5736
5737  get output () {
5738    return {
5739      text: this.textValue,
5740      transform: `translateX(${this._translateX}px) translateX(-${this._centerPercent}%)`
5741    };
5742  }
5743
5744  _getRatio (value) {
5745    return (value - this._min) / this._rangeWidth;
5746  }
5747
5748  get progress () {
5749    return this._progress;
5750  }
5751
5752  update () {
5753    this._update();
5754  }
5755
5756  _update () {
5757    this._innerWidth = this._width - this._innerPadding;
5758    const ratio = this._getRatio(this._value);
5759    this._translateX = ratio * this._width;
5760    this._centerPercent = ratio * 100;
5761    this._progress = {
5762      right: `${(this._innerWidth * ratio + this._innerPadding * 0.5).toFixed(2)}px`
5763    };
5764  }
5765}
5766
5767class RangeModelStep extends RangeModel {
5768  get stepWidth () {
5769    return `${this._stepWidth.toFixed(3)}px`;
5770  }
5771
5772  _update () {
5773    super._update();
5774    const steps = this._rangeWidth / this._step;
5775    this._stepWidth = this._innerWidth / steps;
5776    if (this._stepWidth < 1 || !isFinite(this._stepWidth)) this._stepWidth = 4;
5777    while (this._stepWidth < 4) this._stepWidth *= 2;
5778  }
5779}
5780
5781class RangeModelDouble extends RangeModel {
5782  get value2 () {
5783    return this._value;
5784  }
5785
5786  set value2 (value) {
5787    if (this._value2 === value) return;
5788    this._value2 = value;
5789    this.update();
5790  }
5791
5792  get textValue () {
5793    return `${this._decorate(this._value)} - ${this._decorate(this._value2)}`;
5794  }
5795
5796  setThumbSize (value) {
5797    super.setThumbSize(value, 2);
5798  }
5799
5800  _update () {
5801    super._update();
5802    const ratio = this._getRatio((this._value + this._value2) * 0.5);
5803    this._translateX = ratio * this._width;
5804    this._centerPercent = ratio * 100;
5805    const ratio1 = this._getRatio(this._value);
5806    const ratio2 = this._getRatio(this._value2);
5807    this._progress = {
5808      left: `${(this._innerWidth * ratio1 + this._innerPadding * 0.25).toFixed(2)}px`,
5809      right: `${(this._innerWidth * ratio2 + this._innerPadding * 0.75).toFixed(2)}px`
5810    };
5811  }
5812}
5813
5814class RangeModelDoubleStep extends RangeModelDouble {
5815  get stepWidth () {
5816    return `${this._stepWidth.toFixed(3)}px`;
5817  }
5818
5819  _update () {
5820    super._update();
5821    const steps = this._rangeWidth / this._step;
5822    this._stepWidth = this._innerWidth / steps;
5823    if (this._stepWidth < 4) this._stepWidth *= Math.ceil(4 / this._stepWidth);
5824  }
5825}
5826
5827const RangeTypes = {
5828  STEP: 'step',
5829  DOUBLE: 'double',
5830  DOUBLE_STEP: 'double-step',
5831  DEFAULT: 'default'
5832};
5833
5834class Range extends api.core.Instance {
5835  static get instanceClassName () {
5836    return 'Range';
5837  }
5838
5839  init () {
5840    this._retrieveType();
5841    this._retrieveSize();
5842    if (this.isLegacy) {
5843      this.isResizing = true;
5844      this.isMouseMoving = true;
5845    } else {
5846      this._observer = new ResizeObserver(this.resize.bind(this));
5847      this._observer.observe(this.node);
5848    }
5849
5850    this.addAscent(RangeEmission.CONSTRAINTS, this.setConstraints.bind(this));
5851    this.addAscent(RangeEmission.VALUE, this.setValue.bind(this));
5852    this.addAscent(RangeEmission.VALUE2, this.setValue2.bind(this));
5853    if (this.getAttribute(RangeSelector.RANGE_PREFIX)) this.setPrefix(this.getAttribute(RangeSelector.RANGE_PREFIX));
5854    if (this.getAttribute(RangeSelector.RANGE_SUFFIX)) this.setSuffix(this.getAttribute(RangeSelector.RANGE_SUFFIX));
5855    this.update();
5856  }
5857
5858  _retrieveType () {
5859    switch (true) {
5860      case this.matches(RangeSelector.RANGE_DOUBLE_STEP):
5861        this.type = RangeTypes.DOUBLE;
5862        break;
5863
5864      case this.matches(RangeSelector.RANGE_DOUBLE):
5865        this.type = RangeTypes.DOUBLE;
5866        break;
5867
5868      case this.matches(RangeSelector.RANGE_STEP):
5869        this.type = RangeTypes.STEP;
5870        break;
5871
5872      default:
5873        this.type = RangeTypes.DEFAULT;
5874    }
5875  }
5876
5877  set type (value) {
5878    if (this._type === value) return;
5879    this._type = value;
5880
5881    const oldModel = this._model;
5882
5883    switch (this._type) {
5884      case RangeTypes.DOUBLE_STEP:
5885        this._model = new RangeModelDoubleStep();
5886        break;
5887
5888      case RangeTypes.DOUBLE:
5889        this._model = new RangeModelDouble();
5890        break;
5891
5892      case RangeTypes.STEP:
5893        this._model = new RangeModelStep();
5894        break;
5895
5896      default:
5897        this._model = new RangeModel();
5898    }
5899
5900    this._model.configure(oldModel);
5901  }
5902
5903  get type () {
5904    return this._type;
5905  }
5906
5907  _retrieveSize () {
5908    this._model.isSm = this.matches(RangeSelector.RANGE_SM);
5909  }
5910
5911  resize () {
5912    this._retrieveWidth();
5913    this.update();
5914  }
5915
5916  _retrieveWidth () {
5917    this._model.width = this.getRect().width;
5918  }
5919
5920  setValue (value) {
5921    this._model.value = value;
5922    switch (this._type) {
5923      case RangeTypes.DOUBLE_STEP:
5924      case RangeTypes.DOUBLE:
5925        this.descend(RangeEmission.VALUE, value);
5926        break;
5927    }
5928    this.update();
5929  }
5930
5931  setValue2 (value) {
5932    this._model.value2 = value;
5933    this.descend(RangeEmission.VALUE2, value);
5934    this.update();
5935  }
5936
5937  setConstraints (constraints) {
5938    this._model.setConstraints(constraints);
5939    this.update();
5940    this.descend(RangeEmission.CONSTRAINTS, constraints);
5941  }
5942
5943  setPrefix (value) {
5944    this._model.setPrefix(value);
5945    this.update();
5946  }
5947
5948  setSuffix (value) {
5949    this._model.setSuffix(value);
5950    this.update();
5951  }
5952
5953  mutate (attributesNames) {
5954    switch (true) {
5955      case attributesNames.includes('class'):
5956        this._retrieveType();
5957        this._retrieveSize();
5958        break;
5959
5960      case attributesNames.includes(RangeSelector.RANGE_PREFIX):
5961      case attributesNames.includes(RangeSelector.RANGE_SUFFIX):
5962        this._model.setPrefix(this.getAttribute(RangeSelector.RANGE_PREFIX));
5963        this._model.setSuffix(this.getAttribute(RangeSelector.RANGE_SUFFIX));
5964        this.update();
5965        break;
5966    }
5967  }
5968
5969  update () {
5970    this._model.update();
5971    this.descend(RangeEmission.OUTPUT, this._model.output);
5972    this.descend(RangeEmission.MIN, this._model.textMin);
5973    this.descend(RangeEmission.MAX, this._model.textMax);
5974    const progress = this._model.progress;
5975    if (progress.left) {
5976      this.style.setProperty('--progress-left', progress.left);
5977    } else {
5978      this.style.removeProperty('--progress-left');
5979    }
5980    if (progress.right) {
5981      this.style.setProperty('--progress-right', progress.right);
5982      if (this.isLegacy) {
5983        if (progress.left) {
5984          this.style.setProperty('background-position-x', progress.left);
5985          this.style.setProperty('background-size', `${parseFloat(progress.right) - parseFloat(progress.left)}px ${this._model.isSm ? '8px' : '12px'}`);
5986        }
5987      }
5988    } else {
5989      this.style.removeProperty('--progress-right');
5990      if (this.isLegacy) {
5991        this.style.removeProperty('background-size');
5992        this.style.removeProperty('background-position-x');
5993      }
5994    }
5995    if (this._model.stepWidth) this.style.setProperty('--step-width', this._model.stepWidth);
5996    else this.style.removeProperty('--step-width');
5997  }
5998
5999  mouseMove (point) {
6000    if (this._type !== RangeTypes.DOUBLE && this._type !== RangeTypes.DOUBLE_STEP) return;
6001    const x = point.x - this.getRect().left;
6002    this.descend(RangeEmission.ENABLE_POINTER, (parseFloat(this._model.progress.right) - parseFloat(this._model.progress.left)) / 2 + parseFloat(this._model.progress.left) < x ? 2 : 1);
6003  }
6004
6005  dispose () {
6006    this._observer.disconnect();
6007  }
6008}
6009
6010class RangeConstraints {
6011  constructor (node) {
6012    this._min = isNaN(node.min) ? 0 : node.min;
6013    this._max = isNaN(node.max) ? 100 : node.max;
6014    this._step = isNaN(node.step) ? 1 : node.step;
6015    this._rangeWidth = this._max - this._min;
6016  }
6017
6018  get min () {
6019    return this._min;
6020  }
6021
6022  get max () {
6023    return this._max;
6024  }
6025
6026  get step () {
6027    return this._step;
6028  }
6029
6030  get rangeWidth () {
6031    return this._rangeWidth;
6032  }
6033
6034  test (min, max, step) {
6035    return this._min === min && this._max === max && this._step === step;
6036  }
6037}
6038
6039class RangeInput extends api.core.Instance {
6040  static get instanceClassName () {
6041    return 'RangeInput';
6042  }
6043
6044  init () {
6045    this._init();
6046    this.
vendor: 3,430 bytes, lines 6046-6174
6046node.value = this.getAttribute('value');
6047    this._changing = this.change.bind(this);
6048    this._listenerType = this.isLegacy ? 'change' : 'input';
6049    this.listen(this._listenerType, this._changing);
6050    if (this.isLegacy) this.addDescent(RangeEmission.ENABLE_POINTER, this._enablePointer.bind(this));
6051    this.change();
6052  }
6053
6054  _init () {
6055    this._pointerId = 1;
6056    this.request(() => {
6057      if (!this.hasAttribute('min')) this.setAttribute('min', 0);
6058      this.ascend(RangeEmission.CONSTRAINTS, new RangeConstraints(this.node));
6059      this.ascend(RangeEmission.DISABLED, this.node.disabled);
6060    });
6061
6062    this.addDescent(RangeEmission.VALUE2, this.setValue.bind(this));
6063  }
6064
6065  _enablePointer (pointerId) {
6066    const isEnabled = pointerId === this._pointerId;
6067    if (this._isPointerEnabled === isEnabled) return;
6068    this._isPointerEnabled = isEnabled;
6069    if (isEnabled) this.style.removeProperty('pointer-events');
6070    else this.style.setProperty('pointer-events', 'none');
6071  }
6072
6073  setValue (value) {
6074    if (parseFloat(this.node.value) > value) {
6075      this.node.value = value;
6076      this.dispatch('change', undefined, true);
6077      this.change();
6078    }
6079  }
6080
6081  change () {
6082    this.ascend(RangeEmission.VALUE, parseFloat(this.node.value));
6083  }
6084
6085  mutate (attributesNames) {
6086    if (attributesNames.includes('disabled')) this.ascend(RangeEmission.DISABLED, this.node.disabled);
6087    if (attributesNames.includes('min') || attributesNames.includes('max') || attributesNames.includes('step')) {
6088      this.ascend(RangeEmission.CONSTRAINTS, new RangeConstraints(this.node));
6089      this.change();
6090    }
6091  }
6092
6093  dispose () {
6094    if (this._listenerType) this.unlisten(this._listenerType, this._changing);
6095  }
6096}
6097
6098class RangeInput2 extends RangeInput {
6099  static get instanceClassName () {
6100    return 'RangeInput2';
6101  }
6102
6103  _init () {
6104    this._pointerId = 2;
6105    this.addDescent(RangeEmission.CONSTRAINTS, this.setConstraints.bind(this));
6106    this.addDescent(RangeEmission.VALUE, this.setValue.bind(this));
6107  }
6108
6109  setValue (value) {
6110    if (parseFloat(this.node.value) < value) {
6111      this.node.value = value;
6112      this.dispatch('change', undefined, true);
6113      this.change();
6114    }
6115  }
6116
6117  change () {
6118    this.ascend(RangeEmission.VALUE2, parseFloat(this.node.value));
6119  }
6120
6121  setConstraints (constraints) {
6122    this.node.min = constraints.min;
6123    this.node.max = constraints.max;
6124    this.node.step = constraints.step;
6125    this.change();
6126  }
6127
6128  mutate (attributesNames) {}
6129}
6130
6131class RangeOutput extends api.core.Instance {
6132  static get instanceClassName () {
6133    return 'RangeOutput';
6134  }
6135
6136  init () {
6137    this.addDescent(RangeEmission.OUTPUT, this.change.bind(this));
6138  }
6139
6140  change (data) {
6141    this.node.innerText = data.text;
6142    this.node.style.transform = data.transform;
6143  }
6144}
6145
6146class RangeLimit extends api.core.Instance {
6147  static get instanceClassName () {
6148    return 'RangeLimit';
6149  }
6150
6151  init () {
6152    switch (true) {
6153      case this.matches(RangeSelector.RANGE_MIN):
6154        this.addDescent(RangeEmission.MIN, this.change.bind(this));
6155        break;
6156
6157      case this.matches(RangeSelector.RANGE_MAX):
6158        this.addDescent(RangeEmission.MAX, this.change.bind(this));
6159        break;
6160    }
6161  }
6162
6163  change (text) {
6164    this.node.innerText = text;
6165  }
6166}
6167
6168api.range = {
6169  Range: Range,
6170  RangeInput: RangeInput,
6171  RangeInput2: RangeInput2,
6172  RangeOutput: RangeOutput,
6173  RangeLimit: RangeLimit,
6174  RangeEmission: RangeEmission,
6175  RangeSelector: RangeSelector
6176};
6177
6178api.internals.register(api.range.RangeSelector.RANGE, api.range.Range);
6179api.internals.register(api.range.RangeSelector.RANGE_INPUT, api.range.RangeInput);
6180api.internals.register(api.range.RangeSelector.RANGE_INPUT2, api.range.RangeInput2);
6181api.internals.register(api.range.RangeSelector.RANGE_OUTPUT, api.range.RangeOutput);
6182api.internals.register(api.range.RangeSelector.RANGE_MIN, api.range.RangeLimit);
6183api.internals.register(api.range.RangeSelector.RANGE_MAX, api.range.RangeLimit);
6184
6185const HeaderSelector = {
6186  HEADER: api.internals.ns.selector('header'),
6187  TOOLS_LINKS: api.internals.ns.selector('header__tools-links'),
6188  MENU_LINKS: api.internals.ns.selector('header__menu-links'),
6189  BUTTONS: `${api.internals.ns.selector('header__tools-links')} ${api.internals.ns.selector('btns-group')}, ${api.internals.ns.selector('header__tools-links')} ${api.internals.ns.selector('links-group')}`,
6190  MODALS: `${api.internals.ns.selector('header__search')}${api.internals.ns.selector('modal')}, ${api.internals.ns.selector('header__menu')}${api.internals.ns.selector('modal')}`
6191};
6192
6193class HeaderLinks extends api.core.Instance {
6194  static get instanceClassName () {
6195    return 'HeaderLinks';
6196  }
6197
6198  init () {
6199    const header = this.queryParentSelector(HeaderSelector.HEADER);
6200    this.toolsLinks = header.querySelector(HeaderSelector.TOOLS_LINKS);
6201    this.menuLinks = header.querySelector(HeaderSelector.MENU_LINKS);
6202    const copySuffix = '-mobile';
6203
6204    const toolsHtml = this.toolsLinks.innerHTML.replace(/  +/g, ' ');
6205    const menuHtml = this.menuLinks.innerHTML.replace(/  +/g, ' ');
6206    // Pour éviter de dupliquer des id, on ajoute un suffixe aux id et aria-controls duppliqués.
6207    let toolsHtmlIdList = toolsHtml.match(/id="(.*?)"/gm) || [];
6208
6209    // on a besoin d'échapper les backslash dans la chaine de caractère
6210    // eslint-disable-next-line no-useless-escape
6211    toolsHtmlIdList = toolsHtmlIdList.map(element => element.replace('id=\"', '').replace('\"', ''));
6212
6213    const toolsHtmlAriaControlList = toolsHtml.match(/aria-controls="(.*?)"/gm);
6214    let toolsHtmlDuplicateId = toolsHtml.replace(/id="(.*?)"/gm, 'id="$1' + copySuffix + '"');
6215    if (toolsHtmlAriaControlList) {
6216      for (const element of toolsHtmlAriaControlList) {
6217        const ariaControlsValue = element.replace('aria-controls="', '').replace('"', '');
6218        if (toolsHtmlIdList.includes(ariaControlsValue)) {
6219          toolsHtmlDuplicateId = toolsHtmlDuplicateId.replace(`aria-controls="${ariaControlsValue}"`, `aria-controls="${ariaControlsValue + copySuffix}"`);
6220        }      }
6221    }
6222
6223    if (toolsHtmlDuplicateId === menuHtml) return;
6224
6225    switch (api.mode) {
6226      case api.Modes.ANGULAR:
6227      case api.Modes.REACT:
6228      case api.Modes.VUE:
6229        this.warn(`header__tools-links content is different from header__menu-links content.
6230As you're using a dynamic framework, you should handle duplication of this content yourself, please refer to documentation:
6231${api.header.doc}`);
6232        break;
6233
6234      default:
6235        this.menuLinks.innerHTML = toolsHtmlDuplicateId;
6236    }
6237  }
6238}
6239
6240class HeaderModal extends api.core.Instance {
6241  static get instanceClassName () {
6242    return 'HeaderModal';
6243  }
6244
6245  init () {
6246    this.isResizing = true;
6247  }
6248
6249  resize () {
6250    if (this.isBreakpoint(api.core.Breakpoints.LG)) this.deactivateModal();
6251    else this.activateModal();
6252  }
6253
6254  activateModal () {
6255    const modal = this.element.getInstance('Modal');
6256    if (!modal) return;
6257    modal.isEnabled = true;
6258    this.listenClick({ capture: true });
6259  }
6260
6261  deactivateModal () {
6262    const modal = this.element.getInstance('Modal');
6263    if (!modal) return;
6264    modal.conceal();
6265    modal.isEnabled = false;
6266    this.unlistenClick({ capture: true });
6267  }
6268
6269  handleClick (e) {
6270    if (e.target.matches('a, button') && !e.target.matches('[aria-controls]') && !e.target.matches(api.core.DisclosureSelector.PREVENT_CONCEAL)) {
6271      const modal = this.element.getInstance('Modal');
6272      modal.conceal();
6273    }
6274  }
6275}
6276
6277api.header = {
6278  HeaderLinks: HeaderLinks,
6279  HeaderModal: HeaderModal,
6280  HeaderSelector: HeaderSelector,
6281  doc: 'https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/en-tete'
6282};
6283
6284api.internals.register(api.header.HeaderSelector.TOOLS_LINKS, api.header.HeaderLinks);
6285api.internals.register(api.header.HeaderSelector.MODALS, api.header.HeaderModal);
6286
6287const DisplaySelector = {
6288  DISPLAY: api.internals.ns.selector('display'),
6289  RADIO_BUTTONS: `input[name="${api.internals.ns('radios-theme')}"]`,
6290  FIELDSET: api.internals.ns.selector('fieldset')
6291};
6292
6293class Display extends api.core.Instance {
6294  static get instanceClassName () {
6295    return 'Display';
6296  }
6297
6298  init () {
6299    this.radios = this.querySelectorAll(DisplaySelector.RADIO_BUTTONS);
6300
6301    if (api.scheme) {
6302      this.changing = this.change.bind(this);
6303      for (const radio of this.radios) radio.addEventListener('change', this.changing);
vendor: 6,489 bytes, lines 6304-6536
6304      this.addDescent(api.scheme.SchemeEmission.SCHEME, this.apply.bind(this));
6305      this.ascend(api.scheme.SchemeEmission.ASK);
6306    } else {
6307      this.querySelector(DisplaySelector.FIELDSET).setAttribute('disabled', '');
6308    }
6309  }
6310
6311  get scheme () {
6312    return this._scheme;
6313  }
6314
6315  set scheme (value) {
6316    if (this._scheme === value || !api.scheme) return;
6317    switch (value) {
6318      case api.scheme.SchemeValue.SYSTEM:
6319      case api.scheme.SchemeValue.LIGHT:
6320      case api.scheme.SchemeValue.DARK:
6321        this._scheme = value;
6322        for (const radio of this.radios) {
6323          radio.checked = radio.value === value;
6324        }
6325        this.ascend(api.scheme.SchemeEmission.SCHEME, value);
6326        break;
6327    }
6328  }
6329
6330  change () {
6331    for (const radio of this.radios) {
6332      if (radio.checked) {
6333        this.scheme = radio.value;
6334        return;
6335      }
6336    }
6337  }
6338
6339  apply (value) {
6340    this.scheme = value;
6341  }
6342
6343  dispose () {
6344    for (const radio of this.radios) radio.removeEventListener('change', this.changing);
6345  }
6346}
6347
6348api.display = {
6349  Display: Display,
6350  DisplaySelector: DisplaySelector
6351};
6352
6353api.internals.register(api.display.DisplaySelector.DISPLAY, api.display.Display);
6354
6355const TableEmission = {
6356  SCROLLABLE: api.internals.ns.emission('table', 'scrollable'),
6357  CHANGE: api.internals.ns.emission('table', 'change'),
6358  CAPTION_HEIGHT: api.internals.ns.emission('table', 'captionheight'),
6359  CAPTION_WIDTH: api.internals.ns.emission('table', 'captionwidth')
6360};
6361
6362class Table extends api.core.Instance {
6363  static get instanceClassName () {
6364    return 'Table';
6365  }
6366
6367  init () {
6368    this.addAscent(TableEmission.CAPTION_HEIGHT, this.setCaptionHeight.bind(this));
6369  }
6370
6371  setCaptionHeight (value) {
6372    this.setProperty('--table-offset', value);
6373  }
6374}
6375
6376class TableWrapper extends api.core.Instance {
6377  static get instanceClassName () {
6378    return 'TableWrapper';
6379  }
6380
6381  init () {
6382    this.addAscent(TableEmission.CAPTION_HEIGHT, this.setCaptionHeight.bind(this));
6383  }
6384
6385  setCaptionHeight (value) {
6386    requestAnimationFrame(() => this.ascend(TableEmission.CAPTION_HEIGHT, 0));
6387    this.setProperty('--table-offset', value);
6388  }
6389}
6390
6391const TableSelector = {
6392  TABLE: api.internals.ns.selector('table'),
6393  TABLE_WRAPPER: [`${api.internals.ns.selector('table')} ${api.internals.ns.selector('table__wrapper')}`],
6394  SHADOW: api.internals.ns.selector('table__shadow'),
6395  SHADOW_LEFT: api.internals.ns.selector('table__shadow--left'),
6396  SHADOW_RIGHT: api.internals.ns.selector('table__shadow--right'),
6397  ELEMENT: [`${api.internals.ns.selector('table')}:not(${api.internals.ns.selector('table--no-scroll')}) table`],
6398  CAPTION: `${api.internals.ns.selector('table')} table caption`,
6399  ROW: `${api.internals.ns.selector('table')} tbody tr`,
6400  COL: `${api.internals.ns.selector('table')} thead th`
6401};
6402
6403const SCROLL_OFFSET = 0; // valeur en px du scroll avant laquelle le shadow s'active ou se desactive
6404
6405class TableElement extends api.core.Instance {
6406  static get instanceClassName () {
6407    return 'TableElement';
6408  }
6409
6410  init () {
6411    this.listen('scroll', this.scroll.bind(this));
6412    this.content = this.querySelector('tbody');
6413    this.tableOffsetHeight = 0;
6414    this.isResizing = true;
6415  }
6416
6417  get isScrolling () {
6418    return this._isScrolling;
6419  }
6420
6421  set isScrolling (value) {
6422    if (this._isScrolling === value) return;
6423    this._isScrolling = value;
6424
6425    if (value) {
6426      this.addClass(TableSelector.SHADOW);
6427      this.scroll();
6428    } else {
6429      this.removeClass(TableSelector.SHADOW);
6430      this.removeClass(TableSelector.SHADOW_LEFT);
6431      this.removeClass(TableSelector.SHADOW_RIGHT);
6432    }
6433  }
6434
6435  /* ajoute la classe fr-table__shadow-left ou fr-table__shadow-right sur fr-table en fonction d'une valeur de scroll et du sens (right, left) */
6436  scroll () {
6437    const isMin = this.node.scrollLeft <= SCROLL_OFFSET;
6438    const max = this.content.offsetWidth - this.node.offsetWidth - SCROLL_OFFSET;
6439    const isMax = Math.abs(this.node.scrollLeft) >= max;
6440    const isRtl = document.documentElement.getAttribute('dir') === 'rtl';
6441    const minSelector = isRtl ? TableSelector.SHADOW_RIGHT : TableSelector.SHADOW_LEFT;
6442    const maxSelector = isRtl ? TableSelector.SHADOW_LEFT : TableSelector.SHADOW_RIGHT;
6443
6444    if (isMin) {
6445      this.removeClass(minSelector);
6446    } else {
6447      this.addClass(minSelector);
6448    }
6449
6450    if (isMax) {
6451      this.removeClass(maxSelector);
6452    } else {
6453      this.addClass(maxSelector);
6454    }
6455  }
6456
6457  resize () {
6458    this.isScrolling = this.content.offsetWidth > this.node.offsetWidth;
6459  }
6460
6461  dispose () {
6462    this.isScrolling = false;
6463  }
6464}
6465
6466const PADDING = '1rem'; // padding de 4v sur le caption
6467class TableCaption extends api.core.Instance {
6468  static get instanceClassName () {
6469    return 'TableCaption';
6470  }
6471
6472  init () {
6473    this.height = 0;
6474    this.isResizing = true;
6475  }
6476
6477  resize () {
6478    const height = this.getRect().height;
6479    if (this.height === height) return;
6480    this.height = height;
6481    this.ascend(TableEmission.CAPTION_HEIGHT, `calc(${height}px + ${PADDING})`);
6482  }
6483}
6484
6485class TableRow extends api.core.Instance {
6486  static get instanceClassName () {
6487    return 'TableRow';
6488  }
6489
6490  init () {
6491    if (api.checkbox) {
6492      this.addAscent(CheckboxEmission.CHANGE, this._handleCheckboxChange.bind(this));
6493      this.descend(CheckboxEmission.RETRIEVE);
6494    }
6495  }
6496
6497  _handleCheckboxChange (node) {
6498    if (node.name === 'row-select') {
6499      this.isSelected = node.checked === true;
6500    }
6501  }
6502
6503  render () {
6504    const height = this.getRect().height + 2;
6505    if (this._height === height) return;
6506    this._height = height;
6507    this.setProperty('--row-height', `${this._height}px`);
6508  }
6509
6510  get isSelected () {
6511    return this._isSelected;
6512  }
6513
6514  set isSelected (value) {
6515    if (this._isSelected === value) return;
6516    this.isRendering = value;
6517    this._isSelected = value;
6518    this.setAttribute('aria-selected', value);
6519  }
6520}
6521
6522api.table = {
6523  Table: Table,
6524  TableWrapper: TableWrapper,
6525  TableElement: TableElement,
6526  TableCaption: TableCaption,
6527  TableSelector: TableSelector,
6528  TableRow: TableRow
6529};
6530
6531api.internals.register(api.table.TableSelector.TABLE, api.table.Table);
6532api.internals.register(api.table.TableSelector.TABLE_WRAPPER, api.table.TableWrapper);
6533api.internals.register(api.table.TableSelector.ELEMENT, api.table.TableElement);
6534api.internals.register(api.table.TableSelector.CAPTION, api.table.TableCaption);
6535api.internals.register(api.table.TableSelector.ROW, api.table.TableRow);
6536//# sourceMappingURL=dsfr.module.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.