
# La grille matricielle

Le seul composant de données qui ne dessine aucun enregistrement. Une `matrix` croise deux ensembles de **nœuds de graphe** en une grille dont les cellules sont des glyphes plutôt que des mots — une marque qui dit « créer et lire, ni modifier ni supprimer » en une forme dont on peut parcourir une colonne entière. Elle lie un point de lecture, jamais une table : là où `chart` et `kpi` agrègent des enregistrements, une matrice lit les nœuds et les arêtes d'un graphe et dessine les relations entre eux.

Recourez-y quand la question est _lesquels de ceux-ci atteignent lesquels de ceux-là, et avec quelle force_ — des permissions à travers des rôles, des fonctionnalités à travers des formules, une couverture à travers des équipes. Recourez plutôt à un `table` quand les cellules sont des valeurs qu'un lecteur doit lire mot à mot.

| Propriété      | Description                                                                       |
| -------------- | --------------------------------------------------------------------------------- |
| `dataSource`   | La liaison au graphe : `system.endpoint`, plus `nodesKey`, `edgesKey` et `query`. |
| `rows`         | L'axe des lignes : `kinds`, `groupBy`, `sortBy`, `sortDirection`.                 |
| `columns`      | L'axe des colonnes, avec les quatre mêmes clés.                                   |
| `cell`         | Ce qui remplit une intersection : `from`, `kind`, `glyph`, `opsField`, `flag`.    |
| `label`        | Le nom du dessin, pour les technologies d'assistance.                             |
| `emptyMessage` | La ligne affichée quand le graphe ne rend rien.                                   |

Toutes les propriétés sont optionnelles. Une matrice à qui manquent ses axes affiche son état vide ; elle n'empêche pas votre application de démarrer.

## Lier un graphe

Une matrice lit deux collections qui s'adressent l'une à l'autre par identifiant : sa liaison nomme donc les deux, contrairement au `rowsKey` unique d'une source système ordinaire. `endpoint` est requis ; `nodesKey` et `edgesKey` valent `nodes` et `edges` par défaut, et `query` fusionne des paramètres statiques dans chaque requête.

Les nœuds deviennent les axes ; les arêtes deviennent les cellules. Comme la lecture s'exécute au nom du visiteur, il ne voit jamais que la part du graphe qu'il aurait pu lire lui-même — et une matrice posée sur une page qu'il n'a pas le droit de lire ne dessine rien plutôt que les données de quelqu'un d'autre.

## Les deux axes

`rows` et `columns` prennent les quatre mêmes clés : apprendre l'un vous enseigne l'autre. `kinds` admet des natures de nœuds sur l'axe, telles que le point d'entrée les orthographie — omettez-le et tous les nœuds sont admis. `groupBy` découpe l'axe en bandes libellées, dessinées sur les deux axes. `sortBy` l'ordonne, les nœuds dépourvus du champ conservant leur ordre source après ceux qui le portent, et `sortDirection` vaut `asc` par défaut.

Aucun des deux axes n'est celui qui compte. Une bande enveloppe les lignes ou les colonnes qu'elle contient plutôt que de les légender à distance, si bien que le regroupement survit à un réordonnancement et se lit correctement à un lecteur d'écran.

Deux détails en découlent, sur l'un comme sur l'autre axe. L'ordre _à l'intérieur_ d'une bande est l'ordre propre de l'axe : `sortBy` continue donc d'agir dans chaque groupe au lieu d'être écrasé par lui, et les bandes elles-mêmes arrivent dans l'ordre où leurs valeurs apparaissent pour la première fois le long de l'axe. Et un nœud qui ne porte pas le champ atterrit dans une bande **sans nom**, qui ne dessine aucune légende — déclarer `groupBy` ne cache donc jamais un nœud, il en laisse seulement un sans groupe.

`kinds`, `groupBy` et `sortBy` nomment des choses dans le vocabulaire de **votre point d'entrée**, pas dans celui de Sovrium. Rien ici n'est une énumération : pointez une matrice vers un autre graphe et ses propres natures de nœuds et ses propres champs fonctionnent sans changement.

## Remplir une cellule

`cell.from` est la collection d'où les cellules sont lues, `edgesKey` par défaut. `kind` admet une nature d'arête ; omettez-la et chaque arête entre une paire d'axes remplit sa cellule. `glyph` vaut `quadrant`, `filled` ou `ops-label`. `opsField` nomme le champ d'arête qui porte les lettres d'opérations que lit le glyphe — omettez-le et chaque cellule remplie est `filled`. `flag` est `{ field, label }`, un champ booléen d'arête marqué sur la cellule, et les deux clés sont requises ensemble.

Une intersection sans arête correspondante se rend tout de même comme une cellule — vide, tenant la forme de la grille. Une ligne dont toutes les cellules sont vides est une information : c'est une chose que rien n'atteint.

### Quand le glyphe ne peut pas exprimer la cellule

`glyph` est une valeur unique et une vraie grille en demande généralement plusieurs, parce que la bonne marque dépend de la **forme des opérations**, pas de la ligne. `glyph` nomme donc le rendu _primaire_ de la cellule, et une cellule qu'il ne peut pas exprimer se rabat plutôt que de perdre ce qu'elle sait :

1. une cellule dont le glyphe déclaré peut exprimer les opérations est dessinée avec lui ;
2. une cellule qu'il ne peut pas exprimer se rabat sur `ops-label` — les lettres sont imprimées plutôt qu'abandonnées, puisque les abandonner ferait paraître identiques deux droits différents ;
3. une arête correspondante ne portant **aucune** opération se rend en `filled` — connectée, sans rien affirmer de plus.

Une même grille déclarant `glyph: quadrant` dessine donc des quadrants là où les opérations ont quatre parties, des lettres là où elles n'en ont pas, et des marques pleines là où il n'y en a aucune. Vous ne configurez pas cela ligne par ligne ; cela suit les données.

## Accessibilité

Une grille de glyphes n'est pas lisible par elle-même : une matrice rend donc toujours un **jumeau accessible**, un vrai tableau sous la grille, avec une ligne par cellule remplie, nommant les deux extrémités, les opérations et le marqueur. Rien ne le désactive. C'est l'artefact principal, pas un repli.

`label` décide de la façon dont le _dessin_ est annoncé. Défini, la grille est une figure nommée avec `role="img"` ; omis, la grille est masquée aux technologies d'assistance. Le jumeau se rend dans les deux cas. Une figure sans nom annoncée comme une figure est du bruit : une matrice sans `label` reste donc silencieuse et laisse le tableau parler.

`flag.label` est le mot qu'emploie le jumeau pour une cellule marquée, et le texte au survol de cette cellule. C'est pourquoi il est requis à côté de `flag.field` : le tableau est l'endroit où une marque est réellement lue, et une marque sans nom n'y laisse rien à lire.

## Rendu

Une matrice est dessinée sur le serveur. La grille et son jumeau sont dans la première réponse — pas d'hydratation, rien d'ajouté au paquet du navigateur, et lisible avec les scripts désactivés. Une page peut en porter une sans payer une bibliothèque de graphiques.

```yaml
pages:
  - name: Access
    path: /access
    components:
      - type: matrix
        dataSource:
          system: { endpoint: /api/admin/organisation/graph }
        rows:
          kinds: [table, page, form, bucket, agent-resource]
          groupBy: family
        columns:
          kinds: [role, team, open]
          sortBy: level
          sortDirection: desc
        cell:
          kind: grant
          glyph: quadrant
          opsField: ops
          flag: { field: viaOpenRung, label: granted to everyone }
        label: Who can do what to what
        emptyMessage: No grants declared.
```

## Pages connexes

- [Le graphe](/fr/docs/data-components-graph) — l'autre composant qui lit des nœuds et des arêtes.
- [Liaison de données](/fr/docs/pages-data-binding) — les sources système et leurs enveloppes.
