@refraction-ui/react 0.11.0 → 0.12.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/dist/index.cjs +235 -163
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +235 -163
- package/dist/index.js.map +1 -1
- package/dist/internal/react-conversation/index.d.cts +4 -1
- package/dist/internal/react-conversation/index.d.ts +4 -1
- package/dist/internal/react-cookie-consent/index.d.cts +1 -2
- package/dist/internal/react-cookie-consent/index.d.ts +1 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3427,6 +3427,8 @@ function Composer({
|
|
|
3427
3427
|
toolbar = true,
|
|
3428
3428
|
emoji = true,
|
|
3429
3429
|
attachments = true,
|
|
3430
|
+
error,
|
|
3431
|
+
onRetry,
|
|
3430
3432
|
onSubmit,
|
|
3431
3433
|
onStop,
|
|
3432
3434
|
onSlashCommand,
|
|
@@ -3567,148 +3569,154 @@ ${sel}
|
|
|
3567
3569
|
submit();
|
|
3568
3570
|
}
|
|
3569
3571
|
}
|
|
3572
|
+
const iconBtn = "flex h-8 w-8 items-center justify-center rounded-lg text-muted-foreground hover:bg-accent hover:text-foreground";
|
|
3570
3573
|
const toolbarBtn = (label, title, kind) => h(
|
|
3571
3574
|
"button",
|
|
3572
3575
|
{
|
|
3573
3576
|
key: kind,
|
|
3574
3577
|
type: "button",
|
|
3575
3578
|
title,
|
|
3576
|
-
className: "
|
|
3579
|
+
className: cn(iconBtn, "text-xs font-medium"),
|
|
3577
3580
|
onMouseDown: (e) => e.preventDefault(),
|
|
3578
3581
|
// keep textarea selection
|
|
3579
3582
|
onClick: () => format(kind)
|
|
3580
3583
|
},
|
|
3581
3584
|
label
|
|
3582
3585
|
);
|
|
3583
|
-
|
|
3586
|
+
const menu = menuOpen ? h(
|
|
3584
3587
|
"div",
|
|
3585
|
-
{
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
+
{
|
|
3589
|
+
className: "absolute bottom-full left-0 z-20 mb-2 w-72 overflow-hidden rounded-xl border border-border bg-popover shadow-lg",
|
|
3590
|
+
role: "listbox"
|
|
3591
|
+
},
|
|
3592
|
+
h(
|
|
3588
3593
|
"div",
|
|
3589
|
-
{ className: "
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
"
|
|
3603
|
-
)
|
|
3604
|
-
|
|
3594
|
+
{ className: "border-b border-border px-3 py-1.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground" },
|
|
3595
|
+
trigger?.type === "/" ? "Commands" : trigger?.type === "@" ? "Mentions" : "Emoji"
|
|
3596
|
+
),
|
|
3597
|
+
...items.map(
|
|
3598
|
+
(it, i) => h(
|
|
3599
|
+
"button",
|
|
3600
|
+
{
|
|
3601
|
+
key: it.key,
|
|
3602
|
+
type: "button",
|
|
3603
|
+
role: "option",
|
|
3604
|
+
"aria-selected": i === active,
|
|
3605
|
+
className: cn(
|
|
3606
|
+
"flex w-full items-center gap-2 px-3 py-2 text-left text-sm",
|
|
3607
|
+
i === active ? "bg-accent" : "hover:bg-accent/50"
|
|
3608
|
+
),
|
|
3609
|
+
onMouseEnter: () => setActive(i),
|
|
3610
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
3611
|
+
onClick: () => selectItem(i)
|
|
3612
|
+
},
|
|
3613
|
+
it.icon ? h("span", { className: "w-4 text-center text-muted-foreground" }, it.icon) : null,
|
|
3614
|
+
h("span", { className: "flex-1 truncate" }, it.primary),
|
|
3615
|
+
it.secondary ? h("span", { className: "truncate text-xs text-muted-foreground" }, it.secondary) : null
|
|
3605
3616
|
)
|
|
3606
|
-
)
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
toolbarBtn("B", "Bold (\u2318B)", "bold"),
|
|
3612
|
-
toolbarBtn("\u{1D456}", "Italic (\u2318I)", "italic"),
|
|
3613
|
-
toolbarBtn("</>", "Code (\u2318E)", "code"),
|
|
3614
|
-
toolbarBtn("\u{1F517}", "Link (\u2318K)", "link"),
|
|
3615
|
-
toolbarBtn("\u275D", "Quote", "quote"),
|
|
3616
|
-
toolbarBtn("\u2022", "Bulleted list", "ul"),
|
|
3617
|
-
toolbarBtn("1.", "Numbered list", "ol")
|
|
3618
|
-
) : null,
|
|
3619
|
-
// input row (relative for the popup menu)
|
|
3617
|
+
)
|
|
3618
|
+
) : null;
|
|
3619
|
+
return h(
|
|
3620
|
+
"div",
|
|
3621
|
+
{ className: "p-3" },
|
|
3620
3622
|
h(
|
|
3621
3623
|
"div",
|
|
3622
|
-
{ className: "relative
|
|
3623
|
-
|
|
3624
|
+
{ className: "relative" },
|
|
3625
|
+
menu,
|
|
3626
|
+
// unified input card
|
|
3627
|
+
h(
|
|
3624
3628
|
"div",
|
|
3625
3629
|
{
|
|
3626
|
-
className: "
|
|
3627
|
-
role: "listbox"
|
|
3630
|
+
className: "overflow-hidden rounded-2xl border border-border bg-background transition focus-within:border-primary focus-within:ring-2 focus-within:ring-primary/40"
|
|
3628
3631
|
},
|
|
3632
|
+
// error banner
|
|
3633
|
+
error ? h(
|
|
3634
|
+
"div",
|
|
3635
|
+
{ className: "flex items-center gap-2 border-b border-border bg-destructive/5 px-3 py-2 text-xs text-destructive", role: "alert" },
|
|
3636
|
+
h("span", { className: "flex-1 truncate" }, error),
|
|
3637
|
+
onRetry ? h("button", { type: "button", className: "font-medium underline", onClick: () => onRetry() }, "Retry") : null
|
|
3638
|
+
) : null,
|
|
3639
|
+
// attachment chips
|
|
3640
|
+
pending.length > 0 ? h(
|
|
3641
|
+
"div",
|
|
3642
|
+
{ className: "flex flex-wrap gap-2 px-3 pt-3" },
|
|
3643
|
+
...pending.map(
|
|
3644
|
+
(a) => h(
|
|
3645
|
+
"span",
|
|
3646
|
+
{ key: a.id, className: "inline-flex items-center gap-1 rounded-md bg-muted px-2 py-0.5 text-xs" },
|
|
3647
|
+
a.name,
|
|
3648
|
+
h(
|
|
3649
|
+
"button",
|
|
3650
|
+
{ type: "button", className: "text-muted-foreground hover:text-destructive", onClick: () => setPending((p) => p.filter((x) => x.id !== a.id)) },
|
|
3651
|
+
"\u2715"
|
|
3652
|
+
)
|
|
3653
|
+
)
|
|
3654
|
+
)
|
|
3655
|
+
) : null,
|
|
3656
|
+
// textarea (borderless)
|
|
3657
|
+
h("textarea", {
|
|
3658
|
+
ref,
|
|
3659
|
+
className: "block max-h-40 w-full resize-none bg-transparent px-3.5 py-3 text-sm placeholder:text-muted-foreground focus:outline-none",
|
|
3660
|
+
rows: 1,
|
|
3661
|
+
value,
|
|
3662
|
+
placeholder,
|
|
3663
|
+
autoFocus,
|
|
3664
|
+
"aria-label": "Message",
|
|
3665
|
+
onChange: (e) => syncFromTextarea(e.target),
|
|
3666
|
+
onClick: (e) => syncFromTextarea(e.currentTarget),
|
|
3667
|
+
onKeyUp: (e) => syncFromTextarea(e.currentTarget),
|
|
3668
|
+
onKeyDown,
|
|
3669
|
+
onBlur: () => setTimeout(() => setTrigger(null), 120)
|
|
3670
|
+
}),
|
|
3671
|
+
// bottom action bar
|
|
3629
3672
|
h(
|
|
3630
3673
|
"div",
|
|
3631
|
-
{ className: "
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3674
|
+
{ className: "flex items-center gap-0.5 px-2 pb-2" },
|
|
3675
|
+
attachments ? h(
|
|
3676
|
+
React11.Fragment,
|
|
3677
|
+
null,
|
|
3678
|
+
h("input", {
|
|
3679
|
+
ref: fileRef,
|
|
3680
|
+
type: "file",
|
|
3681
|
+
accept: "image/*",
|
|
3682
|
+
multiple: true,
|
|
3683
|
+
className: "hidden",
|
|
3684
|
+
onChange: (e) => {
|
|
3685
|
+
onFiles(e.target.files);
|
|
3686
|
+
e.target.value = "";
|
|
3687
|
+
}
|
|
3688
|
+
}),
|
|
3689
|
+
h("button", { type: "button", className: iconBtn, "aria-label": "Attach image or GIF", onClick: () => fileRef.current?.click() }, "\u{1F4CE}")
|
|
3690
|
+
) : null,
|
|
3691
|
+
attachments && toolbar ? h("span", { className: "mx-1 h-5 w-px bg-border" }) : null,
|
|
3692
|
+
toolbar ? h(
|
|
3693
|
+
React11.Fragment,
|
|
3694
|
+
null,
|
|
3695
|
+
toolbarBtn("B", "Bold (\u2318B)", "bold"),
|
|
3696
|
+
toolbarBtn("\u{1D456}", "Italic (\u2318I)", "italic"),
|
|
3697
|
+
toolbarBtn("</>", "Code (\u2318E)", "code"),
|
|
3698
|
+
toolbarBtn("\u{1F517}", "Link (\u2318K)", "link"),
|
|
3699
|
+
toolbarBtn("\u275D", "Quote", "quote"),
|
|
3700
|
+
toolbarBtn("\u2022", "Bulleted list", "ul"),
|
|
3701
|
+
toolbarBtn("1.", "Numbered list", "ol")
|
|
3702
|
+
) : null,
|
|
3703
|
+
h("div", { className: "flex-1" }),
|
|
3704
|
+
busy ? h(
|
|
3705
|
+
"button",
|
|
3706
|
+
{ type: "button", "aria-label": "Stop", className: "flex h-8 w-8 items-center justify-center rounded-lg bg-primary text-primary-foreground", onClick: () => onStop?.() },
|
|
3707
|
+
"\u25A0"
|
|
3708
|
+
) : h(
|
|
3636
3709
|
"button",
|
|
3637
3710
|
{
|
|
3638
|
-
key: it.key,
|
|
3639
3711
|
type: "button",
|
|
3640
|
-
|
|
3641
|
-
"
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
i === active ? "bg-accent" : "hover:bg-accent/50"
|
|
3645
|
-
),
|
|
3646
|
-
onMouseEnter: () => setActive(i),
|
|
3647
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
3648
|
-
onClick: () => selectItem(i)
|
|
3712
|
+
"aria-label": "Send",
|
|
3713
|
+
className: "flex h-8 w-8 items-center justify-center rounded-lg bg-primary text-base font-semibold text-primary-foreground transition disabled:opacity-40",
|
|
3714
|
+
disabled: !value.trim() && pending.length === 0,
|
|
3715
|
+
onClick: submit
|
|
3649
3716
|
},
|
|
3650
|
-
|
|
3651
|
-
h("span", { className: "flex-1 truncate" }, it.primary),
|
|
3652
|
-
it.secondary ? h("span", { className: "truncate text-xs text-muted-foreground" }, it.secondary) : null
|
|
3717
|
+
"\u2191"
|
|
3653
3718
|
)
|
|
3654
3719
|
)
|
|
3655
|
-
) : null,
|
|
3656
|
-
attachments ? h(
|
|
3657
|
-
React11.Fragment,
|
|
3658
|
-
null,
|
|
3659
|
-
h("input", {
|
|
3660
|
-
ref: fileRef,
|
|
3661
|
-
type: "file",
|
|
3662
|
-
accept: "image/*",
|
|
3663
|
-
multiple: true,
|
|
3664
|
-
className: "hidden",
|
|
3665
|
-
onChange: (e) => {
|
|
3666
|
-
onFiles(e.target.files);
|
|
3667
|
-
e.target.value = "";
|
|
3668
|
-
}
|
|
3669
|
-
}),
|
|
3670
|
-
h(
|
|
3671
|
-
"button",
|
|
3672
|
-
{
|
|
3673
|
-
type: "button",
|
|
3674
|
-
className: "rounded-md border border-border px-2 py-2 text-sm hover:bg-accent",
|
|
3675
|
-
"aria-label": "Attach image or GIF",
|
|
3676
|
-
onClick: () => fileRef.current?.click()
|
|
3677
|
-
},
|
|
3678
|
-
"\u{1F4CE}"
|
|
3679
|
-
)
|
|
3680
|
-
) : null,
|
|
3681
|
-
h("textarea", {
|
|
3682
|
-
ref,
|
|
3683
|
-
className: "max-h-40 flex-1 resize-none rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary",
|
|
3684
|
-
rows: 1,
|
|
3685
|
-
value,
|
|
3686
|
-
placeholder,
|
|
3687
|
-
autoFocus,
|
|
3688
|
-
"aria-label": "Message",
|
|
3689
|
-
onChange: (e) => syncFromTextarea(e.target),
|
|
3690
|
-
onClick: (e) => syncFromTextarea(e.currentTarget),
|
|
3691
|
-
onKeyUp: (e) => syncFromTextarea(e.currentTarget),
|
|
3692
|
-
onKeyDown,
|
|
3693
|
-
onBlur: () => setTimeout(() => setTrigger(null), 120)
|
|
3694
|
-
}),
|
|
3695
|
-
busy ? h(
|
|
3696
|
-
"button",
|
|
3697
|
-
{
|
|
3698
|
-
type: "button",
|
|
3699
|
-
className: "rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground",
|
|
3700
|
-
onClick: () => onStop?.()
|
|
3701
|
-
},
|
|
3702
|
-
"Stop"
|
|
3703
|
-
) : h(
|
|
3704
|
-
"button",
|
|
3705
|
-
{
|
|
3706
|
-
type: "button",
|
|
3707
|
-
className: "rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground disabled:opacity-50",
|
|
3708
|
-
disabled: !value.trim() && pending.length === 0,
|
|
3709
|
-
onClick: submit
|
|
3710
|
-
},
|
|
3711
|
-
"Send"
|
|
3712
3720
|
)
|
|
3713
3721
|
)
|
|
3714
3722
|
);
|
|
@@ -4056,9 +4064,13 @@ function Chat({
|
|
|
4056
4064
|
const timeline = selectMainTimeline(state.messages, state.threadingMode);
|
|
4057
4065
|
const activeConv = state.conversations.find((c) => c.id === state.activeConversationId);
|
|
4058
4066
|
const busy = state.status === "sending" || state.status === "streaming";
|
|
4067
|
+
const error = state.status === "error" ? state.error : null;
|
|
4068
|
+
const onRetry = () => void conversation.retryLast();
|
|
4059
4069
|
const mainComposer = h2(Composer, {
|
|
4060
4070
|
placeholder,
|
|
4061
4071
|
busy,
|
|
4072
|
+
error,
|
|
4073
|
+
onRetry,
|
|
4062
4074
|
slashCommands,
|
|
4063
4075
|
mentions,
|
|
4064
4076
|
onSlashCommand,
|
|
@@ -4069,6 +4081,8 @@ function Chat({
|
|
|
4069
4081
|
const threadComposer = state.openThreadRootId ? h2(Composer, {
|
|
4070
4082
|
placeholder: "Reply\u2026",
|
|
4071
4083
|
busy,
|
|
4084
|
+
error,
|
|
4085
|
+
onRetry,
|
|
4072
4086
|
slashCommands,
|
|
4073
4087
|
mentions,
|
|
4074
4088
|
onSlashCommand,
|
|
@@ -4372,14 +4386,56 @@ function useCookieConsent(config) {
|
|
|
4372
4386
|
};
|
|
4373
4387
|
}
|
|
4374
4388
|
var h3 = React11.createElement;
|
|
4375
|
-
var
|
|
4376
|
-
var
|
|
4377
|
-
var
|
|
4389
|
+
var btnBase = "inline-flex items-center justify-center rounded-lg px-3.5 py-2 text-sm font-medium transition-colors";
|
|
4390
|
+
var btnPrimary = cn(btnBase, "bg-primary text-primary-foreground hover:opacity-90");
|
|
4391
|
+
var btnGhost = cn(btnBase, "border border-border hover:bg-accent");
|
|
4392
|
+
var btnLink = "text-sm font-medium text-muted-foreground underline-offset-4 hover:text-foreground hover:underline";
|
|
4393
|
+
function Toggle({
|
|
4394
|
+
checked,
|
|
4395
|
+
disabled,
|
|
4396
|
+
onChange,
|
|
4397
|
+
label
|
|
4398
|
+
}) {
|
|
4399
|
+
if (disabled) {
|
|
4400
|
+
return h3(
|
|
4401
|
+
"span",
|
|
4402
|
+
{ className: "rounded-full bg-muted px-2 py-0.5 text-xs font-medium text-muted-foreground" },
|
|
4403
|
+
"Always on"
|
|
4404
|
+
);
|
|
4405
|
+
}
|
|
4406
|
+
return h3(
|
|
4407
|
+
"button",
|
|
4408
|
+
{
|
|
4409
|
+
type: "button",
|
|
4410
|
+
role: "switch",
|
|
4411
|
+
"aria-checked": checked,
|
|
4412
|
+
"aria-label": label,
|
|
4413
|
+
onClick: () => onChange(!checked),
|
|
4414
|
+
className: cn(
|
|
4415
|
+
"relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors",
|
|
4416
|
+
checked ? "bg-primary" : "bg-muted"
|
|
4417
|
+
)
|
|
4418
|
+
},
|
|
4419
|
+
h3("span", {
|
|
4420
|
+
className: cn(
|
|
4421
|
+
"inline-block h-4 w-4 transform rounded-full bg-background shadow transition-transform",
|
|
4422
|
+
checked ? "translate-x-[1.125rem]" : "translate-x-0.5"
|
|
4423
|
+
)
|
|
4424
|
+
})
|
|
4425
|
+
);
|
|
4426
|
+
}
|
|
4427
|
+
function CookieIcon() {
|
|
4428
|
+
return h3(
|
|
4429
|
+
"div",
|
|
4430
|
+
{ className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-accent text-xl", "aria-hidden": true },
|
|
4431
|
+
"\u{1F36A}"
|
|
4432
|
+
);
|
|
4433
|
+
}
|
|
4378
4434
|
function CookieConsent({
|
|
4379
4435
|
consent,
|
|
4380
4436
|
position = "bottom",
|
|
4381
4437
|
title = "We use cookies",
|
|
4382
|
-
description = "We use cookies to run the site, remember your preferences, and measure traffic. Choose which
|
|
4438
|
+
description = "We use cookies to run the site, remember your preferences, and measure traffic. Choose which to allow.",
|
|
4383
4439
|
policyUrl,
|
|
4384
4440
|
policyLabel = "Cookie policy",
|
|
4385
4441
|
className
|
|
@@ -4387,64 +4443,80 @@ function CookieConsent({
|
|
|
4387
4443
|
const { state, acceptAll, rejectAll, savePreferences, setPreference } = consent;
|
|
4388
4444
|
const [settings, setSettings] = React11.useState(false);
|
|
4389
4445
|
if (!state.open) return null;
|
|
4390
|
-
const wrapper = cn(
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
);
|
|
4395
|
-
const panel = "mx-auto max-w-3xl rounded-xl border border-border bg-background p-4 shadow-lg";
|
|
4396
|
-
const header = h3(
|
|
4446
|
+
const wrapper = cn("fixed inset-x-0 z-50 p-4", position === "bottom" ? "bottom-0" : "top-0", className);
|
|
4447
|
+
const panel = "mx-auto max-w-2xl overflow-hidden rounded-2xl border border-border bg-background shadow-lg";
|
|
4448
|
+
const policy = policyUrl ? h3("a", { href: policyUrl, target: "_blank", rel: "noreferrer", className: cn(btnLink, "whitespace-nowrap") }, policyLabel) : null;
|
|
4449
|
+
const promptView = h3(
|
|
4397
4450
|
"div",
|
|
4398
|
-
|
|
4399
|
-
h3(
|
|
4400
|
-
h3(
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4451
|
+
{ className: "flex flex-col gap-4 p-5 sm:flex-row sm:items-center" },
|
|
4452
|
+
h3(CookieIcon),
|
|
4453
|
+
h3(
|
|
4454
|
+
"div",
|
|
4455
|
+
{ className: "min-w-0 flex-1" },
|
|
4456
|
+
h3("p", { className: "text-sm font-semibold" }, title),
|
|
4457
|
+
h3(
|
|
4458
|
+
"p",
|
|
4459
|
+
{ className: "mt-0.5 text-sm leading-relaxed text-muted-foreground" },
|
|
4460
|
+
description,
|
|
4461
|
+
policy ? h3(React11.Fragment, null, " ", policy) : null
|
|
4462
|
+
)
|
|
4463
|
+
),
|
|
4464
|
+
h3(
|
|
4465
|
+
"div",
|
|
4466
|
+
{ className: "flex flex-wrap items-center gap-2 sm:shrink-0" },
|
|
4467
|
+
h3("button", { type: "button", className: btnLink, onClick: () => setSettings(true) }, "Customize"),
|
|
4468
|
+
h3("button", { type: "button", className: btnGhost, onClick: () => rejectAll() }, "Reject all"),
|
|
4469
|
+
h3("button", { type: "button", className: btnPrimary, onClick: () => acceptAll() }, "Accept all")
|
|
4470
|
+
)
|
|
4409
4471
|
);
|
|
4410
4472
|
const settingsView = h3(
|
|
4411
4473
|
"div",
|
|
4412
|
-
{ className: "
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
h3(
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4474
|
+
{ className: "p-5" },
|
|
4475
|
+
h3(
|
|
4476
|
+
"div",
|
|
4477
|
+
{ className: "flex items-center gap-3" },
|
|
4478
|
+
h3(CookieIcon),
|
|
4479
|
+
h3(
|
|
4480
|
+
"div",
|
|
4481
|
+
null,
|
|
4482
|
+
h3("p", { className: "text-sm font-semibold" }, "Cookie preferences"),
|
|
4483
|
+
h3("p", { className: "text-xs text-muted-foreground" }, "Toggle the categories you want to allow.")
|
|
4484
|
+
)
|
|
4485
|
+
),
|
|
4486
|
+
h3(
|
|
4487
|
+
"div",
|
|
4488
|
+
{ className: "mt-4 space-y-2" },
|
|
4489
|
+
...state.categories.map(
|
|
4490
|
+
(cat) => h3(
|
|
4491
|
+
"div",
|
|
4492
|
+
{ key: cat.id, className: "flex items-center justify-between gap-4 rounded-xl border border-border p-3" },
|
|
4493
|
+
h3(
|
|
4494
|
+
"div",
|
|
4495
|
+
{ className: "min-w-0" },
|
|
4496
|
+
h3("p", { className: "text-sm font-medium" }, cat.label),
|
|
4497
|
+
cat.description ? h3("p", { className: "mt-0.5 text-xs text-muted-foreground" }, cat.description) : null
|
|
4498
|
+
),
|
|
4499
|
+
h3(Toggle, {
|
|
4500
|
+
checked: !!state.preferences[cat.id],
|
|
4501
|
+
disabled: cat.required,
|
|
4502
|
+
label: cat.label,
|
|
4503
|
+
onChange: (v) => setPreference(cat.id, v)
|
|
4504
|
+
})
|
|
4505
|
+
)
|
|
4434
4506
|
)
|
|
4435
4507
|
),
|
|
4436
4508
|
h3(
|
|
4437
4509
|
"div",
|
|
4438
|
-
{ className: "flex flex-wrap items-center gap-2
|
|
4439
|
-
h3("button", { type: "button", className:
|
|
4440
|
-
h3("button", { type: "button", className: btnGhost, onClick: () => acceptAll() }, "Accept all"),
|
|
4441
|
-
h3("button", { type: "button", className:
|
|
4510
|
+
{ className: "mt-4 flex flex-wrap items-center gap-2" },
|
|
4511
|
+
h3("button", { type: "button", className: btnLink, onClick: () => setSettings(false) }, "\u2190 Back"),
|
|
4512
|
+
h3("button", { type: "button", className: cn(btnGhost, "sm:ml-auto"), onClick: () => acceptAll() }, "Accept all"),
|
|
4513
|
+
h3("button", { type: "button", className: btnPrimary, onClick: () => savePreferences(state.preferences) }, "Save preferences")
|
|
4442
4514
|
)
|
|
4443
4515
|
);
|
|
4444
4516
|
return h3(
|
|
4445
4517
|
"div",
|
|
4446
4518
|
{ className: wrapper, role: "dialog", "aria-label": "Cookie consent", "aria-modal": false },
|
|
4447
|
-
h3("div", { className: panel },
|
|
4519
|
+
h3("div", { className: panel }, settings ? settingsView : promptView)
|
|
4448
4520
|
);
|
|
4449
4521
|
}
|
|
4450
4522
|
|