@supersoniks/concorde 5.0.3 → 5.0.5

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 (151) hide show
  1. package/.agents/skills/concorde-component-docs/SKILL.md +194 -0
  2. package/.agents/skills/concorde-component-docs/template.md +45 -0
  3. package/ai/cursor/rules/concorde-theme.mdc +1 -1
  4. package/ai/cursor/rules/concorde.mdc +1 -1
  5. package/ai/skills/concorde/SKILL.md +1 -1
  6. package/ai/skills/concorde-theme/SKILL.md +21 -10
  7. package/build-infos.json +1 -1
  8. package/concorde-core.bundle.js +515 -521
  9. package/concorde-core.es.js +5151 -5056
  10. package/dist/concorde-core.bundle.js +515 -521
  11. package/dist/concorde-core.es.js +5151 -5056
  12. package/dist/docs-mock-api-sw.js +2 -0
  13. package/dist/docs-mock-api-sw.js.map +2 -2
  14. package/docs/assets/index-CD4WyL6o.css +1 -0
  15. package/docs/assets/{index-BnK6OS7w.js → index-wVZpLVYW.js} +815 -808
  16. package/docs/crawl/core/components/ui/alert/alert.html +76 -5
  17. package/docs/crawl/core/components/ui/alert-messages/alert-messages.html +113 -5
  18. package/docs/crawl/core/components/ui/badge/badge.html +57 -8
  19. package/docs/crawl/core/components/ui/captcha/captcha.html +90 -8
  20. package/docs/crawl/core/components/ui/card/card.html +122 -12
  21. package/docs/crawl/core/components/ui/divider/divider.html +117 -31
  22. package/docs/crawl/core/components/ui/form/fieldset/fieldset.html +232 -101
  23. package/docs/crawl/core/components/ui/form/form-actions/form-actions.html +95 -52
  24. package/docs/crawl/core/components/ui/form/form-layout/form-layout.html +97 -38
  25. package/docs/crawl/core/components/ui/group/group.html +60 -38
  26. package/docs/crawl/core/components/ui/icon/icon.html +136 -47
  27. package/docs/crawl/core/components/ui/image/image.html +118 -6
  28. package/docs/crawl/core/components/ui/link/link.html +65 -7
  29. package/docs/crawl/core/components/ui/loader/loader.html +97 -23
  30. package/docs/crawl/core/components/ui/menu/menu.html +162 -90
  31. package/docs/crawl/core/components/ui/modal/modal.html +275 -50
  32. package/docs/crawl/core/components/ui/pop/pop.html +242 -124
  33. package/docs/crawl/core/components/ui/progress/progress.html +103 -30
  34. package/docs/crawl/core/components/ui/table/table.html +303 -171
  35. package/docs/crawl/core/components/ui/theme/theme.html +131 -0
  36. package/docs/crawl/core/components/ui/toast/toast.html +170 -59
  37. package/docs/crawl/core/components/ui/tooltip/tooltip.html +90 -29
  38. package/docs/crawl/docs/_decorators/ancestor-attribute.html +3 -2
  39. package/docs/crawl/docs/_getting-started/start.html +1 -1
  40. package/docs/crawl/docs/_getting-started/theming.html +311 -63
  41. package/docs/crawl/hubs/form-components.html +71 -49
  42. package/docs/crawl/index.html +7 -6
  43. package/docs/docs-mock-api-sw.js +2 -0
  44. package/docs/docs-mock-api-sw.js.map +2 -2
  45. package/docs/index.html +6 -4
  46. package/docs/llms-full.txt +1468 -405
  47. package/docs/llms.txt +23 -30
  48. package/docs/sitemap.xml +3 -0
  49. package/docs/src/core/components/ui/alert/alert.md +21 -2
  50. package/docs/src/core/components/ui/alert-messages/alert-messages.md +85 -0
  51. package/docs/src/core/components/ui/badge/badge.md +19 -6
  52. package/docs/src/core/components/ui/captcha/captcha.md +65 -6
  53. package/docs/src/core/components/ui/card/card.md +73 -10
  54. package/docs/src/core/components/ui/divider/divider.md +107 -13
  55. package/docs/src/core/components/ui/form/fieldset/fieldset.md +175 -99
  56. package/docs/src/core/components/ui/form/form-actions/form-actions.md +75 -52
  57. package/docs/src/core/components/ui/form/form-layout/form-layout.md +109 -34
  58. package/docs/src/core/components/ui/group/group.md +36 -36
  59. package/docs/src/core/components/ui/icon/icon.md +132 -43
  60. package/docs/src/core/components/ui/image/image.md +35 -3
  61. package/docs/src/core/components/ui/link/link.md +43 -5
  62. package/docs/src/core/components/ui/loader/loader.md +79 -22
  63. package/docs/src/core/components/ui/menu/menu.md +133 -92
  64. package/docs/src/core/components/ui/modal/modal.md +163 -47
  65. package/docs/src/core/components/ui/pop/pop.md +217 -123
  66. package/docs/src/core/components/ui/progress/progress.md +76 -30
  67. package/docs/src/core/components/ui/table/table.md +147 -171
  68. package/docs/src/core/components/ui/theme/theme.md +122 -0
  69. package/docs/src/core/components/ui/toast/toast.md +108 -58
  70. package/docs/src/core/components/ui/tooltip/tooltip.md +68 -26
  71. package/docs/src/docs/_decorators/ancestor-attribute.md +3 -2
  72. package/docs/src/docs/_getting-started/start.md +1 -1
  73. package/docs/src/docs/_getting-started/theming.md +223 -61
  74. package/docs/src/docs/search/docs-search.json +2504 -399
  75. package/docs/src/tsconfig.json +18 -0
  76. package/index.html +4 -2
  77. package/package.json +7 -1
  78. package/public/docs-mock-api-sw.js +2 -0
  79. package/public/docs-mock-api-sw.js.map +2 -2
  80. package/src/core/components/ui/_css/align.ts +1 -0
  81. package/src/core/components/ui/_css/type.ts +86 -8
  82. package/src/core/components/ui/_i18n/ui-aria-labels.ts +8 -0
  83. package/src/core/components/ui/alert/alert.md +21 -2
  84. package/src/core/components/ui/alert-messages/alert-messages.md +85 -0
  85. package/src/core/components/ui/badge/badge.md +19 -6
  86. package/src/core/components/ui/badge/badge.ts +8 -9
  87. package/src/core/components/ui/button/button.ts +5 -15
  88. package/src/core/components/ui/captcha/captcha.md +65 -6
  89. package/src/core/components/ui/card/card.md +73 -10
  90. package/src/core/components/ui/card/card.ts +24 -22
  91. package/src/core/components/ui/divider/divider.md +107 -13
  92. package/src/core/components/ui/divider/divider.ts +40 -33
  93. package/src/core/components/ui/form/fieldset/fieldset.md +175 -99
  94. package/src/core/components/ui/form/fieldset/fieldset.ts +15 -28
  95. package/src/core/components/ui/form/fieldset/legend.ts +13 -13
  96. package/src/core/components/ui/form/form-actions/form-actions.md +75 -52
  97. package/src/core/components/ui/form/form-actions/form-actions.ts +7 -5
  98. package/src/core/components/ui/form/form-layout/form-layout.md +109 -34
  99. package/src/core/components/ui/form/form-layout/form-layout.ts +27 -24
  100. package/src/core/components/ui/form/textarea/textarea.ts +4 -3
  101. package/src/core/components/ui/group/group.md +36 -36
  102. package/src/core/components/ui/group/group.ts +5 -10
  103. package/src/core/components/ui/icon/icon.md +132 -43
  104. package/src/core/components/ui/image/image.md +35 -3
  105. package/src/core/components/ui/link/link.md +43 -5
  106. package/src/core/components/ui/loader/loader.md +79 -22
  107. package/src/core/components/ui/loader/loader.ts +67 -27
  108. package/src/core/components/ui/loader/styles/fixed.ts +6 -11
  109. package/src/core/components/ui/menu/menu.md +133 -92
  110. package/src/core/components/ui/menu/menu.ts +53 -58
  111. package/src/core/components/ui/modal/modal.md +163 -47
  112. package/src/core/components/ui/modal/modal.ts +2 -4
  113. package/src/core/components/ui/pop/pop.md +217 -123
  114. package/src/core/components/ui/pop/pop.ts +0 -1
  115. package/src/core/components/ui/progress/progress.md +76 -30
  116. package/src/core/components/ui/progress/progress.ts +25 -56
  117. package/src/core/components/ui/table/table-caption.ts +2 -2
  118. package/src/core/components/ui/table/table-tbody.ts +3 -3
  119. package/src/core/components/ui/table/table-td.ts +23 -18
  120. package/src/core/components/ui/table/table-th.ts +8 -8
  121. package/src/core/components/ui/table/table-tr.ts +4 -4
  122. package/src/core/components/ui/table/table.md +147 -171
  123. package/src/core/components/ui/table/table.ts +20 -19
  124. package/src/core/components/ui/theme/theme-collection/auto.ts +15 -0
  125. package/src/core/components/ui/theme/theme-collection/core-variables.ts +8 -31
  126. package/src/core/components/ui/theme/theme-collection/dark.ts +1 -7
  127. package/src/core/components/ui/theme/theme-collection/light.ts +30 -26
  128. package/src/core/components/ui/theme/theme.md +122 -0
  129. package/src/core/components/ui/theme/theme.ts +30 -7
  130. package/src/core/components/ui/toast/toast-item.ts +6 -9
  131. package/src/core/components/ui/toast/toast.md +108 -58
  132. package/src/core/components/ui/toast/types.ts +1 -1
  133. package/src/core/components/ui/tooltip/tooltip.md +68 -26
  134. package/src/core/decorators/subscriber/ancestorAttribute.spec.ts +26 -0
  135. package/src/core/decorators/subscriber/ancestorAttribute.ts +3 -4
  136. package/src/core/utils/AncestorAttributeObserver.ts +183 -70
  137. package/src/docs/_decorators/ancestor-attribute.md +3 -2
  138. package/src/docs/_getting-started/start.md +1 -1
  139. package/src/docs/_getting-started/theming.md +223 -61
  140. package/src/docs/code.ts +125 -58
  141. package/src/docs/header/header.ts +62 -54
  142. package/src/docs/mock-api/router.ts +2 -0
  143. package/src/docs/navigation/navigation.ts +6 -3
  144. package/src/docs/search/docs-search.json +2504 -399
  145. package/src/docs/search/markdown-renderer.ts +6 -6
  146. package/src/docs/search/search.ts +4 -4
  147. package/src/docs/tailwind/css/tailwind.css +6 -5
  148. package/src/tsconfig.json +18 -0
  149. package/src/tsconfig.tsbuildinfo +1 -1
  150. package/tailwind.config.js +19 -0
  151. package/docs/assets/index--GpD7R7a.css +0 -1
@@ -12,6 +12,7 @@ import {
12
12
  import "@supersoniks/concorde/core/components/ui/menu/menu-item";
13
13
  import { Size } from "../_css/size";
14
14
  import { Shadow, shadowable } from "../_css/shadow";
15
+ import { Align } from "../_css/align";
15
16
 
16
17
  const queryAssignedElements = (
17
18
  options?: QueryAssignedElementsOptions,
@@ -26,7 +27,7 @@ export class MenuItems extends LitElement {
26
27
  css`
27
28
  :host {
28
29
  display: block;
29
- --sc-menu-gap: 0.15rem;
30
+ --sc-_gap: 0.15rem;
30
31
  }
31
32
 
32
33
  :host > menu {
@@ -39,9 +40,14 @@ export class MenuItems extends LitElement {
39
40
  display: none !important;
40
41
  }
41
42
 
43
+ :host([shadow]) .shadowable {
44
+ border-radius: min(calc(var(--sc-btn-rounded) * 2), 0.4em);
45
+ }
46
+
42
47
  /* SCROLLABLE*/
43
48
  #menu-content {
44
49
  display: flex;
50
+ gap: var(--sc-_gap);
45
51
  padding: 0.35em;
46
52
  margin: 0;
47
53
  }
@@ -115,7 +121,7 @@ export class MenuItems extends LitElement {
115
121
  to bottom,
116
122
  rgba(0, 0, 0, 0),
117
123
  rgba(0, 0, 0, 1) 10%
118
- );queryAssignedElements
124
+ );
119
125
  mask-image: linear-gradient(
120
126
  to bottom,
121
127
  rgba(0, 0, 0, 0),
@@ -160,21 +166,11 @@ export class MenuItems extends LitElement {
160
166
  * tels que les dividers / boutons,... qui n'auraient pas d'attribut size précisés.
161
167
  */
162
168
  @property({ type: String, reflect: true }) size?: Size;
163
- /**
164
- * Direction
165
- */
166
169
  @property({ type: String, reflect: true }) direction: "row" | "column" =
167
170
  "column";
168
- @property({ type: String }) gap = "var(--sc-menu-gap)";
169
171
 
170
- @property({ type: String, reflect: true }) align:
171
- | "center"
172
- | "left"
173
- | "right" = "left";
172
+ @property({ type: String, reflect: true }) align: Align = "left";
174
173
 
175
- /**
176
- * Ombre
177
- */
178
174
  @property({ type: String, reflect: true }) shadow: Shadow = null;
179
175
 
180
176
  @property({ type: String }) moreShape: "square" | "circle" = "circle";
@@ -182,17 +178,18 @@ export class MenuItems extends LitElement {
182
178
 
183
179
  observer: ResizeObserver | null = null;
184
180
  attributeObserver: MutationObserver | null = null;
181
+ private scrollDragBound = false;
185
182
 
186
- /**
187
- * Propriété min-width du bouton
188
- */
189
183
  @property({ type: String }) minWidth = "0";
190
184
 
191
185
  @query("menu") menu!: HTMLElement;
192
186
  @query("#menu-content") menuContent!: HTMLElement;
193
187
 
194
- @queryAssignedElements({ selector: "*" })
195
- menuChildren!: Array<HTMLElement>;
188
+ @queryAssignedElements({ selector: "sonic-divider" })
189
+ dividerChildren!: Array<HTMLElement>;
190
+
191
+ @queryAssignedElements({ selector: "sonic-menu-item" })
192
+ menuItemChildren!: Array<HTMLElement>;
196
193
 
197
194
  @queryAssignedElements({ slot: "more", selector: "*" })
198
195
  moreElements!: Array<HTMLElement>;
@@ -224,8 +221,8 @@ export class MenuItems extends LitElement {
224
221
  }
225
222
 
226
223
  mainSlotChange() {
227
- this.setChildrenSize(this.menuChildren);
228
- this.setDividersSize(this.menuChildren);
224
+ this.setChildrenSize(this.menuItemChildren);
225
+ this.setDividersSize(this.dividerChildren);
229
226
  this.updateIsScollable();
230
227
  this.updateScrollPosition();
231
228
  this.observeMenuItemsAttributes();
@@ -241,7 +238,7 @@ export class MenuItems extends LitElement {
241
238
  });
242
239
 
243
240
  // Observer chaque menu-item
244
- this.menuChildren.forEach((item) => {
241
+ this.menuItemChildren.forEach((item) => {
245
242
  this.attributeObserver!.observe(item, {
246
243
  attributes: true,
247
244
  attributeFilter: ["active"],
@@ -252,7 +249,7 @@ export class MenuItems extends LitElement {
252
249
  updateScrollPosition() {
253
250
  // Si on est en mode scrollable et qu'il y a exactement un seul menu-item actif
254
251
  if (this.scrollable) {
255
- const activeItems = this.menuChildren.filter(
252
+ const activeItems = this.menuItemChildren.filter(
256
253
  (item) =>
257
254
  item.hasAttribute("active") &&
258
255
  item.getAttribute("active") !== "false",
@@ -303,41 +300,44 @@ export class MenuItems extends LitElement {
303
300
  };
304
301
 
305
302
  initScrollable(): void {
303
+ if (!this.scrollable || this.scrollDragBound) {
304
+ return;
305
+ }
306
+ this.scrollDragBound = true;
307
+
306
308
  let isDown = false;
307
309
  let startX: number;
308
310
  let scrollLeft: number;
309
311
 
310
- if (this.scrollable) {
311
- this.addEventListener("mousedown", (e) => {
312
- isDown = true;
313
- this.classList.add("active");
312
+ this.addEventListener("mousedown", (e) => {
313
+ isDown = true;
314
+ this.classList.add("active");
314
315
 
315
- startX = e.pageX - this.menuContent.offsetLeft;
316
- scrollLeft = this.menuContent.scrollLeft;
317
- });
318
- this.addEventListener("mouseleave", () => {
319
- isDown = false;
320
- this.classList.remove("active");
321
- });
322
- this.addEventListener("mouseup", () => {
323
- isDown = false;
324
- this.classList.remove("active");
325
- });
326
- this.addEventListener("mousemove", (e) => {
327
- if (!isDown) return;
328
- e.preventDefault();
329
- const x = e.pageX - this.menuContent.offsetLeft;
330
- const walk = (x - startX) * 1.5; //scroll-fast
331
- this.menuContent.scrollLeft = scrollLeft - walk;
332
- this.setScrollShadow(this.menuContent, this.direction);
333
- });
334
- this.addEventListener("scroll", (e) => {
335
- e.preventDefault();
336
- // const delta = Math.sign(e.deltaY);
337
- // this.scrollLeft += delta * 50;
338
- this.setScrollShadow(this.menuContent, this.direction);
339
- });
340
- }
316
+ startX = e.pageX - this.menuContent.offsetLeft;
317
+ scrollLeft = this.menuContent.scrollLeft;
318
+ });
319
+ this.addEventListener("mouseleave", () => {
320
+ isDown = false;
321
+ this.classList.remove("active");
322
+ });
323
+ this.addEventListener("mouseup", () => {
324
+ isDown = false;
325
+ this.classList.remove("active");
326
+ });
327
+ this.addEventListener("mousemove", (e) => {
328
+ if (!isDown) return;
329
+ e.preventDefault();
330
+ const x = e.pageX - this.menuContent.offsetLeft;
331
+ const walk = (x - startX) * 1.5; //scroll-fast
332
+ this.menuContent.scrollLeft = scrollLeft - walk;
333
+ this.setScrollShadow(this.menuContent, this.direction);
334
+ });
335
+ this.addEventListener("scroll", (e) => {
336
+ e.preventDefault();
337
+ // const delta = Math.sign(e.deltaY);
338
+ // this.scrollLeft += delta * 50;
339
+ this.setScrollShadow(this.menuContent, this.direction);
340
+ });
341
341
  }
342
342
 
343
343
  setScrollShadow(target: HTMLElement, direction: string): void {
@@ -397,7 +397,6 @@ export class MenuItems extends LitElement {
397
397
  const isMenuRow = this.direction == "row";
398
398
 
399
399
  const menuContentStyles = {
400
- gap: this.gap,
401
400
  flexDirection: this.direction,
402
401
  };
403
402
 
@@ -411,11 +410,7 @@ export class MenuItems extends LitElement {
411
410
  marginLeft: isMenuRow ? "" : ".55em",
412
411
  };
413
412
 
414
- return html`<menu
415
- part="menu"
416
- class="shadowable"
417
- style=${styleMap(menuStyles)}
418
- >
413
+ return html`<menu class="shadowable" style=${styleMap(menuStyles)}>
419
414
  <slot
420
415
  @slotchange=${this.mainSlotChange}
421
416
  id="menu-content"
@@ -1,68 +1,62 @@
1
- ## Modal
1
+ # Modal
2
+
3
+ **`sonic-modal`** presents focused content in a `<dialog>` overlay with backdrop, enter/exit animation, and a built-in close control. Compose **`sonic-modal-title`** / **`sonic-modal-subtitle`** / **`sonic-modal-content`** / **`sonic-modal-actions`**, or use the default slot. Call **`show()`** on the element to open; use **`hideModal`** on action buttons or **`hide()`** from script. Set **`forceAction`** when dismissal must go through explicit actions only. Imperative dialogs: **`Modal.create()`** (also **`window.SonicModal`**).
4
+
5
+ ## Basic example
6
+
7
+ Click the trigger to open. **`sonic-modal-actions`** lays out footer buttons; **`hideModal`** closes the modal on click. Scope form state with **`formDataProvider`** on **`sonic-modal-actions`** so child **`sonic-button`** elements share one publisher.
2
8
 
3
9
  <sonic-code>
4
10
  <template>
5
11
  <sonic-button onclick="document.getElementById('modalExample').show()">
6
- Simple modal
12
+ Open modal
7
13
  </sonic-button>
8
14
  <sonic-modal id="modalExample">
9
- <sonic-modal-title
10
- >Lorem ipsum dolor sit amet <sonic-badge type="danger" size="sm">+33</sonic-badge></sonic-modal-title
11
- >
12
- <sonic-modal-subtitle>Donec sed vestibulum augue.</sonic-modal-subtitle>
15
+ <sonic-modal-title>
16
+ Export ready
17
+ <sonic-badge type="success" size="sm">New</sonic-badge>
18
+ </sonic-modal-title>
19
+ <sonic-modal-subtitle>Your report finished processing.</sonic-modal-subtitle>
13
20
  <sonic-modal-content>
14
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget quam eu mi luctus faucibus.
21
+ Download the CSV now or review the summary in your dashboard before sharing.
15
22
  </sonic-modal-content>
16
23
  <sonic-modal-actions formDataProvider="ModalMiniForm">
17
- <sonic-button FormCheckable minWidth="8rem" value="true" name="click">
18
- Click don't close
24
+ <sonic-button minWidth="8rem" value="true" name="click">
25
+ Save draft
19
26
  </sonic-button>
20
- <sonic-button minWidth="8rem" type="success" hideModal>Confirm</sonic-button>
27
+ <sonic-button minWidth="8rem" type="success" hideModal>Download</sonic-button>
21
28
  </sonic-modal-actions>
22
29
  </sonic-modal>
23
30
  </template>
24
31
  </sonic-code>
25
32
 
33
+ ## Scrollable content
26
34
 
27
- ## Long text
35
+ Long copy scrolls inside the dialog. Default **`maxHeight`** is `90vh`. Default **`align`** is `left`.
28
36
 
29
37
  <sonic-code>
30
38
  <template>
31
- <sonic-button onclick="document.getElementById('modalText').show()"> Long text </sonic-button>
39
+ <sonic-button onclick="document.getElementById('modalText').show()">Venue details</sonic-button>
32
40
  <sonic-modal align="left" id="modalText">
33
- <sonic-modal-title>Infos et tarifs </sonic-modal-title>
41
+ <sonic-modal-title>Hours and tickets</sonic-modal-title>
34
42
  <sonic-modal-content>
35
43
  <div class="prose">
36
44
  <p>
37
- <strong>Horaires d’ouverture </strong><br />
38
- Du mercredi au samedi de 13h30 à 19h et le dimanche de 13h30 à 18h<br />
39
- + horaires spécifiques pour événements ou festivals&nbsp;
45
+ <strong>Opening hours</strong><br />
46
+ Wednesday–Saturday, 1:30 p.m.–7:00 p.m.; Sunday, 1:30 p.m.–6:00 p.m.
40
47
  </p>
41
48
  <p>
42
- <strong> Billetterie&nbsp;<br /></strong>
43
- La participation à certains événements et activités est soumise à un système de billetterie avec achats ou
44
- réservations disponibles en ligne ou au guichet.&nbsp;&nbsp;<strong><br /></strong>
49
+ <strong>Ticketing</strong><br />
50
+ Some events require online or box-office reservations. Prices vary by event; booking ahead is recommended when capacity is limited.
45
51
  </p>
46
52
  <p>
47
- Les tarifs (Tarif plein / Tarif Réduit / Tarif Spécifique) sont indiqués pour chaque événement et peuvent
48
- varier selon la nature de l’événement. Les tarifs sont identiques en ligne et au guichet. Il est néanmoins
49
- conseillé de réserver les billets en avance pour s’assurer une place.
53
+ <strong>Contact</strong><br />
54
+ tickets@example.com · +33 3 28 33 48 33
50
55
  </p>
51
56
  <p>
52
- L’accès au Skatepark, Fablab et Halle C sont soumis à adhésions. Les adhésions sont gratuites et
53
- nominatives. Elle donnent accès aux espaces dans la limite des places disponibles.
54
- </p>
55
- <p>
56
- <strong>+ d’infos <br /></strong>billetterie@laconditionpublique.com <br />+33 (0)328334833&nbsp;
57
- </p>
58
- <br />
59
- <p>
60
- <strong>Accès <br /></strong>14, place Faidherbe <br />59100 Roubaix <br />Métro / Tram : Arrêt
61
- Eurotéléport, Ligne 2 <br />Bus / V’Lille : Arrêt Condition Publique&nbsp;
62
- </p>
63
- <p>
64
- Accès handicapés : nous contacter avant votre venue au 03 28 33 48 33 ou par mail
65
- billetterie@laconditionpublique.com
57
+ <strong>Access</strong><br />
58
+ 14 Place Faidherbe, 59100 Roubaix<br />
59
+ Metro line 2, Eurotéléport stop
66
60
  </p>
67
61
  </div>
68
62
  </sonic-modal-content>
@@ -72,33 +66,44 @@
72
66
 
73
67
  ## Force action
74
68
 
69
+ With **`forceAction`**, backdrop click, Escape, and the default close button are disabled. Provide **`sonic-modal-actions`** (or **`sonic-modal-close`**) so users can finish the flow.
70
+
75
71
  <sonic-code>
76
72
  <template>
77
- <sonic-button onclick="document.getElementById('force').show()"> Force action to close</sonic-button>
73
+ <sonic-button onclick="document.getElementById('force').show()">Cookie consent</sonic-button>
78
74
  <sonic-modal forceAction id="force">
79
- <sonic-modal-title>Do you want some cookies ? </sonic-modal-title>
75
+ <sonic-modal-title>Allow analytics cookies?</sonic-modal-title>
80
76
  <sonic-modal-content>
81
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget quam eu mi luctus faucibus.
77
+ We use cookies to measure traffic and improve the product. You can change this later in settings.
82
78
  </sonic-modal-content>
83
- <sonic-modal-actions >
84
- <sonic-button hideModal minWidth="8rem"> Nope </sonic-button>
85
- <sonic-button hideModal minWidth="8rem" type="success">Hell yes !</sonic-button>
79
+ <sonic-modal-actions>
80
+ <sonic-button hideModal minWidth="8rem">Decline</sonic-button>
81
+ <sonic-button hideModal minWidth="8rem" type="success">Accept</sonic-button>
86
82
  </sonic-modal-actions>
87
83
  </sonic-modal>
88
- </sonic-modal>
89
84
  </template>
90
85
  </sonic-code>
91
86
 
92
87
  ## Custom dimensions
93
88
 
89
+ Set **`width`** / **`height`** / **`maxWidth`** / **`maxHeight`** (CSS lengths). On narrow viewports the panel becomes a bottom sheet. Use **`rounded="none"`** for edge-to-edge media.
90
+
94
91
  <sonic-code>
95
92
  <template>
96
- <sonic-button onclick="document.getElementById('CustomWidth').show()"> Custom width </sonic-button>
97
- <sonic-modal maxHeight="50vh" maxWidth="90vw" width="100%" height="100%" id="CustomWidth">
93
+ <sonic-button onclick="document.getElementById('CustomWidth').show()">Image preview</sonic-button>
94
+ <sonic-modal
95
+ rounded="none"
96
+ maxHeight="50vh"
97
+ maxWidth="90vw"
98
+ width="100%"
99
+ height="100%"
100
+ id="CustomWidth"
101
+ >
98
102
  <sonic-image
99
103
  cover
100
104
  objectPosition="center 20%"
101
105
  src="https://thegoodlife.fr/wp-content/uploads/sites/2/2022/03/compagnies-aeriennes-nostalgie-coeur-insert-03-dr.jpg"
106
+ alt="View from an airplane window"
102
107
  ></sonic-image>
103
108
  </sonic-modal>
104
109
  </template>
@@ -106,14 +111,125 @@
106
111
 
107
112
  ## Fullscreen
108
113
 
114
+ **`fullscreen`** fills the viewport and hides the backdrop.
115
+
109
116
  <sonic-code>
110
117
  <template>
111
- <sonic-button onclick="document.getElementById('Fullscreen').show()"> Fullscreen </sonic-button>
118
+ <sonic-button onclick="document.getElementById('Fullscreen').show()">Fullscreen</sonic-button>
112
119
  <sonic-modal fullscreen id="Fullscreen">
113
120
  <sonic-image
114
121
  cover
115
122
  src="https://thegoodlife.fr/wp-content/uploads/sites/2/2022/03/compagnies-aeriennes-nostalgie-coeur-insert-03-dr.jpg"
123
+ alt="View from an airplane window"
116
124
  ></sonic-image>
117
125
  </sonic-modal>
118
126
  </template>
119
- </sonic-code>
127
+ </sonic-code>
128
+
129
+ ## Programmatic creation
130
+
131
+ Use **`Modal.create(options)`** when there is no modal in the template—for confirmations, toasts that need a follow-up, or one-off flows from script. The modal is appended to the nearest **`sonic-theme`** pop container (same as declarative modals), opened automatically, and returns the **`sonic-modal`** instance. Set **`removeOnHide: true`** to detach it from the DOM after close. In the browser, **`window.SonicModal`** is the same class after the module loads.
132
+
133
+ Pass **`title`** / **`subtitle`** / **`content`** / **`actions`** as HTML strings (or Lit template results from application code). Put **`hideModal`** on action buttons in the **`actions`** string so clicks close the dialog.
134
+
135
+ <sonic-code>
136
+ <template>
137
+ <sonic-button
138
+ onclick="window.SonicModal.create({
139
+ title: 'Send invite?',
140
+ subtitle: 'The recipient can join immediately.',
141
+ content: 'We will email an invitation to alex@example.com.',
142
+ actions: '&lt;sonic-button hideModal minWidth=\'8rem\'&gt;Cancel&lt;/sonic-button&gt;&lt;sonic-button hideModal minWidth=\'8rem\' type=\'success\'&gt;Send&lt;/sonic-button&gt;',
143
+ removeOnHide: true
144
+ })"
145
+ >
146
+ Open programmatic modal
147
+ </sonic-button>
148
+ </template>
149
+ </sonic-code>
150
+
151
+ <sonic-code language="javascript">
152
+ <template>
153
+ import { Modal } from "@supersoniks/concorde/core/components/ui/modal/modal";
154
+
155
+ const modal = Modal.create({
156
+ title: "Delete project?",
157
+ subtitle: "This cannot be undone.",
158
+ content: "<p>All files in <strong>Acme HQ</strong> will be removed.</p>",
159
+ actions: `
160
+ <sonic-button hideModal minWidth="8rem">Cancel</sonic-button>
161
+ <sonic-button hideModal minWidth="8rem" type="danger">Delete</sonic-button>
162
+ `,
163
+ removeOnHide: true,
164
+ forceAction: false,
165
+ maxWidth: "min(100vw, 28rem)",
166
+ });
167
+
168
+ modal.addEventListener("hidden", () => {
169
+ console.log("Modal removed from the DOM");
170
+ });
171
+
172
+ // Or close from script: await modal.hide(); await modal.dispose();
173
+ </template>
174
+ </sonic-code>
175
+
176
+ ## API reference
177
+
178
+ ### `sonic-modal`
179
+
180
+ | Attribute | Values | Description |
181
+ |----------|---------|-------------|
182
+ | `align` | `left` (default) · `center` · `right` | Align title and slotted content |
183
+ | `maxWidth` | CSS length (default `min(100vw, 40rem)`) | Dialog max width |
184
+ | `maxHeight` | CSS length (default `90vh`) | Scrollable body max height |
185
+ | `width` | CSS length (default `100%`) | Dialog width |
186
+ | `height` | CSS length (default `fit-content`) | Dialog height |
187
+ | `paddingX` · `paddingY` | CSS length | Override content padding (`--sc-modal-px` / `--sc-modal-py`) |
188
+ | `zIndex` | CSS number | Stacking order (default `990`) |
189
+ | `effect` | `slide` (default) · `fade` · `none` | Open/close animation |
190
+ | `fullscreen` | boolean | Full viewport; no backdrop |
191
+ | `forceAction` | boolean | Disable overlay, Escape, and default close button |
192
+ | `noCloseButton` | boolean | Hide built-in close when not **`forceAction`** |
193
+ | `closeButtonType` | **`sonic-button`** `type` | Style of built-in close |
194
+ | `visible` | boolean | When toggled, opens or closes the dialog |
195
+ | `removeOnHide` | boolean | Remove element from DOM after close |
196
+ | `removeHashOnHide` | boolean | Clear URL hash on close |
197
+ | `closeOnLocationChange` | boolean | Close when app location changes |
198
+ | `resetDataProviderOnHide` | string | Reset named **`formDataProvider`** on close |
199
+ | `rounded` | `none` | Square dialog corners (useful for full-bleed media) |
200
+
201
+ | Slot | Description |
202
+ |------|-------------|
203
+ | *(default)* | Additional markup alongside structured children |
204
+
205
+ | Event | Description |
206
+ |-------|-------------|
207
+ | `show` | Fired when open animation completes |
208
+ | `hide` | Fired when close starts |
209
+ | `hidden` | Fired when close finishes |
210
+
211
+ Methods: **`show()`** · **`hide()`** · **`dispose()`** (hide and remove). Static **`Modal.create(options)`** appends a modal to the theme pop container and opens it. **`options`** / **`styleSheet`** are JavaScript-only.
212
+
213
+ ### `sonic-modal-title` · `sonic-modal-subtitle` · `sonic-modal-content`
214
+
215
+ | Slot | Description |
216
+ |------|-------------|
217
+ | *(default)* | Title, subtitle, or main body content |
218
+
219
+ ### `sonic-modal-actions`
220
+
221
+ | Slot | Description |
222
+ |------|-------------|
223
+ | *(default)* | Footer actions (typically **`sonic-button`**) |
224
+
225
+ Put **`hideModal`** on a **`sonic-button`** to close the parent modal on click. Ancestor **`formDataProvider`** on this element is inherited by child form controls.
226
+
227
+ ### `sonic-modal-close`
228
+
229
+ Rendered automatically unless **`forceAction`** or **`noCloseButton`** is set. Calls **`hide()`** on the parent modal.
230
+
231
+ | Attribute | Values | Description |
232
+ |----------|---------|-------------|
233
+ | `type` | **`sonic-button`** `type` | Close button color |
234
+ | `reset` | string | Passed to inner **`sonic-button`** **`reset`** |
235
+ | `translation` | UI label object | Overrides default close **`aria-label`** |
@@ -20,6 +20,7 @@ import { unsafeHTML } from "lit/directives/unsafe-html.js";
20
20
  import { ifDefined } from "lit/directives/if-defined.js";
21
21
  import { ButtonType } from "../button/button";
22
22
  import { ModalStyleSheetInput, normalizeStyleSheets } from "./modal-utils";
23
+ import { Align } from "../_css/align";
23
24
 
24
25
  declare const window: ConcordeWindow;
25
26
  declare type ModalCreateOptions = {
@@ -211,10 +212,7 @@ export class Modal extends Subscriber(LitElement) {
211
212
  @property({ type: Boolean }) noCloseButton = false;
212
213
  @property({ type: Boolean }) removeOnHide = false;
213
214
  @property({ type: Boolean }) removeHashOnHide = false;
214
- @property({ type: String, reflect: true }) align:
215
- | "center"
216
- | "right"
217
- | "left" = "left";
215
+ @property({ type: String, reflect: true }) align: Align = "left";
218
216
 
219
217
  // Settings de base
220
218
  @property({ type: String }) paddingX?: string;