@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
@@ -0,0 +1,145 @@
1
+ import { expect, vi } from "vitest";
2
+ import TestUtils from "@supersoniks/concorde/test-utils/TestUtils";
3
+ import "./alert";
4
+ import { Alert } from "./alert";
5
+
6
+ async function create(attributes: string) {
7
+ const element = TestUtils.bootstrap(
8
+ `<sonic-alert ${attributes}></sonic-alert>`
9
+ )[0] as Alert;
10
+ await element.updateComplete;
11
+ return element;
12
+ }
13
+
14
+ describe("SonicAlert", () => {
15
+ it("utilise status=default par défaut", async () => {
16
+ const elt = await create("");
17
+ expect(elt.getAttribute("status")).toBe("default");
18
+ });
19
+
20
+ it("conserve status=error", async () => {
21
+ const elt = await create('status="error"');
22
+ expect(elt.status).toBe("error");
23
+ expect(elt.getAttribute("status")).toBe("error");
24
+ });
25
+
26
+ it.each(["warning", "success", "info"])(
27
+ "accepte status=%s",
28
+ async (value) => {
29
+ const elt = await create(`status="${value}"`);
30
+ expect(elt.getAttribute("status")).toBe(value);
31
+ }
32
+ );
33
+
34
+ it("n'expose pas role ni aria-live sans announce", async () => {
35
+ const elt = await create('status="error"');
36
+ expect(elt.hasAttribute("role")).toBe(false);
37
+ expect(elt.hasAttribute("aria-live")).toBe(false);
38
+ });
39
+
40
+ it("avec announce, role=alert pour error sans aria-live explicite", async () => {
41
+ const error = await create('announce status="error"');
42
+ expect(error.getAttribute("role")).toBe("alert");
43
+ expect(error.hasAttribute("aria-live")).toBe(false);
44
+ });
45
+
46
+ it("avec announce, role=status et aria-live=polite pour les autres status", async () => {
47
+ const info = await create('announce status="info"');
48
+ expect(info.getAttribute("role")).toBe("status");
49
+ expect(info.getAttribute("aria-live")).toBe("polite");
50
+ });
51
+
52
+ it("retire role et aria-live quand announce repasse à false", async () => {
53
+ const elt = await create("announce status=info");
54
+ expect(elt.getAttribute("role")).toBe("status");
55
+ elt.announce = false;
56
+ await elt.updateComplete;
57
+ expect(elt.hasAttribute("role")).toBe(false);
58
+ expect(elt.hasAttribute("aria-live")).toBe(false);
59
+ });
60
+
61
+ it("affiche un bouton de fermeture uniquement si dismissible", async () => {
62
+ const dismissible = await create("dismissible");
63
+ expect(dismissible.shadowRoot?.querySelector(".close-btn")).not.toBeNull();
64
+ const plain = await create("");
65
+ expect(plain.shadowRoot?.querySelector(".close-btn")).toBeNull();
66
+ });
67
+
68
+ it("retire l'alerte au clic sur le bouton dismissible", async () => {
69
+ const container = document.createElement("div");
70
+ document.body.appendChild(container);
71
+ container.innerHTML = '<sonic-alert dismissible text="msg"></sonic-alert>';
72
+ const elt = container.querySelector("sonic-alert") as Alert;
73
+ await elt.updateComplete;
74
+ const closeBtn = elt.shadowRoot?.querySelector(
75
+ ".close-btn"
76
+ ) as HTMLElement | null;
77
+ expect(closeBtn).not.toBeNull();
78
+ closeBtn!.click();
79
+ expect(container.querySelector("sonic-alert")).toBeNull();
80
+ container.remove();
81
+ });
82
+
83
+ it("masque l'icône décorative aux lecteurs d'écran", async () => {
84
+ const elt = await create('status="info"');
85
+ expect(
86
+ elt.shadowRoot?.querySelector("sonic-icon")?.getAttribute("aria-hidden")
87
+ ).toBe("true");
88
+ });
89
+
90
+ it("n'affiche pas l'icône si noIcon", async () => {
91
+ const elt = await create("noIcon");
92
+ expect(elt.shadowRoot?.querySelector("sonic-icon")).toBeNull();
93
+ });
94
+
95
+ it("traduit le libellé de fermeture selon la langue du document", async () => {
96
+ const previous = document.documentElement.lang;
97
+ document.documentElement.lang = "fr";
98
+ const fr = await create("dismissible");
99
+ expect(
100
+ (fr.shadowRoot?.querySelector(".close-btn") as HTMLElement & {
101
+ ariaLabel?: string;
102
+ })?.ariaLabel
103
+ ).toBe("Fermer");
104
+ document.documentElement.lang = "it";
105
+ const it = await create("dismissible");
106
+ expect(
107
+ (it.shadowRoot?.querySelector(".close-btn") as HTMLElement & {
108
+ ariaLabel?: string;
109
+ })?.ariaLabel
110
+ ).toBe("Chiudi");
111
+ document.documentElement.lang = previous;
112
+ });
113
+
114
+ it("n'interprète pas le HTML du label", async () => {
115
+ const elt = await create('label="<b>x</b>"');
116
+ expect(elt.shadowRoot?.querySelector(".label b")).toBeNull();
117
+ expect(elt.shadowRoot?.querySelector(".label")?.textContent).toBe(
118
+ "<b>x</b>"
119
+ );
120
+ });
121
+
122
+ it("mémorise la fermeture avec dismissForever et un id", async () => {
123
+ localStorage.clear();
124
+ const elt = await create('dismissForever id="my-alert"');
125
+ elt.close();
126
+ expect(JSON.parse(localStorage.getItem("sonic-alert-dismissed")!)).toEqual(
127
+ { "my-alert": true }
128
+ );
129
+ const children = TestUtils.bootstrap(
130
+ '<sonic-alert dismissForever id="my-alert"></sonic-alert>'
131
+ );
132
+ expect(children.length).toBe(0);
133
+ });
134
+
135
+ it("ne mémorise rien avec dismissForever sans id", async () => {
136
+ localStorage.clear();
137
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
138
+ const elt = await create("dismissForever");
139
+ elt.close();
140
+ expect(localStorage.getItem("sonic-alert-dismissed")).toBeNull();
141
+ expect(warn).toHaveBeenCalled();
142
+ warn.mockRestore();
143
+ });
144
+
145
+ });
@@ -1,20 +1,28 @@
1
- import { html, LitElement, css, nothing } from "lit";
1
+ import { html, LitElement, css, nothing, PropertyValues } from "lit";
2
2
  import { customElement, property } from "lit/decorators.js";
3
3
  import {
4
4
  fontSize,
5
5
  Size,
6
6
  } from "@supersoniks/concorde/core/components/ui/_css/size";
7
- import { unsafeHTML } from "lit/directives/unsafe-html.js";
8
- const icon = {
9
- warning: "warning-circled-outline",
10
- success: "check-circled-outline",
11
- error: "warning-circled-outline",
12
- info: "info-empty",
13
- default: "info-empty",
14
- };
15
-
16
- export type AlertStatus = keyof typeof icon;
7
+ import {
8
+ StatusIconKey,
9
+ statusAriaLive,
10
+ statusAriaRole,
11
+ statusColor,
12
+ statusIcon,
13
+ } from "@supersoniks/concorde/core/components/ui/_css/type";
14
+ import {
15
+ isDismissed,
16
+ markDismissed,
17
+ } from "@supersoniks/concorde/core/utils/dismissed";
18
+ import {
19
+ resolveUiLabel,
20
+ uiAriaLabels,
21
+ } from "@supersoniks/concorde/core/components/ui/_i18n/ui-aria-labels";
22
+
23
+ export type AlertStatus = StatusIconKey;
17
24
  const tagName = "sonic-alert";
25
+ const dismissStorageKey = "sonic-alert-dismissed";
18
26
 
19
27
  /**
20
28
  * Affiche un message en ligne.
@@ -24,66 +32,29 @@ const tagName = "sonic-alert";
24
32
  export class Alert extends LitElement {
25
33
  static styles = [
26
34
  fontSize,
35
+ statusColor,
27
36
  css`
28
37
  :host {
29
- --sc_color: var(--sc-base-content, #000);
30
- --sc_rounded: var(--sc-rounded);
31
- --sc_fw: var(--sc-font-weight-base, 400);
32
- --sc_fst: var(--sc-font-style-base, normal);
33
- --sc_label-fw: bold;
34
-
35
- font-weight: var(--sc_fw);
36
- font-style: var(--sc_fst);
37
- color: var(--sc_color);
38
+ --sc-_rounded: var(--sc-rounded);
38
39
  position: relative;
39
40
  display: flex;
40
41
  gap: 0.4em;
41
- border-radius: var(--sc_rounded);
42
+ border-radius: var(--sc-_rounded);
42
43
  }
43
44
 
44
45
  .label {
45
- font-weight: var(--sc_label-fw);
46
+ font-weight: bold;
46
47
  margin-bottom: 0.15em;
47
48
  display: block;
48
49
  }
49
50
 
50
- :host([status="warning"]) {
51
- --sc_color: var(--sc-warning, var(--sc-base-content, #000));
52
- }
53
- :host([status="error"]) {
54
- --sc_color: var(--sc-danger, var(--sc-base-content, #000));
55
- }
56
- :host([status="info"]) {
57
- --sc_color: var(--sc-info, var(--sc-base-content, #000));
58
- }
59
- :host([status="success"]) {
60
- --sc_color: var(--sc-success, var(--sc-base-content, #000));
61
- }
62
-
63
51
  /*background*/
64
- :host([dismissible]),
65
52
  :host([background]) {
66
- background: var(--sc-base, #fff);
67
- padding: 0.8em 1.15em;
68
- }
69
- :host([dismissible]):before,
70
- :host([background]):before {
71
- background-color: currentColor;
72
- content: "";
73
- display: block;
74
- position: absolute;
75
- left: 0;
76
- top: 0;
77
- right: 0;
78
- bottom: 0;
79
- opacity: 0.08;
80
- border-radius: var(--sc_rounded);
81
- pointer-events: none;
53
+ background: color-mix(in srgb, currentColor 8%, var(--sc-base, #fff));
54
+ padding: 0.8em;
82
55
  }
83
56
 
84
57
  .content {
85
- z-index: 2;
86
- position: relative;
87
58
  flex: 1;
88
59
  }
89
60
 
@@ -91,30 +62,34 @@ export class Alert extends LitElement {
91
62
  display: block;
92
63
  }
93
64
 
94
- .hidden {
95
- display: none !important;
96
- }
97
-
98
65
  /*Rounded*/
99
66
  :host([size="2xs"]),
100
67
  :host([size="xs"]),
101
68
  :host([size="sm"]) {
102
- --sc_rounded: var(--sc-rounded-sm);
69
+ --sc-_rounded: var(--sc-rounded-sm);
103
70
  }
104
71
 
105
72
  /*Dismissible*/
106
- :host([dismissible]) {
73
+ .close-btn {
74
+ flex-shrink: 0;
75
+ align-self: flex-start;
76
+ border-left: var(--sc-border-width, 1px) solid currentColor;
77
+ padding-left: 0.5em;
78
+ margin-left: 0.5em;
79
+ }
80
+ :host([dismissible][background]) {
107
81
  padding-right: 3rem;
108
82
  }
109
- :host([dismissible]) .close-btn {
83
+ :host([dismissible][background]) .close-btn {
110
84
  position: absolute;
111
85
  top: 0.4rem;
112
86
  right: 0.3rem;
87
+ border-left: none;
113
88
  }
114
89
  `,
115
90
  ];
116
91
  /**
117
- * Titre du message d'erreur
92
+ * Titre du message (texte brut, utiliser le slot pour du contenu riche)
118
93
  */
119
94
  @property({ type: String }) label = "";
120
95
 
@@ -125,8 +100,6 @@ export class Alert extends LitElement {
125
100
  */
126
101
  @property({ type: String }) text = "";
127
102
 
128
- @property({ type: String }) id = new Date().getTime().toString();
129
-
130
103
  @property({ type: String, reflect: true }) size?: Size;
131
104
 
132
105
  @property({ type: Boolean, reflect: true }) dismissible = false;
@@ -135,33 +108,58 @@ export class Alert extends LitElement {
135
108
 
136
109
  @property({ type: String, reflect: true }) status: AlertStatus = "default";
137
110
 
111
+ /**
112
+ * Mémorise la fermeture dans le localStorage. Nécessite un `id`.
113
+ */
138
114
  @property({ type: Boolean, reflect: true }) dismissForever = false;
139
115
 
116
+ /**
117
+ * Annonce le message aux lecteurs d'écran (role alert/status).
118
+ * À activer pour les messages injectés dynamiquement, pas pour une alerte déjà dans la page.
119
+ */
120
+ @property({ type: Boolean, reflect: true }) announce = false;
121
+
140
122
  connectedCallback() {
141
- if (this.dismissForever) {
142
- const dismissed = localStorage.getItem("sonic-alert-dismissed") || "{}";
143
- const dismissedObj = JSON.parse(dismissed);
144
- if (dismissedObj[this.id]) {
145
- this.remove();
146
- }
147
- }
148
123
  super.connectedCallback();
124
+ if (
125
+ this.dismissForever &&
126
+ this.id &&
127
+ isDismissed(dismissStorageKey, this.id)
128
+ ) {
129
+ this.remove();
130
+ }
131
+ }
132
+
133
+ willUpdate(changed: PropertyValues<this>) {
134
+ if (changed.has("announce") || changed.has("status")) {
135
+ this._syncAnnounceA11y();
136
+ }
137
+ }
138
+
139
+ private _syncAnnounceA11y() {
140
+ if (!this.announce) {
141
+ this.removeAttribute("role");
142
+ this.removeAttribute("aria-live");
143
+ return;
144
+ }
145
+ this.setAttribute("role", statusAriaRole(this.status));
146
+ const live = statusAriaLive(this.status);
147
+ if (live) this.setAttribute("aria-live", live);
148
+ else this.removeAttribute("aria-live");
149
149
  }
150
150
 
151
151
  render() {
152
152
  return html`
153
- <slot name="icon" class="${this.noIcon ? "hidden" : ""}"
154
- >${!this.noIcon
155
- ? html`<div>
156
- ${this.status &&
157
- html`<sonic-icon name=${icon[this.status]}></sonic-icon>`}
158
- </div>`
159
- : nothing}</slot
160
- >
153
+ ${this.noIcon
154
+ ? nothing
155
+ : html`<slot name="icon">
156
+ <sonic-icon
157
+ aria-hidden="true"
158
+ name=${statusIcon[this.status] ?? statusIcon.default}
159
+ ></sonic-icon>
160
+ </slot>`}
161
161
  <div class="content">
162
- ${this.label
163
- ? html`<span class="label">${unsafeHTML(this.label)}</span>`
164
- : nothing}
162
+ ${this.label ? html`<span class="label">${this.label}</span>` : nothing}
165
163
  <div>${this.text}<slot></slot></div>
166
164
  </div>
167
165
  ${this.dismissible
@@ -171,6 +169,7 @@ export class Alert extends LitElement {
171
169
  variant="unstyled"
172
170
  shape="circle"
173
171
  icon
172
+ .ariaLabel=${resolveUiLabel(uiAriaLabels.closeAlert)}
174
173
  >
175
174
  <sonic-icon name="cancel"></sonic-icon>
176
175
  </sonic-button>`
@@ -180,15 +179,11 @@ export class Alert extends LitElement {
180
179
 
181
180
  close() {
182
181
  this.remove();
183
- // if dismiss forever, save in localstorage
184
- if (this.dismissForever) {
185
- const dismissed = localStorage.getItem("sonic-alert-dismissed") || "{}";
186
- const dismissedObj = JSON.parse(dismissed);
187
- dismissedObj[this.id] = true;
188
- localStorage.setItem(
189
- "sonic-alert-dismissed",
190
- JSON.stringify(dismissedObj)
191
- );
182
+ if (!this.dismissForever) return;
183
+ if (!this.id) {
184
+ console.warn("sonic-alert : dismissForever nécessite un id.");
185
+ return;
192
186
  }
187
+ markDismissed(dismissStorageKey, this.id);
193
188
  }
194
189
  }
@@ -4,7 +4,6 @@ import Subscriber from "@supersoniks/concorde/core/mixins/Subscriber";
4
4
  import { Message } from "@supersoniks/concorde/core/_types/types";
5
5
  import { map } from "lit/directives/map.js";
6
6
  import { Size } from "@supersoniks/concorde/core/components/ui/_css/size";
7
-
8
7
  import { ifDefined } from "lit/directives/if-defined.js";
9
8
  import { APIResult } from "@supersoniks/concorde/core/components/ui/toast/message-subscriber";
10
9
 
@@ -37,6 +36,7 @@ export class AlertMessages extends Subscriber(LitElement, {} as APIResult) {
37
36
  ${map(this.messages, (message) => {
38
37
  if (message.type == "public") {
39
38
  return html`<sonic-alert
39
+ announce
40
40
  status=${message.status || "default"}
41
41
  text=${ifDefined(message.content)}
42
42
  size=${this.size}