@supersoniks/concorde 5.1.2 → 5.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/.agents/skills/concorde-docs/SKILL.md +1 -1
  2. package/README.md +1 -1
  3. package/ai/README.md +29 -41
  4. package/ai/skills/concorde/SKILL.md +54 -324
  5. package/ai/skills/concorde/rules/composition.md +32 -0
  6. package/ai/skills/concorde/rules/data.md +47 -0
  7. package/ai/skills/concorde/rules/http.md +25 -0
  8. package/ai/skills/concorde/rules/lists-forms.md +35 -0
  9. package/ai/skills/concorde/rules/styling.md +46 -0
  10. package/ai/skills/concorde/rules/troubleshooting.md +45 -0
  11. package/build-infos.json +1 -1
  12. package/concorde-core.bundle.js +21 -21
  13. package/concorde-core.es.js +977 -980
  14. package/custom-elements-manifest.public.config.mjs +8 -0
  15. package/{.tmp-cem/custom-elements.json → custom-elements.json} +11722 -8868
  16. package/dist/concorde-core.bundle.js +21 -21
  17. package/dist/concorde-core.es.js +977 -980
  18. package/dist/docs-mock-api-sw.js +58 -223
  19. package/dist/docs-mock-api-sw.js.map +4 -4
  20. package/dist/img/concorde/plane_01.jpg +0 -0
  21. package/dist/img/concorde/plane_02.jpg +0 -0
  22. package/dist/img/concorde/plane_03.jpg +0 -0
  23. package/dist/img/concorde/plane_04.jpg +0 -0
  24. package/dist/img/concorde/plane_05.jpg +0 -0
  25. package/dist/img/concorde/plane_06.jpg +0 -0
  26. package/dist/img/concorde/plane_07.jpg +0 -0
  27. package/dist/img/concorde/plane_08.jpg +0 -0
  28. package/dist/img/concorde/plane_09.jpg +0 -0
  29. package/dist/img/concorde/plane_10.jpg +0 -0
  30. package/dist/img/concorde/plane_11.jpg +0 -0
  31. package/dist/img/concorde/plane_12.jpg +0 -0
  32. package/dist/img/concorde/plane_13.jpg +0 -0
  33. package/dist/img/og-concorde.jpg +0 -0
  34. package/dist/robots.txt +11 -10
  35. package/docs/.htaccess +7 -0
  36. package/docs/about.html +111 -0
  37. package/docs/about.md +22 -0
  38. package/docs/assets/{index-BgG6FFPt.js → index-6sS76xWj.js} +482 -500
  39. package/docs/assets/{index-x89XINSG.css → index-DkdPbH0F.css} +1 -1
  40. package/docs/core/components/functional/date/date.md +1 -1
  41. package/docs/core/components/functional/list/list.html +7 -5
  42. package/docs/core/components/functional/list/list.md +6 -2
  43. package/docs/core/components/ui/card/card.html +1 -1
  44. package/docs/core/components/ui/card/card.md +1 -1
  45. package/docs/core/components/ui/image/image.html +17 -17
  46. package/docs/core/components/ui/image/image.md +17 -17
  47. package/docs/core/components/ui/modal/modal.html +2 -2
  48. package/docs/core/components/ui/modal/modal.md +2 -2
  49. package/docs/custom-elements.json +16559 -0
  50. package/docs/docs/decorators/bind.html +22 -21
  51. package/docs/docs/decorators/bind.md +23 -24
  52. package/docs/docs/getting-started/ai-agents.html +50 -94
  53. package/docs/docs/getting-started/ai-agents.md +29 -55
  54. package/docs/docs/getting-started/dataFlow.html +1 -1
  55. package/docs/docs/getting-started/dataFlow.md +1 -1
  56. package/docs/docs/index.html +1 -1
  57. package/docs/hubs/decorators.html +11 -16
  58. package/docs/hubs/remote-data.html +5 -9
  59. package/docs/img/og-concorde.jpg +0 -0
  60. package/docs/index.html +91 -2
  61. package/docs/index.md +2 -2
  62. package/docs/llms-full.txt +58 -74
  63. package/docs/llms.txt +6 -4
  64. package/docs/privacy.html +122 -0
  65. package/docs/privacy.md +32 -0
  66. package/docs/sitemap.xml +6 -0
  67. package/docs/src/core/components/functional/date/date.md +1 -1
  68. package/docs/src/core/components/functional/list/list.md +6 -2
  69. package/docs/src/core/components/functional/sdui/component-catalog.gaps.json +1 -1
  70. package/docs/src/core/components/functional/sdui/component-catalog.json +1 -1
  71. package/docs/src/core/components/ui/card/card.md +1 -1
  72. package/docs/src/core/components/ui/image/image.md +17 -17
  73. package/docs/src/core/components/ui/modal/modal.md +2 -2
  74. package/docs/src/docs/decorators/bind.md +23 -24
  75. package/docs/src/docs/getting-started/ai-agents.md +29 -55
  76. package/docs/src/docs/getting-started/dataFlow.md +1 -1
  77. package/docs/src/docs/search/docs-search.json +100 -55
  78. package/docs/src/tsconfig.json +11 -5
  79. package/index.html +89 -0
  80. package/package.json +8 -4
  81. package/public/img/og-concorde.jpg +0 -0
  82. package/scripts/ai-init.mjs +104 -379
  83. package/scripts/ai-init.test.mjs +81 -239
  84. package/scripts/docs-markdown-vite-plugin.ts +11 -5
  85. package/scripts/docs-public-url.mjs +6 -0
  86. package/scripts/docs.htaccess +7 -0
  87. package/scripts/generate-cem.mjs +244 -0
  88. package/scripts/generate-cem.test.mjs +122 -0
  89. package/scripts/generate-crawl-docs.mjs +29 -5
  90. package/scripts/generate-sdui-catalog.mjs +11 -10
  91. package/scripts/post-build-docs.js +3 -0
  92. package/scripts/pre-publish.mjs +2 -1
  93. package/scripts/site-pages.mjs +212 -0
  94. package/scripts/site-pages.test.mjs +116 -0
  95. package/site-pages/about.md +22 -0
  96. package/site-pages/privacy.md +32 -0
  97. package/src/core/components/functional/date/date.md +1 -1
  98. package/src/core/components/functional/list/list.md +6 -2
  99. package/src/core/components/functional/sdui/component-catalog.gaps.json +1 -1
  100. package/src/core/components/functional/sdui/component-catalog.json +1 -1
  101. package/src/core/components/ui/card/card.md +1 -1
  102. package/src/core/components/ui/image/image.md +17 -17
  103. package/src/core/components/ui/modal/modal.md +2 -2
  104. package/src/core/decorators/subscriber/bind.ts +9 -14
  105. package/src/docs/components/docs-demo-sources.ts +3 -3
  106. package/src/docs/decorators/bind.md +23 -24
  107. package/src/docs/docs-location.spec.ts +10 -0
  108. package/src/docs/docs-location.ts +10 -0
  109. package/src/docs/example/decorators-demo-bind-demos.ts +11 -28
  110. package/src/docs/example/docs-toggle-demos.ts +1 -1
  111. package/src/docs/getting-started/ai-agents.md +29 -55
  112. package/src/docs/getting-started/dataFlow.md +1 -1
  113. package/src/docs/home/home.ts +3 -1
  114. package/src/docs/navigation/navigation.ts +1 -1
  115. package/src/docs/search/docs-search.json +100 -55
  116. package/src/docs/search/markdown-renderer.ts +6 -1
  117. package/src/docs/tailwind/css/docs/content.css +4 -5
  118. package/src/tsconfig.json +11 -5
  119. package/src/tsconfig.tsbuildinfo +1 -1
  120. package/ai/AGENTS.md +0 -56
  121. package/ai/cursor/rules/concorde-menu.mdc +0 -15
  122. package/ai/cursor/rules/concorde-scope.mdc +0 -14
  123. package/ai/cursor/rules/concorde-theme.mdc +0 -13
  124. package/ai/cursor/rules/concorde.mdc +0 -66
  125. package/ai/jetbrains/rules/concorde.md +0 -53
  126. package/ai/skills/concorde-get-set-dp/SKILL.md +0 -194
  127. package/ai/skills/concorde-imports/SKILL.md +0 -78
  128. package/ai/skills/concorde-menu/SKILL.md +0 -74
  129. package/ai/skills/concorde-scope/SKILL.md +0 -70
  130. package/ai/skills/concorde-theme/SKILL.md +0 -57
@@ -105,7 +105,7 @@ The library is named after Concorde: every example tells a small aviation story.
105
105
 
106
106
  ### Images
107
107
 
108
- Use `img/concorde/plane_XX.jpg` (relative path, served from `public/`). Always set a meaningful `alt`.
108
+ Use `/img/concorde/plane_XX.jpg` (absolute from the site root, files in `public/img/`). Always set a meaningful `alt`.
109
109
 
110
110
  | File | Subject | Fits |
111
111
  |------|---------|------|
package/README.md CHANGED
@@ -23,7 +23,7 @@ yarn ai-init
23
23
  node node_modules/@supersoniks/concorde/scripts/ai-init.mjs
24
24
  ```
25
25
 
26
- Installe `.cursor/skills`, `.cursor/rules`, `.aiassistant/rules` et `AGENTS.md`. Voir [ai/README.md](ai/README.md).
26
+ Installe la skill `concorde` dans `.agents/skills` (liée depuis `.claude/skills` et `.junie/skills`). `AGENTS.md` n’est jamais touché. Voir [ai/README.md](ai/README.md).
27
27
 
28
28
  ## 📁 Structure du projet
29
29
 
package/ai/README.md CHANGED
@@ -1,58 +1,46 @@
1
1
  # Agent IA — Concorde
2
2
 
3
- Fichiers installables pour **Cursor** et **JetBrains AI Assistant**.
3
+ Une skill unique, `concorde` (format [Agent Skills](https://agentskills.io)), installable dans un projet : Cursor, Claude Code, JetBrains Junie et tout agent qui lit `.agents/skills`.
4
4
 
5
- ## Installation dans un projet
6
-
7
- ```bash
8
- node node_modules/@supersoniks/concorde/scripts/ai-init.mjs
9
- ```
10
-
11
- Options :
5
+ ## Structure
12
6
 
13
- - `--overlay <dir>` — couche projet ; lit `AGENTS.concorde.md` (legacy : `AGENTS.overlay.md`, `AGENTS.starter.md`)
14
- - `--skip-agents` — n’écrit jamais `AGENTS.md` (skills / rules seulement)
15
- - `--merge-agents` — opt-in : conserve le préambule projet et ajoute / rafraîchit le bloc Concorde
16
- - `--force-agents` — opt-in : **remplace** tout `AGENTS.md` (destructif)
17
- - `--cursor-only` / `--jetbrains-only`
7
+ Sur le modèle de la skill shadcn : un point d’entrée court, des fichiers de règles lus à la demande.
18
8
 
19
- Depuis le dépôt Concorde (dev) : `yarn ai-init`
9
+ ```text
10
+ skills/concorde/
11
+ SKILL.md point d’entrée : sources (projet, doc, custom-elements.json), règles critiques, imports
12
+ rules/data.md store, DataProviderKey, décorateurs, sub(), get / set / dp
13
+ rules/http.md Endpoint, @get / @post, configuration API
14
+ rules/lists-forms.md
15
+ rules/styling.md thème, tokens, règles de style
16
+ rules/composition.md parties des composants composés, états intégrés
17
+ rules/troubleshooting.md symptôme → cause → correction
18
+ ```
20
19
 
21
- ## Politique `AGENTS.md` (non invasive)
20
+ Ajouter un sujet = un fichier dans `rules/` + une ligne dans le tableau « Rules files » de `SKILL.md`. Pas de nouvelle skill sauf besoin vraiment distinct.
22
21
 
23
- | Situation | Comportement par défaut |
24
- |-----------|-------------------------|
25
- | Pas de `AGENTS.md` | Création du guide Concorde |
26
- | Fichier avec `<!-- concorde-ai -->` | Rafraîchit la zone gérée seulement |
27
- | Fichier **sans** marker (notes projet) | **Laissé intact** — skills / rules suffisent |
28
- | `--merge-agents` | Préambule projet + bloc Concorde après le marker |
29
- | `--force-agents` | Remplacement complet |
30
- | `--skip-agents` | Jamais d’écriture `AGENTS.md` |
22
+ ## Installation dans un projet
31
23
 
32
- ```text
33
- [optional project preamble — short, project-only]
34
- <!-- concorde-ai -->
35
- <package ai/AGENTS.md>
36
- [--- + overlay AGENTS.concorde.md]
24
+ ```bash
25
+ node node_modules/@supersoniks/concorde/scripts/ai-init.mjs
37
26
  ```
38
27
 
39
- - Tout **après** `<!-- concorde-ai -->` est **régénéré** à chaque run (pas d’empilement).
40
- - Ne pas recopier le guide Concorde dans le préambule : notes projet → `overlay/AGENTS.concorde.md`.
41
- - Si le préambule duplique `ai/AGENTS.md`, `ai-init` le **allège / drop** et affiche un warning.
42
- - Legacy : `AGENTS.overlay.md` / `AGENTS.starter.md` encore lus si `AGENTS.concorde.md` est absent (warning de dépréciation).
28
+ Depuis le dépôt Concorde : `yarn ai-init`.
29
+
30
+ | Source | Cible dans le projet |
31
+ |--------|---------------------|
32
+ | `skills/<nom>/` | `.agents/skills/<nom>/` (copie ; lue directement par Cursor) |
33
+ | — | `.claude/skills/<nom>` et `.junie/skills/<nom>` : liens symboliques (copie si les liens sont interdits) |
43
34
 
44
- ## Contenu
35
+ Options :
45
36
 
46
- | Dossier | Cible |
47
- |---------|--------|
48
- | `skills/` | `.cursor/skills/` (concorde, imports, scope, theme, menu) |
49
- | `cursor/rules/` | `.cursor/rules/` |
50
- | `jetbrains/rules/` | `.aiassistant/rules/` |
51
- | `AGENTS.md` | racine du projet **seulement** si absent, déjà marqué, ou via `--merge-agents` / `--force-agents` |
37
+ - `--overlay <dir>` — skills supplémentaires d’un kit projet (`<dir>/skills/<nom>/`)
38
+ - `--no-links` — `.agents/skills` seulement
39
+ - `--project-root <dir>`, `--concorde-ai <dir>`
52
40
 
53
- ## Template starter
41
+ **`AGENTS.md` appartient au projet** : `ai-init` ne le lit ni ne l’écrit. Les agents trouvent la skill seuls, par sa description.
54
42
 
55
- Le package `create-concorde-ts-starter` ajoute un overlay via `yarn ai:sync`.
43
+ Seules les skills du package sont remplacées ; une skill du projet portant le même nom n’est jamais écrasée. Si `.claude/skills` pointe déjà vers `.agents/skills`, aucun lien par skill n’est créé.
56
44
 
57
45
  ## Tests
58
46
 
@@ -1,348 +1,78 @@
1
1
  ---
2
2
  name: concorde
3
3
  description: >-
4
- Composants Web Concorde (Lit) : DataProvider, scope, theme, Endpoint,
5
- formDataProvider, sonic-list/sonic-queue, @subscribe/@handle/@get.
6
- @subscribe feuille par feuille (pas d’objet parent + getters).
7
- Imports courts (@supersoniks/concorde/menu, /list, /utils…).
4
+ Entry point for any work in a project that uses Concorde
5
+ (@supersoniks/concorde), the Lit web components library: writing components,
6
+ reading or writing the DataProvider store, calling APIs, lists, forms,
7
+ styling with sonic-* components and theme tokens, imports. Use whenever code
8
+ imports @supersoniks/concorde or uses sonic-* elements.
8
9
  ---
9
10
 
10
- # Concorde — patterns et migrations
11
+ # Concorde
11
12
 
12
- Source de vérité : fichiers `.md` dans `node_modules/@supersoniks/concorde/src/` (composants, décorateurs, docs).
13
+ Lit + TypeScript web components (`sonic-*`) with a shared data store, the **DataProvider**. This file holds the critical rules; read the matching file in `rules/` before working on that topic.
13
14
 
14
- **Imports** : toujours les chemins **les plus courts** — voir skill `concorde-imports` et section ci-dessous.
15
+ ## Rules files
15
16
 
16
- **Vocabulaire** : toujours **DataProvider**. Accès programmatique : **`get(chemin)`** (alias Concorde `dp`), **`set(chemin, valeur)`**. **Pas** `PublisherManager` ni `getDataProvider`.
17
+ | Topic | Read |
18
+ |-------|------|
19
+ | Store, `DataProviderKey`, `@subscribe` / `@publish` / `@bind` / `@handle`, `sub()`, `get` / `set` / `dp` | [rules/data.md](rules/data.md) |
20
+ | HTTP: `Endpoint`, `@get` / `@post`, API configuration | [rules/http.md](rules/http.md) |
21
+ | `sonic-list` / `sonic-queue`, forms | [rules/lists-forms.md](rules/lists-forms.md) |
22
+ | Theme, tokens, classes, styling rules | [rules/styling.md](rules/styling.md) |
23
+ | Which parts go in which component, built-in states | [rules/composition.md](rules/composition.md) |
24
+ | Something does not update, render or send | [rules/troubleshooting.md](rules/troubleshooting.md) |
17
25
 
18
- ## Imports (règle prioritaire)
26
+ ## Sources of truth
19
27
 
20
- Préférer `@supersoniks/concorde/menu`, `/list`, etc. **dans les apps consommatrices**. Dans le **dépôt Concorde** (lib + doc), utiliser `core/components/…` ou imports relatifs — voir skill `concorde-imports` (section « Dans le dépôt Concorde »).
28
+ 1. **The project.** Check the installed version (`npm ls @supersoniks/concorde`); an API missing from it is not available. Reuse the project's `DataProviderKey`s, `Endpoint`s, API configuration and components before creating new ones.
29
+ 2. **The docs.** Every page is Markdown when you append `.md` to its URL. Index: https://concorde.supersoniks.org/llms.txt · offline: `node_modules/@supersoniks/concorde/src/**/*.md`.
30
+ 3. **The element API.** Attributes with allowed values, properties, events and slots are in `node_modules/@supersoniks/concorde/custom-elements.json`. It is large: query one element.
21
31
 
22
- Référence complète : skill **`concorde-imports`** (`.cursor/skills/concorde-imports/SKILL.md`).
23
-
24
- ## Interdits pour du **nouveau** code
25
-
26
- - **Ne pas** étendre les mixins `Subscriber` / `Fetcher` sur des composants métier.
27
- - **Ne pas** utiliser `data-bind`, `data-publish`, `data-subscribe` en HTML.
28
- - **Ne pas** mettre `@input`, `@change` ou `.value` + assignation manuelle sur **`sonic-input`** quand `formDataProvider` + `name` suffit.
29
- - **Ne pas** introduire `@onAssign` — préférer `@handle` + `DataProviderKey`.
30
- - **Ne pas** utiliser **`@bind`** sur les composants métier — préférer **`@subscribe`** + `DataProviderKey<T, U>` (typage + placeholders `${prop}` sur l’hôte).
31
- - **Ne pas** utiliser **`sonic-fetch`** — préférer **`sonic-queue`** (+ filtre `formDataProvider`) ou **`@get`** + `Endpoint`.
32
- - Les décorateurs API **`@get`**, **`@post`**, **`@put`** et **`@patch`**
33
- s'adaptent aux propriétés et aux méthodes ; la méthode reçoit le
34
- `ApiResult` complet.
35
- - **Ne pas** importer **`PublisherManager`** — utiliser **`get` / `set`** (réexport Concorde ou wrapper projet).
36
- - **Ne pas** promouvoir les templates HTML (`<template>`, `data-value`) pour **`sonic-list`** / **`sonic-queue`** — préférer **`.items`**, **`.noItems`**, **`.skeleton`**, **`.separator`** (binding propriété Lit obligatoire pour les fonctions).
37
-
38
- ## DataProvider
39
-
40
- Store observable adressé par un chemin string :
41
-
42
- ```typescript
43
- import { dp, get, set } from "@supersoniks/concorde/utils";
44
- import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
45
-
46
- const counterKey = new DataProviderKey<{ count: number }>("myCounter");
47
-
48
- set(counterKey, { count: 0 });
49
- dp(counterKey.count).set(1);
50
- get(counterKey); // snapshot { count: 1 }
51
- ```
52
-
53
- Chemins **statiques** uniquement pour `get` / `set` / `dp`. Clés avec `${…}` → décorateurs ou **`sub(clé)`** dans les templates. Migration : skill **`concorde-get-set-dp`**.
54
-
55
- Attributs HTML courants :
56
-
57
- | Attribut | Rôle |
58
- |----------|------|
59
- | `dataProvider` | Lie un composant au DataProvider à ce chemin |
60
- | `formDataProvider` | Conteneur de formulaire — les champs `name` écrivent dedans |
61
- | `dataFilterProvider` | Filtre lu par `sonic-queue` (relance les requêtes) |
62
-
63
- ## DataProviderKey
64
-
65
- ### Chemins statiques
66
-
67
- ```typescript
68
- const counterKey = new DataProviderKey<{ count: number }>("myCounter");
69
- counterKey.count.path; // "myCounter.count"
70
- ```
71
-
72
- ### Chemins dynamiques (placeholder)
73
-
74
- Placeholder `${prop}` dans une **chaîne normale** (pas de backticks). Résolu depuis les propriétés du composant hôte ; ré-abonnement automatique quand elles changent.
75
-
76
- ```typescript
77
- export const userKey = new DataProviderKey<User, { userIndex: number }>(
78
- "users.${userIndex}",
79
- );
80
-
81
- @property({ type: Number }) userIndex = 0;
82
-
83
- @subscribe(userKey)
84
- @state() user: User | null = null;
85
- ```
86
-
87
- Même mécanisme pour `@handle`, `@publish`, `@subscribe`. Éviter `@bind` (bidirectionnel / chemins string legacy).
88
-
89
- Doc : `src/docs/misc/dataProviderKey.md`, `src/docs/decorators/subscribe.md`, `handle.md`.
90
-
91
- ## Endpoint
92
-
93
- ```typescript
94
- const users = new Endpoint<UsersResponse>("users?offset=$offset&limit=$limit");
95
- users.path;
96
- ```
97
-
98
- Utilisé avec `@get(endpoint)` ou `@get(endpoint, apiConfigKey)` — voir **Scope** ci-dessous.
99
-
100
- ### Décorateurs API sur une méthode
101
-
102
- `@get`, `@post`, `@put` et `@patch` peuvent décorer une propriété ou une
103
- méthode. En mode méthode, le callback reçoit le `ApiResult` complet :
104
-
105
- ```typescript
106
- @get(endpoints.ticket)
107
- handleTicket(payload: ApiResult<PurchaseItem> | undefined) {
108
- if (!payload?.result || !payload.response?.ok) return;
109
- dp<PurchaseItem>(this.dataProvider).set(payload.result);
110
- }
111
- ```
112
-
113
- La méthode reçoit le payload complet (`result`, `response`, `request`).
114
- `undefined` représente un appel terminé sans payload, par exemple une erreur
115
- réseau. Si un refetch nommé est nécessaire, conserver le handle et décorer la
116
- méthode avec lui :
117
-
118
- ```typescript
119
- const ticketGet = get(endpoints.ticket);
120
-
121
- @ticketGet
122
- handleTicket(payload: ApiResult<PurchaseItem> | undefined) {}
123
-
124
- @refetch(ticketGet)
125
- reloadTicket() {}
126
- ```
127
-
128
- `@send(handle)` reste le décorateur de méthode qui déclenche explicitement une
129
- écriture ; les mutations du body, triggers et polling conservent leur
130
- comportement.
131
-
132
- Exemple écriture :
133
-
134
- ```typescript
135
- @post(endpoints.ticket, ticketBodyKey)
136
- handleTicketCreation(payload: ApiResult<PurchaseItem> | undefined) {
137
- if (payload?.response?.ok) console.log(payload.result);
138
- }
139
- ```
140
-
141
- ## Scope — defaults hérités
142
-
143
- Skill dédié : **`concorde-scope`**.
144
-
145
- `<sonic-scope>` (light DOM) : les descendants héritent des attributs (`serviceURL`, `token`, `formDataProvider`, icônes custom…).
146
-
147
- ```typescript
148
- import "@supersoniks/concorde/sonic-scope";
149
- ```
150
-
151
- ```html
152
- <sonic-scope serviceURL="https://api.example.com" formDataProvider="checkout">
153
- …app…
154
- </sonic-scope>
155
- ```
156
-
157
- **API** — type `APIConfiguration` (`@supersoniks/concorde/utils/api`) :
158
-
159
- | Mode | `@get` | Config |
160
- |------|--------|--------|
161
- | Scope | `@get(endpoint)` | hérite `serviceURL`, `token`, … du scope |
162
- | DataProvider | `@get(endpoint, apiConfigKey)` | objet publié via `set(apiConfigKey, { … })` |
163
-
164
- Champs courants : `serviceURL`, `token`, `userName`/`password`, `credentials`, `authToken`, `tokenProvider`.
165
- Avancés : `cache`, `blockUntilDone`, `keepAlive`, `addHTTPResponse`.
166
-
167
- **Ne pas confondre** avec **theme** (couleurs / typo) — skill **`concorde-theme`**.
168
-
169
- ## Theme — design tokens
170
-
171
- Skill dédié : **`concorde-theme`**.
172
-
173
- `<sonic-theme color font class="block bg-base">` + variables CSS `--sc-*` (surfaces, sémantique, typo). Pas pour l’API.
174
-
175
- ```typescript
176
- import "@supersoniks/concorde/theme";
177
- ```
178
-
179
- ## @publish / @subscribe
180
-
181
- ```typescript
182
- @publish(counterKey.count)
183
- @state()
184
- count = 0;
185
-
186
- @subscribe(counterKey.count)
187
- @state()
188
- subscribedCount = 0;
189
- ```
190
-
191
- ### Règle impérative — une souscription par valeur affichée
192
-
193
- Sur un composant **`LitElement`** métier, chaque donnée lue dans `render()` doit avoir **son propre** `@subscribe` + `@state()` (ou `@property` si besoin explicite) sur le **publisher feuille** — jamais un abonnement à l’objet parent + getters.
194
-
195
- | Anti-pattern | Pourquoi |
196
- |--------------|----------|
197
- | `@subscribe(dpKeys.currentSession)` + `get edito()` | Si seul `edito` change (même référence `Session`), Lit peut **ne pas** re-rendre |
198
- | `@subscribe` sur un parent + `sub()` enfant pour le détail | Mélange deux modèles ; préférer des feuilles cohérentes |
199
-
200
- ```typescript
201
- // ❌ — re-render non garanti sur sous-clés
202
- @subscribe(dpKeys.currentSession)
203
- @state() session?: Session;
204
- get edito() { return this.session?.edito; }
205
-
206
- // ✅ — une propriété réactive par champ du template
207
- @subscribe(dpKeys.currentSession.slug)
208
- @state() slug = "";
209
-
210
- @subscribe(dpKeys.currentSession.edito)
211
- @state() edito: Edito | null = null;
212
-
213
- @subscribe(dpKeys.currentSession.settings)
214
- @state() settings: SettingsSessionAPI | null = null;
32
+ ```bash
33
+ node -e 'const t=process.argv[1];for(const m of require("@supersoniks/concorde/custom-elements.json").modules)for(const d of m.declarations)if(d.tagName===t)console.log(JSON.stringify({attributes:d.attributes?.map(a=>[a.name,a.type?.text,a.default]),properties:d.members?.filter(p=>p.kind==="field"&&!p.attribute).map(p=>p.name),events:d.events?.map(e=>e.name),slots:d.slots?.map(s=>s.name)},null,1))' sonic-select
215
34
  ```
216
35
 
217
- **Navigation typée** : chaîner `DataProviderKey` — `dpKeys.currentSession.edito` → `"app.currentSession.edito"`.
218
-
219
- **Granularité** : descendre jusqu’à la **feuille** réellement affichée si les mutations ne remplacent pas l’objet intermédiaire (ex. `@subscribe(dpKeys.currentSession.edito.title)` si seul `title` change sans nouvel objet `edito`).
36
+ ## Critical rules
220
37
 
221
- **Templates** : même règle avec `sub(dpKeys.currentSession.edito.title)` plutôt que `sub(dpKeys.currentSession)` + accès JS.
38
+ - `LitElement` + decorators. In new code, and when touching old code: `Subscriber` mixin → decorators · `sonic-fetch` → `@get`, or `sonic-list` with `fetch` · `@onAssign` → `@handle` · `PublisherManager` → `get` / `set` / `dp` · `data-bind` → `sub()`.
39
+ - Store access through a typed `DataProviderKey`, never a string path.
40
+ - Display store values with `sub(key.leaf)`; subscribe to the leaf you render, not to its parent object.
41
+ - Lists render rows with `.items` / `.noItems` / `.skeleton` (Lit properties, with the dot).
42
+ - Form fields write to the store by themselves: `formDataProvider` + `name`, no `@input` wiring.
43
+ - `@post` sends on every body mutation by default: forms use `autoPostOnBodyMutation: false` + `send()`.
44
+ - Use `sonic-*` components and their attributes before custom markup; semantic tokens only, no raw colors, no `dark:`.
222
45
 
223
- ### Cas hybride — hôte `Subscriber` + enfants sonic
46
+ ## Component shape
224
47
 
225
- Des composants catalogue (`sonic-event-location-hall`, `sonic-date`, `sonic-product-title`, …) remontent l’arbre pour `dataProvider` et utilisent le **template filling** du mixin `Subscriber` — pas un `@subscribe` local.
48
+ ```ts
49
+ import { html, LitElement } from "lit";
50
+ import { customElement, state } from "lit/decorators.js";
51
+ import { subscribe, DataProviderKey } from "@supersoniks/concorde/decorators";
226
52
 
227
- | Situation | Approche |
228
- |-----------|----------|
229
- | Composant métier **sans** enfants `Subscriber` | `LitElement` + `@subscribe` **feuille par feuille** |
230
- | Composant **hôte** d’enfants sonic `Subscriber` | `extends Subscriber(LitElement)` + `@property` remplies par template filling ; **exposer** `dataProvider` aux descendants |
53
+ type Flight = { code: string; gate: string };
54
+ const flightKey = new DataProviderKey<Flight>("flight");
231
55
 
232
- **`dataProvider` imbriqué** (éviter la clé plate `"app.currentSession"`) :
56
+ @customElement("app-flight")
57
+ export class AppFlight extends LitElement {
58
+ @subscribe(flightKey.gate)
59
+ @state()
60
+ gate = "";
233
61
 
234
- ```html
235
- <mon-composant-hote dataProvider="app" subDataProvider="currentSession"></mon-composant-hote>
236
- ```
237
-
238
- Après `initPublisher`, refléter le chemin résolu sur l’attribut (ex. `app/currentSession`) pour que les **enfants** héritent le bon publisher — ils ne lisent pas `subDataProvider` sur l’ancêtre.
239
-
240
- **Liste / queue** : chaque ligne a son publisher — l’hôte **hérite** de l’ancêtre ; ne pas forcer `app.currentSession` sur un item de liste.
241
-
242
- ### Piège migration `Subscriber` → `LitElement` (checklist)
243
-
244
- Lors du remplacement de `sonic-fetch` ou du retrait du mixin `Subscriber` sur un composant **métier** :
245
-
246
- | Étape | Vérification |
247
- |-------|----------------|
248
- | Champs affichés dans `render()` | Chaque `@property` autrefois remplie par template filling → **`@subscribe(dpKey.feuille)` + `@state()`** (pas laisser des `@property` orphelins) |
249
- | Enfant d’un `@get` | `@get` + `@publish`/`@handle` vers le DataProvider cible ; l’UI lit ce DP via `@subscribe`, pas via des props vides |
250
- | Placeholders `Endpoint` | Les noms `${prop}` doivent exister sur l’hôte (`@property` ou copie dans `willUpdate` si le scan utilise un autre nom, ex. `checkCode` → `code`) |
251
- | Modale / portal | `@get(endpoint, apiConfigKey)` si pas de `serviceURL` ascendant fiable (`Modal` → `Theme.getPopContainer()`) |
252
- | Remplacement `sonic-fetch` | Expliciter `dataProvider` + `subDataProvider` sur les hôtes `Subscriber` enfants (ex. `app` + `currentScanTicket`) |
253
-
254
- ```typescript
255
- // ❌ — Subscriber retiré, props jamais alimentées
256
- export class TicketInfos extends LitElement {
257
- @property({ type: Object }) owner = {};
258
- render() { return html`${this.owner?.firstName}`; }
62
+ render() {
63
+ return html`Gate ${this.gate}`;
64
+ }
259
65
  }
260
-
261
- // ✅ — une souscription par champ affiché
262
- @subscribe(dpKeys.currentScanTicket.owner)
263
- @state() owner: Contact = {};
264
- ```
265
-
266
- **`@subscribe` + décorateur Lit** : préférer **`@state()`** (pas `@property`) pour les champs purement lus depuis le DataProvider.
267
-
268
- ## formDataProvider
269
-
270
- ```html
271
- <div formDataProvider="myForm">
272
- <sonic-input name="value" label="Texte"></sonic-input>
273
- </div>
274
66
  ```
275
67
 
276
- Initialisation : `set("myForm", { value: "" })`.
277
-
278
- ## sonic-queue — scroll infini + recherche
279
-
280
- Pagination (`$offset` / `$limit`) **automatisée** avec `lazyload`.
281
-
282
- ```html
283
- <div formDataProvider="myFilter">
284
- <sonic-input name="q" type="search" label="Rechercher"></sonic-input>
285
- </div>
286
- <sonic-queue
287
- lazyload
288
- dataFilterProvider="myFilter"
289
- dataProviderExpression="users?offset=$offset&limit=$limit"
290
- serviceurl="…"
291
- key="data"
292
- limit="4"
293
- .items=${renderUser}
294
- ></sonic-queue>
295
- ```
296
-
297
- ## Templates sonic-list / sonic-queue
298
-
299
- Propriétés Lit (recommandé) :
300
-
301
- | Propriété | Rôle |
302
- |-----------|------|
303
- | `.items=${fn}` | Rendu de chaque ligne — **point obligatoire** (Lit ne passe pas les fonctions en attribut HTML) |
304
- | `.separator` | Entre chaque item (pas après le dernier) |
305
- | `.noItems` | Liste vide |
306
- | `.skeleton` | Chargement pendant un `fetch` |
307
-
308
- `sonic-queue` transmet ces propriétés à chaque lot (`sonic-list` interne). `.noItems` ne s’applique qu’au **premier** lot.
309
-
310
- ## Décorateurs
311
-
312
- | Besoin | API |
313
- |--------|-----|
314
- | Lire (affichage Lit) | `@subscribe(dpKey.leaf)` + `@state()` — **une fois par champ** du `render()` |
315
- | Effet typé | `@handle(dpKey.a, …)` |
316
- | API HTTP | `@get(Endpoint)` ou `@get(Endpoint, apiConfigKey)` |
317
- | Effet après GET | `@get(endpoint)` sur une méthode |
318
- | Effet après écriture | `@post` / `@put` / `@patch` sur une méthode |
319
- | Écriture classe (hors form) | `@publish` |
320
- | Lecture classe (hors form) | `@subscribe` + `DataProviderKey` — pas `@bind` |
321
-
322
- ## Migrations courantes
323
-
324
- | Ancien | Nouveau |
325
- |--------|---------|
326
- | `PublisherManager.get(…)` | `get(…)` ou `set(…)` |
327
- | « publisher » | DataProvider |
328
- | `sonic-input` + `@input` | `formDataProvider` + `name` |
329
- | `sonic-fetch` | `sonic-queue` + filtre, ou `@get` + `@publish`/`@handle` + `@subscribe` / hôte `Subscriber` |
330
- | `extends Subscriber(LitElement)` (métier seul) | `LitElement` + `@subscribe` feuille par feuille / `sub()` — **ne pas oublier** les champs template-filled |
331
- | `extends Subscriber` (hôte d’enfants sonic) | Conserver `Subscriber` + `dataProvider` / `subDataProvider` corrects |
332
- | `@get` dans modale | `@get(endpoint, apiConfigKey)` si config API hors scope DOM |
333
- | `data-bind` HTML | `@subscribe` / `sub()` |
334
- | `@bind` décorateur | `@subscribe` + `DataProviderKey` (lecture) ou `@publish` (écriture) |
335
- | `@onAssign` | `@handle` + `DataProviderKey` |
336
- | Templates HTML list/queue | `items`, `.separator`, `.noItems`, `.skeleton` (propriétés Lit) |
68
+ ## Imports
337
69
 
338
- ## Recettes
70
+ | What | From |
71
+ |------|------|
72
+ | Components (side-effect import) | `@supersoniks/concorde/button` · `/input` · `/list` · `/queue` · `/sonic-scope` · `/theme` … |
73
+ | Decorators, `DataProviderKey`, `Endpoint`, `ApiResult` | `@supersoniks/concorde/decorators` |
74
+ | `sub()` | `@supersoniks/concorde/directives` |
75
+ | `get` / `set` / `dp`, `derive` | `@supersoniks/concorde/utils` |
76
+ | `APIConfiguration` type | `@supersoniks/concorde/utils/api` |
339
77
 
340
- - **Initialiser un DataProvider** : `set(key, { … })` ou `set(key.path, { … })`.
341
- - **Formulaire** : `formDataProvider` + `name` → `sub()` ou `@subscribe`.
342
- - **Liste scroll infini** : `sonic-queue` + `lazyload` + `dataFilterProvider`.
343
- - **Templates list/queue** : `items`, `separator`, `noItems`, `skeleton` (depuis un parent Lit).
344
- - **Config API app-wide** : `<sonic-scope serviceURL="…">` ou `DataProviderKey<APIConfiguration>`.
345
- - **Theme / couleurs** : `<sonic-theme>` + CSS `--sc-*`.
346
- - **Clé dynamique** : `"chemin.${prop}"` + `DataProviderKey<T, { prop: … }>`.
347
- - **GET avec effet de bord** : `@get(endpoint)` sur une méthode ; conserver
348
- `const request = get(endpoint)` si un refetch nommé est nécessaire.
78
+ `get` exists twice: the HTTP decorator (`/decorators`) and the store read (`/utils`). Alias one when a file needs both: `import { get as getRequest } from "@supersoniks/concorde/decorators"`. Inside the Concorde repository itself, short entry points do not resolve: import `@supersoniks/concorde/core/…` or relative paths.
@@ -0,0 +1,32 @@
1
+ # Composition and states
2
+
3
+ Docs: [Components](https://concorde.supersoniks.org/docs/getting-started/components). Exact attributes: query `custom-elements.json` (see `SKILL.md`).
4
+
5
+ ## Parts
6
+
7
+ Compound components keep their parts inside them; do not rebuild a part with a `div`. A nav is `sonic-menu` + `sonic-menu-item`, not a stack of ghost buttons.
8
+
9
+ | Component | Parts |
10
+ |-----------|-------|
11
+ | `sonic-card` | `sonic-card-header` (+ `sonic-card-header-description`) · `sonic-card-main` · `sonic-card-footer` |
12
+ | `sonic-modal` | `sonic-modal-title` (always) · `sonic-modal-subtitle` · `sonic-modal-content` · `sonic-modal-actions`; inside the actions, a `sonic-button` with `hideModal` closes it |
13
+ | `sonic-menu` | `sonic-menu-item` only; sections with `sonic-divider label="…"` |
14
+ | `sonic-fieldset` | `sonic-legend` (or `label` / `description`), then `sonic-form-layout` |
15
+ | Form body | `sonic-form-layout` for fields, `sonic-form-actions` last for the buttons |
16
+ | `sonic-table` | `sonic-thead` · `sonic-tbody` · `sonic-tfoot` → `sonic-tr` → `sonic-th` / `sonic-td`; rows from `sonic-list` |
17
+
18
+ Icons go in a button's `prefix` / `suffix` slot as `sonic-icon`, not as inline SVG.
19
+
20
+ ## States
21
+
22
+ Use the state a component already has before adding `@state` flags and `if` branches.
23
+
24
+ | State | Use |
25
+ |-------|-----|
26
+ | Action running | `loading` on `sonic-button` (spinner, blocks clicks) |
27
+ | List loading / empty | `.skeleton` / `.noItems` on `sonic-list` / `sonic-queue`, or their `loader` attribute |
28
+ | Other content loading | `sonic-loader mode="inline"`; without `mode` it covers the viewport |
29
+ | Field validation | `required` / `pattern` / `min` / `max`; `status="error"` and `description` for the message |
30
+ | Inline message | `sonic-alert status="…"` |
31
+ | Short feedback | `SonicToast.add({ text, status })` from `@supersoniks/concorde/toast` |
32
+ | Disabled | `disabled` on the button or field, not a class |
@@ -0,0 +1,47 @@
1
+ # Data: store and keys
2
+
3
+ Docs: [Data flow](https://concorde.supersoniks.org/docs/getting-started/dataFlow) · [DataProviderKey](https://concorde.supersoniks.org/docs/misc/dataProviderKey) · [Dynamic paths](https://concorde.supersoniks.org/docs/misc/dynamic-path) · [@subscribe](https://concorde.supersoniks.org/docs/decorators/subscribe) · [@bind](https://concorde.supersoniks.org/docs/decorators/bind) · [@handle](https://concorde.supersoniks.org/docs/decorators/handle) · [sub()](https://concorde.supersoniks.org/docs/directives/sub)
4
+
5
+ The app state is one store, the **DataProvider**, addressed by dot paths. Always go through a typed `DataProviderKey<T>`: `cartKey.items[0].qty` builds the path and checks the type.
6
+
7
+ | Need | Use |
8
+ |------|-----|
9
+ | Display a value in a template | `sub(key.field)` |
10
+ | Value used in logic / `willUpdate` | `@subscribe(key.field)` + `@state()` (read only) |
11
+ | Write a property to the store | `@publish(key.field)` |
12
+ | Read **and** write the same path | `@bind(key.field, { reflect: true })` |
13
+ | Side effect on change | `@handle(keyA, keyB)` method |
14
+ | Imperative read / write | `get(key)` · `set(key, value)` · `dp(key)` |
15
+ | Inherit an ancestor attribute | `@ancestorAttribute("dataProvider")` |
16
+
17
+ ## Subscribe to the leaf you render
18
+
19
+ A `set` on a child mutates the parent object in place and does not notify subscribers of the parent. `@subscribe(sessionKey)` + `this.session.title` misses title changes: use `sub(sessionKey.title)` or `@subscribe(sessionKey.title)`.
20
+
21
+ `sub()` in templates, `get()` in code: `get()` in a template renders once and never updates.
22
+
23
+ ## Dynamic paths
24
+
25
+ Placeholders go in a plain string (not a template literal) and are declared in the key's second generic. They resolve from properties of the host component, in decorators and in `sub()`:
26
+
27
+ ```ts
28
+ const userKey = new DataProviderKey<User, { userId: string }>("users.${userId}");
29
+
30
+ @property() userId = "";
31
+ @subscribe(userKey.name) @state() name = "";
32
+ ```
33
+
34
+ `get`, `set` and `dp` **throw** if the path they receive still contains `${…}` or `{$…}`. In imperative code, build the resolved key instead:
35
+
36
+ ```ts
37
+ const usersKey = new DataProviderKey<Record<string, User>>("users");
38
+ set(usersKey[userId], user);
39
+ set(`app.pages.${index}.done`, true); // fine too: JS resolves it before the call
40
+ ```
41
+
42
+ ## Moving old code to keys
43
+
44
+ - `get("app.widget.distance")` → `get(widgetKey.distance)`.
45
+ - `dp(key.path)` / `set(key.path, v)` → `dp(key)` / `set(key, v)`.
46
+ - A key with placeholders passed to `get` / `set` / `dp` → a decorator, or the resolved key above.
47
+ - Leave `sub()` and decorators with placeholders as they are. Grepping `${` is not enough: what matters is the string received at runtime.
@@ -0,0 +1,25 @@
1
+ # HTTP
2
+
3
+ Docs: [@get](https://concorde.supersoniks.org/docs/decorators/get) · [@post](https://concorde.supersoniks.org/docs/decorators/post) · [Endpoint](https://concorde.supersoniks.org/docs/misc/endpoint) · [API configuration](https://concorde.supersoniks.org/docs/misc/api-configuration)
4
+
5
+ ```ts
6
+ const boardEndpoint = new Endpoint<FlightBoard, { direction: string }>(
7
+ "flights?direction=${direction}",
8
+ );
9
+
10
+ @property() direction = "departures";
11
+
12
+ @get(boardEndpoint)
13
+ @state()
14
+ board?: ApiResult<FlightBoard>; // { result, response, request } | undefined
15
+ ```
16
+
17
+ - `@get` on a property stores the `ApiResult<T>`; on a method, the method receives it. A change of a placeholder property runs the request again; while a placeholder is `null` / `undefined`, nothing is sent.
18
+ - To reload: keep the handle (`const load = get(endpoint)`, then `@load` on the property) and call `load.refetch(this)`, or decorate a method with `@refetch(load)`.
19
+ - `@post(endpoint, bodyKey)` (and `@put` / `@patch`) send the store value at `bodyKey`, **on every body mutation by default**. For a form submitted by a button: `post(endpoint, bodyKey, { autoPostOnBodyMutation: false })` kept in a constant, then `save.send(this)` or `@send(save)` on a method.
20
+
21
+ ## API configuration
22
+
23
+ `serviceURL`, `token`, `credentials`… are read from ancestor attributes by default, usually `<sonic-scope serviceURL="…">` at the app root. A component rendered outside that DOM (modal, portal) gets them from the store instead: pass a `DataProviderKey<APIConfiguration>` as second argument, `@get(endpoint, apiKey)`.
24
+
25
+ Do not put API settings on `sonic-theme`: it is for styling only.