# SDUI — points d’extension publics

Aide-mémoire pour les dépôts externes (adaptateurs, shells).  
**Pas une page de la doc site** — à lire dans le package npm  
(`node_modules/@supersoniks/concorde/src/core/components/functional/sdui/sdui-extension-points.md`).  
La doc utilisateur reste `sdui.md` (auto-suffisante).

**Aucune mention de protocoles tiers ici** : uniquement les API génériques Concorde.

## 1. Profil `safe` (opt-in)

```html
<sonic-sdui profile="safe" …>
```

| Refusé | Autorisé |
|--------|----------|
| `js`, `markup`, `innerHTML`, `prefix`, `suffix` | `textContent`, structure, attributs, `action`, `childNodeIds` |

- Nœud refusé → ignoré + `console.warn` (pas de crash)
- Helper pur : `validateSafeDescriptor(descriptor)` depuis `sdui-safe`

## 2. Événement `sdui-action`

Sur un nœud :

```json
{
  "tagName": "sonic-button",
  "nodeId": "confirm",
  "textContent": "OK",
  "action": { "name": "confirm", "context": { "step": 1 } }
}
```

Au clic, `sonic-sdui` émet :

- type : `sdui-action`
- `detail` : `{ name, context, sourceNodeId? }`
- `bubbles: true`, `composed: true`

Ne remplace pas `sonic-submit` / POST / `messagesKey`.

## 3. Catalogue de composants (build only)

- Fichier publié : `component-catalog.json`
- Import : `@supersoniks/concorde/sdui/component-catalog.json`
- Régénération : `yarn generate:sdui-catalog` (aussi `prebuild`)
- Gaps d’annotations : `component-catalog.gaps.json`
- **Aucun impact runtime**

## 4. Rendu partiel (opt-in)

```html
<sonic-sdui partial …>
```

- Registre plat : `nodeById`
- Enfants par id : `childNodeIds`
- Id manquant + `partial` → placeholder (`data-sdui-placeholder`, `data-sdui-node-id`, `display: contents`)
- Sans `partial` → warning + skip

## 5. Ops incrémentales (opt-in, chemin à côté)

Le descripteur entier + rebuild reste le chemin par défaut. Les ops mutent un descripteur local et mettent à jour le DOM **chirurgicalement** (frères préservés : focus, valeurs d’input, état composants).

### Méthodes publiques sur `sonic-sdui`

```ts
upsertNode(node, parentId?, index?)  // node.nodeId requis
removeNode(nodeId)
setData(path, value)                 // chemin publisher, ex. "form.email"
applyOp(op)                          // { op: "upsertNode"|"removeNode"|"setData", … }
endIncremental()                     // revient au mode props → rebuild
```

### Flux optionnel

Attribut `opsDataProvider` : chaque valeur assignée (`SDUIOp` ou `SDUIOp[]`) est passée à `applyOp`.

### Comportement

- Première op → clone local du descripteur + mode partial automatique
- `data-sdui-node-id` marque les nœuds rendus
- Remplacement d’un placeholder / nœud existant via `replaceWith` (pas de `removeChildren` global)

## Imports utiles

| Artefact | Chemin |
|----------|--------|
| Composant | `@supersoniks/concorde/sdui` |
| Types | `…/sdui/types` (via package exports / short path) |
| Safe | `@supersoniks/concorde/sdui-safe` |
| Catalogue | `@supersoniks/concorde/sdui/component-catalog.json` |
