The code challenge

The code challenge

Hello à tous!

Si vous êtes ici c'est que :

  1. Vous savez programmer en javascript avec React
  2. Vous êtes curieux(se)
  3. La problématique vous titille les neurones

Pourquoi relever ce défi ?

  1. Pour le fun
  2. J'adore relever des challenges
  3. Obtenir une reconnaissance éternelle, c'est bon pour le moral
  4. Et pourquoi pas intégrer l'équipe de Bond Inbox ? 🤔

Reprenons donc :

Le but est d'insérer dans une div "contentEditable" des composants reacts complexes (appels d'API pour en enrichir le contenu, boutons d'action etc..).

Il faut que ces composants puissent être insérés à n'importe quel endroit du texte comme un vulgaire bullet point.

Ca fonctionnerait un peu comme dans Gmail lorsqu'on entre une adresse email qui devient une sorte d'objet lorsque celle-ci est validée. Sauf que dans notre cas l'objet en question contiendrait plus d'éléments complexes à l'intérieur (multiples champs, dropdown etc.)

On doit pouvoir insérer autant de composants complexes qu'on le souhaite, et potentiellement du texte avant et après chacun de ces composants.

On doit pouvoir éditer le texte comme avec n'importe quel éditeur classique sans que ça corrompe les composants au passage, et quel que soit le scénario (sélections, copier / coller, CTRL+Z etc.)

On doit pouvoir manipuler facilement ces composants et les déplacer dans le contentEditable, notamment avec un simple drag & drop, ou bien un copier coller.

On doit pouvoir éditer facilement ces composants en double cliquant dessus. Toujours comme dans gmail où lorsqu'on double-clique sur une adresse email alors l'objet email passe en mode édition, et on peut modifier l'adresse email en question.

Solution 1:

A chaque fois qu'on souhaite insérer un composant on crée une div à cet endroit avec la propriété absolute dessus. Bon ok je sors. 😁

Solution 2:

On pourrait alimenter le contentEditable avec une liste représentant soit du texte soit un composant. Par exemple:

<div contentEditable=true>

<span> Some text... blablabla </span>

<ComplexComponent />

<span> Some more text</span>

<ComplexComponent />

</div>

Ainsi le rendu serait intéressant, les composants seraient bien insérés au milieu du texte et la liste de textes/composants s'ajusteraient en fonction des actions du user.

Mais

Il y aurait une énorme lourdeur à gérer tous les évènements utilisateur pour les garder sous contrôle.

Par exemple:

Une fois rendus par React, les composants au milieu du texte seraient considérés comme du texte modifiable ; ils seraient donc même effaçables n'importe comment si on ne mettait pas en place un algorithme pour les protéger.

Pour la même raison Chrome ne ferait pas la distinction tout seul si on faisait un Ctrl+X sur une selection qui inclurait un composant React, la structure deviendrait difficile à maintenir... sauf ajoutait de règles spéciales

On doit impérativement garder le style des composants... alors que faire si le user sélectionnait un composant parmi le texte et le mettait en gras? voire même en faisait une liste à puce ? les noeuds du DOM disjoncteraient... sauf règles spéciales à nouveau

Une astuce: on pourrait jouer avec les keys des textes ou composants pour forcer leur re-création à des moment opportuns (on éviterait les render classique pour ne pas reset le curseur à chaque fois qu'on appuie sur une touche...)

etc. etc. etc.

Le challenge:

  • Quelle autre architecture que cette liste textes/composants serait plus appropriée?
  • Comment adopter une structure de code claire et maintenable ? Tant que faire se peut, on souhaite éviter de créer des fonctions au fur et à mesure que l'on rencontre des problèmes, de ranger ces fonctions dans le fonctional composant du contentEditable, qui s'allongerait alors rapidement.... Ca ferait un peu artisanal, surtout avec cette liste de textes/composants. A priori React ne préconise pas particulièrement d'architecture classique objet avec ses héritages etc...

Voilà pour les précisions et la difficulté de ce challenge.

Vous vous sentez prêt(e) à relever ce défi pas si évident?

Vous pouvez soumettre votre réponse via les canaux ci-dessous.

👉 via email sur wcalvat [at] bondinbox [dot] com

👉 via twitter

👉 via linkedin

👉 via Discord: bond inbox#7852

- William -