@supersoniks/concorde 5.0.2 → 5.0.4

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 (266) hide show
  1. package/.github/workflows/ci.yml +21 -0
  2. package/.github-export-ignore +30 -0
  3. package/CONTRIBUTING.md +59 -0
  4. package/DEV.md +54 -0
  5. package/LICENSE +21 -0
  6. package/OPEN_SOURCE_CHECKPOINT.md +133 -0
  7. package/build-infos.json +1 -1
  8. package/concorde-core.bundle.js +66 -66
  9. package/concorde-core.es.js +1368 -1318
  10. package/dist/concorde-core.bundle.js +66 -66
  11. package/dist/concorde-core.es.js +1368 -1318
  12. package/docs/altcha-widget.js +2662 -0
  13. package/docs/assets/index-D8MVWqY6.js +12251 -0
  14. package/docs/assets/index-DiD0qYvE.css +1 -0
  15. package/docs/crawl/core/components/functional/date/date.html +190 -0
  16. package/docs/crawl/core/components/functional/fetch/fetch.html +109 -0
  17. package/docs/crawl/core/components/functional/if/if.html +27 -0
  18. package/docs/crawl/core/components/functional/jsonata/jsonata.html +79 -0
  19. package/docs/crawl/core/components/functional/list/list.html +70 -0
  20. package/docs/crawl/core/components/functional/mix/mix.html +45 -0
  21. package/docs/crawl/core/components/functional/queue/queue.html +96 -0
  22. package/docs/crawl/core/components/functional/router/router.html +106 -0
  23. package/docs/crawl/core/components/functional/sdui/sdui.html +269 -0
  24. package/docs/crawl/core/components/functional/states/states.html +66 -0
  25. package/docs/crawl/core/components/functional/submit/submit.html +160 -0
  26. package/docs/crawl/core/components/functional/subscriber/subscriber.html +67 -0
  27. package/docs/crawl/core/components/functional/value/value.html +51 -0
  28. package/docs/crawl/core/components/ui/alert/alert.html +110 -0
  29. package/docs/crawl/core/components/ui/alert-messages/alert-messages.html +23 -0
  30. package/docs/crawl/core/components/ui/badge/badge.html +119 -0
  31. package/docs/crawl/core/components/ui/button/button.html +149 -0
  32. package/docs/crawl/core/components/ui/captcha/captcha.html +30 -0
  33. package/docs/crawl/core/components/ui/card/card.html +99 -0
  34. package/docs/crawl/core/components/ui/divider/divider.html +58 -0
  35. package/docs/crawl/core/components/ui/form/checkbox/checkbox.html +73 -0
  36. package/docs/crawl/core/components/ui/form/fieldset/fieldset.html +135 -0
  37. package/docs/crawl/core/components/ui/form/form-actions/form-actions.html +79 -0
  38. package/docs/crawl/core/components/ui/form/form-layout/form-layout.html +62 -0
  39. package/docs/crawl/core/components/ui/form/input/input.html +109 -0
  40. package/docs/crawl/core/components/ui/form/input-autocomplete/input-autocomplete.html +38 -0
  41. package/docs/crawl/core/components/ui/form/radio/radio.html +56 -0
  42. package/docs/crawl/core/components/ui/form/select/select.html +73 -0
  43. package/docs/crawl/core/components/ui/form/switch/switch.html +56 -0
  44. package/docs/crawl/core/components/ui/form/textarea/textarea.html +59 -0
  45. package/docs/crawl/core/components/ui/group/group.html +82 -0
  46. package/docs/crawl/core/components/ui/icon/icon.html +133 -0
  47. package/docs/crawl/core/components/ui/image/image.html +110 -0
  48. package/docs/crawl/core/components/ui/link/link.html +42 -0
  49. package/docs/crawl/core/components/ui/loader/loader.html +50 -0
  50. package/docs/crawl/core/components/ui/menu/menu.html +322 -0
  51. package/docs/crawl/core/components/ui/modal/modal.html +117 -0
  52. package/docs/crawl/core/components/ui/pop/pop.html +102 -0
  53. package/docs/crawl/core/components/ui/progress/progress.html +58 -0
  54. package/docs/crawl/core/components/ui/table/table.html +413 -0
  55. package/docs/crawl/core/components/ui/toast/toast.html +122 -0
  56. package/docs/crawl/core/components/ui/tooltip/tooltip.html +79 -0
  57. package/docs/crawl/docs/_core-concept/dataFlow.html +177 -0
  58. package/docs/crawl/docs/_core-concept/overview.html +66 -0
  59. package/docs/crawl/docs/_core-concept/subscriber.html +75 -0
  60. package/docs/crawl/docs/_decorators/ancestor-attribute.html +116 -0
  61. package/docs/crawl/docs/_decorators/auto-subscribe.html +202 -0
  62. package/docs/crawl/docs/_decorators/bind.html +141 -0
  63. package/docs/crawl/docs/_decorators/get.html +149 -0
  64. package/docs/crawl/docs/_decorators/handle.html +165 -0
  65. package/docs/crawl/docs/_decorators/on-assign.html +355 -0
  66. package/docs/crawl/docs/_decorators/patch.html +78 -0
  67. package/docs/crawl/docs/_decorators/post.html +139 -0
  68. package/docs/crawl/docs/_decorators/publish.html +61 -0
  69. package/docs/crawl/docs/_decorators/put.html +78 -0
  70. package/docs/crawl/docs/_decorators/subscribe.html +109 -0
  71. package/docs/crawl/docs/_decorators/wait-for-ancestors.html +137 -0
  72. package/docs/crawl/docs/_directives/sub.html +93 -0
  73. package/docs/crawl/docs/_getting-started/ai-agents.html +173 -0
  74. package/docs/crawl/docs/_getting-started/concorde-manual-install.html +100 -0
  75. package/docs/crawl/docs/_getting-started/concorde-outside.html +58 -0
  76. package/docs/crawl/docs/_getting-started/create-a-component.html +111 -0
  77. package/docs/crawl/docs/_getting-started/my-first-component.html +189 -0
  78. package/docs/crawl/docs/_getting-started/my-first-subscriber.html +110 -0
  79. package/docs/crawl/docs/_getting-started/pubsub.html +62 -0
  80. package/docs/crawl/docs/_getting-started/start.html +76 -0
  81. package/docs/crawl/docs/_getting-started/theming.html +85 -0
  82. package/docs/crawl/docs/_misc/api-configuration.html +149 -0
  83. package/docs/crawl/docs/_misc/dataProviderKey.html +135 -0
  84. package/docs/crawl/docs/_misc/docs-mock-api.html +158 -0
  85. package/docs/crawl/docs/_misc/dynamic-path.html +180 -0
  86. package/docs/crawl/docs/_misc/endpoint.html +50 -0
  87. package/docs/crawl/docs/_misc/formelement-subscriber-removal.html +138 -0
  88. package/docs/crawl/docs/_misc/html-integration.html +48 -0
  89. package/docs/crawl/hubs/decorators.html +547 -0
  90. package/docs/crawl/hubs/form-components.html +359 -0
  91. package/docs/crawl/hubs/remote-data.html +452 -0
  92. package/docs/crawl/index.html +101 -0
  93. package/docs/css/docs.css +0 -0
  94. package/docs/docs-mock-api-sw.js +724 -0
  95. package/docs/docs-mock-api-sw.js.map +7 -0
  96. package/docs/fonts/ClashGrotesk-Bold.eot +0 -0
  97. package/docs/fonts/ClashGrotesk-Bold.ttf +0 -0
  98. package/docs/fonts/ClashGrotesk-Bold.woff +0 -0
  99. package/docs/fonts/ClashGrotesk-Bold.woff2 +0 -0
  100. package/docs/fonts/ClashGrotesk-Extralight.eot +0 -0
  101. package/docs/fonts/ClashGrotesk-Extralight.ttf +0 -0
  102. package/docs/fonts/ClashGrotesk-Extralight.woff +0 -0
  103. package/docs/fonts/ClashGrotesk-Extralight.woff2 +0 -0
  104. package/docs/fonts/ClashGrotesk-Light.eot +0 -0
  105. package/docs/fonts/ClashGrotesk-Light.ttf +0 -0
  106. package/docs/fonts/ClashGrotesk-Light.woff +0 -0
  107. package/docs/fonts/ClashGrotesk-Light.woff2 +0 -0
  108. package/docs/fonts/ClashGrotesk-Medium.eot +0 -0
  109. package/docs/fonts/ClashGrotesk-Medium.ttf +0 -0
  110. package/docs/fonts/ClashGrotesk-Medium.woff +0 -0
  111. package/docs/fonts/ClashGrotesk-Medium.woff2 +0 -0
  112. package/docs/fonts/ClashGrotesk-Regular.eot +0 -0
  113. package/docs/fonts/ClashGrotesk-Regular.ttf +0 -0
  114. package/docs/fonts/ClashGrotesk-Regular.woff +0 -0
  115. package/docs/fonts/ClashGrotesk-Regular.woff2 +0 -0
  116. package/docs/fonts/ClashGrotesk-Semibold.eot +0 -0
  117. package/docs/fonts/ClashGrotesk-Semibold.ttf +0 -0
  118. package/docs/fonts/ClashGrotesk-Semibold.woff +0 -0
  119. package/docs/fonts/ClashGrotesk-Semibold.woff2 +0 -0
  120. package/docs/fonts/ClashGrotesk-Variable.eot +0 -0
  121. package/docs/fonts/ClashGrotesk-Variable.ttf +0 -0
  122. package/docs/fonts/ClashGrotesk-Variable.woff +0 -0
  123. package/docs/fonts/ClashGrotesk-Variable.woff2 +0 -0
  124. package/docs/img/concorde-icon.svg +5 -0
  125. package/docs/img/concorde-logo.svg +1 -0
  126. package/docs/img/concorde.png +0 -0
  127. package/docs/img/concorde_def.png +0 -0
  128. package/docs/img/concorde_seuil.png.webp +0 -0
  129. package/docs/img/concorde_seuil_invert.png +0 -0
  130. package/docs/img/paul_metrand.jpg +0 -0
  131. package/docs/img/paul_metrand_xs.jpg +0 -0
  132. package/docs/index.html +93 -0
  133. package/docs/llms-full.txt +5761 -0
  134. package/docs/llms.txt +104 -0
  135. package/docs/robots.txt +16 -0
  136. package/docs/sitemap.xml +237 -0
  137. package/docs/src/core/components/functional/date/date.md +290 -0
  138. package/docs/src/core/components/functional/fetch/fetch.md +125 -0
  139. package/docs/src/core/components/functional/if/if.md +9 -0
  140. package/docs/src/core/components/functional/jsonata/jsonata.md +56 -0
  141. package/docs/src/core/components/functional/list/list.md +65 -0
  142. package/docs/src/core/components/functional/mix/mix.md +41 -0
  143. package/docs/src/core/components/functional/queue/queue.md +72 -0
  144. package/docs/src/core/components/functional/router/router.md +94 -0
  145. package/docs/src/core/components/functional/sdui/default-library.json +108 -0
  146. package/docs/src/core/components/functional/sdui/example.json +99 -0
  147. package/docs/src/core/components/functional/sdui/sdui.md +356 -0
  148. package/docs/src/core/components/functional/states/states.md +87 -0
  149. package/docs/src/core/components/functional/submit/submit.md +114 -0
  150. package/docs/src/core/components/functional/subscriber/subscriber.md +91 -0
  151. package/docs/src/core/components/functional/value/value.md +35 -0
  152. package/docs/src/core/components/ui/alert/alert.md +121 -0
  153. package/docs/src/core/components/ui/alert-messages/alert-messages.md +0 -0
  154. package/docs/src/core/components/ui/badge/badge.md +127 -0
  155. package/docs/src/core/components/ui/button/button.md +182 -0
  156. package/docs/src/core/components/ui/captcha/captcha.md +12 -0
  157. package/docs/src/core/components/ui/card/card.md +97 -0
  158. package/docs/src/core/components/ui/divider/divider.md +35 -0
  159. package/docs/src/core/components/ui/form/checkbox/checkbox.md +77 -0
  160. package/docs/src/core/components/ui/form/fieldset/fieldset.md +129 -0
  161. package/docs/src/core/components/ui/form/form-actions/form-actions.md +77 -0
  162. package/docs/src/core/components/ui/form/form-layout/form-layout.md +44 -0
  163. package/docs/src/core/components/ui/form/input/input.md +142 -0
  164. package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +29 -0
  165. package/docs/src/core/components/ui/form/radio/radio.md +57 -0
  166. package/docs/src/core/components/ui/form/select/select.md +71 -0
  167. package/docs/src/core/components/ui/form/switch/switch.md +57 -0
  168. package/docs/src/core/components/ui/form/textarea/textarea.md +65 -0
  169. package/docs/src/core/components/ui/group/group.md +75 -0
  170. package/docs/src/core/components/ui/icon/icon.md +125 -0
  171. package/docs/src/core/components/ui/icon/icons.json +1 -0
  172. package/docs/src/core/components/ui/image/image.md +107 -0
  173. package/docs/src/core/components/ui/link/link.md +43 -0
  174. package/docs/src/core/components/ui/loader/loader.md +55 -0
  175. package/docs/src/core/components/ui/menu/menu.md +329 -0
  176. package/docs/src/core/components/ui/modal/modal.md +119 -0
  177. package/docs/src/core/components/ui/pop/pop.md +96 -0
  178. package/docs/src/core/components/ui/progress/progress.md +63 -0
  179. package/docs/src/core/components/ui/table/table.md +455 -0
  180. package/docs/src/core/components/ui/toast/toast.md +166 -0
  181. package/docs/src/core/components/ui/tooltip/tooltip.md +82 -0
  182. package/docs/src/docs/_core-concept/dataFlow.md +88 -0
  183. package/docs/src/docs/_core-concept/overview.md +57 -0
  184. package/docs/src/docs/_core-concept/subscriber.md +75 -0
  185. package/docs/src/docs/_decorators/ancestor-attribute.md +127 -0
  186. package/docs/src/docs/_decorators/auto-subscribe.md +202 -0
  187. package/docs/src/docs/_decorators/bind.md +167 -0
  188. package/docs/src/docs/_decorators/get.md +162 -0
  189. package/docs/src/docs/_decorators/handle.md +175 -0
  190. package/docs/src/docs/_decorators/on-assign.md +390 -0
  191. package/docs/src/docs/_decorators/patch.md +70 -0
  192. package/docs/src/docs/_decorators/post.md +146 -0
  193. package/docs/src/docs/_decorators/publish.md +55 -0
  194. package/docs/src/docs/_decorators/put.md +70 -0
  195. package/docs/src/docs/_decorators/subscribe.md +100 -0
  196. package/docs/src/docs/_decorators/wait-for-ancestors.md +163 -0
  197. package/docs/src/docs/_directives/sub.md +91 -0
  198. package/docs/src/docs/_getting-started/ai-agents.md +76 -0
  199. package/docs/src/docs/_getting-started/concorde-manual-install.md +133 -0
  200. package/docs/src/docs/_getting-started/concorde-outside.md +33 -0
  201. package/docs/src/docs/_getting-started/create-a-component.md +139 -0
  202. package/docs/src/docs/_getting-started/my-first-component.md +236 -0
  203. package/docs/src/docs/_getting-started/my-first-subscriber.md +120 -0
  204. package/docs/src/docs/_getting-started/pubsub.md +37 -0
  205. package/docs/src/docs/_getting-started/start.md +47 -0
  206. package/docs/src/docs/_getting-started/theming.md +91 -0
  207. package/docs/src/docs/_misc/api-configuration.md +81 -0
  208. package/docs/src/docs/_misc/dataProviderKey.md +168 -0
  209. package/docs/src/docs/_misc/docs-mock-api.md +63 -0
  210. package/docs/src/docs/_misc/dynamic-path.md +71 -0
  211. package/docs/src/docs/_misc/endpoint.md +45 -0
  212. package/docs/src/docs/_misc/formelement-subscriber-removal.md +115 -0
  213. package/docs/src/docs/_misc/html-integration.md +15 -0
  214. package/docs/src/docs/search/docs-search.json +9507 -0
  215. package/docs/src/tag-list.json +1 -0
  216. package/docs/src/tsconfig-model.json +23 -0
  217. package/docs/src/tsconfig.declarations.json +22 -0
  218. package/docs/src/tsconfig.emit.json +23 -0
  219. package/docs/src/tsconfig.json +1182 -0
  220. package/docs/svg/regular/plane.svg +1 -0
  221. package/docs/svg/solid/plane.svg +1 -0
  222. package/gitlab/job_github_mirror.sh +39 -0
  223. package/gitlab/job_tests.sh +0 -0
  224. package/package.json +1 -1
  225. package/scripts/github-export.mjs +150 -0
  226. package/scripts/post-build-docs.js +0 -0
  227. package/scripts/post-build.mjs +0 -0
  228. package/src/core/components/functional/fetch/fetch.md +0 -0
  229. package/src/core/components/functional/if/if.md +0 -0
  230. package/src/core/components/functional/list/list.demo.ts +0 -0
  231. package/src/core/components/functional/list/list.md +0 -0
  232. package/src/core/components/functional/router/router.md +0 -0
  233. package/src/core/components/functional/router/router.ts +0 -0
  234. package/src/core/components/functional/sdui/sdui.md +0 -0
  235. package/src/core/components/functional/states/states.md +0 -0
  236. package/src/core/components/functional/submit/submit.md +0 -0
  237. package/src/core/components/functional/subscriber/subscriber.ts +0 -0
  238. package/src/core/components/ui/_css/size.ts +0 -0
  239. package/src/core/components/ui/captcha/altchaStyles.ts +0 -0
  240. package/src/core/components/ui/captcha/captcha.md +0 -0
  241. package/src/core/components/ui/form/radio/radio.md +0 -0
  242. package/src/core/components/ui/form/select/select.md +0 -0
  243. package/src/core/components/ui/form/switch/switch.md +0 -0
  244. package/src/core/components/ui/loader/loader.md +0 -0
  245. package/src/core/components/ui/menu/menu.md +0 -0
  246. package/src/core/components/ui/modal/modal.md +0 -0
  247. package/src/core/components/ui/table/table-caption.ts +0 -0
  248. package/src/core/components/ui/table/table.md +0 -0
  249. package/src/core/decorators/subscriber/ancestorAttribute.spec.ts +26 -0
  250. package/src/core/decorators/subscriber/ancestorAttribute.ts +3 -4
  251. package/src/core/mixins/Subscriber.ts +0 -0
  252. package/src/core/utils/AncestorAttributeObserver.ts +183 -70
  253. package/src/core/utils/DataBindObserver.ts +0 -0
  254. package/src/core/utils/Objects.ts +0 -0
  255. package/src/core/utils/route.ts +0 -0
  256. package/src/css.d.ts +19 -0
  257. package/src/docs/_core-concept/subscriber.md +0 -0
  258. package/src/docs/_decorators/ancestor-attribute.md +3 -2
  259. package/src/docs/_getting-started/my-first-subscriber.md +0 -0
  260. package/src/docs/_getting-started/pubsub.md +0 -0
  261. package/src/docs/_getting-started/start.md +0 -0
  262. package/src/docs/example/users.ts +0 -0
  263. package/src/docs/search/page.ts +0 -0
  264. package/src/tsconfig.declarations.json +22 -0
  265. package/src/tsconfig.emit.json +23 -0
  266. package/src/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,166 @@
1
+ # Toast
2
+
3
+ ## Utilisation de base
4
+
5
+ <sonic-code>
6
+ <template>
7
+ <sonic-button onclick="window.SonicToast.add({ text: 'Message de notification simple' })">
8
+ Afficher un toast
9
+ </sonic-button>
10
+ </template>
11
+ </sonic-code>
12
+
13
+ ## Statut
14
+
15
+ Les statuts disponibles sont : `success`, `error`, `warning`, `info` ou vide (par défaut).
16
+
17
+ <sonic-code>
18
+ <template>
19
+ <div class="flex flex-wrap gap-2">
20
+ <sonic-button onclick="window.SonicToast.add({ text: 'Message par défaut', status: '' })">
21
+ Default
22
+ </sonic-button>
23
+ <sonic-button onclick="window.SonicToast.add({ text: 'Opération réussie !', status: 'success' })">
24
+ Success
25
+ </sonic-button>
26
+ <sonic-button onclick="window.SonicToast.add({ text: 'Une erreur est survenue', status: 'error' })">
27
+ Error
28
+ </sonic-button>
29
+ <sonic-button onclick="window.SonicToast.add({ text: 'Attention à ce point', status: 'warning' })">
30
+ Warning
31
+ </sonic-button>
32
+ <sonic-button onclick="window.SonicToast.add({ text: 'Information importante', status: 'info' })">
33
+ Info
34
+ </sonic-button>
35
+ </div>
36
+ </template>
37
+ </sonic-code>
38
+
39
+ ## Avec titre
40
+
41
+ <sonic-code>
42
+ <template>
43
+ <div class="flex flex-wrap gap-2">
44
+ <sonic-button onclick="window.SonicToast.add({ title: 'Succès', text: 'Votre demande a été traitée avec succès.', status: 'success' })">
45
+ Toast avec titre
46
+ </sonic-button>
47
+ <sonic-button onclick="window.SonicToast.add({ title: 'Test', text: 'Une erreur est survenue lors du traitement.', status: 'error' })">
48
+ Toast d'erreur avec titre
49
+ </sonic-button>
50
+ </div>
51
+ </template>
52
+ </sonic-code>
53
+
54
+ ## Avec contenu HTML
55
+
56
+ Le contenu du toast peut contenir du HTML.
57
+
58
+ <sonic-code>
59
+ <template>
60
+ <sonic-button onclick="window.SonicToast.add({ text: 'Message avec <strong>HTML</strong> et un <a href=&quot;#&quot;>lien cliquable</a>', status: 'info' })">
61
+ Toast avec HTML
62
+ </sonic-button>
63
+ </template>
64
+ </sonic-code>
65
+
66
+
67
+ ## Persistance
68
+
69
+ Par défaut, les toasts disparaissent automatiquement. Avec `preserve: true`, le toast reste affiché jusqu'à ce qu'il soit fermé manuellement.
70
+
71
+ <sonic-code>
72
+ <template>
73
+ <sonic-button onclick="window.SonicToast.add({ text: 'Ce toast ne disparaîtra pas automatiquement', status: 'info', preserve: true })">
74
+ Toast persistant
75
+ </sonic-button>
76
+ </template>
77
+ </sonic-code>
78
+
79
+ ## Masquer définitivement
80
+
81
+ Avec `dismissForever: true` et un `id`, le toast peut être masqué définitivement. Une fois fermé, il ne réapparaîtra plus même après rechargement de la page.
82
+
83
+ <sonic-code>
84
+ <template>
85
+ <sonic-button onclick="window.SonicToast.add({ id: 'unique-toast-id', text: 'Ce toast peut être masqué définitivement', status: 'info', dismissForever: true })">
86
+ Toast avec dismiss forever
87
+ </sonic-button>
88
+ </template>
89
+ </sonic-code>
90
+
91
+ ## Fantôme
92
+
93
+ Avec `ghost: true`, le toast devient semi-transparent et non-interactif.
94
+
95
+ <sonic-code>
96
+ <template>
97
+ <sonic-button onclick="window.SonicToast.add({ text: 'Toast fantôme (semi-transparent)', status: 'info', ghost: true })">
98
+ Toast ghost
99
+ </sonic-button>
100
+ </template>
101
+ </sonic-code>
102
+
103
+
104
+ ## Méthodes de suppression
105
+
106
+ ### Tout supprimer
107
+
108
+ Supprime tous les toasts sauf ceux marqués comme `ghost`.
109
+
110
+ <sonic-code>
111
+ <template>
112
+ <div class="flex flex-wrap gap-2">
113
+ <sonic-button onclick="window.SonicToast.add({ text: 'Toast 1', status: 'info' })">Ajouter toast 1</sonic-button>
114
+ <sonic-button onclick="window.SonicToast.add({ text: 'Toast 2', status: 'success' })">Ajouter toast 2</sonic-button>
115
+ <sonic-button onclick="window.SonicToast.add({ text: 'Toast 3', status: 'warning' })">Ajouter toast 3</sonic-button>
116
+ <sonic-button onclick="window.SonicToast.removeAll()">Supprimer tous</sonic-button>
117
+ </div>
118
+ </template>
119
+ </sonic-code>
120
+
121
+ ### Supprimer par statut
122
+
123
+ Supprime tous les toasts d'un statut spécifique.
124
+
125
+ <sonic-code>
126
+ <template>
127
+ <div class="flex flex-wrap gap-2">
128
+ <sonic-button onclick="window.SonicToast.add({ text: 'Toast success', status: 'success' })">Success</sonic-button>
129
+ <sonic-button onclick="window.SonicToast.add({ text: 'Toast error', status: 'error' })">Error</sonic-button>
130
+ <sonic-button onclick="window.SonicToast.add({ text: 'Toast warning', status: 'warning' })">Warning</sonic-button>
131
+ <sonic-button onclick="window.SonicToast.removeItemsByStatus('success')">Supprimer success</sonic-button>
132
+ <sonic-button onclick="window.SonicToast.removeItemsByStatus('error')">Supprimer error</sonic-button>
133
+ </div>
134
+ </template>
135
+ </sonic-code>
136
+
137
+ ### Supprimer les éléments temporaires
138
+
139
+ Supprime tous les toasts qui ne sont pas marqués comme `preserve`.
140
+
141
+ <sonic-code>
142
+ <template>
143
+ <div class="flex flex-wrap gap-2">
144
+ <sonic-button onclick="window.SonicToast.add({ text: 'Toast temporaire', status: 'info' })">Temporaire</sonic-button>
145
+ <sonic-button onclick="window.SonicToast.add({ text: 'Toast persistant', status: 'success', preserve: true })">Persistant</sonic-button>
146
+ <sonic-button onclick="window.SonicToast.removeTemporaryItems()">Supprimer temporaires</sonic-button>
147
+ </div>
148
+ </template>
149
+ </sonic-code>
150
+
151
+ ## Exemple complet
152
+
153
+ <sonic-code>
154
+ <template>
155
+ <sonic-button onclick="window.SonicToast.add({
156
+ id: 'welcome-toast',
157
+ title: 'Bienvenue',
158
+ text: 'Bienvenue sur notre plateforme ! Vous pouvez commencer à explorer les fonctionnalités.',
159
+ status: 'success',
160
+ dismissForever: true
161
+ })">
162
+ Toast complet
163
+ </sonic-button>
164
+ </template>
165
+ </sonic-code>
166
+
@@ -0,0 +1,82 @@
1
+ # Tooltip
2
+
3
+ <sonic-code>
4
+ <template>
5
+ <sonic-tooltip label="Tada : Text appears">hover me</sonic-tooltip>
6
+ </template>
7
+ </sonic-code>
8
+
9
+ ## Placement
10
+
11
+ By default, tooltip is centered next to its content
12
+
13
+ <sonic-code>
14
+ <template>
15
+ <sonic-tooltip placement="top" label="Top text">
16
+ <sonic-button>Top</sonic-button>
17
+ </sonic-tooltip>
18
+ <sonic-tooltip placement="bottom" label="Bottom text">
19
+ <sonic-button>Bottom</sonic-button>
20
+ </sonic-tooltip>
21
+ <sonic-tooltip placement="right" label="Right text">
22
+ <sonic-button>Right</sonic-button>
23
+ </sonic-tooltip>
24
+ <sonic-tooltip placement="left" label="Left text">
25
+ <sonic-button>Left</sonic-button>
26
+ </sonic-tooltip>
27
+ </template>
28
+ </sonic-code>
29
+
30
+ ## More placement
31
+ <sonic-code>
32
+ <template>
33
+ <div class="flex gap-3 flex-wrap">
34
+ <sonic-tooltip placement="top-start" label="My tooltip">
35
+ <sonic-button class="size-40 bg-neutral-200 rounded-lg">Top start</sonic-button>
36
+ </sonic-tooltip>
37
+ <sonic-tooltip placement="top-end" label="My tooltip">
38
+ <sonic-button class="size-40 bg-neutral-200 rounded-lg">Top end</sonic-button>
39
+ </sonic-tooltip>
40
+ <sonic-tooltip placement="bottom-start" label="My tooltip">
41
+ <sonic-button class="size-40 bg-neutral-200 rounded-lg">Bottom start</sonic-button>
42
+ </sonic-tooltip>
43
+ <sonic-tooltip placement="bottom-end" label="My tooltip">
44
+ <sonic-button class="size-40 bg-neutral-200 rounded-lg">Bottom end</sonic-button>
45
+ </sonic-tooltip>
46
+ <sonic-tooltip placement="right-start" label="My tooltip">
47
+ <sonic-button class="size-40 bg-neutral-200 rounded-lg">Right start</sonic-button>
48
+ </sonic-tooltip>
49
+ <sonic-tooltip placement="right-end" label="My tooltip">
50
+ <sonic-button class="size-40 bg-neutral-200 rounded-lg">Right end</sonic-button>
51
+ </sonic-tooltip>
52
+ <sonic-tooltip placement="left-start" label="My tooltip">
53
+ <sonic-button class="size-40 bg-neutral-200 rounded-lg">Left start</sonic-button>
54
+ </sonic-tooltip>
55
+ <sonic-tooltip placement="left-end" label="My tooltip">
56
+ <sonic-button class="size-40 bg-neutral-200 rounded-lg">Left end</sonic-button>
57
+ </sonic-tooltip>
58
+ </div>
59
+ </template>
60
+ </sonic-code>
61
+
62
+
63
+ ## Focusable
64
+
65
+ <sonic-code>
66
+ <template>
67
+ <sonic-tooltip focusable label="The Concorde made its first transatlantic crossing on September 26, 1973">
68
+ <sonic-icon library="iconoir" name="chat-bubble-question"></sonic-icon> Focus or hover non interactive element
69
+ </sonic-tooltip>
70
+ </template>
71
+ </sonic-code>
72
+
73
+ ## Disabled
74
+
75
+ <sonic-code>
76
+ <template>
77
+ <sonic-tooltip disabled label="Disabled text">
78
+ <sonic-button>Tooltip disabled</sonic-button>
79
+ </sonic-tooltip>
80
+ </template>
81
+ </sonic-code>
82
+
@@ -0,0 +1,88 @@
1
+ # Data flow
2
+
3
+ Recommended patterns for new Concorde apps (Lit + TypeScript). Under the hood, data lives in a **DataProvider** store (legacy **Publisher** API: [Legacy: Sharing data](#docs/_getting-started/pubsub.md/pubsub)).
4
+
5
+ ## Quick map
6
+
7
+ | Need | Use |
8
+ |------|-----|
9
+ | Read/write in code | `get` / `set` / `dp` + `DataProviderKey` (static paths only) |
10
+ | Reactive Lit template | `sub(key)` or `@subscribe` |
11
+ | Read component state from store | `@subscribe` + `DataProviderKey<T, U>` + `@state` |
12
+ | Inherit ancestor attributes | `@ancestorAttribute` |
13
+ | Write from component state | `@publish` |
14
+ | React to assignments | `@handle` |
15
+ | HTTP GET | `@get` + `Endpoint`, or `sonic-list` / `sonic-queue` with `fetch` |
16
+ | HTTP POST (body from store) | `@post` + `Endpoint` + body `DataProviderKey` |
17
+ | HTTP PUT / PATCH (body from store) | `@put` / `@patch` — same model as `@post` |
18
+ | Forms | `formDataProvider` + `name` on fields (no Subscriber on form elements) |
19
+ | Derived / aggregate (JSONata) | `derive()` or `sonic-jsonata` — [Jsonata](#core/components/functional/jsonata/jsonata.md/jsonata) |
20
+ | Offline doc demos | `serviceURL="/docs-mock-api"` — [Local API demos](#docs/_misc/docs-mock-api.md/docs-mock-api) |
21
+
22
+ Skill: `concorde-get-set-dp` in the package `ai/` folder.
23
+
24
+ ## DataProviderKey
25
+
26
+ <sonic-code language="typescript">
27
+ <template>
28
+ import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
29
+ import { dp, get, set } from "@supersoniks/concorde/utils";
30
+
31
+ const cartKey = new DataProviderKey&lt;{ items: string[] }&gt;("cart");
32
+
33
+ set(cartKey, { items: [] });
34
+ dp(cartKey.items).set(["a", "b"]);
35
+ get(cartKey);
36
+ </template>
37
+ </sonic-code>
38
+
39
+ Dynamic paths (`users.${userId}`) → decorators or `sub()` — not `get("users.${id}")` in imperative code. Resolution rules: [Dynamic path placeholders](#docs/_misc/dynamic-path.md/dynamic-path).
40
+
41
+ [DataProviderKey](#docs/_misc/dataProviderKey.md/dataProviderKey)
42
+
43
+ ## Decorators
44
+
45
+ | Decorator | Role |
46
+ |-----------|------|
47
+ | `@subscribe` | Read-only property from store — [data configuration](#docs/_getting-started/my-first-component.md/my-first-component) (type + key + scope) |
48
+ | `@publish` | Push property writes to store |
49
+ | `@handle` | Method called on assignment |
50
+ | `@ancestorAttribute` | Copy ancestor HTML attribute onto property |
51
+ | `@get` | HTTP GET into `ApiResult&lt;T&gt;` |
52
+ | `@post` | HTTP POST into `ApiResult&lt;T&gt;` (body from a publisher) |
53
+ | `@put` / `@patch` | HTTP PUT / PATCH into `ApiResult&lt;T&gt;` |
54
+
55
+ Walkthrough: [My first component](#docs/_getting-started/my-first-component.md/my-first-component)
56
+
57
+ ## HTTP and lists
58
+
59
+ - [@get](#docs/_decorators/get.md/get) — single GET on a component
60
+ - [@post](#docs/_decorators/post.md/post) — POST with body read from a `DataProviderKey`
61
+ - [@put](#docs/_decorators/put.md/put) · [@patch](#docs/_decorators/patch.md/patch) — PUT / PATCH (same options as `@post`)
62
+ - [List](#core/components/functional/list/list.md/list) — `fetch` + `key="data"` + `/docs-mock-api/api/users`
63
+ - [Queue](#core/components/functional/queue/queue.md/queue) — lazy `offset=$offset&per_page=$limit` + optional `dataFilterProvider` (form → query)
64
+
65
+ ## Starter kit
66
+
67
+ ```bash
68
+ npx @supersoniks/create-concorde-ts-starter my-app
69
+ ```
70
+
71
+ Interactive routes mirror these patterns (`/concepts/*`, `/demo/*`).
72
+
73
+ ## Derived data (`derive` / `sonic-jsonata`)
74
+
75
+ Use when you need **client-side aggregations** (groupby, top N, chart shapes) from existing DataProviders — without inline app JS in SDUI.
76
+
77
+ - Primitive: `derive({ inputs, compute, output, variables? })` from `@supersoniks/concorde/utils` (read-only output, debounce, generation, cycle detection, `{output}/_state_`).
78
+ - SDUI adapter: [`sonic-jsonata`](#core/components/functional/jsonata/jsonata.md/jsonata) (`inputProvider` → `expression` → `outputProvider`, optional `formDataProvider`).
79
+ - vs [`sonic-mix`](#core/components/functional/mix/mix.md/mix): mix composes bidirectionally; jsonata **computes** unidirectionally.
80
+
81
+ ## Legacy integration
82
+
83
+ | Topic | Page |
84
+ |-------|------|
85
+ | `Subscriber` / `Fetcher` mixins on app code | [Legacy: Subscriber mixin](#docs/_core-concept/subscriber.md/subscriber), [Legacy: My first subscriber](#docs/_getting-started/my-first-subscriber.md/my-first-subscriber) |
86
+ | `data-bind` HTML (plain HTML hosts) | [HTML integration](#docs/_misc/html-integration.md/html-integration) — doc demos use Lit in `src/docs/example/` |
87
+ | `@onAssign` | [@onAssign](#docs/_decorators/on-assign.md/on-assign) (prefer `@handle`) |
88
+ | `sonic-fetch` alone | [Fetch](#core/components/functional/fetch/fetch.md/fetch) |
@@ -0,0 +1,57 @@
1
+ # lit + tailwind + vite
2
+
3
+ **Some notes for an overview of Concorde's functioning**
4
+
5
+ ## Standard Web components
6
+ A web component is simply a **custom HTML element** created using web standards:
7
+
8
+ **web component** = [Custom Elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) + [shadowDom](https://developer.mozilla.org/fr/docs/Web/Web_Components/Using_shadow_DOM) + [HTML templates](https://developer.mozilla.org/fr/docs/Web/HTML/Element/template)
9
+
10
+ ## Lit Library
11
+
12
+ Concorde components are written using the lightweight Lit library: https://lit.dev/.
13
+
14
+ A good portion of the elements documented on the Lit website are standard JavaScript concepts (e.g., [mixins](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#mix-ins), [tagged template literals](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Template_literals#gabarits_%C3%A9tiquet%C3%A9s)).
15
+
16
+ The **library simplifies the writing of web components** by automating certain tasks:
17
+
18
+ - Creation of an **open mode shadow DOM** (the component is accessible from the outside via its shadow root property).
19
+ - [Rendering function](https://lit.dev/docs/components/rendering/) based on [tagged template literals](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Template_literals#gabarits_%C3%A9tiquet%C3%A9s)
20
+ - [Reactive properties](https://lit.dev/docs/components/properties/) that trigger rendering when modified.
21
+
22
+ Our use of Lit rarely goes beyond this [hello world](https://lit.dev/playground/#sample=examples/hello-world)
23
+
24
+ ## Typescript Language
25
+
26
+ We write the components in [TypeScript](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html), which is then compiled into JS.
27
+
28
+ Static and inferred typing provides stronger validation of the program's functioning during compilation.
29
+ However, we often use the "any" type due to time constraints.
30
+
31
+ Lit uses TypeScript to simplify development through metadata:
32
+ - Simplified declaration of `custom elements` via @customElement
33
+ - Generation of `reactive properties` via @property.
34
+
35
+ ☢️**Warning**:
36
+ - During development, we operate in interpreted mode, which is faster but allows errors that won't pass during the build.
37
+ - It is important to **build a distribution before pushing the code** to ensure everything is fine.
38
+
39
+ ## Compatibility with Classic JS Libraries
40
+
41
+ Compatibility issues may arise when using JS libraries, particularly regarding DOM traversal.
42
+ This is because these libraries are blocked from traversing the DOM due to the presence of the shadow DOM.
43
+ Here are some examples of things that may cause problems:
44
+
45
+ - Latest FontAwesome in SVG mode, icons are not replaced
46
+ - Libraries associated with jQuery
47
+ - document.getElementById
48
+ - ...
49
+
50
+ ## Topics to Explore for Further Learning
51
+
52
+
53
+ [🧱 Creating components](#docs/_getting-started/create-a-component.md/create-a-component)
54
+
55
+ [🎨 Adding styles](#docs/_getting-started/theming.md/theming)
56
+
57
+ [🥨 Sharing data](#docs/_getting-started/pubsub.md/pubsub)
@@ -0,0 +1,75 @@
1
+ # Legacy: Subscriber mixin
2
+
3
+ > **New app components:** [My first component](#docs/_getting-started/my-first-component.md/my-first-component) and [Data flow](#docs/_core-concept/dataFlow.md/dataFlow) — extend `LitElement` with decorators (`@subscribe`, `@ancestorAttribute`, …). This mixin remains in **core** components (`sonic-list`, `sonic-fetch`, …) and [legacy tutorials](#docs/_getting-started/my-first-subscriber.md/my-first-subscriber).
4
+
5
+ The Subscriber mixin was commonly extended by Concorde core components and older destination components. Pure UI components usually don't extend it, especially those outside of form components.
6
+
7
+ ## DataProvider Attribute: Automatic Filling of Subscriber Properties
8
+
9
+ Upon being added to the DOM (connectedCallback), subscribers search for the first occurrence of the `dataProvider` attribute in their parent's HTML structure.
10
+
11
+ The value of this attribute is the DataProvider path (see [Data flow](#docs/_core-concept/dataFlow.md/dataFlow) and [DataProviderKey](#docs/_misc/dataProviderKey.md/dataProviderKey); legacy API: [Sharing Data](#docs/_getting-started/pubsub.md/pubsub)).
12
+
13
+ The subscriber then subscribes to the publisher as a data template to be filled.
14
+
15
+ The reactive properties of the component reflect in real-time the properties with the same name in the publisher.
16
+
17
+ This functionality is commonly used in the generic components [fetch](#core/components/functional/fetch/fetch.md/fetch), [queue](#core/components/functional/queue/queue.md/queue), and [list](#core/components/functional/list/list.md/list).
18
+
19
+ If the subscriber is inside another subscriber, it can subscribe to a data of its parent using the attribute `subDataProvider = 'address.of.my.data'` instead of the parent's data. This allows for dynamic behavior.
20
+
21
+ ## Automated Translation
22
+
23
+ In a similar manner, searching for ancestor attributes can be used to configure automatic translation for any property starting with "wording" and ending with a label identifier recognized by the wordingProvider API.
24
+
25
+ Normally, this API is globally configured and not within the component. Therefore, remember to prefix translatable label identifiers present in the ticketing system, for example, with "wording".
26
+
27
+ ## Reactive Property `props`
28
+
29
+ The value of this property can be provided as a JSON object or any other value. This value is then assigned to the associated publisher via the `dataProvider` attribute. As a result, the reactive properties of all subscribers associated with the same `dataProvider` are filled as mentioned above.
30
+
31
+ ## Disabling Automatic Filling of Reactive Properties
32
+
33
+ It is possible to disable the automatic filling of reactive properties in a particular component. To do so, set the variable `noAutoFill = true` in the component's class. However, the reactive property `props` will still be updated.
34
+
35
+ For example, `sonic-subscriber` and `sonic-fetch` have this attribute because they do not have reactive properties.
36
+
37
+ **☢ CAUTION:** When creating an object of type Subscriber or Fetcher, make sure to use the mixins and not directly extend the concrete fetch component (`sonic-fetch`) and subscriber component (`sonic-subscriber`). This is because the `noAutofill = true` attribute is set in those components.
38
+
39
+ **TIPS:**
40
+ If you disable automatic filling, you will likely make the rendering dynamic by writing expressions like `this.props.my.subproperty`. If `props` is updated, the rendering will be triggered. However, if `this.props.my.subproperty` is directly modified, the rendering will not be triggered. To achieve more reactivity, you can enable rendering when any subproperty is modified. Simply set the variable `renderOnPropsInternalChange = true` in the class that implements the corresponding mixin.
41
+
42
+ ## Data Binding
43
+
44
+ Suppose that:
45
+
46
+ - You have a subscriber subscribed to a publisher via its `dataProvider` attribute.
47
+ - The published data has the following structure:
48
+
49
+ <sonic-code language="javascript">
50
+ <template>
51
+ {"img": { "avatar": "my-avatar.jpg", "caption": "look at my smile" }, "email": "an.email@example.com" }
52
+ </template>
53
+ </sonic-code>
54
+ - We want to keep the display of an image and its `title` attribute up to date, as well as a "contact" button to email the person in the photo. The content of the subscriber could be as follows:
55
+
56
+ In a **Lit** app, use the same data with [data configuration](#docs/_getting-started/my-first-component.md/my-first-component) (`@subscribe` + `DataProviderKey`) on a small row component — see `docs-user` in `src/docs/example/users.ts`.
57
+
58
+ For **HTML-only** embedding (no Lit), attribute binding is described in [HTML integration](#docs/_misc/html-integration.md/html-integration) and in the Legacy [Subscriber mixin](#docs/_core-concept/subscriber.md/subscriber) pages.
59
+
60
+ This pattern also illustrates:
61
+
62
+ - Binding to subproperties using dot syntax, as done for the `src` attribute of the `img` tag.
63
+ - Using a simple expression to include the property within a string, as in creating a `mailto` link.
64
+ - Using formatting functions, as in the `title` attribute of the `img` tag. You can find (and add) formatting functions in the `core/utils/Format.ts` file.
65
+ - Writing for properties that are in camel case. Convert everything to lowercase and add hyphens. Note that `innerHTML` (or `outerHTML`) is a special case where no hyphens are added between each letter.
66
+
67
+ **Note:** Data binding implies that updating the `img.src` data via the publisher will change the photo without any additional calls.
68
+
69
+ **Special Variables:**
70
+ - `_self_` targets the root of the data. This is useful, for example, when the data is a pure string.
71
+ - `_parent_` targets the parent publisher of the current publisher, if any. For example, the subscribers of lists have the complete data of the list as their parent.
72
+ - `_metadata_` is only used in the case of *sonic-list* at the moment. In a simple list, `_metadata_` see the (list)[] component for further details
73
+
74
+ **Disabling this functionality:**
75
+ You can disable data binding if it is not needed by calling `DataBinding.disable()`.
@@ -0,0 +1,127 @@
1
+ # @ancestorAttribute
2
+
3
+ The `@ancestorAttribute` decorator automatically injects the value of an ancestor's attribute into a class property at the time of `connectedCallback`.
4
+
5
+ ## Principle
6
+
7
+ This decorator uses `HTML.getAncestorAttributeValue` to traverse up the DOM tree from the current element and find the first ancestor that has the specified attribute. The value of this attribute is then assigned to the decorated property.
8
+
9
+ ## Usage
10
+
11
+ ### Import
12
+
13
+ <sonic-code language="typescript">
14
+ <template>
15
+ import { ancestorAttribute } from "@supersoniks/concorde/decorators";
16
+ </template>
17
+ </sonic-code>
18
+
19
+ ### Basic example
20
+
21
+ The component reads `dataProvider` and `testAttribute` from its ancestor wrapper. By default (`dynamic: false`), values are read once at connect.
22
+
23
+ <sonic-code language="typescript">
24
+ <template>
25
+ import { html, LitElement } from "lit";
26
+ import { customElement } from "lit/decorators.js";
27
+ import { ancestorAttribute } from "@supersoniks/concorde/decorators";
28
+
29
+ @customElement("demo-ancestor-attribute")
30
+ export class DemoAncestorAttribute extends LitElement {
31
+ @ancestorAttribute("dataProvider")
32
+ dataProvider: string | null = null;
33
+
34
+ @ancestorAttribute("testAttribute")
35
+ testAttribute: string | null = null;
36
+
37
+ render() {
38
+ return html`
39
+ <p>dataProvider: <strong>${this.dataProvider ?? "null"}</strong></p>
40
+ <p>testAttribute: <strong>${this.testAttribute ?? "null"}</strong></p>
41
+ `;
42
+ }
43
+ }
44
+ </template>
45
+ </sonic-code>
46
+
47
+ <sonic-code>
48
+ <template>
49
+ <div dataProvider="demoDataProvider" testAttribute="test-value-123">
50
+ <docs-demo-sources for="demo-ancestor-attribute"></docs-demo-sources>
51
+ <demo-ancestor-attribute></demo-ancestor-attribute>
52
+ </div>
53
+ </template>
54
+ </sonic-code>
55
+
56
+ ## Use cases
57
+
58
+ This decorator is particularly useful for:
59
+
60
+ - **Retrieving the `dataProvider`** from an ancestor without having to pass it explicitly
61
+ - **Retrieving the `formDataProvider`** in form components
62
+ - **Retrieving the `wordingProvider`** for translation
63
+ - **Retrieving any other attribute** defined on an ancestor
64
+
65
+ ## Behavior
66
+
67
+ - The search starts from the current element and traverses up the DOM tree
68
+ - The injection happens automatically at the time of `connectedCallback`
69
+ - By default (`dynamic: false`), the value is read once at connect time and is not updated afterward
70
+ - With `{ dynamic: true }`, the property stays in sync when:
71
+ - an ancestor **changes** the attribute value
72
+ - a **closer** ancestor **gains** the attribute (that value wins)
73
+ - the **nearest** ancestor **loses** the attribute (falls back to the next one up, or `null`)
74
+ - When `dynamic` is enabled, updates also propagate to `@subscribe` / `@bind` paths that depend on the decorated property (e.g. `${dataProvider}`)
75
+
76
+ ### Dynamic mode
77
+
78
+ Use `{ dynamic: true }` when the decorated property must follow the DOM. With Lit, add **`@state()`** on the same property so template updates are visible when the observer assigns a new value.
79
+
80
+ The live demo below shows only the resolved attribute value — no store, no reparenting.
81
+
82
+ <sonic-code language="typescript">
83
+ <template>
84
+ @customElement("demo-ancestor-attribute-dynamic")
85
+ export class DemoAncestorAttributeDynamic extends LitElement {
86
+ @ancestorAttribute("dataProvider", { dynamic: true })
87
+ @state()
88
+ dataProvider: string | null = null;
89
+
90
+ render() {
91
+ return html`
92
+ &lt;p&gt;Nearest ancestor: &lt;strong&gt;${this.dataProvider ?? "null"}&lt;/strong&gt;&lt;/p&gt;
93
+ `;
94
+ }
95
+ }
96
+ </template>
97
+ </sonic-code>
98
+
99
+ Try in the demo:
100
+
101
+ - **parent-a** / **parent-b** — change the value on the direct parent
102
+ - **Remove parent attr** — falls back to **outer**
103
+ - **Add closer** — a wrapper with `from-closer` becomes the nearest ancestor
104
+ - **Remove closer** — back to parent or outer
105
+ - **Remove outer attr** — if parent has no attribute either, the child shows `null`
106
+
107
+ <sonic-code>
108
+ <template>
109
+ <docs-demo-sources for="demo-ancestor-attribute-dynamic-section"></docs-demo-sources>
110
+ <demo-ancestor-attribute-dynamic-section></demo-ancestor-attribute-dynamic-section>
111
+ </template>
112
+ </sonic-code>
113
+
114
+ Static mode (default) — read once at connect, no observer:
115
+
116
+ <sonic-code language="typescript">
117
+ <template>
118
+ @ancestorAttribute("dataProvider")
119
+ dataProvider: string | null = null;
120
+ </template>
121
+ </sonic-code>
122
+
123
+ ## Notes
124
+
125
+ - This decorator works with any component that has a `connectedCallback` method (such as `LitElement` or components extending `Subscriber`)
126
+ - The search also traverses Shadow DOM if necessary
127
+ - If multiple ancestors have the attribute, the closest one will be used