@supersoniks/concorde 5.0.4 → 5.1.0
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.
- package/.agents/skills/concorde-component-docs/SKILL.md +194 -0
- package/.agents/skills/concorde-component-docs/template.md +45 -0
- package/.tmp-cem/custom-elements.json +13705 -0
- package/ai/cursor/rules/concorde-theme.mdc +1 -1
- package/ai/cursor/rules/concorde.mdc +1 -1
- package/ai/skills/concorde/SKILL.md +1 -1
- package/ai/skills/concorde-theme/SKILL.md +21 -10
- package/build-infos.json +1 -1
- package/concorde-3d.bundle.js +3960 -0
- package/concorde-3d.es.js +33433 -0
- package/concorde-core.bundle.js +507 -513
- package/concorde-core.es.js +4027 -3702
- package/concorde-hugging-face-infer.bundle.js +32 -0
- package/concorde-hugging-face-infer.es.js +2952 -0
- package/concorde-interactive.bundle.js +1157 -0
- package/concorde-interactive.es.js +10734 -0
- package/concorde-shader.bundle.js +116 -0
- package/concorde-shader.es.js +8353 -0
- package/concorde-webgpu.bundle.js +307 -0
- package/concorde-webgpu.es.js +8627 -0
- package/custom-elements-manifest.config.mjs +14 -0
- package/dist/concorde-core.bundle.js +507 -513
- package/dist/concorde-core.es.js +4027 -3702
- package/dist/docs-mock-api-sw.js +2 -0
- package/dist/docs-mock-api-sw.js.map +2 -2
- package/gitlab/job_tests.sh +0 -0
- package/index.html +4 -2
- package/package.json +42 -2
- package/public/docs-mock-api-sw.js +2 -0
- package/public/docs-mock-api-sw.js.map +2 -2
- package/scripts/generate-sdui-catalog.mjs +250 -0
- package/scripts/generate-sdui-catalog.spec.ts +91 -0
- package/scripts/pre-build.mjs +15 -0
- package/src/core/components/functional/if/if.ts +0 -0
- package/src/core/components/functional/sdui/SDUIDescriptorTransformer.ts +5 -5
- package/src/core/components/functional/sdui/__fixtures__/descriptors.ts +251 -0
- package/src/core/components/functional/sdui/__snapshots__/sdui-action.spec.ts.snap +73 -0
- package/src/core/components/functional/sdui/__snapshots__/sdui-incremental.spec.ts.snap +50 -0
- package/src/core/components/functional/sdui/__snapshots__/sdui-partial.spec.ts.snap +50 -0
- package/src/core/components/functional/sdui/__snapshots__/sdui.regression.spec.ts.snap +461 -0
- package/src/core/components/functional/sdui/component-catalog.gaps.json +511 -0
- package/src/core/components/functional/sdui/component-catalog.json +3103 -0
- package/src/core/components/functional/sdui/component-catalog.spec.ts +23 -0
- package/src/core/components/functional/sdui/sdui-action.spec.ts +99 -0
- package/src/core/components/functional/sdui/sdui-dom-snapshot.ts +61 -0
- package/src/core/components/functional/sdui/sdui-extension-points.md +94 -0
- package/src/core/components/functional/sdui/sdui-incremental.spec.ts +137 -0
- package/src/core/components/functional/sdui/sdui-partial.spec.ts +83 -0
- package/src/core/components/functional/sdui/sdui-partial.ts +19 -0
- package/src/core/components/functional/sdui/sdui-safe.spec.ts +188 -0
- package/src/core/components/functional/sdui/sdui-safe.ts +100 -0
- package/src/core/components/functional/sdui/sdui.md +122 -0
- package/src/core/components/functional/sdui/sdui.regression.spec.ts +64 -0
- package/src/core/components/functional/sdui/sdui.ts +442 -34
- package/src/core/components/functional/sdui/types.ts +49 -0
- package/src/core/components/functional/value/value.ts +0 -0
- package/src/core/components/ui/_css/align.ts +1 -0
- package/src/core/components/ui/_css/type.ts +86 -8
- package/src/core/components/ui/_i18n/ui-aria-labels.ts +8 -0
- package/src/core/components/ui/alert/alert.md +21 -2
- package/src/core/components/ui/alert-messages/alert-messages.md +85 -0
- package/src/core/components/ui/badge/badge.md +19 -6
- package/src/core/components/ui/badge/badge.ts +8 -9
- package/src/core/components/ui/button/button.ts +5 -15
- package/src/core/components/ui/captcha/captcha.md +65 -6
- package/src/core/components/ui/card/card.md +73 -10
- package/src/core/components/ui/card/card.ts +24 -22
- package/src/core/components/ui/divider/divider.md +107 -13
- package/src/core/components/ui/divider/divider.ts +40 -33
- package/src/core/components/ui/form/fieldset/fieldset.md +175 -99
- package/src/core/components/ui/form/fieldset/fieldset.ts +15 -28
- package/src/core/components/ui/form/fieldset/legend.ts +13 -13
- package/src/core/components/ui/form/form-actions/form-actions.md +75 -52
- package/src/core/components/ui/form/form-actions/form-actions.ts +7 -5
- package/src/core/components/ui/form/form-layout/form-layout.md +109 -34
- package/src/core/components/ui/form/form-layout/form-layout.ts +27 -24
- package/src/core/components/ui/form/textarea/textarea.ts +4 -3
- package/src/core/components/ui/group/group.md +36 -36
- package/src/core/components/ui/group/group.ts +5 -10
- package/src/core/components/ui/icon/icon.md +132 -43
- package/src/core/components/ui/image/image.md +35 -3
- package/src/core/components/ui/link/link.md +43 -5
- package/src/core/components/ui/loader/loader.md +79 -22
- package/src/core/components/ui/loader/loader.ts +67 -27
- package/src/core/components/ui/loader/styles/fixed.ts +6 -11
- package/src/core/components/ui/menu/menu.md +133 -92
- package/src/core/components/ui/menu/menu.ts +53 -58
- package/src/core/components/ui/modal/modal.md +163 -47
- package/src/core/components/ui/modal/modal.ts +2 -4
- package/src/core/components/ui/pop/pop.md +217 -123
- package/src/core/components/ui/pop/pop.ts +0 -1
- package/src/core/components/ui/progress/progress.md +76 -30
- package/src/core/components/ui/progress/progress.ts +25 -56
- package/src/core/components/ui/table/table-caption.ts +2 -2
- package/src/core/components/ui/table/table-tbody.ts +3 -3
- package/src/core/components/ui/table/table-td.ts +23 -18
- package/src/core/components/ui/table/table-th.ts +8 -8
- package/src/core/components/ui/table/table-tr.ts +4 -4
- package/src/core/components/ui/table/table.md +147 -171
- package/src/core/components/ui/table/table.ts +20 -19
- package/src/core/components/ui/theme/theme-collection/auto.ts +15 -0
- package/src/core/components/ui/theme/theme-collection/core-variables.ts +8 -31
- package/src/core/components/ui/theme/theme-collection/dark.ts +1 -7
- package/src/core/components/ui/theme/theme-collection/light.ts +30 -26
- package/src/core/components/ui/theme/theme.md +122 -0
- package/src/core/components/ui/theme/theme.ts +30 -7
- package/src/core/components/ui/toast/toast-item.ts +6 -9
- package/src/core/components/ui/toast/toast.md +108 -58
- package/src/core/components/ui/toast/types.ts +1 -1
- package/src/core/components/ui/tooltip/tooltip.md +68 -26
- package/src/docs/_getting-started/start.md +1 -1
- package/src/docs/_getting-started/theming.md +223 -61
- package/src/docs/code.ts +125 -58
- package/src/docs/header/header.ts +62 -54
- package/src/docs/mock-api/router.ts +2 -0
- package/src/docs/navigation/navigation.ts +6 -3
- package/src/docs/search/docs-search.json +2504 -399
- package/src/docs/search/markdown-renderer.ts +6 -6
- package/src/docs/search/search.ts +4 -4
- package/src/docs/tailwind/css/tailwind.css +6 -5
- package/src/tsconfig.json +108 -0
- package/src/tsconfig.tsbuildinfo +1 -1
- package/tailwind.config.js +19 -0
|
@@ -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-
|
|
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
|
-
);
|
|
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
|
-
|
|
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.
|
|
228
|
-
this.setDividersSize(this.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
this.classList.add("active");
|
|
312
|
+
this.addEventListener("mousedown", (e) => {
|
|
313
|
+
isDown = true;
|
|
314
|
+
this.classList.add("active");
|
|
314
315
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
-
|
|
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
|
-
|
|
12
|
+
Open modal
|
|
7
13
|
</sonic-button>
|
|
8
14
|
<sonic-modal id="modalExample">
|
|
9
|
-
<sonic-modal-title
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
|
18
|
-
|
|
24
|
+
<sonic-button minWidth="8rem" value="true" name="click">
|
|
25
|
+
Save draft
|
|
19
26
|
</sonic-button>
|
|
20
|
-
<sonic-button minWidth="8rem" type="success" hideModal>
|
|
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
|
-
|
|
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()">
|
|
39
|
+
<sonic-button onclick="document.getElementById('modalText').show()">Venue details</sonic-button>
|
|
32
40
|
<sonic-modal align="left" id="modalText">
|
|
33
|
-
<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>
|
|
38
|
-
|
|
39
|
-
+ horaires spécifiques pour événements ou festivals
|
|
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>
|
|
43
|
-
|
|
44
|
-
réservations disponibles en ligne ou au guichet. <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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
<p>
|
|
56
|
-
<strong>+ d’infos <br /></strong>billetterie@laconditionpublique.com <br />+33 (0)328334833
|
|
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
|
|
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()">
|
|
73
|
+
<sonic-button onclick="document.getElementById('force').show()">Cookie consent</sonic-button>
|
|
78
74
|
<sonic-modal forceAction id="force">
|
|
79
|
-
<sonic-modal-title>
|
|
75
|
+
<sonic-modal-title>Allow analytics cookies?</sonic-modal-title>
|
|
80
76
|
<sonic-modal-content>
|
|
81
|
-
|
|
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">
|
|
85
|
-
<sonic-button hideModal minWidth="8rem" type="success">
|
|
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()">
|
|
97
|
-
<sonic-modal
|
|
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()">
|
|
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: '<sonic-button hideModal minWidth=\'8rem\'>Cancel</sonic-button><sonic-button hideModal minWidth=\'8rem\' type=\'success\'>Send</sonic-button>',
|
|
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;
|