@alfadocs/ui-kit-debug 0.32.3 → 0.32.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.
- package/dist/_chunks/{public-footer.agent-Bh0rnx4i.js → public-footer.agent-Cjfe5jus.js} +63 -63
- package/dist/_chunks/public-footer.agent-Cjfe5jus.js.map +1 -0
- package/dist/_chunks/{reviews-panel-B-18RBSn.js → reviews-panel-Dow8Dzoa.js} +2 -2
- package/dist/_chunks/reviews-panel-Dow8Dzoa.js.map +1 -0
- package/dist/agent-catalog.json +1 -1
- package/dist/components/public-footer/index.js +1 -1
- package/dist/components/public-footer/public-footer.d.ts +9 -4
- package/dist/components/public-footer/public-footer.d.ts.map +1 -1
- package/dist/components/reviews-panel/index.js +1 -1
- package/dist/index.js +2 -2
- package/dist/tokens.css +1 -1
- package/package.json +2 -1
- package/dist/_chunks/public-footer.agent-Bh0rnx4i.js.map +0 -1
- package/dist/_chunks/reviews-panel-B-18RBSn.js.map +0 -1
|
@@ -33,18 +33,18 @@ const L = "https://www.alfadocs.com", F = {
|
|
|
33
33
|
contacts: "/es/contacto"
|
|
34
34
|
}
|
|
35
35
|
}, B = "https://";
|
|
36
|
-
function K(
|
|
37
|
-
return !
|
|
36
|
+
function K(s) {
|
|
37
|
+
return !s || !s.startsWith(B) ? L : s.replace(/\/+$/, "");
|
|
38
38
|
}
|
|
39
|
-
function k(
|
|
39
|
+
function k(s, t, a) {
|
|
40
40
|
var c, l;
|
|
41
|
-
const r = (c = a == null ? void 0 : a[
|
|
41
|
+
const r = (c = a == null ? void 0 : a[t]) == null ? void 0 : c[s];
|
|
42
42
|
if (r) return r;
|
|
43
|
-
const n = (l = Y[
|
|
44
|
-
return n || F[
|
|
43
|
+
const n = (l = Y[s]) == null ? void 0 : l[t];
|
|
44
|
+
return n || F[t];
|
|
45
45
|
}
|
|
46
|
-
function W(
|
|
47
|
-
const r = K(
|
|
46
|
+
function W(s, t, a) {
|
|
47
|
+
const r = K(t), n = (s || "it").split("-")[0];
|
|
48
48
|
return {
|
|
49
49
|
privacy: `${r}${k(n, "privacy", a)}`,
|
|
50
50
|
terms: `${r}${k(n, "terms", a)}`,
|
|
@@ -65,12 +65,12 @@ const X = [
|
|
|
65
65
|
viewBox: "0 0 24 24",
|
|
66
66
|
fill: "currentColor",
|
|
67
67
|
xmlns: "http://www.w3.org/2000/svg"
|
|
68
|
-
}, J = (
|
|
68
|
+
}, J = (s) => /* @__PURE__ */ e("svg", { ...y, ...s, children: /* @__PURE__ */ e("path", { d: "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.063 2.063 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" }) }), Q = (s) => /* @__PURE__ */ e("svg", { ...y, ...s, children: /* @__PURE__ */ e("path", { d: "M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" }) }), Z = (s) => /* @__PURE__ */ e("svg", { ...y, ...s, children: /* @__PURE__ */ e("path", { d: "M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z" }) }), ee = (s) => /* @__PURE__ */ e("svg", { ...y, ...s, children: /* @__PURE__ */ e("path", { d: "M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" }) }), se = {
|
|
69
69
|
linkedin: J,
|
|
70
70
|
youtube: Q,
|
|
71
71
|
instagram: Z,
|
|
72
72
|
facebook: ee
|
|
73
|
-
},
|
|
73
|
+
}, te = "AlfaDocs GmbH", ae = "P.IVA DE301955405", ne = R(
|
|
74
74
|
[
|
|
75
75
|
"ds:w-full",
|
|
76
76
|
"ds:text-[color:var(--muted-foreground)]",
|
|
@@ -113,12 +113,12 @@ const X = [
|
|
|
113
113
|
defaultVariants: { variant: "compact" }
|
|
114
114
|
}
|
|
115
115
|
), re = /^(https?:\/\/|mailto:|tel:|\/(?!\/))/i;
|
|
116
|
-
function I(
|
|
117
|
-
return re.test(
|
|
116
|
+
function I(s) {
|
|
117
|
+
return re.test(s) ? s : "#";
|
|
118
118
|
}
|
|
119
119
|
function M({
|
|
120
|
-
copyright:
|
|
121
|
-
align:
|
|
120
|
+
copyright: s,
|
|
121
|
+
align: t = "center"
|
|
122
122
|
}) {
|
|
123
123
|
return /* @__PURE__ */ e(
|
|
124
124
|
"p",
|
|
@@ -126,15 +126,15 @@ function M({
|
|
|
126
126
|
className: [
|
|
127
127
|
"ds:m-0 ds:text-[color:var(--muted-foreground)]",
|
|
128
128
|
"ds:text-[length:var(--font-size-sm)]",
|
|
129
|
-
|
|
129
|
+
t === "center" ? "ds:text-center" : "ds:text-start"
|
|
130
130
|
].join(" "),
|
|
131
|
-
children:
|
|
131
|
+
children: s
|
|
132
132
|
}
|
|
133
133
|
);
|
|
134
134
|
}
|
|
135
135
|
const ce = H(
|
|
136
136
|
function({
|
|
137
|
-
variant:
|
|
137
|
+
variant: t,
|
|
138
138
|
marketingBaseUrl: a,
|
|
139
139
|
legalUrlOverrides: r,
|
|
140
140
|
linkGroups: n,
|
|
@@ -142,7 +142,7 @@ const ce = H(
|
|
|
142
142
|
logoSlot: l,
|
|
143
143
|
extraNavSlot: d,
|
|
144
144
|
trustBadgesSlot: h,
|
|
145
|
-
showTagline: v = !
|
|
145
|
+
showTagline: v = !1,
|
|
146
146
|
id: g,
|
|
147
147
|
"aria-label": z
|
|
148
148
|
}, p) {
|
|
@@ -153,14 +153,14 @@ const ce = H(
|
|
|
153
153
|
P(
|
|
154
154
|
p,
|
|
155
155
|
() => ({
|
|
156
|
-
getVariant: () =>
|
|
156
|
+
getVariant: () => t,
|
|
157
157
|
getLegalUrls: () => x
|
|
158
158
|
}),
|
|
159
|
-
[
|
|
159
|
+
[t, x]
|
|
160
160
|
);
|
|
161
161
|
const j = (/* @__PURE__ */ new Date()).getFullYear(), N = o("footer.copyright", {
|
|
162
162
|
year: j,
|
|
163
|
-
entity:
|
|
163
|
+
entity: te,
|
|
164
164
|
vat: ae
|
|
165
165
|
}), $ = v ? o("footer.tagline") : void 0, E = z ?? o("footer.nav.label"), w = {
|
|
166
166
|
privacy: o("footer.nav.privacy"),
|
|
@@ -174,10 +174,10 @@ const ce = H(
|
|
|
174
174
|
role: "contentinfo",
|
|
175
175
|
"aria-label": E,
|
|
176
176
|
"data-component": "public-footer",
|
|
177
|
-
"data-variant":
|
|
178
|
-
className: ne({ variant:
|
|
177
|
+
"data-variant": t,
|
|
178
|
+
className: ne({ variant: t }),
|
|
179
179
|
children: [
|
|
180
|
-
|
|
180
|
+
t === "minimal" && /* @__PURE__ */ e(
|
|
181
181
|
ie,
|
|
182
182
|
{
|
|
183
183
|
legalUrls: x,
|
|
@@ -186,7 +186,7 @@ const ce = H(
|
|
|
186
186
|
trustBadgesSlot: h
|
|
187
187
|
}
|
|
188
188
|
),
|
|
189
|
-
|
|
189
|
+
t === "compact" && /* @__PURE__ */ e(
|
|
190
190
|
le,
|
|
191
191
|
{
|
|
192
192
|
legalUrls: x,
|
|
@@ -199,7 +199,7 @@ const ce = H(
|
|
|
199
199
|
t: o
|
|
200
200
|
}
|
|
201
201
|
),
|
|
202
|
-
|
|
202
|
+
t === "full" && /* @__PURE__ */ e(
|
|
203
203
|
de,
|
|
204
204
|
{
|
|
205
205
|
legalUrls: x,
|
|
@@ -220,8 +220,8 @@ const ce = H(
|
|
|
220
220
|
}
|
|
221
221
|
);
|
|
222
222
|
function ie({
|
|
223
|
-
legalUrls:
|
|
224
|
-
labels:
|
|
223
|
+
legalUrls: s,
|
|
224
|
+
labels: t,
|
|
225
225
|
copyright: a,
|
|
226
226
|
trustBadgesSlot: r
|
|
227
227
|
}) {
|
|
@@ -237,22 +237,22 @@ function ie({
|
|
|
237
237
|
/* @__PURE__ */ e(
|
|
238
238
|
f,
|
|
239
239
|
{
|
|
240
|
-
href:
|
|
240
|
+
href: s.privacy,
|
|
241
241
|
external: !0,
|
|
242
242
|
externalIcon: !1,
|
|
243
243
|
intent: "subtle",
|
|
244
|
-
children:
|
|
244
|
+
children: t.privacy
|
|
245
245
|
}
|
|
246
246
|
),
|
|
247
247
|
/* @__PURE__ */ e(m, { orientation: "vertical", className: "ds:h-4" }),
|
|
248
248
|
/* @__PURE__ */ e(
|
|
249
249
|
f,
|
|
250
250
|
{
|
|
251
|
-
href:
|
|
251
|
+
href: s.terms,
|
|
252
252
|
external: !0,
|
|
253
253
|
externalIcon: !1,
|
|
254
254
|
intent: "subtle",
|
|
255
|
-
children:
|
|
255
|
+
children: t.terms
|
|
256
256
|
}
|
|
257
257
|
),
|
|
258
258
|
/* @__PURE__ */ e(m, { orientation: "vertical", className: "ds:h-4" }),
|
|
@@ -260,19 +260,19 @@ function ie({
|
|
|
260
260
|
] });
|
|
261
261
|
}
|
|
262
262
|
function _({
|
|
263
|
-
socials:
|
|
264
|
-
t
|
|
263
|
+
socials: s,
|
|
264
|
+
t,
|
|
265
265
|
size: a
|
|
266
266
|
}) {
|
|
267
|
-
if (
|
|
267
|
+
if (s.length === 0) return null;
|
|
268
268
|
const r = a === "sm" ? "ds:size-4" : "ds:size-5";
|
|
269
269
|
return /* @__PURE__ */ e(
|
|
270
270
|
"ul",
|
|
271
271
|
{
|
|
272
272
|
"data-slot": "socials",
|
|
273
273
|
className: "ds:list-none ds:m-0 ds:p-0 ds:flex ds:items-center ds:gap-[var(--spacing-xs)]",
|
|
274
|
-
children:
|
|
275
|
-
const c =
|
|
274
|
+
children: s.map((n) => {
|
|
275
|
+
const c = se[n.network], l = n.href ?? q[n.network], d = t(`footer.social.aria.${n.network}`);
|
|
276
276
|
return /* @__PURE__ */ e("li", { children: /* @__PURE__ */ e(
|
|
277
277
|
f,
|
|
278
278
|
{
|
|
@@ -297,8 +297,8 @@ function _({
|
|
|
297
297
|
);
|
|
298
298
|
}
|
|
299
299
|
function le({
|
|
300
|
-
legalUrls:
|
|
301
|
-
labels:
|
|
300
|
+
legalUrls: s,
|
|
301
|
+
labels: t,
|
|
302
302
|
copyright: a,
|
|
303
303
|
tagline: r,
|
|
304
304
|
socials: n,
|
|
@@ -337,33 +337,33 @@ function le({
|
|
|
337
337
|
/* @__PURE__ */ e(
|
|
338
338
|
f,
|
|
339
339
|
{
|
|
340
|
-
href:
|
|
340
|
+
href: s.privacy,
|
|
341
341
|
external: !0,
|
|
342
342
|
externalIcon: !1,
|
|
343
343
|
intent: "subtle",
|
|
344
|
-
children:
|
|
344
|
+
children: t.privacy
|
|
345
345
|
}
|
|
346
346
|
),
|
|
347
347
|
/* @__PURE__ */ e(m, { orientation: "vertical", className: "ds:h-4" }),
|
|
348
348
|
/* @__PURE__ */ e(
|
|
349
349
|
f,
|
|
350
350
|
{
|
|
351
|
-
href:
|
|
351
|
+
href: s.terms,
|
|
352
352
|
external: !0,
|
|
353
353
|
externalIcon: !1,
|
|
354
354
|
intent: "subtle",
|
|
355
|
-
children:
|
|
355
|
+
children: t.terms
|
|
356
356
|
}
|
|
357
357
|
),
|
|
358
358
|
/* @__PURE__ */ e(m, { orientation: "vertical", className: "ds:h-4" }),
|
|
359
359
|
/* @__PURE__ */ e(
|
|
360
360
|
f,
|
|
361
361
|
{
|
|
362
|
-
href:
|
|
362
|
+
href: s.contacts,
|
|
363
363
|
external: !0,
|
|
364
364
|
externalIcon: !1,
|
|
365
365
|
intent: "subtle",
|
|
366
|
-
children:
|
|
366
|
+
children: t.contacts
|
|
367
367
|
}
|
|
368
368
|
),
|
|
369
369
|
l && /* @__PURE__ */ i(b, { children: [
|
|
@@ -382,19 +382,19 @@ function le({
|
|
|
382
382
|
) : null
|
|
383
383
|
] });
|
|
384
384
|
}
|
|
385
|
-
function oe(
|
|
385
|
+
function oe(s, t) {
|
|
386
386
|
return {
|
|
387
387
|
key: "legal",
|
|
388
388
|
links: [
|
|
389
|
-
{ href:
|
|
390
|
-
{ href:
|
|
391
|
-
{ href:
|
|
389
|
+
{ href: s.privacy, label: t.privacy, external: !0 },
|
|
390
|
+
{ href: s.terms, label: t.terms, external: !0 },
|
|
391
|
+
{ href: s.contacts, label: t.contacts, external: !0 }
|
|
392
392
|
]
|
|
393
393
|
};
|
|
394
394
|
}
|
|
395
395
|
function de({
|
|
396
|
-
legalUrls:
|
|
397
|
-
labels:
|
|
396
|
+
legalUrls: s,
|
|
397
|
+
labels: t,
|
|
398
398
|
copyright: a,
|
|
399
399
|
tagline: r,
|
|
400
400
|
linkGroups: n,
|
|
@@ -406,7 +406,7 @@ function de({
|
|
|
406
406
|
}) {
|
|
407
407
|
const g = [
|
|
408
408
|
...n ?? [],
|
|
409
|
-
oe(
|
|
409
|
+
oe(s, t)
|
|
410
410
|
];
|
|
411
411
|
return /* @__PURE__ */ i("div", { className: "ds:flex ds:flex-col ds:gap-[var(--spacing-xl)]", children: [
|
|
412
412
|
/* @__PURE__ */ i("div", { className: "ds:flex ds:flex-col ds:gap-[var(--spacing-xl)] ds:lg:flex-row ds:lg:items-start ds:lg:gap-[var(--spacing-xl)]", children: [
|
|
@@ -467,22 +467,22 @@ function de({
|
|
|
467
467
|
/* @__PURE__ */ e(
|
|
468
468
|
f,
|
|
469
469
|
{
|
|
470
|
-
href:
|
|
470
|
+
href: s.privacy,
|
|
471
471
|
external: !0,
|
|
472
472
|
externalIcon: !1,
|
|
473
473
|
intent: "subtle",
|
|
474
|
-
children:
|
|
474
|
+
children: t.privacy
|
|
475
475
|
}
|
|
476
476
|
),
|
|
477
477
|
/* @__PURE__ */ e(m, { orientation: "vertical", className: "ds:h-4" }),
|
|
478
478
|
/* @__PURE__ */ e(
|
|
479
479
|
f,
|
|
480
480
|
{
|
|
481
|
-
href:
|
|
481
|
+
href: s.terms,
|
|
482
482
|
external: !0,
|
|
483
483
|
externalIcon: !1,
|
|
484
484
|
intent: "subtle",
|
|
485
|
-
children:
|
|
485
|
+
children: t.terms
|
|
486
486
|
}
|
|
487
487
|
),
|
|
488
488
|
(h || d) && /* @__PURE__ */ i(b, { children: [
|
|
@@ -519,10 +519,10 @@ function de({
|
|
|
519
519
|
] });
|
|
520
520
|
}
|
|
521
521
|
function me({
|
|
522
|
-
columns:
|
|
523
|
-
t
|
|
522
|
+
columns: s,
|
|
523
|
+
t
|
|
524
524
|
}) {
|
|
525
|
-
return /* @__PURE__ */ e(b, { children:
|
|
525
|
+
return /* @__PURE__ */ e(b, { children: s.map((a, r) => /* @__PURE__ */ i(
|
|
526
526
|
"section",
|
|
527
527
|
{
|
|
528
528
|
"aria-labelledby": `public-footer-group-${r}-${a.key}`,
|
|
@@ -532,7 +532,7 @@ function me({
|
|
|
532
532
|
{
|
|
533
533
|
id: `public-footer-group-${r}-${a.key}`,
|
|
534
534
|
className: "ds:m-0 ds:mb-[var(--spacing-sm)] ds:text-[color:var(--foreground)] ds:text-[length:var(--font-size-sm)] ds:font-medium",
|
|
535
|
-
children:
|
|
535
|
+
children: t(`footer.group.${a.key}`, { defaultValue: a.key })
|
|
536
536
|
}
|
|
537
537
|
),
|
|
538
538
|
/* @__PURE__ */ e("ul", { className: "ds:list-none ds:m-0 ds:p-0 ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]", children: a.links.map((n) => /* @__PURE__ */ e("li", { children: /* @__PURE__ */ e(
|
|
@@ -558,12 +558,12 @@ const ye = {
|
|
|
558
558
|
variant: {
|
|
559
559
|
type: "string",
|
|
560
560
|
description: "Active variant — one of `minimal`, `compact`, `full`.",
|
|
561
|
-
read: (
|
|
561
|
+
read: (s) => s.getVariant()
|
|
562
562
|
},
|
|
563
563
|
legalUrls: {
|
|
564
564
|
type: "object",
|
|
565
565
|
description: "Resolved legal URLs for the active locale + marketingBaseUrl + overrides: `{ privacy, terms, contacts }`.",
|
|
566
|
-
read: (
|
|
566
|
+
read: (s) => s.getLegalUrls()
|
|
567
567
|
}
|
|
568
568
|
},
|
|
569
569
|
actions: {},
|
|
@@ -588,4 +588,4 @@ export {
|
|
|
588
588
|
W as c,
|
|
589
589
|
ye as p
|
|
590
590
|
};
|
|
591
|
-
//# sourceMappingURL=public-footer.agent-
|
|
591
|
+
//# sourceMappingURL=public-footer.agent-Cjfe5jus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-footer.agent-Cjfe5jus.js","sources":["../../src/components/public-footer/legal-urls.ts","../../src/components/public-footer/socials.tsx","../../src/components/public-footer/public-footer.tsx","../../src/components/public-footer/public-footer.agent.ts"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* PublicFooter — legally-required URL composition. */\n/* */\n/* GDPR + Italian/German commercial law require Privacy, Terms-of-use, */\n/* entity name and VAT to be visible on every public AlfaDocs surface. */\n/* The kit owns the slug table so a privacy-policy URL change is a single */\n/* kit bump rather than three repo edits. */\n/* */\n/* For locales without an explicit canonical slug, we fall back to the */\n/* Italian slugs — alfadocs.com defaults to Italian and unlocalised pages */\n/* render the IT version. Marketing supplies updates over time. */\n/* -------------------------------------------------------------------- */\n\nexport const DEFAULT_MARKETING_BASE_URL = 'https://www.alfadocs.com';\n\nexport type LegalUrlKey = 'privacy' | 'terms' | 'contacts';\n\nexport type LegalSlugMap = Record<LegalUrlKey, string>;\n\n/** Per-locale slug override; missing locales fall back to the kit default. */\nexport type LegalUrlOverride = Record<string, string>;\n\nexport interface LegalUrlOverrides {\n privacy?: LegalUrlOverride;\n terms?: LegalUrlOverride;\n contacts?: LegalUrlOverride;\n}\n\n/* Italian default — also used as the fallback for any locale without an\n * explicit entry below. */\nconst ITALIAN_SLUGS: LegalSlugMap = {\n privacy: '/privacy-prenotazione-online',\n terms: '/it/condizioni-di-utilizzo',\n contacts: '/it/contattaci',\n};\n\n/* Canonical per-locale slug table. Explicit entries come from marketing;\n * everything else inherits ITALIAN_SLUGS via the resolver below. */\nconst SLUGS: Record<string, LegalSlugMap> = {\n it: ITALIAN_SLUGS,\n en: {\n privacy: '/en/privacy',\n terms: '/en/terms-of-use',\n contacts: '/en/contact-us',\n },\n de: {\n privacy: '/de/datenschutz',\n terms: '/de/nutzungsbedingungen',\n contacts: '/de/kontakt',\n },\n fr: {\n privacy: '/fr/confidentialite',\n terms: '/fr/conditions-utilisation',\n contacts: '/fr/contact',\n },\n es: {\n privacy: '/es/privacidad',\n terms: '/es/condiciones-uso',\n contacts: '/es/contacto',\n },\n};\n\nconst HTTPS_PREFIX = 'https://';\n\nfunction normaliseBaseUrl(input: string | undefined): string {\n if (!input) return DEFAULT_MARKETING_BASE_URL;\n if (!input.startsWith(HTTPS_PREFIX)) {\n if (import.meta.env.DEV) {\n // eslint-disable-next-line no-console\n console.warn(\n `[PublicFooter] marketingBaseUrl must start with \"https://\" — falling back to ${DEFAULT_MARKETING_BASE_URL}. Received: \"${input}\"`,\n );\n }\n return DEFAULT_MARKETING_BASE_URL;\n }\n // Strip trailing slash so composed URLs don't double up.\n return input.replace(/\\/+$/, '');\n}\n\nfunction pickSlug(\n locale: string,\n key: LegalUrlKey,\n overrides: LegalUrlOverrides | undefined,\n): string {\n const override = overrides?.[key]?.[locale];\n if (override) return override;\n const localeSlug = SLUGS[locale]?.[key];\n if (localeSlug) return localeSlug;\n return ITALIAN_SLUGS[key];\n}\n\n/** Resolved legal URLs for the active locale + baseUrl + overrides. */\nexport interface ResolvedLegalUrls {\n privacy: string;\n terms: string;\n contacts: string;\n}\n\nexport function composeLegalUrls(\n locale: string,\n marketingBaseUrl: string | undefined,\n overrides?: LegalUrlOverrides,\n): ResolvedLegalUrls {\n const base = normaliseBaseUrl(marketingBaseUrl);\n const lang = (locale || 'it').split('-')[0]; // strip region — 'pt-BR' → 'pt'\n return {\n privacy: `${base}${pickSlug(lang, 'privacy', overrides)}`,\n terms: `${base}${pickSlug(lang, 'terms', overrides)}`,\n contacts: `${base}${pickSlug(lang, 'contacts', overrides)}`,\n };\n}\n","/* -------------------------------------------------------------------- */\n/* PublicFooter — default social-network URLs + brand icon components. */\n/* */\n/* AlfaDocs's four canonical social profiles. Consumers can subset via */\n/* `socials={[...]}` or override individual `href` values. */\n/* */\n/* Icons are small inline SVG components (paths from simpleicons.org) */\n/* rendered with `currentColor` so they inherit the footer's */\n/* `--muted-foreground` ink. Lucide-react does not ship brand glyphs, and */\n/* pulling a separate brand-icon package for four logos is not worth the */\n/* bundle cost. */\n/* -------------------------------------------------------------------- */\n\nimport type { ComponentType, SVGProps } from 'react';\n\nexport const SOCIAL_NETWORKS = [\n 'linkedin',\n 'youtube',\n 'instagram',\n 'facebook',\n] as const;\n\nexport type SocialNetwork = (typeof SOCIAL_NETWORKS)[number];\n\nexport const DEFAULT_SOCIAL_URLS: Record<SocialNetwork, string> = {\n linkedin: 'https://www.linkedin.com/company/alfadocs',\n youtube: 'https://www.youtube.com/@alfadocs',\n instagram: 'https://www.instagram.com/alfadocs',\n facebook: 'https://www.facebook.com/alfadocs',\n};\n\ntype IconProps = SVGProps<SVGSVGElement>;\ntype SocialIcon = ComponentType<IconProps>;\n\nconst baseProps = {\n viewBox: '0 0 24 24',\n fill: 'currentColor',\n xmlns: 'http://www.w3.org/2000/svg',\n} as const;\n\nconst LinkedinIcon: SocialIcon = (props) => (\n <svg {...baseProps} {...props}>\n <path d=\"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.063 2.063 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z\" />\n </svg>\n);\n\nconst YoutubeIcon: SocialIcon = (props) => (\n <svg {...baseProps} {...props}>\n <path d=\"M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z\" />\n </svg>\n);\n\nconst InstagramIcon: SocialIcon = (props) => (\n <svg {...baseProps} {...props}>\n <path d=\"M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm6.406-11.845a1.44 1.44 0 1 0 0 2.881 1.44 1.44 0 0 0 0-2.881z\" />\n </svg>\n);\n\nconst FacebookIcon: SocialIcon = (props) => (\n <svg {...baseProps} {...props}>\n <path d=\"M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z\" />\n </svg>\n);\n\nexport const SOCIAL_ICONS: Record<SocialNetwork, SocialIcon> = {\n linkedin: LinkedinIcon,\n youtube: YoutubeIcon,\n instagram: InstagramIcon,\n facebook: FacebookIcon,\n};\n","import {\n forwardRef,\n useImperativeHandle,\n useMemo,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Link } from '../link';\nimport { Separator } from '../separator';\nimport { Logo } from '../logo';\nimport {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from '../accordion';\nimport {\n composeLegalUrls,\n type LegalUrlOverrides,\n type ResolvedLegalUrls,\n} from './legal-urls';\nimport {\n DEFAULT_SOCIAL_URLS,\n SOCIAL_ICONS,\n SOCIAL_NETWORKS,\n type SocialNetwork,\n} from './socials';\n\n/* ------------------------------------------------------------------ */\n/* Constants */\n/* ------------------------------------------------------------------ */\n\nconst ENTITY_NAME = 'AlfaDocs GmbH';\nconst ENTITY_VAT = 'P.IVA DE301955405';\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst rootVariants = cva(\n [\n 'ds:w-full',\n 'ds:text-[color:var(--muted-foreground)]',\n 'ds:text-[length:var(--font-size-sm)]',\n 'ds:bg-[var(--background)]',\n ].join(' '),\n {\n variants: {\n variant: {\n minimal: [\n 'ds:py-[var(--spacing-sm)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:border-block-start ds:border-[var(--border)]',\n ].join(' '),\n // 0.30.5: compact got a polish pass — bumped vertical padding to\n // `lg` (~24px) so the footer reads as a real landmark, not a\n // one-line afterthought, plus a stronger top border in\n // accessible mode (the default `--border` clears 3:1 in light /\n // dark; accessible bumps to a heavier weight).\n //\n // 0.31.2: forced-colors top-border fallback. Windows High\n // Contrast strips `--border` to whatever the system maps it\n // to — which is often invisible against `Canvas`. Pinning to\n // `CanvasText` keeps the landmark edge visible for users on\n // strict HC themes.\n compact: [\n 'ds:py-[var(--spacing-lg)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:border-block-start ds:border-[var(--border)]',\n 'ds:[.theme-accessible_&]:[border-block-start-width:2px]',\n 'ds:forced-colors:[border-block-start-color:CanvasText]',\n ].join(' '),\n full: [\n 'ds:py-[var(--spacing-xl)]',\n 'ds:ps-[var(--spacing-lg)] ds:pe-[var(--spacing-lg)]',\n 'ds:bg-[var(--muted)]',\n ].join(' '),\n },\n },\n defaultVariants: { variant: 'compact' },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport type PublicFooterVariant = NonNullable<\n VariantProps<typeof rootVariants>['variant']\n>;\n\nexport interface PublicFooterLink {\n href: string;\n label: string;\n /** When true, link opens in a new tab with the localised aria-label suffix. */\n external?: boolean;\n}\n\nexport interface PublicFooterLinkGroup {\n /** Stable key — used to look up the column heading via `t('ui.footer.group.<key>')`. */\n key: 'product' | 'resources' | 'company' | 'legal' | (string & {});\n links: PublicFooterLink[];\n}\n\nexport interface PublicFooterSocial {\n network: SocialNetwork;\n /** Override the kit's default URL. */\n href?: string;\n}\n\nexport interface PublicFooterProps {\n variant: PublicFooterVariant;\n /** Origin for legally-required URLs. Default: 'https://www.alfadocs.com'. */\n marketingBaseUrl?: string;\n /** Override individual legal-link slugs per locale. Rare. */\n legalUrlOverrides?: LegalUrlOverrides;\n /** `full` variant: consumer-supplied link columns. Legal column is always rendered. */\n linkGroups?: PublicFooterLinkGroup[];\n /** `full` variant: subset of social networks. Default: all four. Pass `[]` to hide the row. */\n socials?: PublicFooterSocial[];\n /** `full` variant: custom logo node. Default: kit's wordmark Logo. */\n logoSlot?: ReactNode;\n /** Extra surface-specific links — appended after the standard nav row in compact + full. Ignored by minimal. */\n extraNavSlot?: ReactNode;\n /** Trust badges (HIPAA, ISO). Rendered at the start of `minimal`'s row, or in the bottom strip of `full`. */\n trustBadgesSlot?: ReactNode;\n /**\n * @default false\n * Render the brand tagline (\"German technology, Italian design\") in\n * the bottom microcopy row of `compact` and `full` variants.\n *\n * 0.32.4: default flipped to `false`. The tagline was loud on\n * booking-website's deployed footer and didn't carry product\n * meaning for end-users; marketing surfaces can opt back in\n * explicitly with `showTagline`. The `footer.tagline` i18n key\n * stays available so the opt-in path still works.\n */\n showTagline?: boolean;\n 'aria-label'?: string;\n id?: string;\n}\n\nexport interface PublicFooterHandle {\n getVariant: () => PublicFooterVariant;\n /** Resolved legal URLs for the current locale + marketingBaseUrl + overrides. */\n getLegalUrls: () => ResolvedLegalUrls;\n}\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\n/** Allowlist consumer-supplied URLs — public marketing surface, defence in depth. */\nconst SAFE_HREF_RE = /^(https?:\\/\\/|mailto:|tel:|\\/(?!\\/))/i;\nfunction safeHref(href: string): string {\n return SAFE_HREF_RE.test(href) ? href : '#';\n}\n\nfunction CopyrightLine({\n copyright,\n align = 'center',\n}: {\n copyright: string;\n align?: 'start' | 'center';\n}) {\n return (\n <p\n className={[\n 'ds:m-0 ds:text-[color:var(--muted-foreground)]',\n 'ds:text-[length:var(--font-size-sm)]',\n align === 'center' ? 'ds:text-center' : 'ds:text-start',\n ].join(' ')}\n >\n {copyright}\n </p>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* PublicFooter */\n/* ------------------------------------------------------------------ */\n\nexport const PublicFooter = forwardRef<PublicFooterHandle, PublicFooterProps>(\n function PublicFooter(\n {\n variant,\n marketingBaseUrl,\n legalUrlOverrides,\n linkGroups,\n socials,\n logoSlot,\n extraNavSlot,\n trustBadgesSlot,\n showTagline = false,\n id,\n 'aria-label': ariaLabel,\n },\n ref,\n ) {\n const { t, i18n } = useTranslation('ui');\n\n const legalUrls = useMemo(\n () =>\n composeLegalUrls(i18n.language, marketingBaseUrl, legalUrlOverrides),\n [i18n.language, marketingBaseUrl, legalUrlOverrides],\n );\n\n useImperativeHandle(\n ref,\n () => ({\n getVariant: () => variant,\n getLegalUrls: () => legalUrls,\n }),\n [variant, legalUrls],\n );\n\n const year = new Date().getFullYear();\n const copyright = t('footer.copyright', {\n year,\n entity: ENTITY_NAME,\n vat: ENTITY_VAT,\n });\n const tagline = showTagline ? t('footer.tagline') : undefined;\n const landmarkLabel = ariaLabel ?? t('footer.nav.label');\n\n const labels = {\n privacy: t('footer.nav.privacy'),\n terms: t('footer.nav.terms'),\n contacts: t('footer.nav.contacts'),\n };\n\n const resolvedSocials = useMemo<PublicFooterSocial[]>(() => {\n if (socials !== undefined) return socials;\n return SOCIAL_NETWORKS.map((network) => ({ network }));\n }, [socials]);\n\n return (\n <footer\n id={id}\n role=\"contentinfo\"\n aria-label={landmarkLabel}\n data-component=\"public-footer\"\n data-variant={variant}\n className={rootVariants({ variant })}\n >\n {variant === 'minimal' && (\n <MinimalBody\n legalUrls={legalUrls}\n labels={labels}\n copyright={copyright}\n trustBadgesSlot={trustBadgesSlot}\n />\n )}\n {variant === 'compact' && (\n <CompactBody\n legalUrls={legalUrls}\n labels={labels}\n copyright={copyright}\n tagline={tagline}\n socials={resolvedSocials}\n logoSlot={logoSlot}\n extraNavSlot={extraNavSlot}\n t={t}\n />\n )}\n {variant === 'full' && (\n <FullBody\n legalUrls={legalUrls}\n labels={labels}\n copyright={copyright}\n tagline={tagline}\n linkGroups={linkGroups}\n socials={resolvedSocials}\n logoSlot={logoSlot}\n extraNavSlot={extraNavSlot}\n trustBadgesSlot={trustBadgesSlot}\n t={t}\n />\n )}\n </footer>\n );\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Minimal */\n/* ------------------------------------------------------------------ */\n\nfunction MinimalBody({\n legalUrls,\n labels,\n copyright,\n trustBadgesSlot,\n}: {\n legalUrls: ResolvedLegalUrls;\n labels: { privacy: string; terms: string; contacts: string };\n copyright: string;\n trustBadgesSlot?: ReactNode;\n}) {\n return (\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-center ds:gap-x-[var(--spacing-sm)] ds:gap-y-[var(--spacing-sm)]\">\n {trustBadgesSlot && (\n <span\n data-slot=\"trust-badges\"\n className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-sm)] ds:me-[var(--spacing-sm)]\"\n >\n {trustBadgesSlot}\n </span>\n )}\n <Link\n href={legalUrls.privacy}\n external\n externalIcon={false}\n intent=\"subtle\"\n >\n {labels.privacy}\n </Link>\n <Separator orientation=\"vertical\" className=\"ds:h-4\" />\n <Link\n href={legalUrls.terms}\n external\n externalIcon={false}\n intent=\"subtle\"\n >\n {labels.terms}\n </Link>\n <Separator orientation=\"vertical\" className=\"ds:h-4\" />\n <span>{copyright}</span>\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Compact */\n/* ------------------------------------------------------------------ */\n\n// Shared social-icon row — used by Compact and Full. Renders an icon\n// per enabled network; the parent decides where to drop it.\nfunction SocialIconList({\n socials,\n t,\n size,\n}: {\n socials: PublicFooterSocial[];\n t: TFunction;\n size: 'sm' | 'md';\n}) {\n if (socials.length === 0) return null;\n const iconClass = size === 'sm' ? 'ds:size-4' : 'ds:size-5';\n return (\n <ul\n data-slot=\"socials\"\n className=\"ds:list-none ds:m-0 ds:p-0 ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\"\n >\n {socials.map((s) => {\n const Icon = SOCIAL_ICONS[s.network];\n const href = s.href ?? DEFAULT_SOCIAL_URLS[s.network];\n const label = t(`footer.social.aria.${s.network}`);\n return (\n <li key={s.network}>\n <Link\n href={safeHref(href)}\n external\n externalIcon={false}\n intent=\"subtle\"\n aria-label={label}\n className=\"ds:inline-flex ds:items-center ds:justify-center ds:min-w-[var(--min-target-size)] ds:min-h-[var(--min-target-size)]\"\n >\n <Icon\n aria-hidden=\"true\"\n className={iconClass}\n focusable=\"false\"\n />\n </Link>\n </li>\n );\n })}\n </ul>\n );\n}\n\nfunction CompactBody({\n legalUrls,\n labels,\n copyright,\n tagline,\n socials,\n logoSlot,\n extraNavSlot,\n t,\n}: {\n legalUrls: ResolvedLegalUrls;\n labels: { privacy: string; terms: string; contacts: string };\n copyright: string;\n tagline?: string;\n socials: PublicFooterSocial[];\n logoSlot?: ReactNode;\n extraNavSlot?: ReactNode;\n t: TFunction;\n}) {\n // 0.30.5: compact polish — defaults to a social-icon row + (small,\n // muted) wordmark at the start of the link row. Consumers who want\n // the lean treatment can opt out via `socials={[]}` (kills the row)\n // and `logoSlot={<></>}` (kills the wordmark). The lean fallback is\n // still a useful surface for embedded widgets (the booking aside).\n return (\n <div className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-md)]\">\n {socials.length > 0 ? (\n <SocialIconList socials={socials} t={t} size=\"sm\" />\n ) : null}\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-center ds:gap-x-[var(--spacing-sm)] ds:gap-y-[var(--spacing-sm)]\">\n {logoSlot !== undefined ? (\n logoSlot !== null && logoSlot !== false && logoSlot !== '' ? (\n <>\n <span\n data-slot=\"compact-logo\"\n className=\"ds:inline-flex ds:items-center ds:opacity-70\"\n >\n {logoSlot}\n </span>\n <Separator orientation=\"vertical\" className=\"ds:h-4\" />\n </>\n ) : null\n ) : (\n // No consumer override — render the kit's default small\n // wordmark, muted so it reads as marker not headline.\n <>\n <span\n data-slot=\"compact-logo\"\n className=\"ds:inline-flex ds:items-center ds:opacity-70\"\n >\n <Logo variant=\"wordmark\" tone=\"auto\" aria-label=\"AlfaDocs\" />\n </span>\n <Separator orientation=\"vertical\" className=\"ds:h-4\" />\n </>\n )}\n <Link\n href={legalUrls.privacy}\n external\n externalIcon={false}\n intent=\"subtle\"\n >\n {labels.privacy}\n </Link>\n <Separator orientation=\"vertical\" className=\"ds:h-4\" />\n <Link\n href={legalUrls.terms}\n external\n externalIcon={false}\n intent=\"subtle\"\n >\n {labels.terms}\n </Link>\n <Separator orientation=\"vertical\" className=\"ds:h-4\" />\n <Link\n href={legalUrls.contacts}\n external\n externalIcon={false}\n intent=\"subtle\"\n >\n {labels.contacts}\n </Link>\n {extraNavSlot && (\n <>\n <Separator orientation=\"vertical\" className=\"ds:h-4\" />\n <span data-slot=\"extra-nav\">{extraNavSlot}</span>\n </>\n )}\n </div>\n <CopyrightLine copyright={copyright} />\n {tagline ? (\n <p\n data-slot=\"tagline\"\n className=\"ds:m-0 ds:text-center ds:text-[color:var(--muted-foreground)] ds:text-[length:var(--font-size-xs)] ds:italic\"\n >\n {tagline}\n </p>\n ) : null}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Full */\n/* ------------------------------------------------------------------ */\n\ntype TFunction = ReturnType<typeof useTranslation>['t'];\n\nfunction buildLegalColumn(\n legalUrls: ResolvedLegalUrls,\n labels: { privacy: string; terms: string; contacts: string },\n): PublicFooterLinkGroup {\n return {\n key: 'legal',\n links: [\n { href: legalUrls.privacy, label: labels.privacy, external: true },\n { href: legalUrls.terms, label: labels.terms, external: true },\n { href: legalUrls.contacts, label: labels.contacts, external: true },\n ],\n };\n}\n\nfunction FullBody({\n legalUrls,\n labels,\n copyright,\n tagline,\n linkGroups,\n socials,\n logoSlot,\n extraNavSlot,\n trustBadgesSlot,\n t,\n}: {\n legalUrls: ResolvedLegalUrls;\n labels: { privacy: string; terms: string; contacts: string };\n copyright: string;\n tagline?: string;\n linkGroups?: PublicFooterLinkGroup[];\n socials: PublicFooterSocial[];\n logoSlot?: ReactNode;\n extraNavSlot?: ReactNode;\n trustBadgesSlot?: ReactNode;\n t: TFunction;\n}) {\n // The kit-built Legal column is always appended — Privacy / Terms /\n // Contacts must render in every variant per the legal brief.\n const columns: PublicFooterLinkGroup[] = [\n ...(linkGroups ?? []),\n buildLegalColumn(legalUrls, labels),\n ];\n\n const brand = (\n <div\n data-slot=\"brand\"\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\"\n >\n <div className=\"ds:inline-flex\">\n {logoSlot ?? (\n <Logo variant=\"wordmark\" tone=\"auto\" aria-label=\"AlfaDocs\" />\n )}\n </div>\n <SocialIconList socials={socials} t={t} size=\"md\" />\n </div>\n );\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xl)]\">\n {/* Top: brand block on inline-start + link columns to inline-end */}\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xl)] ds:lg:flex-row ds:lg:items-start ds:lg:gap-[var(--spacing-xl)]\">\n <div className=\"ds:lg:w-[15rem] ds:lg:shrink-0\">{brand}</div>\n\n <div className=\"ds:flex-1 ds:min-w-0\">\n {/* md+ — grid of columns */}\n <div\n className=\"ds:hidden ds:md:grid ds:md:grid-cols-2 ds:lg:grid-cols-4 ds:gap-[var(--spacing-lg)]\"\n data-slot=\"link-columns-grid\"\n data-columns={columns.length}\n >\n <FullColumnsGrid columns={columns} t={t} />\n </div>\n\n {/* below md — accordion */}\n <div className=\"ds:md:hidden\" data-slot=\"link-columns-accordion\">\n <Accordion type=\"multiple\">\n {columns.map((group, i) => (\n <AccordionItem\n key={`${i}-${group.key}`}\n value={`${i}-${group.key}`}\n >\n <AccordionTrigger>\n {t(`footer.group.${group.key}`, {\n defaultValue: group.key,\n })}\n </AccordionTrigger>\n <AccordionContent>\n <ul className=\"ds:list-none ds:m-0 ds:p-0 ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {group.links.map((link) => (\n <li key={`${group.key}-${link.href}-${link.label}`}>\n <Link\n href={safeHref(link.href)}\n external={link.external}\n externalIcon={false}\n intent=\"subtle\"\n >\n {link.label}\n </Link>\n </li>\n ))}\n </ul>\n </AccordionContent>\n </AccordionItem>\n ))}\n </Accordion>\n </div>\n </div>\n </div>\n\n <Separator orientation=\"horizontal\" />\n\n {/* Bottom strip: copyright inline-start, mini legal links inline-end\n on the same row. Stacks under sm. */}\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:sm:flex-row ds:sm:items-center ds:sm:justify-between\">\n <CopyrightLine copyright={copyright} align=\"start\" />\n <div\n data-slot=\"bottom-legal\"\n className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)] ds:sm:justify-end\"\n >\n <Link\n href={legalUrls.privacy}\n external\n externalIcon={false}\n intent=\"subtle\"\n >\n {labels.privacy}\n </Link>\n <Separator orientation=\"vertical\" className=\"ds:h-4\" />\n <Link\n href={legalUrls.terms}\n external\n externalIcon={false}\n intent=\"subtle\"\n >\n {labels.terms}\n </Link>\n {(trustBadgesSlot || extraNavSlot) && (\n <>\n <Separator orientation=\"vertical\" className=\"ds:h-4\" />\n {trustBadgesSlot && (\n <span\n data-slot=\"trust-badges\"\n className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-sm)]\"\n >\n {trustBadgesSlot}\n </span>\n )}\n {extraNavSlot && (\n <span\n data-slot=\"extra-nav\"\n className=\"ds:inline-flex ds:items-center\"\n >\n {extraNavSlot}\n </span>\n )}\n </>\n )}\n </div>\n </div>\n\n {tagline ? (\n <p\n data-slot=\"tagline\"\n className=\"ds:m-0 ds:text-center ds:text-[color:var(--muted-foreground)] ds:text-[length:var(--font-size-xs)] ds:italic\"\n >\n {tagline}\n </p>\n ) : null}\n </div>\n );\n}\n\nfunction FullColumnsGrid({\n columns,\n t,\n}: {\n columns: PublicFooterLinkGroup[];\n t: TFunction;\n}) {\n return (\n <>\n {columns.map((group, i) => (\n <section\n key={`${i}-${group.key}`}\n aria-labelledby={`public-footer-group-${i}-${group.key}`}\n >\n {/* h3 so the footer's column headings don't collide with the host\n page's section h2 outline. */}\n <h3\n id={`public-footer-group-${i}-${group.key}`}\n className=\"ds:m-0 ds:mb-[var(--spacing-sm)] ds:text-[color:var(--foreground)] ds:text-[length:var(--font-size-sm)] ds:font-medium\"\n >\n {t(`footer.group.${group.key}`, { defaultValue: group.key })}\n </h3>\n <ul className=\"ds:list-none ds:m-0 ds:p-0 ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {group.links.map((link) => (\n <li key={`${group.key}-${link.href}-${link.label}`}>\n <Link\n href={safeHref(link.href)}\n external={link.external}\n externalIcon={false}\n intent=\"subtle\"\n >\n {link.label}\n </Link>\n </li>\n ))}\n </ul>\n </section>\n ))}\n </>\n );\n}\n\nPublicFooter.displayName = 'PublicFooter';\n","/* -------------------------------------------------------------------- */\n/* Agent adapter — PublicFooter. */\n/* */\n/* PublicFooter is the kit's legally-grounded site footer with three */\n/* visual variants (minimal/compact/full). The adapter surfaces the */\n/* active variant + a `get_legal_urls` read so a host agent can verify */\n/* that the consumer's `marketingBaseUrl` + locale resolve to the */\n/* expected privacy / terms / contacts URLs without scraping DOM. */\n/* No write actions — the footer has no mutable state. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { PublicFooterHandle } from './public-footer';\n\nexport const publicFooterAgent: AgentAdapter<PublicFooterHandle> = {\n id: 'public-footer',\n capabilities: ['navigate'],\n state: {\n variant: {\n type: 'string',\n description: 'Active variant — one of `minimal`, `compact`, `full`.',\n read: (handle) => handle.getVariant(),\n },\n legalUrls: {\n type: 'object',\n description:\n 'Resolved legal URLs for the active locale + marketingBaseUrl + overrides: `{ privacy, terms, contacts }`.',\n read: (handle) => handle.getLegalUrls(),\n },\n },\n actions: {},\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'public-footer',\n description:\n 'Marks the PublicFooter root region. The root also carries `data-variant=\"minimal|compact|full\"` for CSS + agent selectors.',\n },\n instanceId: {\n attr: 'id',\n sourceProp: 'id',\n description: 'Sourced from the `id` prop when provided.',\n },\n },\n};\n"],"names":["DEFAULT_MARKETING_BASE_URL","ITALIAN_SLUGS","SLUGS","HTTPS_PREFIX","normaliseBaseUrl","input","pickSlug","locale","key","overrides","override","_a","localeSlug","_b","composeLegalUrls","marketingBaseUrl","base","lang","SOCIAL_NETWORKS","DEFAULT_SOCIAL_URLS","baseProps","LinkedinIcon","props","jsx","YoutubeIcon","InstagramIcon","FacebookIcon","SOCIAL_ICONS","ENTITY_NAME","ENTITY_VAT","rootVariants","cva","SAFE_HREF_RE","safeHref","href","CopyrightLine","copyright","align","PublicFooter","forwardRef","variant","legalUrlOverrides","linkGroups","socials","logoSlot","extraNavSlot","trustBadgesSlot","showTagline","id","ariaLabel","ref","t","i18n","useTranslation","legalUrls","useMemo","useImperativeHandle","year","tagline","landmarkLabel","labels","resolvedSocials","network","jsxs","MinimalBody","CompactBody","FullBody","Link","Separator","SocialIconList","size","iconClass","s","Icon","label","Fragment","Logo","buildLegalColumn","columns","FullColumnsGrid","Accordion","group","i","AccordionItem","AccordionTrigger","AccordionContent","link","publicFooterAgent","handle"],"mappings":"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"}
|
|
@@ -211,7 +211,7 @@ function ie({
|
|
|
211
211
|
// text on the violet pill (~3:1, AA-fail). Match the
|
|
212
212
|
// row's foreground when selected; slight opacity
|
|
213
213
|
// keeps the count secondary to the label.
|
|
214
|
-
S ? "ds:text-[color:var(--primary-foreground)]
|
|
214
|
+
S ? "ds:text-[color:var(--primary-foreground)]" : "ds:text-[var(--muted-foreground)]"
|
|
215
215
|
].join(" "),
|
|
216
216
|
children: v
|
|
217
217
|
}
|
|
@@ -533,4 +533,4 @@ export {
|
|
|
533
533
|
oe as R,
|
|
534
534
|
re as r
|
|
535
535
|
};
|
|
536
|
-
//# sourceMappingURL=reviews-panel-
|
|
536
|
+
//# sourceMappingURL=reviews-panel-Dow8Dzoa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviews-panel-Dow8Dzoa.js","sources":["../../src/components/reviews-panel/reviews-panel.agent.ts","../../src/components/reviews-panel/reviews-panel.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — ReviewsPanel. */\n/* */\n/* Replaces the legacy patient-reviews Carousel with a single panel that */\n/* surfaces an aggregate score, a star-bucket filter, and a vertical list */\n/* of compact review cards. The adapter exposes the active filter and the */\n/* visible review count so a host agent can drive the panel and observe */\n/* what the user actually sees after the filter is applied. The reviews */\n/* themselves remain owned by the consumer — they never flow through the */\n/* adapter (PHI: pseudonyms + free-text comments stay on the page). */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ReviewFilter, ReviewsPanelHandle } from './reviews-panel';\n\nexport const reviewsPanelAgent: AgentAdapter<ReviewsPanelHandle> = {\n id: 'reviews-panel',\n capabilities: ['filter'],\n state: {\n filter: {\n type: 'string',\n descriptionKey: 'ui.agent.reviewsPanel.state.filter',\n description:\n 'Active star-bucket filter — `\"all\"` or an integer 1..5. Reads the controlled `filter` prop.',\n read: (handle) => handle.getFilter(),\n },\n visibleCount: {\n type: 'number',\n descriptionKey: 'ui.agent.reviewsPanel.state.visibleCount',\n description:\n 'Number of reviews currently rendered after the filter is applied.',\n read: (handle) => handle.getVisibleCount(),\n },\n },\n actions: {\n set_filter: {\n safety: 'read',\n argsType: '{ filter: \"all\" | 1 | 2 | 3 | 4 | 5 }',\n descriptionKey: 'ui.agent.reviewsPanel.actions.setFilter',\n description:\n 'Narrow the visible review list to a star bucket, or `\"all\"` to clear the filter.',\n invoke: (handle, args: { filter: ReviewFilter }) => {\n handle.setFilter(args.filter);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'reviews-panel',\n description: 'Marks the ReviewsPanel root region.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { ChevronDown } from 'lucide-react';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { reviewsPanelAgent } from './reviews-panel.agent';\nimport { Rating } from '../rating/rating';\nimport { Card } from '../card/card';\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '../collapsible/collapsible';\nimport { DescriptionList } from '../description-list/description-list';\nimport { EmptyState } from '../empty-state/empty-state';\nimport { Skeleton } from '../skeleton/skeleton';\nimport { Button } from '../button/button';\n\n/* -------------------------------------------------------------------- */\n/* ReviewsPanel */\n/* */\n/* Replaces the legacy patient-reviews Carousel with a two-column panel */\n/* — a star-bucket filter sidebar + a vertical list of compact review */\n/* cards — that surfaces the aggregate score, the volume, and (via a */\n/* per-card Collapsible) the rich per-axis breakdown alfaDocs already */\n/* collects but the carousel buried. */\n/* -------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------- */\n/* Public types */\n/* -------------------------------------------------------------------- */\n\nexport interface ReviewItem {\n id: string;\n /** When the review was authored (ISO 8601). */\n authoredAt: string;\n /** Anonymised author display (\"Marco T.\", \"Anna_M\"). Falls back to a localised \"Anonymous\". */\n pseudonym?: string;\n /** 0..max — drives the visible star summary on the compact card. */\n overallScore: number;\n /** Short free-text comment shown on the compact card. */\n comment?: string;\n /** Practice reply (revealed in the expanded panel only). */\n reply?: string;\n /** Optional per-axis breakdown — when present, the card grows an\n * \"Expand\" affordance that reveals these in a DescriptionList. */\n breakdown?: {\n appointmentScore?: number;\n communicationScore?: number;\n staffScore?: number;\n overallScore?: number;\n };\n /** Optional categorical follow-ups, surfaced inside the breakdown. */\n futureVisit?: 'yes' | 'no' | 'unsure';\n recommendation?: 'yes' | 'no' | 'unsure';\n}\n\nexport interface ReviewsAggregate {\n /** Total review count across all star buckets (may exceed the loaded set when paginated). */\n count: number;\n /** Average score across the full population (drives the header `Rating`). */\n averageScore: number;\n /**\n * Optional histogram — per-bucket count keyed by integer star value 1..5.\n * When omitted, the panel derives buckets from the loaded `reviews` array\n * (best-effort: paginated consumers SHOULD provide this explicitly).\n */\n histogram?: Record<1 | 2 | 3 | 4 | 5, number>;\n}\n\nexport type ReviewFilter = 'all' | 1 | 2 | 3 | 4 | 5;\n\nexport interface ReviewsPanelHandle {\n getFilter: () => ReviewFilter;\n setFilter: (next: ReviewFilter) => void;\n /** Total visible after filter is applied. */\n getVisibleCount: () => number;\n}\n\nexport interface ReviewsPanelProps extends Omit<\n ComponentPropsWithoutRef<'section'>,\n 'aria-label' | 'children'\n> {\n reviews: ReviewItem[];\n aggregate: ReviewsAggregate;\n\n /**\n * Active star filter. Controlled — consumer owns it for shareability via\n * URL query strings. Omit for uncontrolled (panel-managed) filtering.\n */\n filter?: ReviewFilter;\n onFilterChange?: (next: ReviewFilter) => void;\n\n /**\n * Optional intro callout shown above the list (e.g. \"Riepilogo delle\n * opinioni — i pazienti raccontano…\"). Render-prop slot so the consumer\n * can drop in `<Alert>` / `<Callout>` / plain `<p>`.\n */\n introSlot?: ReactNode;\n\n /** Optional header right-end action (e.g. a \"Leave a review\" button). */\n headerActionSlot?: ReactNode;\n\n /** Override the default region aria-label. */\n 'aria-label'?: string;\n\n /** Agent-readiness id. */\n id?: string;\n\n className?: string;\n\n /**\n * Hide the filter sidebar — useful when the panel mounts under ~640px\n * width or inside a narrow column. Defaults to false.\n */\n hideFilter?: boolean;\n\n /**\n * @default 'flat'\n * `'elevated'` wraps the panel in the equivalent of `Card variant=\"elevated\"`\n * — same tokens (`--card`, `--card-border`, `--shadow-card`,\n * `--radius-lg`), same padding. Use to drop the consumer-side\n * `<Card><Card.Body>` wrap.\n */\n surface?: 'flat' | 'elevated';\n\n /** Render skeletons for the header and the list. */\n loading?: boolean;\n}\n\n/* -------------------------------------------------------------------- */\n/* Constants & helpers */\n/* -------------------------------------------------------------------- */\n\nconst FILTER_VALUES: readonly ReviewFilter[] = ['all', 5, 4, 3, 2, 1] as const;\n\nfunction bucketOf(score: number): 1 | 2 | 3 | 4 | 5 {\n const n = Math.min(5, Math.max(1, Math.floor(score)));\n return n as 1 | 2 | 3 | 4 | 5;\n}\n\nfunction deriveHistogram(\n reviews: ReviewItem[],\n): Record<1 | 2 | 3 | 4 | 5, number> {\n const out: Record<1 | 2 | 3 | 4 | 5, number> = {\n 1: 0,\n 2: 0,\n 3: 0,\n 4: 0,\n 5: 0,\n };\n for (const r of reviews) out[bucketOf(r.overallScore)] += 1;\n return out;\n}\n\n/* -------------------------------------------------------------------- */\n/* FilterSidebar — hand-rolled radiogroup with roving tabindex */\n/* */\n/* Mirrors `ServiceGrid` in `booking.tsx`: the WAI-ARIA RadioGroup */\n/* pattern with full-row click target + icon column. NOT Radix */\n/* `RadioGroup` because we need a row layout with a non-text leading */\n/* glyph (the star ramp) and a trailing count. */\n/* */\n/* Activation is automatic — Arrow keys move BOTH focus and selection, */\n/* so a keyboard user feels the same responsiveness as a mouse user. */\n/* That's the right call here because filter activation is cheap (re- */\n/* renders the visible list); contrast with the booking ServiceGrid */\n/* where activation cascades through downstream selection state. */\n/* -------------------------------------------------------------------- */\n\nconst filterRowVariants = cva(\n [\n 'ds:relative ds:flex ds:w-full ds:items-center ds:justify-between',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:min-h-[var(--min-target-size)]',\n 'ds:rounded-[var(--radius-md)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:pt-[var(--spacing-2xs)] ds:pb-[var(--spacing-2xs)]',\n 'ds:text-start',\n 'ds:transition-[background-color,color]',\n 'ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:cursor-pointer',\n ].join(' '),\n {\n variants: {\n state: {\n idle: 'ds:hover:bg-[var(--muted)]/30 ds:text-[var(--foreground)]',\n selected: [\n 'ds:bg-[var(--primary)]',\n 'ds:text-[var(--primary-foreground)]',\n 'ds:font-[var(--font-weight-semibold)]',\n ].join(' '),\n },\n },\n defaultVariants: { state: 'idle' },\n },\n);\n\ninterface FilterSidebarProps {\n filter: ReviewFilter;\n histogram: Record<1 | 2 | 3 | 4 | 5, number>;\n totalCount: number;\n onChange: (next: ReviewFilter) => void;\n}\n\nfunction FilterSidebar({\n filter,\n histogram,\n totalCount,\n onChange,\n}: FilterSidebarProps) {\n const { t } = useTranslation();\n const labelId = useId();\n\n // Roving tabindex tracks where keyboard focus is. We use AUTOMATIC\n // activation: arrow keys move focus AND fire onChange (see the rationale\n // above the component). To keep the visible aria-checked row and the\n // tab-stop aligned when the parent changes `filter` externally (e.g.\n // from a `?filter=4` URL parameter on page load), sync focusIndex to\n // the current filter via the effect below — without it, the tab stop\n // could land on `All` while the highlight shows `4`.\n const [focusIndex, setFocusIndex] = useState<number>(() =>\n Math.max(0, FILTER_VALUES.indexOf(filter)),\n );\n useEffect(() => {\n const i = FILTER_VALUES.indexOf(filter);\n if (i >= 0) setFocusIndex(i);\n }, [filter]);\n\n const rowRefs = useRef<Map<number, HTMLButtonElement>>(new Map());\n const focusAt = useCallback((index: number) => {\n rowRefs.current.get(index)?.focus();\n }, []);\n\n const total = FILTER_VALUES.length;\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLButtonElement>, index: number) => {\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowRight': {\n event.preventDefault();\n const next = (index + 1) % total;\n setFocusIndex(next);\n focusAt(next);\n onChange(FILTER_VALUES[next]);\n break;\n }\n case 'ArrowUp':\n case 'ArrowLeft': {\n event.preventDefault();\n const prev = (index - 1 + total) % total;\n setFocusIndex(prev);\n focusAt(prev);\n onChange(FILTER_VALUES[prev]);\n break;\n }\n case 'Home': {\n event.preventDefault();\n setFocusIndex(0);\n focusAt(0);\n onChange(FILTER_VALUES[0]);\n break;\n }\n case 'End': {\n event.preventDefault();\n const last = total - 1;\n setFocusIndex(last);\n focusAt(last);\n onChange(FILTER_VALUES[last]);\n break;\n }\n case 'Enter':\n case ' ': {\n event.preventDefault();\n onChange(FILTER_VALUES[index]);\n break;\n }\n default:\n break;\n }\n },\n [total, focusAt, onChange],\n );\n\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n <h3\n id={labelId}\n className=\"type-label ds:font-[var(--font-weight-semibold)] ds:text-[var(--foreground)] ds:m-0\"\n >\n {t('reviewsPanel.filterTitle')}\n </h3>\n <div\n role=\"radiogroup\"\n aria-labelledby={labelId}\n className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-2xs)]\"\n >\n {FILTER_VALUES.map((val, index) => {\n const isAll = val === 'all';\n const stars = isAll ? 0 : (val as 1 | 2 | 3 | 4 | 5);\n const count = isAll\n ? totalCount\n : histogram[stars as 1 | 2 | 3 | 4 | 5];\n const isSelected = val === filter;\n const isFocused = focusIndex === index;\n const ariaLabel = isAll\n ? t('reviewsPanel.filter.allLabel', { count })\n : t('reviewsPanel.filter.starsLabel', { stars, count });\n\n return (\n <button\n key={String(val)}\n ref={(node) => {\n if (node) rowRefs.current.set(index, node);\n else rowRefs.current.delete(index);\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={isSelected}\n aria-label={ariaLabel}\n tabIndex={isFocused ? 0 : -1}\n onClick={() => {\n setFocusIndex(index);\n onChange(val);\n }}\n onFocus={() => setFocusIndex(index)}\n onKeyDown={(e) => handleKeyDown(e, index)}\n data-filter-bucket={String(val)}\n className={filterRowVariants({\n state: isSelected ? 'selected' : 'idle',\n })}\n >\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]\"\n >\n {isAll ? (\n <span className=\"type-label\">\n {t('reviewsPanel.filter.allShort')}\n </span>\n ) : (\n <Rating value={stars} size=\"sm\" decorative />\n )}\n </span>\n <span\n aria-hidden=\"true\"\n className={[\n 'type-meta',\n // Idle row: count is dimmed (--muted-foreground over\n // --background ≈ 4.5:1, AA passes). Selected row\n // paints violet bg + white text on the BUTTON, but\n // the count's own explicit color override would\n // otherwise win the cascade and leave dark navy-grey\n // text on the violet pill (~3:1, AA-fail). Match the\n // row's foreground when selected; slight opacity\n // keeps the count secondary to the label.\n isSelected\n ? 'ds:text-[color:var(--primary-foreground)]'\n : 'ds:text-[var(--muted-foreground)]',\n ].join(' ')}\n >\n {count}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* ReviewCard — compact card with optional Collapsible breakdown */\n/* -------------------------------------------------------------------- */\n\ninterface ReviewCardProps {\n review: ReviewItem;\n locale: string;\n}\n\nfunction ReviewCard({ review, locale }: ReviewCardProps) {\n const { t } = useTranslation();\n const triggerId = useId();\n const contentId = useId();\n const [open, setOpen] = useState(false);\n\n const breakdownHasValues = Boolean(\n review.breakdown && Object.values(review.breakdown).some((v) => v != null),\n );\n const hasDetails =\n Boolean(review.reply) ||\n breakdownHasValues ||\n Boolean(review.futureVisit) ||\n Boolean(review.recommendation);\n\n const formattedDate = useMemo(() => {\n if (!review.authoredAt) return '';\n try {\n const parsed = new Date(review.authoredAt);\n if (Number.isNaN(parsed.getTime())) return review.authoredAt;\n return new Intl.DateTimeFormat(locale, { dateStyle: 'medium' }).format(\n parsed,\n );\n } catch {\n return review.authoredAt;\n }\n }, [review.authoredAt, locale]);\n\n const pseudonym = review.pseudonym ?? t('reviewsPanel.anonymous');\n\n // Compose the full Card body. The Collapsible wraps the footer + the\n // hidden content so both share the same Radix Root and the Trigger's\n // `data-state` reaches the Content automatically (used for the height\n // animation). The Footer + Content are direct Card children so the\n // Card root's flex-col places them in order.\n const footerAndDetails = (\n <Collapsible\n open={hasDetails ? open : false}\n onOpenChange={hasDetails ? setOpen : undefined}\n >\n <Card.Footer>\n <span className=\"type-meta ds:text-[var(--muted-foreground)]\">\n {formattedDate}\n </span>\n {hasDetails ? (\n <CollapsibleTrigger asChild>\n <button\n id={triggerId}\n type=\"button\"\n data-review-trigger\n className=\"ds:ms-auto ds:inline-flex ds:items-center ds:gap-[var(--spacing-2xs)] ds:rounded-[var(--radius-sm)] ds:ps-[var(--spacing-2xs)] ds:pe-[var(--spacing-2xs)] ds:pt-[var(--spacing-2xs)] ds:pb-[var(--spacing-2xs)] ds:bg-transparent ds:border-0 ds:text-[length:var(--font-size-sm)] ds:text-[var(--primary)] ds:hover:underline ds:cursor-pointer ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)] ds:forced-colors:focus-visible:outline-[CanvasText]\"\n >\n {open\n ? t('reviewsPanel.card.collapse')\n : t('reviewsPanel.card.expand')}\n <ChevronDown\n aria-hidden=\"true\"\n className={[\n 'ds:size-4 ds:transition-transform ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n open ? 'ds:rotate-180' : '',\n ]\n .filter(Boolean)\n .join(' ')}\n />\n </button>\n </CollapsibleTrigger>\n ) : null}\n </Card.Footer>\n {hasDetails ? (\n <CollapsibleContent id={contentId} aria-labelledby={triggerId}>\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)] ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:pb-[var(--spacing-md)]\">\n {breakdownHasValues ||\n review.futureVisit ||\n review.recommendation ? (\n <DescriptionList layout=\"inline\" density=\"compact\">\n {review.breakdown?.appointmentScore != null ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('reviewsPanel.breakdown.appointment')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n <Rating\n value={review.breakdown.appointmentScore}\n size=\"sm\"\n />\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n {review.breakdown?.communicationScore != null ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('reviewsPanel.breakdown.communication')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n <Rating\n value={review.breakdown.communicationScore}\n size=\"sm\"\n />\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n {review.breakdown?.staffScore != null ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('reviewsPanel.breakdown.staff')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n <Rating value={review.breakdown.staffScore} size=\"sm\" />\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n {review.breakdown?.overallScore != null ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('reviewsPanel.breakdown.overall')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n <Rating value={review.breakdown.overallScore} size=\"sm\" />\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n {review.futureVisit ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('reviewsPanel.breakdown.futureVisit')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n {t(`reviewsPanel.answer.${review.futureVisit}`)}\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n {review.recommendation ? (\n <DescriptionList.Row>\n <DescriptionList.Term>\n {t('reviewsPanel.breakdown.recommendation')}\n </DescriptionList.Term>\n <DescriptionList.Detail>\n {t(`reviewsPanel.answer.${review.recommendation}`)}\n </DescriptionList.Detail>\n </DescriptionList.Row>\n ) : null}\n </DescriptionList>\n ) : null}\n {review.reply ? (\n <div className=\"ds:rounded-[var(--radius-sm)] ds:bg-[var(--muted)]/40 ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:pt-[var(--spacing-sm)] ds:pb-[var(--spacing-sm)]\">\n <p className=\"type-label ds:m-0 ds:mb-[var(--spacing-2xs)] ds:text-[var(--muted-foreground)] ds:font-[var(--font-weight-semibold)]\">\n {t('reviewsPanel.replyTitle')}\n </p>\n <p className=\"type-body-sm ds:m-0 ds:text-[var(--foreground)] ds:[white-space:pre-line]\">\n {review.reply}\n </p>\n </div>\n ) : null}\n </div>\n </CollapsibleContent>\n ) : null}\n </Collapsible>\n );\n\n return (\n <Card variant=\"default\" className=\"ds:shadow-[var(--shadow-sm)]\">\n <Card.Header>\n <div className=\"ds:flex ds:items-start ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <h4 className=\"type-title-item ds:m-0 ds:text-[var(--foreground)]\">\n {pseudonym}\n </h4>\n <Rating value={review.overallScore} size=\"sm\" />\n </div>\n </Card.Header>\n {review.comment ? (\n <Card.Body>\n <p className=\"type-body ds:m-0 ds:text-[var(--foreground)] ds:line-clamp-2\">\n {review.comment}\n </p>\n </Card.Body>\n ) : null}\n {footerAndDetails}\n </Card>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* PanelSkeleton — loading state */\n/* -------------------------------------------------------------------- */\n\nfunction PanelSkeleton({ hideFilter }: { hideFilter: boolean }) {\n // The parent <section> already carries `aria-busy=\"true\"`, which is the\n // canonical SR signal for \"this region is loading\". Don't add `role=status`\n // + `aria-live=polite` here too — pairing both would double-announce on\n // mount. Skeleton itself is `aria-hidden`.\n return (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)]\">\n <div className=\"ds:flex ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <Skeleton variant=\"text\" width=\"40%\" />\n <Skeleton variant=\"text\" width=\"20%\" />\n </div>\n <div\n className={\n hideFilter\n ? 'ds:flex ds:flex-col ds:gap-[var(--spacing-md)]'\n : 'ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:md:grid-cols-[minmax(0,30%)_minmax(0,1fr)]'\n }\n >\n {!hideFilter ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n {Array.from({ length: 6 }, (_, i) => (\n <Skeleton key={`rp-fs-${i}`} variant=\"rounded\" height=\"2.5rem\" />\n ))}\n </div>\n ) : null}\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\">\n {Array.from({ length: 3 }, (_, i) => (\n <Skeleton key={`rp-rs-${i}`} variant=\"rounded\" height=\"6rem\" />\n ))}\n </div>\n </div>\n </div>\n );\n}\n\n/* -------------------------------------------------------------------- */\n/* Root variants */\n/* -------------------------------------------------------------------- */\n\nconst rootVariants = cva(\n 'ds:flex ds:w-full ds:flex-col ds:gap-[var(--spacing-md)] ds:text-[var(--foreground)]',\n {\n variants: {\n // `surface=\"elevated\"` matches `Card variant=\"elevated\"` — same\n // tokens, same padding, same boundary behaviour — so consumers can\n // drop their own Card wraps without producing a double-card look.\n // Default `'flat'` preserves 0.30.x rendering (no wrapping).\n surface: {\n flat: '',\n elevated: [\n 'ds:rounded-[var(--radius-lg)]',\n 'ds:bg-[var(--card)] ds:text-[var(--card-foreground)]',\n 'ds:border ds:border-[color:var(--card-border)]',\n 'ds:shadow-[var(--shadow-card)]',\n 'ds:p-[var(--spacing-md)]',\n ].join(' '),\n },\n },\n defaultVariants: { surface: 'flat' },\n },\n);\n\n/* -------------------------------------------------------------------- */\n/* ReviewsPanel */\n/* -------------------------------------------------------------------- */\n\nexport const ReviewsPanel = forwardRef<HTMLElement, ReviewsPanelProps>(\n (\n {\n reviews,\n aggregate,\n filter: filterProp,\n onFilterChange,\n introSlot,\n headerActionSlot,\n 'aria-label': ariaLabel,\n id,\n className,\n hideFilter = false,\n surface = 'flat',\n loading = false,\n ...rest\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n const locale = i18n.language ?? 'en';\n\n // Controlled / uncontrolled filter handling. When `filterProp` is\n // undefined the panel manages the filter internally — the consumer can\n // mount the panel and never wire `filter` / `onFilterChange` for the\n // common case where the URL doesn't carry the filter state. When the\n // prop IS provided, the consumer owns the truth.\n const [internalFilter, setInternalFilter] = useState<ReviewFilter>('all');\n const filter = filterProp ?? internalFilter;\n\n const handleFilterChange = useCallback(\n (next: ReviewFilter) => {\n if (filterProp === undefined) setInternalFilter(next);\n onFilterChange?.(next);\n },\n [filterProp, onFilterChange],\n );\n\n // Prefer the consumer-provided histogram; fall back to deriving from the\n // loaded reviews. Pagination consumers SHOULD pass an explicit histogram\n // so the per-bucket counts reflect server-side totals rather than only\n // what's loaded on this page.\n const histogram = useMemo(\n () => aggregate.histogram ?? deriveHistogram(reviews),\n [aggregate.histogram, reviews],\n );\n\n const visibleReviews = useMemo(() => {\n if (filter === 'all') return reviews;\n return reviews.filter((r) => bucketOf(r.overallScore) === filter);\n }, [reviews, filter]);\n\n /* Agent registration — exposes filter + visible count via refs so the\n imperative handle returns the latest values without re-creating the\n handle on every render. */\n const latestFilterRef = useRef(filter);\n latestFilterRef.current = filter;\n const latestVisibleCountRef = useRef(visibleReviews.length);\n latestVisibleCountRef.current = visibleReviews.length;\n\n const agentHandle = useMemo<ReviewsPanelHandle>(\n () => ({\n getFilter: () => latestFilterRef.current,\n setFilter: (next) => handleFilterChange(next),\n getVisibleCount: () => latestVisibleCountRef.current,\n }),\n [handleFilterChange],\n );\n\n const rootRef = useRef<HTMLElement>(null);\n useImperativeHandle(ref, () => rootRef.current as HTMLElement, []);\n useAgentRegistration(reviewsPanelAgent, agentHandle, id);\n\n const resolvedAriaLabel = ariaLabel ?? t('reviewsPanel.regionLabel');\n const dataFilter = String(filter);\n\n /* ---------------------------- Loading ---------------------------- */\n if (loading) {\n return (\n <section\n ref={rootRef as React.Ref<HTMLElement>}\n aria-label={resolvedAriaLabel}\n aria-busy=\"true\"\n id={id}\n data-component=\"reviews-panel\"\n data-component-id={id}\n data-filter={dataFilter}\n data-state=\"loading\"\n className={rootVariants({ surface, className })}\n {...rest}\n >\n <PanelSkeleton hideFilter={hideFilter} />\n </section>\n );\n }\n\n /* ----------------------- Zero-total empty ------------------------ */\n // No header, no filter — just the EmptyState. The region landmark is\n // still emitted so an agent can locate the empty panel by its\n // data-component marker.\n if (aggregate.count === 0 && reviews.length === 0) {\n return (\n <section\n ref={rootRef as React.Ref<HTMLElement>}\n aria-label={resolvedAriaLabel}\n id={id}\n data-component=\"reviews-panel\"\n data-component-id={id}\n data-filter={dataFilter}\n data-state=\"empty\"\n className={rootVariants({ surface, className })}\n {...rest}\n >\n <EmptyState\n variant=\"no-results\"\n title={t('reviewsPanel.empty.title')}\n description={t('reviewsPanel.empty.description')}\n />\n </section>\n );\n }\n\n const showFilterSidebar = !hideFilter;\n\n return (\n <section\n ref={rootRef as React.Ref<HTMLElement>}\n aria-label={resolvedAriaLabel}\n id={id}\n data-component=\"reviews-panel\"\n data-component-id={id}\n data-filter={dataFilter}\n className={rootVariants({ surface, className })}\n {...rest}\n >\n {/* Header row — plain <div>, not <header>: the panel root is a\n region landmark with an accessible name, so a nested <header>\n would emit a banner-inside-region pair that axe's\n landmark-banner-is-top-level rule flags. */}\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-[var(--spacing-sm)]\">\n <h2 className=\"type-title-section ds:m-0 ds:text-[var(--foreground)]\">\n {t('reviewsPanel.title')}\n </h2>\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-md)]\">\n {headerActionSlot}\n <Rating\n value={aggregate.averageScore}\n reviews={{ count: aggregate.count }}\n size=\"md\"\n />\n </div>\n </div>\n\n <div\n className={\n showFilterSidebar\n ? 'ds:grid ds:grid-cols-1 ds:gap-[var(--spacing-md)] ds:md:grid-cols-[minmax(0,30%)_minmax(0,1fr)]'\n : 'ds:flex ds:flex-col ds:gap-[var(--spacing-md)]'\n }\n >\n {showFilterSidebar ? (\n <FilterSidebar\n filter={filter}\n histogram={histogram}\n totalCount={aggregate.count}\n onChange={handleFilterChange}\n />\n ) : null}\n\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-md)] ds:min-w-0\">\n {introSlot\n ? // Render the slot raw — the consumer's introSlot owns\n // its own visual chrome (Alert, Infotip, plain <p>, …).\n // 0.31.x wrapped the slot in a `bg-info/8` tinted box,\n // but when the consumer passed an Alert with its own\n // tinted surface the visual stack rendered TWO concentric\n // tinted boxes (\"double effect\"). The wrapper added no\n // semantic value either (no role, no aria), so dropping\n // it is purely visual.\n introSlot\n : null}\n\n {visibleReviews.length === 0 ? (\n // `role=\"status\"` already implies `aria-live=\"polite\"` —\n // declaring both would queue two announcements when the\n // filter changes (the radio's aria-checked flip + this\n // container's text). Keeping `role` only.\n <div\n role=\"status\"\n data-state=\"no-match\"\n className=\"ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-sm)] ds:rounded-[var(--radius-md)] ds:border ds:border-dashed ds:border-[var(--border)] ds:p-[var(--spacing-lg)] ds:text-center\"\n >\n <p className=\"type-body ds:m-0 ds:text-[var(--muted-foreground)]\">\n {filter === 'all'\n ? t('reviewsPanel.empty.title')\n : t('reviewsPanel.empty.filterDescription', {\n stars: filter,\n })}\n </p>\n {filter !== 'all' ? (\n <Button\n intent=\"secondary\"\n size=\"sm\"\n onClick={() => handleFilterChange('all')}\n >\n {t('reviewsPanel.empty.resetFilter')}\n </Button>\n ) : null}\n </div>\n ) : (\n <ol\n aria-label={t('reviewsPanel.listLabel')}\n className=\"ds:list-none ds:m-0 ds:p-0 ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]\"\n >\n {visibleReviews.map((review) => (\n <li key={review.id} data-review-id={review.id}>\n <ReviewCard review={review} locale={locale} />\n </li>\n ))}\n </ol>\n )}\n </div>\n </div>\n </section>\n );\n },\n);\n\nReviewsPanel.displayName = 'ReviewsPanel';\n"],"names":["reviewsPanelAgent","handle","args","FILTER_VALUES","bucketOf","score","deriveHistogram","reviews","out","r","filterRowVariants","cva","FilterSidebar","filter","histogram","totalCount","onChange","t","useTranslation","labelId","useId","focusIndex","setFocusIndex","useState","useEffect","i","rowRefs","useRef","focusAt","useCallback","index","_a","total","handleKeyDown","event","next","prev","last","jsxs","jsx","val","isAll","stars","count","isSelected","isFocused","ariaLabel","node","e","Rating","ReviewCard","review","locale","triggerId","contentId","open","setOpen","breakdownHasValues","hasDetails","formattedDate","useMemo","parsed","pseudonym","footerAndDetails","Collapsible","Card","CollapsibleTrigger","ChevronDown","CollapsibleContent","DescriptionList","_b","_c","_d","PanelSkeleton","hideFilter","Skeleton","_","rootVariants","ReviewsPanel","forwardRef","aggregate","filterProp","onFilterChange","introSlot","headerActionSlot","id","className","surface","loading","rest","ref","i18n","internalFilter","setInternalFilter","handleFilterChange","visibleReviews","latestFilterRef","latestVisibleCountRef","agentHandle","rootRef","useImperativeHandle","useAgentRegistration","resolvedAriaLabel","dataFilter","EmptyState","showFilterSidebar","Button"],"mappings":"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"}
|