@supersoniks/concorde 5.0.0 → 5.0.2

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 (314) hide show
  1. package/.gitlab-ci.yml +0 -13
  2. package/build-infos.json +1 -1
  3. package/concorde-core.bundle.js +606 -689
  4. package/concorde-core.es.js +4511 -4329
  5. package/dist/concorde-core.bundle.js +606 -689
  6. package/dist/concorde-core.es.js +4511 -4329
  7. package/gitlab/job_tests.sh +25 -12
  8. package/index.html +3 -3
  9. package/package.json +16 -1
  10. package/scripts/post-build-docs.js +0 -0
  11. package/scripts/post-build.mjs +0 -0
  12. package/src/core/components/functional/fetch/fetch.md +0 -0
  13. package/src/core/components/functional/if/if.md +0 -0
  14. package/src/core/components/functional/list/list.demo.ts +0 -0
  15. package/src/core/components/functional/list/list.md +0 -0
  16. package/src/core/components/functional/list/list.ts +0 -0
  17. package/src/core/components/functional/router/router.md +0 -0
  18. package/src/core/components/functional/router/router.ts +0 -0
  19. package/src/core/components/functional/sdui/sdui.md +0 -0
  20. package/src/core/components/functional/states/states.md +0 -0
  21. package/src/core/components/functional/submit/submit.md +0 -0
  22. package/src/core/components/ui/_css/rounded.ts +36 -0
  23. package/src/core/components/ui/_css/size.ts +0 -0
  24. package/src/core/components/ui/_css/type.ts +49 -0
  25. package/src/core/components/ui/_i18n/ui-aria-labels.ts +104 -0
  26. package/src/core/components/ui/alert/alert.md +128 -72
  27. package/src/core/components/ui/alert/alert.spec.ts +145 -0
  28. package/src/core/components/ui/alert/alert.ts +86 -91
  29. package/src/core/components/ui/alert-messages/alert-messages.ts +1 -1
  30. package/src/core/components/ui/badge/badge.md +126 -78
  31. package/src/core/components/ui/badge/badge.ts +29 -81
  32. package/src/core/components/ui/button/button.md +1 -0
  33. package/src/core/components/ui/button/button.ts +11 -8
  34. package/src/core/components/ui/captcha/altchaStyles.ts +0 -0
  35. package/src/core/components/ui/captcha/captcha.md +0 -0
  36. package/src/core/components/ui/card/card-header.ts +7 -2
  37. package/src/core/components/ui/card/card.md +120 -65
  38. package/src/core/components/ui/divider/divider.ts +4 -9
  39. package/src/core/components/ui/form/fieldset/legend-description.ts +1 -1
  40. package/src/core/components/ui/form/fieldset/legend.ts +1 -1
  41. package/src/core/components/ui/form/input/input.md +1 -1
  42. package/src/core/components/ui/form/input/input.ts +19 -15
  43. package/src/core/components/ui/form/radio/radio.md +0 -0
  44. package/src/core/components/ui/form/select/select.md +0 -0
  45. package/src/core/components/ui/form/switch/switch.md +0 -0
  46. package/src/core/components/ui/form/textarea/textarea.md +1 -1
  47. package/src/core/components/ui/image/image.md +147 -53
  48. package/src/core/components/ui/image/image.ts +10 -44
  49. package/src/core/components/ui/link/link.md +2 -2
  50. package/src/core/components/ui/link/link.ts +42 -37
  51. package/src/core/components/ui/loader/loader.md +0 -0
  52. package/src/core/components/ui/menu/menu.md +0 -0
  53. package/src/core/components/ui/modal/modal-close.ts +8 -12
  54. package/src/core/components/ui/modal/modal.md +0 -0
  55. package/src/core/components/ui/modal/modal.ts +18 -18
  56. package/src/core/components/ui/pop/pop.md +105 -1
  57. package/src/core/components/ui/pop/pop.ts +143 -148
  58. package/src/core/components/ui/table/table-caption.ts +0 -0
  59. package/src/core/components/ui/table/table.md +0 -0
  60. package/src/core/components/ui/table/table.ts +2 -8
  61. package/src/core/components/ui/theme/theme.ts +1 -1
  62. package/src/core/components/ui/toast/dismissed.ts +14 -0
  63. package/src/core/components/ui/toast/toast-item.ts +139 -91
  64. package/src/core/components/ui/toast/toast.ts +4 -7
  65. package/src/core/components/ui/tooltip/tooltip.ts +176 -154
  66. package/src/core/utils/LocationHandler.ts +12 -5
  67. package/src/core/utils/dismissed.ts +22 -0
  68. package/src/core/utils/positioning.spec.ts +208 -0
  69. package/src/core/utils/positioning.ts +183 -0
  70. package/src/core/utils/route.ts +0 -0
  71. package/src/directives.ts +2 -3
  72. package/src/docs/_core-concept/subscriber.md +0 -0
  73. package/src/docs/_getting-started/concorde-outside.md +3 -3
  74. package/src/docs/_getting-started/my-first-subscriber.md +0 -0
  75. package/src/docs/_getting-started/pubsub.md +0 -0
  76. package/src/docs/_getting-started/start.md +0 -0
  77. package/src/docs/code.ts +3 -1
  78. package/src/docs/example/users.ts +0 -0
  79. package/src/docs/search/docs-search.json +651 -21
  80. package/src/docs/search/page.ts +0 -0
  81. package/src/docs/tailwind/css/tailwind.css +13 -6
  82. package/src/tsconfig.json +45 -0
  83. package/src/tsconfig.tsbuildinfo +1 -1
  84. package/tailwind.config.js +50 -3
  85. package/vitest.setup.ts +49 -13
  86. package/.github/workflows/ci.yml +0 -21
  87. package/.github-export-ignore +0 -30
  88. package/CONTRIBUTING.md +0 -59
  89. package/DEV.md +0 -54
  90. package/LICENSE +0 -21
  91. package/OPEN_SOURCE_CHECKPOINT.md +0 -133
  92. package/concorde-3d.bundle.js +0 -3960
  93. package/concorde-3d.es.js +0 -33433
  94. package/concorde-hugging-face-infer.bundle.js +0 -32
  95. package/concorde-hugging-face-infer.es.js +0 -2952
  96. package/concorde-shader.bundle.js +0 -116
  97. package/concorde-shader.es.js +0 -8353
  98. package/concorde-webgpu.bundle.js +0 -307
  99. package/concorde-webgpu.es.js +0 -8627
  100. package/docs/altcha-widget.js +0 -2662
  101. package/docs/assets/index-BZiZXMU-.css +0 -1
  102. package/docs/assets/index-FmK4JaIM.js +0 -11992
  103. package/docs/crawl/core/components/functional/date/date.html +0 -190
  104. package/docs/crawl/core/components/functional/fetch/fetch.html +0 -109
  105. package/docs/crawl/core/components/functional/if/if.html +0 -27
  106. package/docs/crawl/core/components/functional/jsonata/jsonata.html +0 -79
  107. package/docs/crawl/core/components/functional/list/list.html +0 -70
  108. package/docs/crawl/core/components/functional/mix/mix.html +0 -45
  109. package/docs/crawl/core/components/functional/queue/queue.html +0 -96
  110. package/docs/crawl/core/components/functional/router/router.html +0 -106
  111. package/docs/crawl/core/components/functional/sdui/sdui.html +0 -269
  112. package/docs/crawl/core/components/functional/states/states.html +0 -66
  113. package/docs/crawl/core/components/functional/submit/submit.html +0 -160
  114. package/docs/crawl/core/components/functional/subscriber/subscriber.html +0 -67
  115. package/docs/crawl/core/components/functional/value/value.html +0 -51
  116. package/docs/crawl/core/components/ui/alert/alert.html +0 -110
  117. package/docs/crawl/core/components/ui/alert-messages/alert-messages.html +0 -23
  118. package/docs/crawl/core/components/ui/badge/badge.html +0 -119
  119. package/docs/crawl/core/components/ui/button/button.html +0 -149
  120. package/docs/crawl/core/components/ui/captcha/captcha.html +0 -30
  121. package/docs/crawl/core/components/ui/card/card.html +0 -99
  122. package/docs/crawl/core/components/ui/divider/divider.html +0 -58
  123. package/docs/crawl/core/components/ui/form/checkbox/checkbox.html +0 -73
  124. package/docs/crawl/core/components/ui/form/fieldset/fieldset.html +0 -135
  125. package/docs/crawl/core/components/ui/form/form-actions/form-actions.html +0 -79
  126. package/docs/crawl/core/components/ui/form/form-layout/form-layout.html +0 -62
  127. package/docs/crawl/core/components/ui/form/input/input.html +0 -109
  128. package/docs/crawl/core/components/ui/form/input-autocomplete/input-autocomplete.html +0 -106
  129. package/docs/crawl/core/components/ui/form/radio/radio.html +0 -56
  130. package/docs/crawl/core/components/ui/form/select/select.html +0 -73
  131. package/docs/crawl/core/components/ui/form/switch/switch.html +0 -56
  132. package/docs/crawl/core/components/ui/form/textarea/textarea.html +0 -59
  133. package/docs/crawl/core/components/ui/group/group.html +0 -82
  134. package/docs/crawl/core/components/ui/icon/icon.html +0 -133
  135. package/docs/crawl/core/components/ui/image/image.html +0 -110
  136. package/docs/crawl/core/components/ui/link/link.html +0 -42
  137. package/docs/crawl/core/components/ui/loader/loader.html +0 -50
  138. package/docs/crawl/core/components/ui/menu/menu.html +0 -322
  139. package/docs/crawl/core/components/ui/modal/modal.html +0 -117
  140. package/docs/crawl/core/components/ui/pop/pop.html +0 -102
  141. package/docs/crawl/core/components/ui/progress/progress.html +0 -58
  142. package/docs/crawl/core/components/ui/table/table.html +0 -413
  143. package/docs/crawl/core/components/ui/toast/toast.html +0 -122
  144. package/docs/crawl/core/components/ui/tooltip/tooltip.html +0 -79
  145. package/docs/crawl/docs/_core-concept/dataFlow.html +0 -177
  146. package/docs/crawl/docs/_core-concept/overview.html +0 -66
  147. package/docs/crawl/docs/_core-concept/subscriber.html +0 -75
  148. package/docs/crawl/docs/_decorators/ancestor-attribute.html +0 -116
  149. package/docs/crawl/docs/_decorators/auto-subscribe.html +0 -202
  150. package/docs/crawl/docs/_decorators/bind.html +0 -141
  151. package/docs/crawl/docs/_decorators/get.html +0 -149
  152. package/docs/crawl/docs/_decorators/handle.html +0 -165
  153. package/docs/crawl/docs/_decorators/on-assign.html +0 -355
  154. package/docs/crawl/docs/_decorators/patch.html +0 -78
  155. package/docs/crawl/docs/_decorators/post.html +0 -139
  156. package/docs/crawl/docs/_decorators/publish.html +0 -61
  157. package/docs/crawl/docs/_decorators/put.html +0 -78
  158. package/docs/crawl/docs/_decorators/subscribe.html +0 -109
  159. package/docs/crawl/docs/_decorators/wait-for-ancestors.html +0 -137
  160. package/docs/crawl/docs/_directives/sub.html +0 -93
  161. package/docs/crawl/docs/_getting-started/ai-agents.html +0 -173
  162. package/docs/crawl/docs/_getting-started/concorde-manual-install.html +0 -100
  163. package/docs/crawl/docs/_getting-started/concorde-outside.html +0 -58
  164. package/docs/crawl/docs/_getting-started/create-a-component.html +0 -111
  165. package/docs/crawl/docs/_getting-started/my-first-component.html +0 -189
  166. package/docs/crawl/docs/_getting-started/my-first-subscriber.html +0 -110
  167. package/docs/crawl/docs/_getting-started/pubsub.html +0 -62
  168. package/docs/crawl/docs/_getting-started/start.html +0 -76
  169. package/docs/crawl/docs/_getting-started/theming.html +0 -85
  170. package/docs/crawl/docs/_misc/api-configuration.html +0 -149
  171. package/docs/crawl/docs/_misc/dataProviderKey.html +0 -135
  172. package/docs/crawl/docs/_misc/docs-mock-api.html +0 -158
  173. package/docs/crawl/docs/_misc/dynamic-path.html +0 -180
  174. package/docs/crawl/docs/_misc/endpoint.html +0 -50
  175. package/docs/crawl/docs/_misc/formelement-subscriber-removal.html +0 -138
  176. package/docs/crawl/docs/_misc/html-integration.html +0 -48
  177. package/docs/crawl/hubs/decorators.html +0 -547
  178. package/docs/crawl/hubs/form-components.html +0 -357
  179. package/docs/crawl/hubs/remote-data.html +0 -452
  180. package/docs/crawl/index.html +0 -101
  181. package/docs/css/docs.css +0 -0
  182. package/docs/docs-mock-api-sw.js +0 -720
  183. package/docs/docs-mock-api-sw.js.map +0 -7
  184. package/docs/fonts/ClashGrotesk-Bold.eot +0 -0
  185. package/docs/fonts/ClashGrotesk-Bold.ttf +0 -0
  186. package/docs/fonts/ClashGrotesk-Bold.woff +0 -0
  187. package/docs/fonts/ClashGrotesk-Bold.woff2 +0 -0
  188. package/docs/fonts/ClashGrotesk-Extralight.eot +0 -0
  189. package/docs/fonts/ClashGrotesk-Extralight.ttf +0 -0
  190. package/docs/fonts/ClashGrotesk-Extralight.woff +0 -0
  191. package/docs/fonts/ClashGrotesk-Extralight.woff2 +0 -0
  192. package/docs/fonts/ClashGrotesk-Light.eot +0 -0
  193. package/docs/fonts/ClashGrotesk-Light.ttf +0 -0
  194. package/docs/fonts/ClashGrotesk-Light.woff +0 -0
  195. package/docs/fonts/ClashGrotesk-Light.woff2 +0 -0
  196. package/docs/fonts/ClashGrotesk-Medium.eot +0 -0
  197. package/docs/fonts/ClashGrotesk-Medium.ttf +0 -0
  198. package/docs/fonts/ClashGrotesk-Medium.woff +0 -0
  199. package/docs/fonts/ClashGrotesk-Medium.woff2 +0 -0
  200. package/docs/fonts/ClashGrotesk-Regular.eot +0 -0
  201. package/docs/fonts/ClashGrotesk-Regular.ttf +0 -0
  202. package/docs/fonts/ClashGrotesk-Regular.woff +0 -0
  203. package/docs/fonts/ClashGrotesk-Regular.woff2 +0 -0
  204. package/docs/fonts/ClashGrotesk-Semibold.eot +0 -0
  205. package/docs/fonts/ClashGrotesk-Semibold.ttf +0 -0
  206. package/docs/fonts/ClashGrotesk-Semibold.woff +0 -0
  207. package/docs/fonts/ClashGrotesk-Semibold.woff2 +0 -0
  208. package/docs/fonts/ClashGrotesk-Variable.eot +0 -0
  209. package/docs/fonts/ClashGrotesk-Variable.ttf +0 -0
  210. package/docs/fonts/ClashGrotesk-Variable.woff +0 -0
  211. package/docs/fonts/ClashGrotesk-Variable.woff2 +0 -0
  212. package/docs/img/concorde-icon.svg +0 -5
  213. package/docs/img/concorde-logo.svg +0 -1
  214. package/docs/img/concorde.png +0 -0
  215. package/docs/img/concorde_def.png +0 -0
  216. package/docs/img/concorde_seuil.png.webp +0 -0
  217. package/docs/img/concorde_seuil_invert.png +0 -0
  218. package/docs/img/paul_metrand.jpg +0 -0
  219. package/docs/img/paul_metrand_xs.jpg +0 -0
  220. package/docs/index.html +0 -93
  221. package/docs/llms-full.txt +0 -5787
  222. package/docs/llms.txt +0 -104
  223. package/docs/robots.txt +0 -16
  224. package/docs/sitemap.xml +0 -237
  225. package/docs/src/core/components/functional/date/date.md +0 -290
  226. package/docs/src/core/components/functional/fetch/fetch.md +0 -125
  227. package/docs/src/core/components/functional/if/if.md +0 -9
  228. package/docs/src/core/components/functional/jsonata/jsonata.md +0 -56
  229. package/docs/src/core/components/functional/list/list.md +0 -65
  230. package/docs/src/core/components/functional/mix/mix.md +0 -41
  231. package/docs/src/core/components/functional/queue/queue.md +0 -72
  232. package/docs/src/core/components/functional/router/router.md +0 -94
  233. package/docs/src/core/components/functional/sdui/default-library.json +0 -108
  234. package/docs/src/core/components/functional/sdui/example.json +0 -99
  235. package/docs/src/core/components/functional/sdui/sdui.md +0 -356
  236. package/docs/src/core/components/functional/states/states.md +0 -87
  237. package/docs/src/core/components/functional/submit/submit.md +0 -114
  238. package/docs/src/core/components/functional/subscriber/subscriber.md +0 -91
  239. package/docs/src/core/components/functional/value/value.md +0 -35
  240. package/docs/src/core/components/ui/alert/alert.md +0 -121
  241. package/docs/src/core/components/ui/alert-messages/alert-messages.md +0 -0
  242. package/docs/src/core/components/ui/badge/badge.md +0 -127
  243. package/docs/src/core/components/ui/button/button.md +0 -182
  244. package/docs/src/core/components/ui/captcha/captcha.md +0 -12
  245. package/docs/src/core/components/ui/card/card.md +0 -97
  246. package/docs/src/core/components/ui/divider/divider.md +0 -35
  247. package/docs/src/core/components/ui/form/checkbox/checkbox.md +0 -77
  248. package/docs/src/core/components/ui/form/fieldset/fieldset.md +0 -129
  249. package/docs/src/core/components/ui/form/form-actions/form-actions.md +0 -77
  250. package/docs/src/core/components/ui/form/form-layout/form-layout.md +0 -44
  251. package/docs/src/core/components/ui/form/input/input.md +0 -142
  252. package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -133
  253. package/docs/src/core/components/ui/form/radio/radio.md +0 -57
  254. package/docs/src/core/components/ui/form/select/select.md +0 -71
  255. package/docs/src/core/components/ui/form/switch/switch.md +0 -57
  256. package/docs/src/core/components/ui/form/textarea/textarea.md +0 -65
  257. package/docs/src/core/components/ui/group/group.md +0 -75
  258. package/docs/src/core/components/ui/icon/icon.md +0 -125
  259. package/docs/src/core/components/ui/icon/icons.json +0 -1
  260. package/docs/src/core/components/ui/image/image.md +0 -107
  261. package/docs/src/core/components/ui/link/link.md +0 -43
  262. package/docs/src/core/components/ui/loader/loader.md +0 -55
  263. package/docs/src/core/components/ui/menu/menu.md +0 -329
  264. package/docs/src/core/components/ui/modal/modal.md +0 -119
  265. package/docs/src/core/components/ui/pop/pop.md +0 -96
  266. package/docs/src/core/components/ui/progress/progress.md +0 -63
  267. package/docs/src/core/components/ui/table/table.md +0 -455
  268. package/docs/src/core/components/ui/toast/toast.md +0 -166
  269. package/docs/src/core/components/ui/tooltip/tooltip.md +0 -82
  270. package/docs/src/docs/_core-concept/dataFlow.md +0 -88
  271. package/docs/src/docs/_core-concept/overview.md +0 -57
  272. package/docs/src/docs/_core-concept/subscriber.md +0 -75
  273. package/docs/src/docs/_decorators/ancestor-attribute.md +0 -127
  274. package/docs/src/docs/_decorators/auto-subscribe.md +0 -202
  275. package/docs/src/docs/_decorators/bind.md +0 -167
  276. package/docs/src/docs/_decorators/get.md +0 -162
  277. package/docs/src/docs/_decorators/handle.md +0 -175
  278. package/docs/src/docs/_decorators/on-assign.md +0 -390
  279. package/docs/src/docs/_decorators/patch.md +0 -70
  280. package/docs/src/docs/_decorators/post.md +0 -146
  281. package/docs/src/docs/_decorators/publish.md +0 -55
  282. package/docs/src/docs/_decorators/put.md +0 -70
  283. package/docs/src/docs/_decorators/subscribe.md +0 -100
  284. package/docs/src/docs/_decorators/wait-for-ancestors.md +0 -163
  285. package/docs/src/docs/_directives/sub.md +0 -91
  286. package/docs/src/docs/_getting-started/ai-agents.md +0 -76
  287. package/docs/src/docs/_getting-started/concorde-manual-install.md +0 -133
  288. package/docs/src/docs/_getting-started/concorde-outside.md +0 -33
  289. package/docs/src/docs/_getting-started/create-a-component.md +0 -139
  290. package/docs/src/docs/_getting-started/my-first-component.md +0 -236
  291. package/docs/src/docs/_getting-started/my-first-subscriber.md +0 -120
  292. package/docs/src/docs/_getting-started/pubsub.md +0 -37
  293. package/docs/src/docs/_getting-started/start.md +0 -47
  294. package/docs/src/docs/_getting-started/theming.md +0 -91
  295. package/docs/src/docs/_misc/api-configuration.md +0 -81
  296. package/docs/src/docs/_misc/dataProviderKey.md +0 -168
  297. package/docs/src/docs/_misc/docs-mock-api.md +0 -63
  298. package/docs/src/docs/_misc/dynamic-path.md +0 -71
  299. package/docs/src/docs/_misc/endpoint.md +0 -45
  300. package/docs/src/docs/_misc/formelement-subscriber-removal.md +0 -115
  301. package/docs/src/docs/_misc/html-integration.md +0 -15
  302. package/docs/src/docs/search/docs-search.json +0 -9512
  303. package/docs/src/tag-list.json +0 -1
  304. package/docs/src/tsconfig-model.json +0 -23
  305. package/docs/src/tsconfig.declarations.json +0 -22
  306. package/docs/src/tsconfig.emit.json +0 -23
  307. package/docs/src/tsconfig.json +0 -858
  308. package/docs/svg/regular/plane.svg +0 -1
  309. package/docs/svg/solid/plane.svg +0 -1
  310. package/gitlab/job_github_mirror.sh +0 -39
  311. package/scripts/github-export.mjs +0 -150
  312. package/src/css.d.ts +0 -19
  313. package/src/tsconfig.declarations.json +0 -22
  314. package/src/tsconfig.emit.json +0 -23
@@ -1,165 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="fr" data-crawl-url="https://concorde.supersoniks.org/crawl/docs/_decorators/handle.html" data-doc-id="docs/_decorators/handle">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>@handle — Concorde</title>
7
- <meta name="description" content="Typed callback on one or more DataProviderKey&lt;T&gt; paths: invokes the decorated method when a publisher assigns a value (calculations, side effects, updating other @state properties, etc.).">
8
- <meta name="keywords" content="Concorde, supersoniks, docs/_decorators/handle, handle, @handle, decorator, DataProviderKey, @state, HandleOptions, null, undefined, @bind, @subscribe, ${user.firstName} ${user.lastName}">
9
- <meta name="concorde-doc-id" content="docs/_decorators/handle">
10
- <link rel="canonical" href="https://concorde.supersoniks.org/crawl/docs/_decorators/handle.html">
11
- </head>
12
- <body>
13
- <header>
14
- <p><a href="../../index.html">Concorde documentation (crawl)</a> · <a href="https://concorde.supersoniks.org/#docs/_decorators/handle.md/handle" rel="nofollow">interactive version</a></p>
15
- </header>
16
- <main>
17
- <article>
18
- <p class="doc-lead" id="doc-summary"><strong>Concorde decorator — @handle</strong>. Typed callback on one or more DataProviderKey&lt;T&gt; paths: invokes the decorated method when a publisher assigns a value (calculations, side effects, updating other @state properties, etc.). <span>Doc ID: <code>docs/_decorators/handle</code>. Keywords: Concorde, supersoniks, docs/_decorators/handle, handle, @handle, decorator, DataProviderKey, @state, HandleOptions, null, undefined, @bind, @subscribe, ${user.firstName} ${user.lastName}. URL: <a href="https://concorde.supersoniks.org/crawl/docs/_decorators/handle.html">https://concorde.supersoniks.org/crawl/docs/_decorators/handle.html</a>.</span></p>
19
- <h1 id="handle">@handle</h1>
20
- <p>Typed callback on one or more <code>DataProviderKey&lt;T&gt;</code> paths: invokes the decorated <strong>method</strong> when a publisher assigns a value (calculations, side effects, updating other <code>@state</code> properties, etc.).</p>
21
- <p>Unlike <a href="./subscribe.html#subscribe">@subscribe</a>, nothing is bound to the decorated member — only your method runs. <code>@handle</code> is typed and accepts up to <strong>3 keys</strong> plus an optional trailing <code>HandleOptions</code> object. It supersedes the string-based <a href="./on-assign.html#on-assign">@onAssign</a>.</p>
22
- <p>By default the method is called on <strong>every</strong> assignment, even when the value is <code>null</code> / <code>undefined</code>. Use the options below to restrict that.</p>
23
- <h2 id="import">Import</h2>
24
- <pre><code class="language-typescript">import { handle, Skip } from &quot;@supersoniks/concorde/decorators&quot;;
25
- import { DataProviderKey } from &quot;@supersoniks/concorde/dataProviderKey&quot;;
26
- import { get, set } from &quot;@supersoniks/concorde/utils&quot;;
27
- </code></pre>
28
- <h2 id="basic-example">Basic example</h2>
29
- <pre><code class="language-typescript">type DemoCounterData = { count: number };
30
- const demoDataKey = new DataProviderKey&amp;lt;DemoCounterData&amp;gt;(&quot;demoData&quot;);
31
-
32
- @customElement(&quot;demo-handle&quot;)
33
- export class DemoHandle extends LitElement {
34
- @state() doubled = 0;
35
- @state() lastUpdate = &quot;&quot;;
36
-
37
- @handle(demoDataKey.count)
38
- onCountChange(count: number) {
39
- this.doubled = count * 2;
40
- this.lastUpdate = new Date().toLocaleTimeString();
41
- }
42
-
43
- incrementCount() {
44
- const data = get(demoDataKey);
45
- set(demoDataKey, { ...data, count: data.count + 1 });
46
- }
47
-
48
- render() {
49
- return html`
50
- &amp;lt;p&amp;gt;Doubled count: ${this.doubled}&amp;lt;/p&amp;gt;
51
- &amp;lt;p&amp;gt;&amp;lt;small&amp;gt;Last update: ${this.lastUpdate}&amp;lt;/small&amp;gt;&amp;lt;/p&amp;gt;
52
- &amp;lt;sonic-button @click=${this.incrementCount}&amp;gt;Increment&amp;lt;/sonic-button&amp;gt;
53
- `;
54
- }
55
- }
56
- </code></pre>
57
- <pre><code>&lt;docs-demo-sources for=&quot;demo-handle&quot;&gt;&lt;/docs-demo-sources&gt;
58
- &lt;demo-handle&gt;&lt;/demo-handle&gt;
59
- </code></pre>
60
- <h2 id="dynamic-path">Dynamic path</h2>
61
- <p>Placeholders in <code>DataProviderKey</code> resolve from the host component’s properties (same rules as <code>@bind</code> / <code>@subscribe</code>).</p>
62
- <pre><code class="language-typescript">type User = { firstName: string; lastName: string; email: string };
63
-
64
- @customElement(&quot;demo-handle-dynamic&quot;)
65
- export class DemoHandleDynamic extends LitElement {
66
- @property({ type: Number })
67
- userIndex = 0;
68
-
69
- @state() displayName = &quot;&quot;;
70
- @state() lastUpdate = &quot;&quot;;
71
-
72
- @handle(new DataProviderKey&amp;lt;User, { userIndex: number }&amp;gt;(&quot;demoUsers.${userIndex}&quot;))
73
- onUserAssigned(user: User) {
74
- this.displayName = `${user.firstName} ${user.lastName}`;
75
- this.lastUpdate = new Date().toLocaleTimeString();
76
- }
77
-
78
- render() {
79
- return html`...`;
80
- }
81
- }
82
- </code></pre>
83
- <pre><code>&lt;docs-demo-sources for=&quot;demo-handle-dynamic&quot;&gt;&lt;/docs-demo-sources&gt;
84
- &lt;demo-handle-dynamic&gt;&lt;/demo-handle-dynamic&gt;
85
- </code></pre>
86
- <h2 id="multiple-paths">Multiple paths</h2>
87
- <p><code>@handle</code> accepts up to <strong>3 keys</strong>; the method receives one strongly-typed argument per key, in order. Each assignment triggers the method, so make your method safe against partial values (or use <code>waitForAllDefined</code>, see below).</p>
88
- <pre><code class="language-typescript">type QueueConfig = { onInactivity: { stillHere: { show: boolean } } };
89
- const config = new DataProviderKey&amp;lt;QueueConfig&amp;gt;(&quot;sessionQueueConfig&quot;);
90
- const idle = new DataProviderKey&amp;lt;{ isIdle: boolean }&amp;gt;(&quot;idleStatus&quot;);
91
-
92
- @customElement(&quot;demo-handle-multi&quot;)
93
- export class DemoHandleMulti extends LitElement {
94
-
95
- // show: boolean, isIdle: boolean — fully typed from the keys
96
- @handle(config.onInactivity.stillHere.show, idle.isIdle)
97
- onInactivity(show: boolean, isIdle: boolean) {
98
- if (show === true &amp;&amp; isIdle === true) this.openModal();
99
- else this.closeModal();
100
- }
101
- }
102
- </code></pre>
103
- <h2 id="options-handleoptions">Options (<code>HandleOptions</code>)</h2>
104
- <p>Pass an options object as the <strong>last</strong> argument. The names map to real situations seen in the apps.</p>
105
- <h3 id="waitforalldefined"><code>waitForAllDefined</code></h3>
106
- <p>Only call the method once <strong>all</strong> watched keys are defined (non <code>null</code> / <code>undefined</code>). This reproduces the historical <code>@onAssign</code> semantics — use it when the logic only makes sense with every source ready (e.g. building a date from <code>date</code> + <code>timeZone</code> + <code>direction</code>).</p>
107
- <pre><code class="language-typescript">@handle(trip.departureDate, trip.event.timeZone, form.direction, {
108
- waitForAllDefined: true,
109
- })
110
- updateDepartureDate(date: number, timeZone: string, direction: string) {
111
- // called only when the three values are all available
112
- this.formDate = formatDate(date, timeZone, direction);
113
- }
114
- </code></pre>
115
- <h3 id="skip"><code>skip</code></h3>
116
- <p>Do <strong>not</strong> call the method when a received value belongs to one of the listed <strong>categories</strong> (the <code>Skip</code> enum). Each entry is a named category — not a value — so there is no value/pattern ambiguity (e.g. <code>{}</code> is <code>Skip.EmptyObject</code>, an explicit &quot;empty object&quot; category, never a value comparison).</p>
117
- <table>
118
- <thead>
119
- <tr>
120
- <th>Category</th>
121
- <th>Matches</th>
122
- </tr>
123
- </thead>
124
- <tbody><tr>
125
- <td><code>Skip.Nullish</code></td>
126
- <td><code>null</code> or <code>undefined</code> (a publisher always emits <code>null</code>, never <code>undefined</code>)</td>
127
- </tr>
128
- <tr>
129
- <td><code>Skip.EmptyString</code></td>
130
- <td><code>&quot;&quot;</code></td>
131
- </tr>
132
- <tr>
133
- <td><code>Skip.EmptyObject</code></td>
134
- <td>object with no keys (<code>{}</code>), arrays excluded</td>
135
- </tr>
136
- <tr>
137
- <td><code>Skip.EmptyArray</code></td>
138
- <td>empty array (<code>[]</code>)</td>
139
- </tr>
140
- </tbody></table>
141
- <p>Useful when a not-yet-initialized publisher emits <code>{}</code> as a &quot;loading&quot; state. For a <strong>specific value</strong> (e.g. a particular string), guard inside the method instead.</p>
142
- <pre><code class="language-typescript">@handle(user.profile, { skip: [Skip.Nullish, Skip.EmptyObject] })
143
- onProfile(profile: Profile) {
144
- // not called while the publisher still holds {} (not loaded yet)
145
- this.displayName = profile.firstName;
146
- }
147
- </code></pre>
148
- <blockquote>
149
- <p>Options can be combined, e.g. <code>@handle(a, b, { waitForAllDefined: true, skip: [Skip.Nullish] })</code>. For any <strong>arbitrary</strong> validation on a specific value, just guard inside the method (<code>if (!isValid(v)) return;</code>) — that is exactly what an <code>accept</code>-style predicate would do, since <code>@handle</code> only runs your method.</p>
150
- </blockquote>
151
- <h3 id="skipemptyplaceholder"><code>skipEmptyPlaceholder</code></h3>
152
- <p>On a <strong>dynamic key path</strong> (<code>&quot;items.${itemId}&quot;</code>), if <code>true</code>, a placeholder resolved to <code>&#39;&#39;</code> is treated as not ready (no subscription) — <strong>empty string only</strong>, not <code>0</code> or <code>false</code>. See <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a>.</p>
153
- <h2 id="highlights">Highlights</h2>
154
- <ul>
155
- <li>Strict typing: the method receives one argument per key, in order.</li>
156
- <li>Up to 3 keys; for 4+ keys (rare), keep <a href="./on-assign.html#on-assign">@onAssign</a> for now.</li>
157
- <li>By default the method runs on <strong>every</strong> assignment, even with <code>null</code> / <code>undefined</code> (unlike <code>@onAssign</code>, which waits for all values). Opt back into that behavior with <code>waitForAllDefined</code>.</li>
158
- <li><code>skip</code> filters out values by <strong>named category</strong> (e.g. <code>[Skip.Nullish, Skip.EmptyObject]</code>); for arbitrary checks on a specific value, guard inside the method.</li>
159
- </ul>
160
- <p>See also <a href="../_misc/dataProviderKey.html#dataProviderKey">DataProviderKey</a> and <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a>.</p>
161
-
162
- </article>
163
- </main>
164
- </body>
165
- </html>
@@ -1,355 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="fr" data-crawl-url="https://concorde.supersoniks.org/crawl/docs/_decorators/on-assign.html" data-doc-id="docs/_decorators/on-assign">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>@onAssign — Concorde</title>
7
- <meta name="description" content="&gt; New apps: use @handle with DataProviderKey (Data flow). @onAssign uses untyped string paths; it remains documented for existing codebases — see Migrating to @handle below.">
8
- <meta name="keywords" content="Concorde, supersoniks, docs/_decorators/on-assign, on-assign, @onAssign, decorator, onAssign, DataProviderKey, set, get, User n°${userNumber}, user-${userNumber}@example.com">
9
- <meta name="concorde-doc-id" content="docs/_decorators/on-assign">
10
- <link rel="canonical" href="https://concorde.supersoniks.org/crawl/docs/_decorators/on-assign.html">
11
- </head>
12
- <body>
13
- <header>
14
- <p><a href="../../index.html">Concorde documentation (crawl)</a> · <a href="https://concorde.supersoniks.org/#docs/_decorators/on-assign.md/on-assign" rel="nofollow">interactive version</a></p>
15
- </header>
16
- <main>
17
- <article>
18
- <p class="doc-lead" id="doc-summary"><strong>Concorde decorator — @onAssign</strong>. &gt; New apps: use @handle with DataProviderKey (Data flow). @onAssign uses untyped string paths; it remains documented for existing codebases — see Migrating to @handle below. <span>Doc ID: <code>docs/_decorators/on-assign</code>. Keywords: Concorde, supersoniks, docs/_decorators/on-assign, on-assign, @onAssign, decorator, onAssign, DataProviderKey, set, get, User n°${userNumber}, user-${userNumber}@example.com. URL: <a href="https://concorde.supersoniks.org/crawl/docs/_decorators/on-assign.html">https://concorde.supersoniks.org/crawl/docs/_decorators/on-assign.html</a>.</span></p>
19
- <h1 id="onassign">@onAssign</h1>
20
- <blockquote>
21
- <p><strong>New apps:</strong> use <a href="./handle.html#handle">@handle</a> with <code>DataProviderKey</code> (<a href="../_core-concept/dataFlow.html#dataFlow">Data flow</a>). <code>@onAssign</code> uses untyped string paths; it remains documented for existing codebases — see <strong>Migrating to @handle</strong> below.</p>
22
- </blockquote>
23
- <p>The <code>@onAssign</code> decorator allows you to execute a method when one or more publishers are updated. The method is called only when all specified publishers have been assigned values.</p>
24
- <p>For a <strong>typed</strong> equivalent (recommended), use <a href="./handle.html#handle">@handle</a>.</p>
25
- <h2 id="principle">Principle</h2>
26
- <p>This decorator subscribes to one or more publishers by <strong>string path</strong> (legacy). When all specified publishers have been assigned values (via <code>set</code>), the decorated method is called with all the values as arguments. Prefer <a href="./handle.html#handle">@handle</a> + <code>DataProviderKey</code> and <code>get</code> / <code>set</code> from <a href="../_core-concept/dataFlow.html#dataFlow">Data flow</a>.</p>
27
- <p>This is particularly useful when you need to wait for multiple data sources to be ready before executing logic.</p>
28
- <h2 id="usage">Usage</h2>
29
- <h3 id="import">Import</h3>
30
- <pre><code class="language-typescript">import { onAssign } from &quot;@supersoniks/concorde/decorators&quot;;
31
- </code></pre>
32
- <h3 id="basic-example">Basic example</h3>
33
- <pre><code class="language-typescript">//...
34
- @customElement(&quot;demo-on-assign&quot;)
35
- export class DemoOnAssign extends LitElement {
36
- static styles = [tailwind];
37
-
38
- @state() userWithSettings: any = null;
39
- @state() isReady: boolean = false;
40
- @state() lastUpdate: string = &quot;&quot;;
41
-
42
- @onAssign(&quot;demoUser&quot;, &quot;demoUserSettings&quot;)
43
- handleDataReady(user: any, settings: any) {
44
- this.isReady = Object.keys(user).length &gt; 0 &amp;&amp; Object.keys(settings).length &gt; 0;
45
- this.userWithSettings = { ...user, ...settings };
46
- this.lastUpdate = new Date().toLocaleTimeString();
47
- this.requestUpdate();
48
- }
49
-
50
- render() {
51
- const { name, email, theme, language } = this.userWithSettings;
52
- return //...
53
- }
54
-
55
- updateData() {
56
- const user = PublisherManager.get(&quot;demoUser&quot;);
57
- const userSettings = PublisherManager.get(&quot;demoUserSettings&quot;);
58
- const userNumber = Math.floor(Math.random() * 100);
59
- user.set({
60
- name: `User n°${userNumber}`,
61
- email: `user-${userNumber}@example.com`,
62
- });
63
-
64
- userSettings.set({
65
- theme: [&quot;light&quot;, &quot;dark&quot;, &quot;auto&quot;][Math.floor(Math.random() * 3)],
66
- language: [&quot;en&quot;, &quot;fr&quot;, &quot;es&quot;][Math.floor(Math.random() * 3)],
67
- });
68
- }
69
- }
70
- </code></pre>
71
- <pre><code>&lt;docs-demo-sources for=&quot;demo-on-assign&quot;&gt;&lt;/docs-demo-sources&gt;
72
- &lt;demo-on-assign&gt;&lt;/demo-on-assign&gt;
73
- </code></pre>
74
- <h3 id="example-with-nested-paths">Example with nested paths</h3>
75
- <pre><code class="language-typescript">@customElement(&quot;product-view&quot;)
76
- export class ProductView extends LitElement {
77
- product: any = null;
78
- inventory: any = null;
79
-
80
- @onAssign(&quot;store.product&quot;, &quot;store.inventory&quot;)
81
- handleProductData(product: any, inventory: any) {
82
- this.product = product;
83
- this.inventory = inventory;
84
- this.requestUpdate();
85
- }
86
-
87
- render() {
88
- if (!this.product) return html`&lt;div&gt;Loading...&lt;/div&gt;`;
89
-
90
- const stock = this.inventory[this.product.id] || 0;
91
- return html`
92
- &lt;div&gt;
93
- &lt;h2&gt;${this.product.name}&lt;/h2&gt;
94
- &lt;p&gt;Price: ${this.product.price}€&lt;/p&gt;
95
- &lt;p&gt;Stock: ${stock}&lt;/p&gt;
96
- &lt;/div&gt;
97
- `;
98
- }
99
- }
100
- </code></pre>
101
- <h2 id="path-syntax">Path syntax</h2>
102
- <p>The path uses dot notation to navigate through the publisher structure:</p>
103
- <ul>
104
- <li><strong>First segment</strong>: dataProvider identifier (e.g., <code>&quot;userData&quot;</code>)</li>
105
- <li><strong>Following segments</strong>: nested properties (e.g., <code>&quot;store.product&quot;</code>)</li>
106
- <li><strong>Array access</strong>: use numeric index (e.g., <code>&quot;data.items.0&quot;</code>)</li>
107
- </ul>
108
- <h3 id="dynamic-path-driven-by-class-properties">Dynamic path driven by class properties</h3>
109
- <p>You can now build the paths dynamically by referencing the host class properties inside the strings passed to <code>@onAssign</code>. Two placeholder syntaxes are supported:</p>
110
- <ul>
111
- <li><code>${myProperty}</code> or <code>${this.myProperty}</code></li>
112
- <li><code>{$myProperty}</code></li>
113
- </ul>
114
- <p>Each placeholder is replaced at runtime with the current value of the corresponding property. <code>@onAssign</code> automatically watches those properties and:</p>
115
- <ul>
116
- <li>re-evaluates the final paths when one of them changes,</li>
117
- <li>removes the previous subscriptions before attaching the new ones,</li>
118
- <li>observe the changes inside <code>willUpdate(changedProperties)</code> so nothing touches the getters/setters.</li>
119
- </ul>
120
- <p>While a placeholder is <code>null</code>/<code>undefined</code>, subscriptions are detached. Optional <code>skipEmptyPlaceholder</code> on <a href="./handle.html#handle">@handle</a> (typed replacement). Details: <a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a>.</p>
121
- <pre><code class="language-typescript">@customElement(&quot;demo-on-assign-dynamic&quot;)
122
- export class DemoOnAssignDynamic extends LitElement {
123
- static styles = [tailwind];
124
-
125
- @property({ type: String })
126
- dataProvider: &quot;demoUsers&quot; | &quot;demoUsersAlt&quot; = &quot;demoUsers&quot;;
127
-
128
- @property({ type: Number })
129
- userIndex: number = 0;
130
-
131
- @state() user: any = null;
132
- @state() userSettings: any = null;
133
-
134
- @onAssign(&quot;${dataProvider}.${userIndex}&quot;, &quot;${dataProvider}Settings.${userIndex}&quot;)
135
- handleUserDataReady(user: any, settings: any) {
136
- this.user = user;
137
- this.userSettings = settings;
138
- }
139
-
140
- updateUserIndex(e: Event) {
141
- this.userIndex = parseInt((e.target as HTMLInputElement).value);
142
- }
143
-
144
- updateDataProvider(e: Event) {
145
- this.dataProvider = (e.target as HTMLSelectElement).value as
146
- | &quot;demoUsers&quot;
147
- | &quot;demoUsersAlt&quot;;
148
- }
149
-
150
- updateCurrentUserData() {
151
- const usersPublisher = PublisherManager.get(this.dataProvider);
152
- const settingsPublisher = PublisherManager.get(
153
- `${this.dataProvider}Settings`
154
- );
155
- const userPublisher = Objects.traverse(
156
- usersPublisher,
157
- [String(this.userIndex)]
158
- ) as PublisherProxy;
159
- const settingPublisher = Objects.traverse(
160
- settingsPublisher,
161
- [String(this.userIndex)]
162
- ) as PublisherProxy;
163
-
164
- if (userPublisher &amp;&amp; settingPublisher) {
165
- // Générer de nouvelles données aléatoires
166
- const randomNames = [
167
- { firstName: &quot;Alice&quot;, lastName: &quot;Wonder&quot; },
168
- { firstName: &quot;Bob&quot;, lastName: &quot;Builder&quot; },
169
- { firstName: &quot;Charlie&quot;, lastName: &quot;Chaplin&quot; },
170
- ];
171
- const randomThemes = [&quot;light&quot;, &quot;dark&quot;, &quot;auto&quot;];
172
- const randomLanguages = [&quot;en&quot;, &quot;fr&quot;, &quot;es&quot;];
173
-
174
- const randomName =
175
- randomNames[Math.floor(Math.random() * randomNames.length)];
176
- const randomEmail = `${randomName.firstName.toLowerCase()}.${randomName.lastName.toLowerCase()}@example.com`;
177
- const randomTheme =
178
- randomThemes[Math.floor(Math.random() * randomThemes.length)];
179
- const randomLanguage =
180
- randomLanguages[Math.floor(Math.random() * randomLanguages.length)];
181
-
182
- // Mettre à jour l&#39;utilisateur directement
183
- const currentUser = userPublisher.get() || {};
184
- userPublisher.set({
185
- ...currentUser,
186
- firstName: randomName.firstName,
187
- lastName: randomName.lastName,
188
- email: randomEmail,
189
- });
190
-
191
- // Mettre à jour les settings directement
192
- settingPublisher.set({
193
- theme: randomTheme,
194
- language: randomLanguage,
195
- });
196
- }
197
- }
198
-
199
- render() {
200
- return html`
201
- &amp;lt;div class=&quot;flex flex-col gap-2&quot;&amp;gt;
202
- &amp;lt;sonic-select label=&quot;Users set&quot; @change=${this.updateDataProvider}&amp;gt;
203
- &amp;lt;option value=&quot;demoUsers&quot;&amp;gt;First set of users&amp;lt;/option&amp;gt;
204
- &amp;lt;option value=&quot;demoUsersAlt&quot;&amp;gt;Second set of users&amp;lt;/option&amp;gt;
205
- &amp;lt;/sonic-select&amp;gt;
206
- &amp;lt;sonic-input
207
- type=&quot;number&quot;
208
- .value=${this.userIndex}
209
- @input=${this.updateUserIndex}
210
- min=&quot;0&quot;
211
- max=&quot;9&quot;
212
- label=&quot;Index&quot;
213
- class=&quot;block&quot;
214
- &amp;gt;&amp;lt;/sonic-input&amp;gt;
215
- &amp;lt;sonic-button @click=${this.updateCurrentUserData}&amp;gt;
216
- Update current user data
217
- &amp;lt;/sonic-button&amp;gt;
218
- &amp;lt;div class=&quot;flex flex-col gap-2 border p-2&quot;&amp;gt;
219
- &amp;lt;div&amp;gt;
220
- &amp;lt;sonic-icon name=&quot;user&quot; library=&quot;heroicons&quot;&amp;gt;&amp;lt;/sonic-icon&amp;gt;
221
- ${this.user?.firstName} ${this.user?.lastName}
222
- &amp;lt;/div&amp;gt;
223
- &amp;lt;div&amp;gt;
224
- &amp;lt;sonic-icon name=&quot;envelope&quot; library=&quot;heroicons&quot;&amp;gt;&amp;lt;/sonic-icon&amp;gt;
225
- ${this.user?.email}
226
- &amp;lt;/div&amp;gt;
227
- &amp;lt;div&amp;gt;
228
- Theme: ${this.userSettings?.theme} | Language:
229
- ${this.userSettings?.language}
230
- &amp;lt;/div&amp;gt;
231
- &amp;lt;/div&amp;gt;
232
- &amp;lt;/div&amp;gt;
233
- `;
234
- }
235
- }
236
- </code></pre>
237
- <pre><code>&lt;docs-demo-sources for=&quot;demo-on-assign-dynamic&quot;&gt;&lt;/docs-demo-sources&gt;
238
- &lt;demo-on-assign-dynamic&gt;&lt;/demo-on-assign-dynamic&gt;
239
- </code></pre>
240
- <blockquote>
241
- <p>⚠️ Use classic string literals: <code>@onAssign(&quot;${dataProvider}.${profileId}&quot;, &quot;settings.${profileId}&quot;)</code>. Do <strong>not</strong> use template literals (backticks), otherwise JavaScript would try to interpolate the value immediately.</p>
242
- </blockquote>
243
- <p>Additional constraints:</p>
244
- <ul>
245
- <li>The hosting class must expose a <code>willUpdate(changedProperties?: Map&lt;PropertyKey, unknown&gt;)</code> method (LitElement already provides it) so that <code>@onAssign</code> can listen to dependency changes.</li>
246
- <li>Dependencies need to be reactive (e.g. <code>@property()</code> on LitElement) or you must call <code>this.requestUpdate(&quot;myProp&quot;)</code> manually after changing them, otherwise <code>willUpdate</code> will never be notified.</li>
247
- <li>If you use nested expressions like <code>${user.id}</code>, the first segment (<code>user</code>) is the one being observed: you need to reassign <code>this.user</code> (e.g. with a new object) so that the binding can detect the change.</li>
248
- </ul>
249
- <h2 id="behavior">Behavior</h2>
250
- <ul>
251
- <li>The method is called only when <strong>all</strong> specified publishers have been assigned values</li>
252
- <li>The method receives the values of all publishers as arguments, in the same order as specified</li>
253
- <li>Subscription happens at the time of <code>connectedCallback</code></li>
254
- <li>Unsubscription happens automatically at the time of <code>disconnectedCallback</code></li>
255
- <li>If a publisher doesn&#39;t exist yet, it will be created with the value <code>null</code></li>
256
- <li>The method is called with <code>this</code> bound to the component instance</li>
257
- </ul>
258
- <h2 id="use-cases">Use cases</h2>
259
- <p>This decorator is particularly useful for:</p>
260
- <ul>
261
- <li><strong>Waiting for multiple data sources</strong> before rendering or executing logic</li>
262
- <li><strong>Synchronizing data</strong> from different publishers</li>
263
- <li><strong>Initializing components</strong> that depend on multiple data providers</li>
264
- <li><strong>Handling complex data dependencies</strong> where you need all data to be ready</li>
265
- </ul>
266
- <h2 id="complete-example">Complete example</h2>
267
- <pre><code class="language-typescript">import { html, LitElement } from &quot;lit&quot;;
268
- import { customElement } from &quot;lit/decorators.js&quot;;
269
- import { onAssign } from &quot;@supersoniks/concorde/decorators&quot;;
270
- import { PublisherManager } from &quot;@supersoniks/concorde/core/utils/PublisherProxy&quot;;
271
-
272
- @customElement(&quot;order-summary&quot;)
273
- export class OrderSummary extends LitElement {
274
- order: any = null;
275
- customer: any = null;
276
- shipping: any = null;
277
-
278
- @onAssign(&quot;orderData&quot;, &quot;customerData&quot;, &quot;shippingData&quot;)
279
- handleOrderReady(order: any, customer: any, shipping: any) {
280
- this.order = order;
281
- this.customer = customer;
282
- this.shipping = shipping;
283
- this.requestUpdate();
284
- }
285
-
286
- render() {
287
- if (!this.order || !this.customer || !this.shipping) {
288
- return html`&lt;div&gt;Loading order details...&lt;/div&gt;`;
289
- }
290
-
291
- return html`
292
- &lt;div class=&quot;order-summary&quot;&gt;
293
- &lt;h2&gt;Order #${this.order.id}&lt;/h2&gt;
294
- &lt;p&gt;Customer: ${this.customer.name}&lt;/p&gt;
295
- &lt;p&gt;Shipping to: ${this.shipping.address}&lt;/p&gt;
296
- &lt;p&gt;Total: ${this.order.total}€&lt;/p&gt;
297
- &lt;/div&gt;
298
- `;
299
- }
300
- }
301
- // Somewhere in your code, update the publishers:
302
- const orderPub = PublisherManager.get(&quot;orderData&quot;);
303
- const customerPub = PublisherManager.get(&quot;customerData&quot;);
304
- const shippingPub = PublisherManager.get(&quot;shippingData&quot;);
305
- // The method will be called only when all three are set:
306
- orderPub.set({ id: &quot;123&quot;, total: 99.99 });
307
- customerPub.set({ name: &quot;John Doe&quot;, email: &quot;john@example.com&quot; });
308
- shippingPub.set({ address: &quot;123 Main St&quot; });
309
- // handleOrderReady will be called with all three values
310
- </code></pre>
311
- <h2 id="migrating-to-handle">Migrating to @handle</h2>
312
- <p><code>@handle</code> is the typed successor of <code>@onAssign</code>. The key behavioral difference: <code>@onAssign</code> waits for <strong>all</strong> values to be defined before calling the method, whereas <code>@handle</code> calls it on <strong>every</strong> assignment by default. Use the <code>waitForAllDefined</code> option to keep the old semantics.</p>
313
- <h3 id="why-migrate">Why migrate</h3>
314
- <ul>
315
- <li><strong>Typed paths</strong>: keys are <code>DataProviderKey&lt;T&gt;</code>, so the method arguments are strongly typed (no more <code>any</code>).</li>
316
- <li><strong>Explicit intent</strong>: <code>waitForAllDefined</code> and <code>skip</code> replace implicit behavior.</li>
317
- <li><strong>Single API</strong>: <code>@handle</code> covers the mono- and multi-path cases (up to 3 keys).</li>
318
- </ul>
319
- <h3 id="equivalent-semantics-waitforalldefined">Equivalent semantics (<code>waitForAllDefined</code>)</h3>
320
- <pre><code class="language-typescript">// Before
321
- @onAssign(&quot;demoUser&quot;, &quot;demoUserSettings&quot;)
322
- handleDataReady(user: any, settings: any) { /* ... */ }
323
-
324
- // After — same &quot;wait for everything&quot; behavior, but typed
325
- const user = new DataProviderKey&amp;lt;User&amp;gt;(&quot;demoUser&quot;);
326
- const settings = new DataProviderKey&amp;lt;Settings&amp;gt;(&quot;demoUserSettings&quot;);
327
-
328
- @handle(user, settings, { waitForAllDefined: true })
329
- handleDataReady(user: User, settings: Settings) { /* ... */ }
330
- </code></pre>
331
- <h3 id="single-path">Single path</h3>
332
- <pre><code class="language-typescript">// Before
333
- @onAssign(&quot;settings.modules.logs_route.enabled&quot;)
334
- onLogRoute(value: boolean) { /* ... */ }
335
-
336
- // After
337
- const settings = new DataProviderKey&amp;lt;AppSettings&amp;gt;(&quot;settings&quot;);
338
-
339
- @handle(settings.modules.logs_route.enabled)
340
- onLogRoute(value: boolean) { /* ... */ }
341
- </code></pre>
342
- <h3 id="4-paths">4+ paths</h3>
343
- <p><code>@handle</code> is capped at 3 keys. For the rare case of 4 or more publishers, keep <code>@onAssign</code> for now, or split the logic into several <code>@handle</code> methods that each store their value and call a shared method (guarding against partial values).</p>
344
- <h2 id="notes">Notes</h2>
345
- <ul>
346
- <li>This decorator works with any component that has <code>connectedCallback</code> and <code>disconnectedCallback</code> methods (such as <code>LitElement</code> or components extending <code>Subscriber</code>)</li>
347
- <li>The method is called synchronously when all publishers are ready</li>
348
- <li>If you need to update the UI, remember to call <code>this.requestUpdate()</code> inside the method</li>
349
- <li>For more information about publishers, see the documentation on <a href="../_getting-started/pubsub.html#pubsub">Sharing data</a></li>
350
- </ul>
351
-
352
- </article>
353
- </main>
354
- </body>
355
- </html>
@@ -1,78 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="fr" data-crawl-url="https://concorde.supersoniks.org/crawl/docs/_decorators/patch.html" data-doc-id="docs/_decorators/patch">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>@patch — Concorde</title>
7
- <meta name="description" content="@patch applies a partial update with the body from a publisher. It uses the">
8
- <meta name="keywords" content="Concorde, supersoniks, docs/_decorators/patch, patch, @patch, decorator, Endpoint, DataProviderKey, ApiResult, send(component),
9
-
10
- , when: &quot;before&quot;, autoPostOnBodyMutation: false, autoPostOnBodyMutation, skipIfBodyMissing">
11
- <meta name="concorde-doc-id" content="docs/_decorators/patch">
12
- <link rel="canonical" href="https://concorde.supersoniks.org/crawl/docs/_decorators/patch.html">
13
- </head>
14
- <body>
15
- <header>
16
- <p><a href="../../index.html">Concorde documentation (crawl)</a> · <a href="https://concorde.supersoniks.org/#docs/_decorators/patch.md/patch" rel="nofollow">interactive version</a></p>
17
- </header>
18
- <main>
19
- <article>
20
- <p class="doc-lead" id="doc-summary"><strong>Concorde decorator — @patch</strong>. @patch applies a partial update with the body from a publisher. It uses the <span>Doc ID: <code>docs/_decorators/patch</code>. Keywords: Concorde, supersoniks, docs/_decorators/patch, patch, @patch, decorator, Endpoint, DataProviderKey, ApiResult, send(component),
21
-
22
- , when: &quot;before&quot;, autoPostOnBodyMutation: false, autoPostOnBodyMutation, skipIfBodyMissing. URL: <a href="https://concorde.supersoniks.org/crawl/docs/_decorators/patch.html">https://concorde.supersoniks.org/crawl/docs/_decorators/patch.html</a>.</span></p>
23
- <h1 id="patch">@patch</h1>
24
- <p><code>@patch</code> applies a partial update with the body from a publisher. It uses the
25
- same model as <a href="./post.html#post">@post</a>:
26
- <code>Endpoint&lt;T&gt;</code>, <code>DataProviderKey&lt;B&gt;</code>, <code>ApiResult&lt;T&gt;</code>, options, and the
27
- <code>send(component)</code> handle.</p>
28
- <h2 id="minimal-usage">Minimal usage</h2>
29
- <pre><code class="language-typescript">const bodyKey = new DataProviderKey&lt;Partial&lt;User&gt;&gt;(&quot;users.patch&quot;);
30
- const patchUser = patch(new Endpoint&lt;User&gt;(&quot;users/42&quot;), bodyKey);
31
-
32
- @patchUser
33
- @state()
34
- payload?: ApiResult&lt;User&gt;;
35
- </code></pre>
36
- <p>The same decorator adapts to a method:</p>
37
- <pre><code class="language-typescript">@patch(new Endpoint&lt;User&gt;(&quot;users/42&quot;), bodyKey)
38
- handlePatch(payload?: ApiResult&lt;User&gt;) {
39
- if (payload?.response?.ok) console.log(payload.result);
40
- }
41
- </code></pre>
42
- <p>To run the operation again from the component:</p>
43
- <pre><code class="language-typescript">async savePatch() {
44
- await patchUser.send(this);
45
- }
46
- </code></pre>
47
- <p><code>send(component)</code> returns a Promise resolved after the PATCH completes. See
48
- <a href="./post.html#post">@post</a> for the method-decorator form and the
49
- <code>when: &quot;before&quot;</code> option.</p>
50
- <p>The PATCH is also sent automatically when the body mutates, unless
51
- <code>autoPostOnBodyMutation: false</code> is set. The available options are described in
52
- <a href="./post.html#post">@post</a>:</p>
53
- <ul>
54
- <li><code>autoPostOnBodyMutation</code></li>
55
- <li><code>skipIfBodyMissing</code></li>
56
- <li><code>refetchEveryMs</code></li>
57
- <li><code>skipEmptyPlaceholder</code></li>
58
- <li><code>triggerKey</code></li>
59
- </ul>
60
- <p>Pass explicit API configuration as the third argument:</p>
61
- <pre><code class="language-typescript">@patch(endpoint, bodyKey, apiConfigurationKey)
62
- </code></pre>
63
- <h2 id="import">Import</h2>
64
- <pre><code class="language-typescript">import { patch, type ApiResult } from &quot;@supersoniks/concorde/decorators&quot;;
65
- import { DataProviderKey } from &quot;@supersoniks/concorde/dataProviderKey&quot;;
66
- import { Endpoint } from &quot;@supersoniks/concorde/utils/endpoint&quot;;
67
- </code></pre>
68
- <h2 id="see-also">See also</h2>
69
- <ul>
70
- <li><a href="./post.html#post">@post</a> — options and triggers</li>
71
- <li><a href="./put.html#put">@put</a> — full replacement</li>
72
- <li><a href="../_misc/dynamic-path.html#dynamic-path">Dynamic path placeholders</a></li>
73
- </ul>
74
-
75
- </article>
76
- </main>
77
- </body>
78
- </html>