@supersoniks/concorde 5.0.1 → 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 (50) hide show
  1. package/build-infos.json +1 -1
  2. package/concorde-core.bundle.js +519 -586
  3. package/concorde-core.es.js +3783 -3689
  4. package/dist/concorde-core.bundle.js +519 -586
  5. package/dist/concorde-core.es.js +3783 -3689
  6. package/index.html +2 -2
  7. package/package.json +14 -1
  8. package/src/core/components/ui/_css/rounded.ts +36 -0
  9. package/src/core/components/ui/_css/type.ts +49 -0
  10. package/src/core/components/ui/_i18n/ui-aria-labels.ts +104 -0
  11. package/src/core/components/ui/alert/alert.md +128 -72
  12. package/src/core/components/ui/alert/alert.spec.ts +145 -0
  13. package/src/core/components/ui/alert/alert.ts +86 -91
  14. package/src/core/components/ui/alert-messages/alert-messages.ts +1 -1
  15. package/src/core/components/ui/badge/badge.md +126 -78
  16. package/src/core/components/ui/badge/badge.ts +29 -81
  17. package/src/core/components/ui/button/button.md +1 -0
  18. package/src/core/components/ui/button/button.ts +11 -8
  19. package/src/core/components/ui/card/card-header.ts +7 -2
  20. package/src/core/components/ui/card/card.md +120 -65
  21. package/src/core/components/ui/divider/divider.ts +4 -9
  22. package/src/core/components/ui/form/fieldset/legend-description.ts +1 -1
  23. package/src/core/components/ui/form/fieldset/legend.ts +1 -1
  24. package/src/core/components/ui/form/input/input.md +1 -1
  25. package/src/core/components/ui/form/input/input.ts +19 -15
  26. package/src/core/components/ui/form/textarea/textarea.md +1 -1
  27. package/src/core/components/ui/image/image.md +147 -53
  28. package/src/core/components/ui/image/image.ts +10 -44
  29. package/src/core/components/ui/link/link.md +2 -2
  30. package/src/core/components/ui/link/link.ts +42 -37
  31. package/src/core/components/ui/modal/modal-close.ts +8 -12
  32. package/src/core/components/ui/modal/modal.ts +18 -18
  33. package/src/core/components/ui/pop/pop.md +7 -5
  34. package/src/core/components/ui/pop/pop.ts +78 -38
  35. package/src/core/components/ui/table/table.ts +2 -8
  36. package/src/core/components/ui/toast/dismissed.ts +14 -0
  37. package/src/core/components/ui/toast/toast-item.ts +139 -91
  38. package/src/core/components/ui/toast/toast.ts +4 -7
  39. package/src/core/components/ui/tooltip/tooltip.ts +6 -8
  40. package/src/core/utils/LocationHandler.ts +12 -5
  41. package/src/core/utils/dismissed.ts +22 -0
  42. package/src/core/utils/positioning.spec.ts +28 -0
  43. package/src/core/utils/positioning.ts +19 -0
  44. package/src/docs/_getting-started/concorde-outside.md +3 -3
  45. package/src/docs/code.ts +3 -1
  46. package/src/docs/search/docs-search.json +541 -1
  47. package/src/docs/tailwind/css/tailwind.css +6 -0
  48. package/src/tsconfig.json +422 -383
  49. package/src/tsconfig.tsbuildinfo +1 -1
  50. package/tailwind.config.js +50 -3
@@ -8,6 +8,7 @@ import { ifDefined } from "lit/directives/if-defined.js";
8
8
  import { styleMap, StyleInfo } from "lit/directives/style-map.js";
9
9
  import "@supersoniks/concorde/core/components/ui/toast/toast-item";
10
10
  import { renderToastContent } from "@supersoniks/concorde/core/components/ui/toast/render-content";
11
+ import { isToastDismissed } from "@supersoniks/concorde/core/components/ui/toast/dismissed";
11
12
  import {
12
13
  Toast,
13
14
  ToastContent,
@@ -66,7 +67,7 @@ export class SonicToast extends LitElement {
66
67
  bottom: "1.25rem",
67
68
  right: "1.25rem",
68
69
  zIndex: "10000",
69
- maxWidth: "64ch",
70
+ maxWidth: "45ch",
70
71
  flexDirection: "column-reverse",
71
72
  };
72
73
  }
@@ -215,12 +216,8 @@ export class SonicToast extends LitElement {
215
216
  };
216
217
 
217
218
  // check if the toast is dismissed
218
- if (conf.dismissForever && conf.id) {
219
- const dismissed = localStorage.getItem("sonic-toast-dismissed") || "{}";
220
- const dismissedObj = JSON.parse(dismissed);
221
- if (dismissedObj[conf.id]) {
222
- return null;
223
- }
219
+ if (conf.dismissForever && conf.id && isToastDismissed(conf.id)) {
220
+ return null;
224
221
  }
225
222
 
226
223
  if (toastComponent?.toasts.length) {
@@ -2,16 +2,16 @@ import { html, LitElement, css, PropertyValues } from "lit";
2
2
  import { customElement, property, query } from "lit/decorators.js";
3
3
  import {
4
4
  computeFloatingPosition,
5
- FloatingAlign,
6
- FloatingSide,
5
+ FloatingPlacement,
7
6
  getFloatingBounds,
7
+ parsePlacement,
8
8
  startFrameLoop,
9
9
  supportsPopover,
10
10
  } from "@supersoniks/concorde/core/utils/positioning";
11
11
 
12
12
  const tagName = "sonic-tooltip";
13
13
 
14
- type TooltipPlacement = FloatingSide | `${FloatingSide}-${FloatingAlign}`;
14
+ type TooltipPlacement = FloatingPlacement;
15
15
 
16
16
  const GAP = 4;
17
17
 
@@ -102,15 +102,13 @@ export class Tooltip extends LitElement {
102
102
  return;
103
103
  }
104
104
 
105
- const [side = "top", align = "center"] = (this.placement ?? "top").split(
106
- "-",
107
- );
105
+ const { side, align } = parsePlacement(this.placement, "top", "center");
108
106
 
109
107
  const { x, y } = computeFloatingPosition({
110
108
  anchor: this.getBoundingClientRect(),
111
109
  floating: bubble.getBoundingClientRect(),
112
- side: side as FloatingSide,
113
- align: align as FloatingAlign,
110
+ side,
111
+ align,
114
112
  gap: GAP,
115
113
  bounds: getFloatingBounds(this, GAP),
116
114
  });
@@ -1,13 +1,20 @@
1
1
  import { Route } from "./route";
2
2
 
3
+ export type AutoActiveMode =
4
+ | "strict"
5
+ | "partial"
6
+ | "disabled"
7
+ | "strict-path-only";
8
+
3
9
  declare type Listener = {
4
10
  location: string;
5
11
  };
6
- declare type ActivableLink = HTMLElement & {
12
+
13
+ export type ActivableLink = HTMLElement & {
7
14
  location?: string;
8
15
  href?: Route | string;
9
16
  goBack?: Route | string | null;
10
- autoActive?: "strict" | "partial" | "disabled" | "strict-path-only";
17
+ autoActive?: AutoActiveMode;
11
18
  setAttribute(name: string, value: string): void;
12
19
  removeAttribute(name: string): void;
13
20
  };
@@ -22,7 +29,7 @@ export default class LocationHandler {
22
29
  static listening = false;
23
30
  static prevURL: string = document.location?.href.replace(
24
31
  document.location.origin,
25
- ""
32
+ "",
26
33
  );
27
34
  static listen() {
28
35
  if (!LocationHandler.listening) {
@@ -30,7 +37,7 @@ export default class LocationHandler {
30
37
  }
31
38
  const newURL = document.location?.href.replace(
32
39
  document.location.origin,
33
- ""
40
+ "",
34
41
  );
35
42
  if (LocationHandler.prevURL && LocationHandler.prevURL != newURL) {
36
43
  LocationHandler.prevURL = newURL;
@@ -116,7 +123,7 @@ export default class LocationHandler {
116
123
  prevSp = sp;
117
124
  }
118
125
 
119
- to = "/" + newPathName.join("/") + url.search + (url.hash ? +url.hash : "");
126
+ to = "/" + newPathName.join("/") + url.search + (url.hash ? url.hash : "");
120
127
  if (component.hasAttribute("pushState")) {
121
128
  history.pushState(null, "", to);
122
129
  } else if (component.hasAttribute("replaceState")) {
@@ -0,0 +1,22 @@
1
+ function readDismissed(storageKey: string): Record<string, boolean> {
2
+ try {
3
+ const parsed = JSON.parse(localStorage.getItem(storageKey) || "{}");
4
+ return parsed && typeof parsed === "object" ? parsed : {};
5
+ } catch {
6
+ return {};
7
+ }
8
+ }
9
+
10
+ export function isDismissed(storageKey: string, id: string | number): boolean {
11
+ return !!readDismissed(storageKey)[id];
12
+ }
13
+
14
+ export function markDismissed(storageKey: string, id: string | number): void {
15
+ const dismissed = readDismissed(storageKey);
16
+ dismissed[id] = true;
17
+ try {
18
+ localStorage.setItem(storageKey, JSON.stringify(dismissed));
19
+ } catch {
20
+ // stockage indisponible (mode privé, quota)
21
+ }
22
+ }
@@ -3,6 +3,7 @@ import {
3
3
  computeFloatingPosition,
4
4
  FloatingBounds,
5
5
  FloatingSide,
6
+ parsePlacement,
6
7
  } from "./positioning";
7
8
 
8
9
  type Rect = {
@@ -178,3 +179,30 @@ describe("computeFloatingPosition", () => {
178
179
  });
179
180
  });
180
181
  });
182
+
183
+ describe("parsePlacement", () => {
184
+ it("lit côté et alignement", () => {
185
+ expect(parsePlacement("left-end", "bottom", "start")).toEqual({
186
+ side: "left",
187
+ align: "end",
188
+ });
189
+ });
190
+
191
+ it("applique l'alignement par défaut quand il est absent", () => {
192
+ expect(parsePlacement("top", "bottom", "start")).toEqual({
193
+ side: "top",
194
+ align: "start",
195
+ });
196
+ });
197
+
198
+ it("retombe sur les défauts pour une valeur inconnue", () => {
199
+ expect(parsePlacement("foo-bar", "top", "center")).toEqual({
200
+ side: "top",
201
+ align: "center",
202
+ });
203
+ expect(parsePlacement(undefined, "top", "center")).toEqual({
204
+ side: "top",
205
+ align: "center",
206
+ });
207
+ });
208
+ });
@@ -2,6 +2,25 @@ import HTML, { SearchableDomElement } from "./HTML";
2
2
 
3
3
  export type FloatingSide = "top" | "right" | "bottom" | "left";
4
4
  export type FloatingAlign = "start" | "center" | "end";
5
+ export type FloatingPlacement =
6
+ | FloatingSide
7
+ | `${FloatingSide}-${FloatingAlign}`;
8
+
9
+ const SIDES: readonly string[] = ["top", "right", "bottom", "left"];
10
+ const ALIGNS: readonly string[] = ["start", "center", "end"];
11
+
12
+ /** Découpe `"côté-alignement"` ; une valeur inconnue retombe sur le défaut. */
13
+ export function parsePlacement(
14
+ placement: string | undefined,
15
+ defaultSide: FloatingSide,
16
+ defaultAlign: FloatingAlign,
17
+ ): { side: FloatingSide; align: FloatingAlign } {
18
+ const [side, align] = (placement ?? "").split("-");
19
+ return {
20
+ side: SIDES.includes(side) ? (side as FloatingSide) : defaultSide,
21
+ align: ALIGNS.includes(align) ? (align as FloatingAlign) : defaultAlign,
22
+ };
23
+ }
5
24
 
6
25
  export type FloatingBounds = {
7
26
  minX: number;
@@ -1,8 +1,8 @@
1
1
  # Installation
2
2
 
3
- <sonic-alert status="success" label="Recommended — use the starter" size="xl" background>
4
- <p><strong>For almost all new projects, use <a href="https://www.npmjs.com/package/@supersoniks/create-concorde-ts-starter">create-concorde-ts-starter</a>.</strong></p>
5
- <p>You get Vite + TypeScript + Lit + Tailwind, an example component, <code>npx concorde enable-short-paths</code> ready to run, and <code>yarn ai:sync</code> for <a href="#docs/_getting-started/ai-agents.md/ai-agents">AI agent skills</a> (<code>AGENTS.md</code>, Cursor / JetBrains rules) without extra setup.</p>
3
+ <sonic-alert status="info" label="Recommended — use the starter" background>
4
+ <p>For almost all new projects, use <a href="https://www.npmjs.com/package/@supersoniks/create-concorde-ts-starter">create-concorde-ts-starter</a></p>
5
+ <p>You get Vite + TypeScript + Lit + Tailwind, an example component, <code>npx concorde enable-short-paths</code> ready to run, and <code>yarn ai:sync</code> for <a href="#docs/_getting-started/ai-agents.md/ai-agents">AI agent skills</a> (<code>AGENTS.md</code>, Cursor / JetBrains rules) without extra setup.</p>
6
6
  </sonic-alert>
7
7
 
8
8
  ## Starter
package/src/docs/code.ts CHANGED
@@ -36,6 +36,8 @@ export class DocsCode extends LitElement {
36
36
  pre {
37
37
  font-size: 13px !important;
38
38
  padding-right: 5rem !important;
39
+ border: 1px solid var(--sc-base-200);
40
+ border-radius: var(--sc-rounded);
39
41
  }
40
42
  .custom-scroll {
41
43
  overflow: auto !important;
@@ -239,7 +241,7 @@ export class DocsCode extends LitElement {
239
241
  return html`
240
242
  <div
241
243
  class="relative ${this.language === "markup"
242
- ? "border border-neutral-100 p-4 rounded-md"
244
+ ? "rounded-md border border-neutral-200 bg-neutral-50/80 dark:border-neutral-700/80 dark:bg-neutral-900/40 p-4"
243
245
  : ""}"
244
246
  >
245
247
  ${this.language === "markup" && !this.noOutput