@brokr/sdk 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react-notifications.js +63 -50
- package/dist/react-notifications.mjs +63 -50
- package/dist/react-styles.js +113 -75
- package/dist/react-styles.mjs +113 -75
- package/dist/react-theme.js +6 -4
- package/dist/react-theme.mjs +6 -4
- package/dist/react.js +325 -246
- package/dist/react.mjs +360 -281
- package/dist/src/react/account/AccountPanel.d.ts.map +1 -1
- package/dist/src/react/account/UserButton.d.ts.map +1 -1
- package/dist/src/react/chat/AIChat.d.ts.map +1 -1
- package/dist/src/react/chat/ChatInput.d.ts.map +1 -1
- package/dist/src/react/chat/MessagePane.d.ts.map +1 -1
- package/dist/src/react/chat/ModelSelector.d.ts.map +1 -1
- package/dist/src/react/chat/ThreadSidebar.d.ts.map +1 -1
- package/dist/src/react/composites/FabAI.d.ts.map +1 -1
- package/dist/src/react/css/account.d.ts +1 -1
- package/dist/src/react/css/account.d.ts.map +1 -1
- package/dist/src/react/css/auth.d.ts +1 -1
- package/dist/src/react/css/auth.d.ts.map +1 -1
- package/dist/src/react/css/chat-extras.d.ts +1 -1
- package/dist/src/react/css/chat-extras.d.ts.map +1 -1
- package/dist/src/react/css/chat.d.ts +1 -1
- package/dist/src/react/css/chat.d.ts.map +1 -1
- package/dist/src/react/css/composites.d.ts +1 -1
- package/dist/src/react/css/composites.d.ts.map +1 -1
- package/dist/src/react/css/markdown.d.ts +1 -1
- package/dist/src/react/css/markdown.d.ts.map +1 -1
- package/dist/src/react/css/notifications.d.ts +1 -1
- package/dist/src/react/css/notifications.d.ts.map +1 -1
- package/dist/src/react/css/tokens.d.ts +1 -1
- package/dist/src/react/css/tokens.d.ts.map +1 -1
- package/dist/src/react/notifications/NotificationBell.d.ts.map +1 -1
- package/dist/src/react/notifications/NotificationList.d.ts.map +1 -1
- package/dist/src/react/notifications/Toast.d.ts.map +1 -1
- package/dist/src/react/payments/Plans.d.ts.map +1 -1
- package/dist/src/react/theme.d.ts.map +1 -1
- package/dist/src/react/types.d.ts +4 -4
- package/dist/src/react/types.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -4173,10 +4173,12 @@ function getBrokrRootStyle(theme) {
|
|
|
4173
4173
|
...theme.colors.error ? { ["--brokr-error"]: theme.colors.error } : {},
|
|
4174
4174
|
...theme.colors.success ? { ["--brokr-success"]: theme.colors.success } : {},
|
|
4175
4175
|
...theme.colors.warning ? { ["--brokr-warning"]: theme.colors.warning } : {},
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4176
|
+
// Toast vars always emitted with smart defaults — toasts stay light in dark mode.
|
|
4177
|
+
// Users can override via theme.colors.toastBg etc.
|
|
4178
|
+
["--brokr-toast-bg"]: theme.colors.toastBg ?? "#ffffff",
|
|
4179
|
+
["--brokr-toast-text"]: theme.colors.toastText ?? "#0a0a0a",
|
|
4180
|
+
["--brokr-toast-text-secondary"]: theme.colors.toastTextSecondary ?? "#52525b",
|
|
4181
|
+
["--brokr-toast-border"]: theme.colors.toastBorder ?? "#e4e4e7",
|
|
4180
4182
|
["--brokr-radius-card"]: `${theme.radii.card}px`,
|
|
4181
4183
|
["--brokr-radius-input"]: `${theme.radii.input}px`,
|
|
4182
4184
|
["--brokr-radius-button"]: `${theme.radii.button}px`
|
|
@@ -4298,6 +4300,37 @@ function resolveNotificationType(registry, type, data) {
|
|
|
4298
4300
|
|
|
4299
4301
|
// src/react/notifications/Toast.tsx
|
|
4300
4302
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4303
|
+
function ToastItem({
|
|
4304
|
+
notification,
|
|
4305
|
+
exiting,
|
|
4306
|
+
registry,
|
|
4307
|
+
onDismiss
|
|
4308
|
+
}) {
|
|
4309
|
+
const handleDismiss = useCallback(() => onDismiss(notification.id), [notification.id, onDismiss]);
|
|
4310
|
+
const notifData = notification.data ?? {};
|
|
4311
|
+
const notifType = notifData.type ?? "default";
|
|
4312
|
+
const resolved = resolveNotificationType(registry, notifType, notifData);
|
|
4313
|
+
return /* @__PURE__ */ React.createElement(
|
|
4314
|
+
"div",
|
|
4315
|
+
{
|
|
4316
|
+
className: `brokr-toast brokr-toast--${notification.variant}${exiting ? " brokr-toast--exit" : ""}`,
|
|
4317
|
+
role: "alert",
|
|
4318
|
+
"aria-live": "polite"
|
|
4319
|
+
},
|
|
4320
|
+
resolved.image ? /* @__PURE__ */ React.createElement("img", { src: resolved.image.url, alt: resolved.image.alt, className: "brokr-toast-provider-logo" }) : /* @__PURE__ */ React.createElement("span", { className: `brokr-toast-icon brokr-toast-icon--${notification.variant}` }),
|
|
4321
|
+
/* @__PURE__ */ React.createElement("div", { className: "brokr-toast-content" }, /* @__PURE__ */ React.createElement("span", { className: "brokr-toast-title" }, notification.title), /* @__PURE__ */ React.createElement("span", { className: "brokr-toast-message" }, notification.message)),
|
|
4322
|
+
/* @__PURE__ */ React.createElement(
|
|
4323
|
+
"button",
|
|
4324
|
+
{
|
|
4325
|
+
type: "button",
|
|
4326
|
+
className: "brokr-toast-dismiss",
|
|
4327
|
+
onClick: handleDismiss,
|
|
4328
|
+
"aria-label": "Dismiss notification"
|
|
4329
|
+
},
|
|
4330
|
+
/* @__PURE__ */ React.createElement("svg", { "aria-hidden": "true", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M18 6 6 18M6 6l12 12" }))
|
|
4331
|
+
)
|
|
4332
|
+
);
|
|
4333
|
+
}
|
|
4301
4334
|
var DEFAULT_DURATION = 4e3;
|
|
4302
4335
|
var DEFAULT_MAX_VISIBLE = 3;
|
|
4303
4336
|
var EXIT_ANIMATION_MS = 300;
|
|
@@ -4308,6 +4341,26 @@ function ToastLayer({ toasts, config, registry, onDismiss }) {
|
|
|
4308
4341
|
const duration = config.toast?.duration ?? DEFAULT_DURATION;
|
|
4309
4342
|
const maxVisible = config.toast?.maxVisible ?? DEFAULT_MAX_VISIBLE;
|
|
4310
4343
|
const position = config.toast?.position ?? "top-right";
|
|
4344
|
+
const onDismissRef = useRef(onDismiss);
|
|
4345
|
+
onDismissRef.current = onDismiss;
|
|
4346
|
+
const exitingRef = useRef(/* @__PURE__ */ new Set());
|
|
4347
|
+
const dismissToast = useCallback((id) => {
|
|
4348
|
+
if (exitingRef.current.has(id)) return;
|
|
4349
|
+
exitingRef.current.add(id);
|
|
4350
|
+
setEntries(
|
|
4351
|
+
(prev) => prev.map((e) => e.notification.id === id ? { ...e, exiting: true } : e)
|
|
4352
|
+
);
|
|
4353
|
+
setTimeout(() => {
|
|
4354
|
+
setEntries((prev) => prev.filter((e) => e.notification.id !== id));
|
|
4355
|
+
onDismissRef.current(id);
|
|
4356
|
+
exitingRef.current.delete(id);
|
|
4357
|
+
}, EXIT_ANIMATION_MS);
|
|
4358
|
+
const timer = timersRef.current.get(id);
|
|
4359
|
+
if (timer) {
|
|
4360
|
+
clearTimeout(timer);
|
|
4361
|
+
timersRef.current.delete(id);
|
|
4362
|
+
}
|
|
4363
|
+
}, []);
|
|
4311
4364
|
useEffect(() => {
|
|
4312
4365
|
for (const toast of toasts) {
|
|
4313
4366
|
if (processedRef.current.has(toast.id)) continue;
|
|
@@ -4326,21 +4379,7 @@ function ToastLayer({ toasts, config, registry, onDismiss }) {
|
|
|
4326
4379
|
timersRef.current.set(toast.id, timer);
|
|
4327
4380
|
}
|
|
4328
4381
|
}
|
|
4329
|
-
}, [toasts, duration, maxVisible]);
|
|
4330
|
-
const dismissToast = useCallback((id) => {
|
|
4331
|
-
setEntries(
|
|
4332
|
-
(prev) => prev.map((e) => e.notification.id === id ? { ...e, exiting: true } : e)
|
|
4333
|
-
);
|
|
4334
|
-
setTimeout(() => {
|
|
4335
|
-
setEntries((prev) => prev.filter((e) => e.notification.id !== id));
|
|
4336
|
-
onDismiss(id);
|
|
4337
|
-
}, EXIT_ANIMATION_MS);
|
|
4338
|
-
const timer = timersRef.current.get(id);
|
|
4339
|
-
if (timer) {
|
|
4340
|
-
clearTimeout(timer);
|
|
4341
|
-
timersRef.current.delete(id);
|
|
4342
|
-
}
|
|
4343
|
-
}, [onDismiss]);
|
|
4382
|
+
}, [toasts, duration, maxVisible, dismissToast]);
|
|
4344
4383
|
useEffect(() => {
|
|
4345
4384
|
return () => {
|
|
4346
4385
|
for (const timer of timersRef.current.values()) {
|
|
@@ -4360,39 +4399,16 @@ function ToastLayer({ toasts, config, registry, onDismiss }) {
|
|
|
4360
4399
|
return map[position] ?? "brokr-toast-layer--bottom-right";
|
|
4361
4400
|
}, [position]);
|
|
4362
4401
|
if (entries.length === 0) return null;
|
|
4363
|
-
return /* @__PURE__ */ React.createElement("div", { className: `brokr-toast-layer ${positionClass}` }, entries.map(({ notification, exiting }) =>
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
"aria-live": "polite"
|
|
4374
|
-
},
|
|
4375
|
-
resolved.image ? /* @__PURE__ */ React.createElement(
|
|
4376
|
-
"img",
|
|
4377
|
-
{
|
|
4378
|
-
src: resolved.image.url,
|
|
4379
|
-
alt: resolved.image.alt,
|
|
4380
|
-
className: "brokr-toast-provider-logo"
|
|
4381
|
-
}
|
|
4382
|
-
) : /* @__PURE__ */ React.createElement("span", { className: `brokr-toast-icon brokr-toast-icon--${notification.variant}` }),
|
|
4383
|
-
/* @__PURE__ */ React.createElement("div", { className: "brokr-toast-content" }, /* @__PURE__ */ React.createElement("span", { className: "brokr-toast-title" }, notification.title), /* @__PURE__ */ React.createElement("span", { className: "brokr-toast-message" }, notification.message)),
|
|
4384
|
-
/* @__PURE__ */ React.createElement(
|
|
4385
|
-
"button",
|
|
4386
|
-
{
|
|
4387
|
-
type: "button",
|
|
4388
|
-
className: "brokr-toast-dismiss",
|
|
4389
|
-
onClick: () => dismissToast(notification.id),
|
|
4390
|
-
"aria-label": "Dismiss notification"
|
|
4391
|
-
},
|
|
4392
|
-
/* @__PURE__ */ React.createElement("svg", { "aria-hidden": "true", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }, /* @__PURE__ */ React.createElement("path", { d: "M18 6 6 18M6 6l12 12" }))
|
|
4393
|
-
)
|
|
4394
|
-
);
|
|
4395
|
-
}));
|
|
4402
|
+
return /* @__PURE__ */ React.createElement("div", { className: `brokr-toast-layer ${positionClass}` }, entries.map(({ notification, exiting }) => /* @__PURE__ */ React.createElement(
|
|
4403
|
+
ToastItem,
|
|
4404
|
+
{
|
|
4405
|
+
key: notification.id,
|
|
4406
|
+
notification,
|
|
4407
|
+
exiting,
|
|
4408
|
+
registry,
|
|
4409
|
+
onDismiss: dismissToast
|
|
4410
|
+
}
|
|
4411
|
+
)));
|
|
4396
4412
|
}
|
|
4397
4413
|
|
|
4398
4414
|
// src/react/notifications/provider.tsx
|
|
@@ -5515,6 +5531,26 @@ function filterDefined(defaults, overrides) {
|
|
|
5515
5531
|
}
|
|
5516
5532
|
|
|
5517
5533
|
// src/react/account/AccountPanel.tsx
|
|
5534
|
+
function AccountTabButton({
|
|
5535
|
+
tab,
|
|
5536
|
+
active,
|
|
5537
|
+
icon,
|
|
5538
|
+
label,
|
|
5539
|
+
onSelect
|
|
5540
|
+
}) {
|
|
5541
|
+
const handleClick = useCallback8(() => onSelect(tab), [tab, onSelect]);
|
|
5542
|
+
return /* @__PURE__ */ React10.createElement(
|
|
5543
|
+
"button",
|
|
5544
|
+
{
|
|
5545
|
+
className: "brokr-account-tab",
|
|
5546
|
+
"data-active": active,
|
|
5547
|
+
onClick: handleClick,
|
|
5548
|
+
type: "button"
|
|
5549
|
+
},
|
|
5550
|
+
/* @__PURE__ */ React10.createElement("span", { className: "brokr-account-tab-icon" }, icon),
|
|
5551
|
+
/* @__PURE__ */ React10.createElement("span", null, label)
|
|
5552
|
+
);
|
|
5553
|
+
}
|
|
5518
5554
|
var TAB_META = {
|
|
5519
5555
|
general: {
|
|
5520
5556
|
label: "General"
|
|
@@ -5646,16 +5682,15 @@ function AccountPanel(inlineProps) {
|
|
|
5646
5682
|
}
|
|
5647
5683
|
}, []);
|
|
5648
5684
|
return /* @__PURE__ */ React10.createElement("section", { className: "brokr-account-panel", "data-density": density }, /* @__PURE__ */ React10.createElement("aside", { className: "brokr-account-sidebar" }, groupedTabs.map((group) => /* @__PURE__ */ React10.createElement("div", { className: "brokr-account-sidebar-group", key: group.label }, /* @__PURE__ */ React10.createElement("span", { className: "brokr-account-sidebar-kicker" }, group.label), /* @__PURE__ */ React10.createElement("nav", { className: "brokr-account-tab-list", "aria-label": `${group.label} settings` }, group.tabs.map((tab) => /* @__PURE__ */ React10.createElement(
|
|
5649
|
-
|
|
5685
|
+
AccountTabButton,
|
|
5650
5686
|
{
|
|
5651
|
-
className: "brokr-account-tab",
|
|
5652
|
-
"data-active": activeTab === tab,
|
|
5653
5687
|
key: tab,
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5688
|
+
tab,
|
|
5689
|
+
active: activeTab === tab,
|
|
5690
|
+
icon: getTabIcon(tab),
|
|
5691
|
+
label: TAB_META[tab].label,
|
|
5692
|
+
onSelect: setActiveTab
|
|
5693
|
+
}
|
|
5659
5694
|
)))))), /* @__PURE__ */ React10.createElement("div", { className: "brokr-account-surface" }, /* @__PURE__ */ React10.createElement("header", { className: "brokr-account-surface-header" }, /* @__PURE__ */ React10.createElement("h2", { className: "brokr-title" }, activeTabMeta.label)), activeTab === "general" ? /* @__PURE__ */ React10.createElement("form", { className: "brokr-account-form", onSubmit: handleSaveProfile }, /* @__PURE__ */ React10.createElement("section", { className: "brokr-account-card" }, /* @__PURE__ */ React10.createElement("div", { className: "brokr-account-photo-row" }, /* @__PURE__ */ React10.createElement(ProfilePhotoButton, { size: 88 }), /* @__PURE__ */ React10.createElement("div", { className: "brokr-account-photo-copy" }, /* @__PURE__ */ React10.createElement("strong", null, "Profile photo"), /* @__PURE__ */ React10.createElement("span", { className: "brokr-copy" }, "PNG, JPEG, and GIF under 10MB"), /* @__PURE__ */ React10.createElement("span", { className: "brokr-account-photo-hint" }, /* @__PURE__ */ React10.createElement(UploadIcon, { size: 14 }), "Upload new picture")))), /* @__PURE__ */ React10.createElement("section", { className: "brokr-account-card brokr-account-field-list" }, /* @__PURE__ */ React10.createElement("div", { className: "brokr-account-field-row" }, /* @__PURE__ */ React10.createElement("div", { className: "brokr-account-field-head" }, /* @__PURE__ */ React10.createElement("label", { className: "brokr-label", htmlFor: "brokr-account-name" }, "Name")), /* @__PURE__ */ React10.createElement("div", { className: "brokr-account-field-body" }, /* @__PURE__ */ React10.createElement(
|
|
5660
5695
|
"input",
|
|
5661
5696
|
{
|
|
@@ -5763,6 +5798,9 @@ function UserButton({
|
|
|
5763
5798
|
setOpen(false);
|
|
5764
5799
|
await signOut();
|
|
5765
5800
|
}, [signOut]);
|
|
5801
|
+
const stopPropagation = useCallback9((event) => {
|
|
5802
|
+
event.stopPropagation();
|
|
5803
|
+
}, []);
|
|
5766
5804
|
useEffect7(() => {
|
|
5767
5805
|
if (!open) return void 0;
|
|
5768
5806
|
const handlePointerDown = (event) => {
|
|
@@ -5796,13 +5834,13 @@ function UserButton({
|
|
|
5796
5834
|
"data-align": align,
|
|
5797
5835
|
role: "dialog"
|
|
5798
5836
|
},
|
|
5799
|
-
/* @__PURE__ */ React12.createElement("div", { className: "brokr-account-menu" }, /* @__PURE__ */ React12.createElement("div", { className: "brokr-account-menu-header" }, /* @__PURE__ */ React12.createElement(Avatar, { email: summary.email, name: summary.name, src: user.image, size: 44 }), /* @__PURE__ */ React12.createElement("div", { className: "brokr-account-menu-copy" }, /* @__PURE__ */ React12.createElement("strong", null, summary.name), /* @__PURE__ */ React12.createElement("span", null, summary.email))), /* @__PURE__ */ React12.createElement("div", { className: "brokr-account-menu-actions" }, /* @__PURE__ */ React12.createElement("button", { className: "brokr-account-menu-action", onClick: openSettings, type: "button" }, /* @__PURE__ */ React12.createElement("span", { className: "brokr-account-menu-action-icon" }, /* @__PURE__ */ React12.createElement(SettingsIcon, { size: 15 })), /* @__PURE__ */ React12.createElement("span", null, "Settings")), /* @__PURE__ */ React12.createElement("button", { className: "brokr-account-menu-action", onClick:
|
|
5837
|
+
/* @__PURE__ */ React12.createElement("div", { className: "brokr-account-menu" }, /* @__PURE__ */ React12.createElement("div", { className: "brokr-account-menu-header" }, /* @__PURE__ */ React12.createElement(Avatar, { email: summary.email, name: summary.name, src: user.image, size: 44 }), /* @__PURE__ */ React12.createElement("div", { className: "brokr-account-menu-copy" }, /* @__PURE__ */ React12.createElement("strong", null, summary.name), /* @__PURE__ */ React12.createElement("span", null, summary.email))), /* @__PURE__ */ React12.createElement("div", { className: "brokr-account-menu-actions" }, /* @__PURE__ */ React12.createElement("button", { className: "brokr-account-menu-action", onClick: openSettings, type: "button" }, /* @__PURE__ */ React12.createElement("span", { className: "brokr-account-menu-action-icon" }, /* @__PURE__ */ React12.createElement(SettingsIcon, { size: 15 })), /* @__PURE__ */ React12.createElement("span", null, "Settings")), /* @__PURE__ */ React12.createElement("button", { className: "brokr-account-menu-action", onClick: handleSignOut, type: "button" }, /* @__PURE__ */ React12.createElement("span", { className: "brokr-account-menu-action-icon" }, /* @__PURE__ */ React12.createElement(LogoutIcon, { size: 15 })), /* @__PURE__ */ React12.createElement("span", null, "Sign out"))))
|
|
5800
5838
|
) : null, settingsOpen ? /* @__PURE__ */ React12.createElement("div", { className: "brokr-modal-backdrop", role: "presentation", onClick: closeSettings }, /* @__PURE__ */ React12.createElement(
|
|
5801
5839
|
"div",
|
|
5802
5840
|
{
|
|
5803
5841
|
"aria-modal": "true",
|
|
5804
5842
|
className: "brokr-panel brokr-modal-dialog brokr-account-settings-dialog",
|
|
5805
|
-
onClick:
|
|
5843
|
+
onClick: stopPropagation,
|
|
5806
5844
|
role: "dialog"
|
|
5807
5845
|
},
|
|
5808
5846
|
/* @__PURE__ */ React12.createElement("div", { className: "brokr-modal-toolbar" }, /* @__PURE__ */ React12.createElement("button", { className: "brokr-button-ghost", onClick: closeSettings, type: "button" }, /* @__PURE__ */ React12.createElement(CloseIcon, { size: 16 }))),
|
|
@@ -5998,6 +6036,28 @@ function AuthWall({ children }) {
|
|
|
5998
6036
|
|
|
5999
6037
|
// src/react/payments/Plans.tsx
|
|
6000
6038
|
import React21, { useCallback as useCallback12, useMemo as useMemo13, useState as useState12 } from "react";
|
|
6039
|
+
function PlanCard({
|
|
6040
|
+
plan,
|
|
6041
|
+
highlight,
|
|
6042
|
+
isPending,
|
|
6043
|
+
onSelect
|
|
6044
|
+
}) {
|
|
6045
|
+
const isHighlighted = highlight === plan.slug;
|
|
6046
|
+
const features = Object.entries(plan.features);
|
|
6047
|
+
const handleClick = useCallback12(() => {
|
|
6048
|
+
void onSelect(plan.slug);
|
|
6049
|
+
}, [plan.slug, onSelect]);
|
|
6050
|
+
return /* @__PURE__ */ React21.createElement("article", { className: "brokr-card brokr-plan-card", "data-highlight": isHighlighted, key: plan.slug }, /* @__PURE__ */ React21.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-3)" } }, /* @__PURE__ */ React21.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ React21.createElement("strong", null, plan.name), plan.isCurrent ? /* @__PURE__ */ React21.createElement("span", { className: "brokr-badge" }, "Current") : null, isHighlighted && !plan.isCurrent ? /* @__PURE__ */ React21.createElement("span", { className: "brokr-badge" }, "Recommended") : null), /* @__PURE__ */ React21.createElement("div", { className: "brokr-plan-price" }, /* @__PURE__ */ React21.createElement("span", { className: "brokr-plan-value" }, plan.price === 0 ? "$0" : `$${(plan.price / 100).toFixed(0)}`), /* @__PURE__ */ React21.createElement("span", { className: "brokr-copy" }, "/", plan.interval)), plan.trialDays ? /* @__PURE__ */ React21.createElement("span", { className: "brokr-copy" }, plan.trialDays, " day trial included.") : null), /* @__PURE__ */ React21.createElement(
|
|
6051
|
+
"button",
|
|
6052
|
+
{
|
|
6053
|
+
className: plan.isCurrent ? "brokr-button-secondary" : "brokr-button",
|
|
6054
|
+
disabled: plan.isCurrent || isPending,
|
|
6055
|
+
onClick: handleClick,
|
|
6056
|
+
type: "button"
|
|
6057
|
+
},
|
|
6058
|
+
plan.isCurrent ? "Current plan" : isPending ? "Redirecting" : "Choose plan"
|
|
6059
|
+
), /* @__PURE__ */ React21.createElement("ul", { className: "brokr-feature-list" }, features.map(([key, value]) => /* @__PURE__ */ React21.createElement("li", { className: "brokr-feature-item", key }, /* @__PURE__ */ React21.createElement(CheckIcon, { size: 14 }), /* @__PURE__ */ React21.createElement("span", null, featureLabel(key), " \xB7 ", featureValueLabel(value))))));
|
|
6060
|
+
}
|
|
6001
6061
|
function Plans({
|
|
6002
6062
|
columns,
|
|
6003
6063
|
highlight,
|
|
@@ -6028,34 +6088,16 @@ function Plans({
|
|
|
6028
6088
|
setPendingPlan(null);
|
|
6029
6089
|
}
|
|
6030
6090
|
}, [checkout, onSelect]);
|
|
6031
|
-
return /* @__PURE__ */ React21.createElement("div", { className: "brokr-section" }, paymentsMode === "sandbox" ? /* @__PURE__ */ React21.createElement("div", { className: "brokr-inline-message" }, "Sandbox mode \u2014 test cards only.") : null, error ? /* @__PURE__ */ React21.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null, /* @__PURE__ */ React21.createElement("div", { className: "brokr-grid-auto", style: layoutStyle }, plans.map((plan) =>
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
className: "brokr-card brokr-plan-card",
|
|
6042
|
-
"data-highlight": isHighlighted,
|
|
6043
|
-
key: plan.slug
|
|
6044
|
-
},
|
|
6045
|
-
/* @__PURE__ */ React21.createElement("div", { className: "brokr-section", style: { gap: "0.75rem" } }, /* @__PURE__ */ React21.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ React21.createElement("strong", null, plan.name), plan.isCurrent ? /* @__PURE__ */ React21.createElement("span", { className: "brokr-badge" }, "Current") : null, isHighlighted && !plan.isCurrent ? /* @__PURE__ */ React21.createElement("span", { className: "brokr-badge" }, "Recommended") : null), /* @__PURE__ */ React21.createElement("div", { className: "brokr-plan-price" }, /* @__PURE__ */ React21.createElement("span", { className: "brokr-plan-value" }, plan.price === 0 ? "$0" : `$${(plan.price / 100).toFixed(0)}`), /* @__PURE__ */ React21.createElement("span", { className: "brokr-copy" }, "/", plan.interval)), plan.trialDays ? /* @__PURE__ */ React21.createElement("span", { className: "brokr-copy" }, plan.trialDays, " day trial included.") : null),
|
|
6046
|
-
/* @__PURE__ */ React21.createElement(
|
|
6047
|
-
"button",
|
|
6048
|
-
{
|
|
6049
|
-
className: plan.isCurrent ? "brokr-button-secondary" : "brokr-button",
|
|
6050
|
-
disabled: plan.isCurrent || isPending,
|
|
6051
|
-
onClick: handleClick,
|
|
6052
|
-
type: "button"
|
|
6053
|
-
},
|
|
6054
|
-
plan.isCurrent ? "Current plan" : isPending ? "Redirecting" : "Choose plan"
|
|
6055
|
-
),
|
|
6056
|
-
/* @__PURE__ */ React21.createElement("ul", { className: "brokr-feature-list" }, features.map(([key, value]) => /* @__PURE__ */ React21.createElement("li", { className: "brokr-feature-item", key }, /* @__PURE__ */ React21.createElement(CheckIcon, { size: 14 }), /* @__PURE__ */ React21.createElement("span", null, featureLabel(key), " \xB7 ", featureValueLabel(value)))))
|
|
6057
|
-
);
|
|
6058
|
-
})));
|
|
6091
|
+
return /* @__PURE__ */ React21.createElement("div", { className: "brokr-section" }, paymentsMode === "sandbox" ? /* @__PURE__ */ React21.createElement("div", { className: "brokr-inline-message" }, "Sandbox mode \u2014 test cards only.") : null, error ? /* @__PURE__ */ React21.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null, /* @__PURE__ */ React21.createElement("div", { className: "brokr-grid-auto", style: layoutStyle }, plans.map((plan) => /* @__PURE__ */ React21.createElement(
|
|
6092
|
+
PlanCard,
|
|
6093
|
+
{
|
|
6094
|
+
key: plan.slug,
|
|
6095
|
+
plan,
|
|
6096
|
+
highlight,
|
|
6097
|
+
isPending: pendingPlan === plan.slug,
|
|
6098
|
+
onSelect: handleSelect
|
|
6099
|
+
}
|
|
6100
|
+
))));
|
|
6059
6101
|
}
|
|
6060
6102
|
|
|
6061
6103
|
// src/react/payments/FeatureMeter.tsx
|
|
@@ -6193,7 +6235,7 @@ function AutoReloadToggle({ onChange }) {
|
|
|
6193
6235
|
setIsPending(false);
|
|
6194
6236
|
}
|
|
6195
6237
|
}, [enabled, onChange]);
|
|
6196
|
-
return /* @__PURE__ */ React26.createElement("div", { className: "brokr-card brokr-gate-card" }, /* @__PURE__ */ React26.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ React26.createElement("div", { className: "brokr-section", style: { gap: "
|
|
6238
|
+
return /* @__PURE__ */ React26.createElement("div", { className: "brokr-card brokr-gate-card" }, /* @__PURE__ */ React26.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ React26.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ React26.createElement("strong", null, "Auto reload"), /* @__PURE__ */ React26.createElement("span", { className: "brokr-copy" }, helperText)), /* @__PURE__ */ React26.createElement(
|
|
6197
6239
|
"button",
|
|
6198
6240
|
{
|
|
6199
6241
|
className: "brokr-button-secondary",
|
|
@@ -6243,7 +6285,7 @@ function CancelSubscription({ onCancel }) {
|
|
|
6243
6285
|
|
|
6244
6286
|
// src/react/chat/AIChat.tsx
|
|
6245
6287
|
import React35, {
|
|
6246
|
-
useCallback as
|
|
6288
|
+
useCallback as useCallback23,
|
|
6247
6289
|
useEffect as useEffect12,
|
|
6248
6290
|
useMemo as useMemo23,
|
|
6249
6291
|
useRef as useRef7,
|
|
@@ -6889,6 +6931,37 @@ function useChat(config) {
|
|
|
6889
6931
|
|
|
6890
6932
|
// src/react/chat/ModelSelector.tsx
|
|
6891
6933
|
import React29, { useCallback as useCallback17, useEffect as useEffect10, useMemo as useMemo19, useRef as useRef6, useState as useState17 } from "react";
|
|
6934
|
+
function ModelOption({
|
|
6935
|
+
provider,
|
|
6936
|
+
isActive,
|
|
6937
|
+
isLocked,
|
|
6938
|
+
onSelect,
|
|
6939
|
+
onCheckout
|
|
6940
|
+
}) {
|
|
6941
|
+
const handleClick = useCallback17(() => {
|
|
6942
|
+
if (isLocked) {
|
|
6943
|
+
void onCheckout({ plan: "pro" });
|
|
6944
|
+
} else {
|
|
6945
|
+
onSelect(provider.model);
|
|
6946
|
+
}
|
|
6947
|
+
}, [isLocked, onCheckout, onSelect, provider.model]);
|
|
6948
|
+
return /* @__PURE__ */ React29.createElement(
|
|
6949
|
+
"button",
|
|
6950
|
+
{
|
|
6951
|
+
"aria-selected": isActive,
|
|
6952
|
+
className: "brokr-model-option",
|
|
6953
|
+
"data-active": isActive,
|
|
6954
|
+
"data-locked": isLocked,
|
|
6955
|
+
disabled: isLocked,
|
|
6956
|
+
onClick: handleClick,
|
|
6957
|
+
title: isLocked ? "Add credits to unlock" : void 0,
|
|
6958
|
+
type: "button"
|
|
6959
|
+
},
|
|
6960
|
+
/* @__PURE__ */ React29.createElement("img", { alt: "", className: "brokr-model-logo", src: provider.logo }),
|
|
6961
|
+
/* @__PURE__ */ React29.createElement("span", { className: "brokr-model-option-label" }, provider.label),
|
|
6962
|
+
isLocked ? /* @__PURE__ */ React29.createElement("span", { className: "brokr-model-lock", "aria-hidden": "true" }, /* @__PURE__ */ React29.createElement(LockIcon, { size: 13 })) : null
|
|
6963
|
+
);
|
|
6964
|
+
}
|
|
6892
6965
|
function ModelSelector({
|
|
6893
6966
|
activeModel,
|
|
6894
6967
|
setSelectedModel,
|
|
@@ -6901,6 +6974,10 @@ function ModelSelector({
|
|
|
6901
6974
|
() => providers.find((p) => p.model === activeModel) ?? providers[0],
|
|
6902
6975
|
[activeModel]
|
|
6903
6976
|
);
|
|
6977
|
+
const handleModelSelect = useCallback17((model) => {
|
|
6978
|
+
setSelectedModel(model);
|
|
6979
|
+
setSelectorOpen(false);
|
|
6980
|
+
}, [setSelectedModel]);
|
|
6904
6981
|
useEffect10(() => {
|
|
6905
6982
|
if (!selectorOpen) return;
|
|
6906
6983
|
const onMouseDown = (e) => {
|
|
@@ -6931,37 +7008,34 @@ function ModelSelector({
|
|
|
6931
7008
|
activeProvider ? /* @__PURE__ */ React29.createElement("img", { alt: "", className: "brokr-model-logo", src: activeProvider.logo }) : /* @__PURE__ */ React29.createElement("span", { className: "brokr-model-dot", style: { background: "currentColor" } }),
|
|
6932
7009
|
activeProvider?.label ?? "Model",
|
|
6933
7010
|
/* @__PURE__ */ React29.createElement(ChevronDownIcon, { size: 13 })
|
|
6934
|
-
), selectorOpen ? /* @__PURE__ */ React29.createElement("div", { className: "brokr-model-dropdown", role: "listbox" }, providers.map((p) =>
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
onClick: () => {
|
|
6946
|
-
if (locked) {
|
|
6947
|
-
void checkout({ plan: "pro" });
|
|
6948
|
-
} else {
|
|
6949
|
-
setSelectedModel(p.model);
|
|
6950
|
-
setSelectorOpen(false);
|
|
6951
|
-
}
|
|
6952
|
-
},
|
|
6953
|
-
title: locked ? "Add credits to unlock" : void 0,
|
|
6954
|
-
type: "button"
|
|
6955
|
-
},
|
|
6956
|
-
/* @__PURE__ */ React29.createElement("img", { alt: "", className: "brokr-model-logo", src: p.logo }),
|
|
6957
|
-
/* @__PURE__ */ React29.createElement("span", { className: "brokr-model-option-label" }, p.label),
|
|
6958
|
-
locked ? /* @__PURE__ */ React29.createElement("span", { className: "brokr-model-lock", "aria-hidden": "true" }, /* @__PURE__ */ React29.createElement(LockIcon, { size: 13 })) : null
|
|
6959
|
-
);
|
|
6960
|
-
})) : null);
|
|
7011
|
+
), selectorOpen ? /* @__PURE__ */ React29.createElement("div", { className: "brokr-model-dropdown", role: "listbox" }, providers.map((p) => /* @__PURE__ */ React29.createElement(
|
|
7012
|
+
ModelOption,
|
|
7013
|
+
{
|
|
7014
|
+
key: p.id,
|
|
7015
|
+
provider: p,
|
|
7016
|
+
isActive: p.model === activeModel,
|
|
7017
|
+
isLocked: !availableProviders.some((a) => a.id === p.id),
|
|
7018
|
+
onSelect: handleModelSelect,
|
|
7019
|
+
onCheckout: checkout
|
|
7020
|
+
}
|
|
7021
|
+
))) : null);
|
|
6961
7022
|
}
|
|
6962
7023
|
|
|
6963
7024
|
// src/react/chat/ThreadSidebar.tsx
|
|
6964
7025
|
import React30, { useCallback as useCallback18, useMemo as useMemo20 } from "react";
|
|
7026
|
+
function ThreadItemButton({ id, title, isActive, onSelect }) {
|
|
7027
|
+
const handleClick = useCallback18(() => onSelect(id), [id, onSelect]);
|
|
7028
|
+
return /* @__PURE__ */ React30.createElement(
|
|
7029
|
+
"button",
|
|
7030
|
+
{
|
|
7031
|
+
className: "brokr-ai-chat-conversation",
|
|
7032
|
+
"data-active": isActive,
|
|
7033
|
+
onClick: handleClick,
|
|
7034
|
+
type: "button"
|
|
7035
|
+
},
|
|
7036
|
+
title
|
|
7037
|
+
);
|
|
7038
|
+
}
|
|
6965
7039
|
function ThreadSidebar() {
|
|
6966
7040
|
const {
|
|
6967
7041
|
startNewChat,
|
|
@@ -7012,15 +7086,14 @@ function ThreadSidebar() {
|
|
|
7012
7086
|
value: renameValue
|
|
7013
7087
|
}
|
|
7014
7088
|
) : /* @__PURE__ */ React30.createElement(
|
|
7015
|
-
|
|
7089
|
+
ThreadItemButton,
|
|
7016
7090
|
{
|
|
7017
|
-
className: "brokr-ai-chat-conversation",
|
|
7018
|
-
"data-active": item.id === activeId,
|
|
7019
7091
|
key: item.id,
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7092
|
+
id: item.id,
|
|
7093
|
+
title: item.title,
|
|
7094
|
+
isActive: item.id === activeId,
|
|
7095
|
+
onSelect: selectThreadAndCloseSidebar
|
|
7096
|
+
}
|
|
7024
7097
|
)));
|
|
7025
7098
|
}, [
|
|
7026
7099
|
threadsLoading,
|
|
@@ -7037,7 +7110,7 @@ function ThreadSidebar() {
|
|
|
7037
7110
|
}
|
|
7038
7111
|
|
|
7039
7112
|
// src/react/chat/MessagePane.tsx
|
|
7040
|
-
import React33, { useMemo as useMemo22 } from "react";
|
|
7113
|
+
import React33, { useCallback as useCallback21, useMemo as useMemo22 } from "react";
|
|
7041
7114
|
|
|
7042
7115
|
// src/react/chat/MessageBubble.tsx
|
|
7043
7116
|
import React32, { useCallback as useCallback20 } from "react";
|
|
@@ -7220,6 +7293,12 @@ function MessageBubble({ message, isTyping, user }) {
|
|
|
7220
7293
|
}
|
|
7221
7294
|
|
|
7222
7295
|
// src/react/chat/MessagePane.tsx
|
|
7296
|
+
function StarterPromptButton({ prompt, onSend }) {
|
|
7297
|
+
const handleClick = useCallback21(() => {
|
|
7298
|
+
void onSend(prompt);
|
|
7299
|
+
}, [prompt, onSend]);
|
|
7300
|
+
return /* @__PURE__ */ React33.createElement("button", { className: "brokr-ai-chat-starter", onClick: handleClick, type: "button" }, prompt);
|
|
7301
|
+
}
|
|
7223
7302
|
function MessagePane({ starterPrompts, emptyTitle, emptyCopy, subtitle }) {
|
|
7224
7303
|
const {
|
|
7225
7304
|
displayMessages,
|
|
@@ -7250,20 +7329,17 @@ function MessagePane({ starterPrompts, emptyTitle, emptyCopy, subtitle }) {
|
|
|
7250
7329
|
);
|
|
7251
7330
|
});
|
|
7252
7331
|
}, [visibleMessages, isSubmitting, user]);
|
|
7253
|
-
return /* @__PURE__ */ React33.createElement("div", { className: "brokr-ai-chat-thread", "data-empty": isEmpty, ref: scrollContainerRef }, isEmpty ? /* @__PURE__ */ React33.createElement("div", { className: "brokr-ai-chat-empty" }, /* @__PURE__ */ React33.createElement(SparkIcon, { size: 28 }), /* @__PURE__ */ React33.createElement("h2", { className: "brokr-title" }, emptyTitle), subtitle ?? emptyCopy ? /* @__PURE__ */ React33.createElement("p", { className: "brokr-copy" }, subtitle ?? emptyCopy) : null, starterPrompts.length > 0 ? /* @__PURE__ */ React33.createElement("div", { className: "brokr-ai-chat-starters" }, starterPrompts.map((sp) => /* @__PURE__ */ React33.createElement(
|
|
7254
|
-
"button",
|
|
7255
|
-
{
|
|
7256
|
-
className: "brokr-ai-chat-starter",
|
|
7257
|
-
key: sp,
|
|
7258
|
-
onClick: () => void sendMessage(sp),
|
|
7259
|
-
type: "button"
|
|
7260
|
-
},
|
|
7261
|
-
sp
|
|
7262
|
-
))) : null) : /* @__PURE__ */ React33.createElement("div", { className: "brokr-ai-chat-thread-inner" }, (isPersist ? hasMoreMessages : memHasMore) ? /* @__PURE__ */ React33.createElement("div", { ref: sentinelRef, className: "brokr-ai-chat-sentinel" }, loadingOlder ? /* @__PURE__ */ React33.createElement("div", { style: { display: "flex", justifyContent: "center", padding: "0.5rem" } }, /* @__PURE__ */ React33.createElement(Skeleton, { width: 120, height: 12, radius: 6 })) : null) : null, messageElements, /* @__PURE__ */ React33.createElement("div", { ref: bottomRef })));
|
|
7332
|
+
return /* @__PURE__ */ React33.createElement("div", { className: "brokr-ai-chat-thread", "data-empty": isEmpty, ref: scrollContainerRef }, isEmpty ? /* @__PURE__ */ React33.createElement("div", { className: "brokr-ai-chat-empty" }, /* @__PURE__ */ React33.createElement(SparkIcon, { size: 28 }), /* @__PURE__ */ React33.createElement("h2", { className: "brokr-title" }, emptyTitle), subtitle ?? emptyCopy ? /* @__PURE__ */ React33.createElement("p", { className: "brokr-copy" }, subtitle ?? emptyCopy) : null, starterPrompts.length > 0 ? /* @__PURE__ */ React33.createElement("div", { className: "brokr-ai-chat-starters" }, starterPrompts.map((sp) => /* @__PURE__ */ React33.createElement(StarterPromptButton, { key: sp, prompt: sp, onSend: sendMessage }))) : null) : /* @__PURE__ */ React33.createElement("div", { className: "brokr-ai-chat-thread-inner" }, (isPersist ? hasMoreMessages : memHasMore) ? /* @__PURE__ */ React33.createElement("div", { ref: sentinelRef, className: "brokr-ai-chat-sentinel" }, loadingOlder ? /* @__PURE__ */ React33.createElement("div", { style: { display: "flex", justifyContent: "center", padding: "0.5rem" } }, /* @__PURE__ */ React33.createElement(Skeleton, { width: 120, height: 12, radius: 6 })) : null) : null, messageElements, /* @__PURE__ */ React33.createElement("div", { ref: bottomRef })));
|
|
7263
7333
|
}
|
|
7264
7334
|
|
|
7265
7335
|
// src/react/chat/ChatInput.tsx
|
|
7266
|
-
import React34, { useCallback as
|
|
7336
|
+
import React34, { useCallback as useCallback22, useEffect as useEffect11 } from "react";
|
|
7337
|
+
function CommandButton({ cmd, chatContext }) {
|
|
7338
|
+
const handleClick = useCallback22(() => {
|
|
7339
|
+
void cmd.run(chatContext);
|
|
7340
|
+
}, [cmd, chatContext]);
|
|
7341
|
+
return /* @__PURE__ */ React34.createElement("button", { className: "brokr-ai-chat-sidebar-button", key: cmd.id, onClick: handleClick, type: "button" }, cmd.text);
|
|
7342
|
+
}
|
|
7267
7343
|
function ChatInput() {
|
|
7268
7344
|
const {
|
|
7269
7345
|
input,
|
|
@@ -7281,29 +7357,20 @@ function ChatInput() {
|
|
|
7281
7357
|
el.style.height = "auto";
|
|
7282
7358
|
el.style.height = `${Math.min(el.scrollHeight, 168)}px`;
|
|
7283
7359
|
}, [input, textareaRef]);
|
|
7284
|
-
const handleSubmit =
|
|
7360
|
+
const handleSubmit = useCallback22((e) => {
|
|
7285
7361
|
e.preventDefault();
|
|
7286
7362
|
void sendMessage();
|
|
7287
7363
|
}, [sendMessage]);
|
|
7288
|
-
const handleKeyDown =
|
|
7364
|
+
const handleKeyDown = useCallback22((e) => {
|
|
7289
7365
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
7290
7366
|
e.preventDefault();
|
|
7291
7367
|
void sendMessage();
|
|
7292
7368
|
}
|
|
7293
7369
|
}, [sendMessage]);
|
|
7294
|
-
const handleChange =
|
|
7370
|
+
const handleChange = useCallback22((e) => {
|
|
7295
7371
|
setInput(e.target.value);
|
|
7296
7372
|
}, [setInput]);
|
|
7297
|
-
return /* @__PURE__ */ React34.createElement("form", { className: "brokr-ai-chat-input-area", onSubmit: handleSubmit }, /* @__PURE__ */ React34.createElement("div", { className: "brokr-ai-chat-input-container" }, composerCommands.length > 0 ? /* @__PURE__ */ React34.createElement("div", { className: "brokr-ai-chat-composer-actions" }, composerCommands.map((cmd) => /* @__PURE__ */ React34.createElement(
|
|
7298
|
-
"button",
|
|
7299
|
-
{
|
|
7300
|
-
className: "brokr-ai-chat-sidebar-button",
|
|
7301
|
-
key: cmd.id,
|
|
7302
|
-
onClick: () => void cmd.run(chatContext),
|
|
7303
|
-
type: "button"
|
|
7304
|
-
},
|
|
7305
|
-
cmd.text
|
|
7306
|
-
))) : null, /* @__PURE__ */ React34.createElement("div", { className: "brokr-ai-chat-input-row" }, /* @__PURE__ */ React34.createElement(
|
|
7373
|
+
return /* @__PURE__ */ React34.createElement("form", { className: "brokr-ai-chat-input-area", onSubmit: handleSubmit }, /* @__PURE__ */ React34.createElement("div", { className: "brokr-ai-chat-input-container" }, composerCommands.length > 0 ? /* @__PURE__ */ React34.createElement("div", { className: "brokr-ai-chat-composer-actions" }, composerCommands.map((cmd) => /* @__PURE__ */ React34.createElement(CommandButton, { key: cmd.id, cmd, chatContext }))) : null, /* @__PURE__ */ React34.createElement("div", { className: "brokr-ai-chat-input-row" }, /* @__PURE__ */ React34.createElement(
|
|
7307
7374
|
"textarea",
|
|
7308
7375
|
{
|
|
7309
7376
|
className: "brokr-ai-chat-textarea",
|
|
@@ -7437,11 +7504,19 @@ function AIChat(inlineProps) {
|
|
|
7437
7504
|
const [sidebarOpen, setSidebarOpen] = useState18(false);
|
|
7438
7505
|
const [threadMenuOpenId, setThreadMenuOpenId] = useState18(null);
|
|
7439
7506
|
const threadMenuRef = useRef7(null);
|
|
7440
|
-
const closeSidebar =
|
|
7441
|
-
const selectThreadAndCloseSidebar =
|
|
7507
|
+
const closeSidebar = useCallback23(() => setSidebarOpen(false), []);
|
|
7508
|
+
const selectThreadAndCloseSidebar = useCallback23((id) => {
|
|
7442
7509
|
chat.selectThread(id);
|
|
7443
7510
|
setSidebarOpen(false);
|
|
7444
7511
|
}, [chat.selectThread]);
|
|
7512
|
+
const handleCopy = useCallback23((content) => {
|
|
7513
|
+
navigator.clipboard.writeText(content).catch(() => {
|
|
7514
|
+
});
|
|
7515
|
+
}, []);
|
|
7516
|
+
const handleStartRename = useCallback23((threadId) => {
|
|
7517
|
+
setThreadMenuOpenId(null);
|
|
7518
|
+
chat.startRename(threadId);
|
|
7519
|
+
}, [chat.startRename]);
|
|
7445
7520
|
useEffect12(() => {
|
|
7446
7521
|
if (!threadMenuOpenId) return;
|
|
7447
7522
|
const onMouseDown = (e) => {
|
|
@@ -7499,17 +7574,11 @@ function AIChat(inlineProps) {
|
|
|
7499
7574
|
startNewChat: chat.startNewChat,
|
|
7500
7575
|
selectThread: chat.selectThread,
|
|
7501
7576
|
deleteThread: chat.deleteThread,
|
|
7502
|
-
handleCopy
|
|
7503
|
-
navigator.clipboard.writeText(content).catch(() => {
|
|
7504
|
-
});
|
|
7505
|
-
},
|
|
7577
|
+
handleCopy,
|
|
7506
7578
|
renamingId: chat.renamingId,
|
|
7507
7579
|
renameValue: chat.renameValue,
|
|
7508
7580
|
setRenameValue: chat.setRenameValue,
|
|
7509
|
-
startRename:
|
|
7510
|
-
setThreadMenuOpenId(null);
|
|
7511
|
-
chat.startRename(threadId);
|
|
7512
|
-
},
|
|
7581
|
+
startRename: handleStartRename,
|
|
7513
7582
|
submitRename: chat.submitRename,
|
|
7514
7583
|
displaySidebarItems: chat.displaySidebarItems,
|
|
7515
7584
|
threadsLoading: chat.threadsLoading,
|
|
@@ -7595,6 +7664,19 @@ function AIChat(inlineProps) {
|
|
|
7595
7664
|
), /* @__PURE__ */ React35.createElement(ChatInput, null))
|
|
7596
7665
|
));
|
|
7597
7666
|
}
|
|
7667
|
+
function CommandButton2({ cmd, chatContext }) {
|
|
7668
|
+
const handleClick = useCallback23(() => {
|
|
7669
|
+
void cmd.run(chatContext);
|
|
7670
|
+
}, [cmd, chatContext]);
|
|
7671
|
+
return /* @__PURE__ */ React35.createElement("button", { className: "brokr-ai-chat-sidebar-button", onClick: handleClick, type: "button" }, cmd.text);
|
|
7672
|
+
}
|
|
7673
|
+
function MenuCommandItem({ cmd, chatContext, onClose }) {
|
|
7674
|
+
const handleClick = useCallback23(() => {
|
|
7675
|
+
onClose();
|
|
7676
|
+
void cmd.run(chatContext);
|
|
7677
|
+
}, [cmd, chatContext, onClose]);
|
|
7678
|
+
return /* @__PURE__ */ React35.createElement("button", { className: "brokr-ai-chat-thread-dropdown-item", onClick: handleClick, type: "button" }, cmd.text);
|
|
7679
|
+
}
|
|
7598
7680
|
function ChatHeader({
|
|
7599
7681
|
activeId,
|
|
7600
7682
|
sidebarVisible,
|
|
@@ -7614,10 +7696,20 @@ function ChatHeader({
|
|
|
7614
7696
|
startRename,
|
|
7615
7697
|
deleteThread
|
|
7616
7698
|
}) {
|
|
7617
|
-
const handleOpenSidebar =
|
|
7618
|
-
const handleToggleMenu =
|
|
7699
|
+
const handleOpenSidebar = useCallback23(() => setSidebarOpen(true), [setSidebarOpen]);
|
|
7700
|
+
const handleToggleMenu = useCallback23(() => {
|
|
7619
7701
|
setThreadMenuOpenId(threadMenuOpenId ? null : activeId);
|
|
7620
7702
|
}, [setThreadMenuOpenId, threadMenuOpenId, activeId]);
|
|
7703
|
+
const closeMenu = useCallback23(() => setThreadMenuOpenId(null), [setThreadMenuOpenId]);
|
|
7704
|
+
const handleRename = useCallback23(() => {
|
|
7705
|
+
if (activeId) startRename(activeId);
|
|
7706
|
+
}, [activeId, startRename]);
|
|
7707
|
+
const handleDelete = useCallback23(() => {
|
|
7708
|
+
if (activeId) {
|
|
7709
|
+
setThreadMenuOpenId(null);
|
|
7710
|
+
void deleteThread(activeId);
|
|
7711
|
+
}
|
|
7712
|
+
}, [activeId, deleteThread, setThreadMenuOpenId]);
|
|
7621
7713
|
return /* @__PURE__ */ React35.createElement("header", { className: "brokr-ai-chat-topbar" }, /* @__PURE__ */ React35.createElement("div", { className: "brokr-ai-chat-topbar-left" }, sidebarVisible ? /* @__PURE__ */ React35.createElement(
|
|
7622
7714
|
"button",
|
|
7623
7715
|
{
|
|
@@ -7627,16 +7719,7 @@ function ChatHeader({
|
|
|
7627
7719
|
type: "button"
|
|
7628
7720
|
},
|
|
7629
7721
|
/* @__PURE__ */ React35.createElement(MenuIcon, { size: 18 })
|
|
7630
|
-
) : null), /* @__PURE__ */ React35.createElement("div", { className: "brokr-ai-chat-topbar-actions" }, headerCommands.map((cmd) => /* @__PURE__ */ React35.createElement(
|
|
7631
|
-
"button",
|
|
7632
|
-
{
|
|
7633
|
-
className: "brokr-ai-chat-sidebar-button",
|
|
7634
|
-
key: cmd.id,
|
|
7635
|
-
onClick: () => void cmd.run(chatContext),
|
|
7636
|
-
type: "button"
|
|
7637
|
-
},
|
|
7638
|
-
cmd.text
|
|
7639
|
-
)), modelSelectorVisible ? /* @__PURE__ */ React35.createElement(
|
|
7722
|
+
) : null), /* @__PURE__ */ React35.createElement("div", { className: "brokr-ai-chat-topbar-actions" }, headerCommands.map((cmd) => /* @__PURE__ */ React35.createElement(CommandButton2, { key: cmd.id, cmd, chatContext })), modelSelectorVisible ? /* @__PURE__ */ React35.createElement(
|
|
7640
7723
|
ModelSelector,
|
|
7641
7724
|
{
|
|
7642
7725
|
activeModel,
|
|
@@ -7657,32 +7740,25 @@ function ChatHeader({
|
|
|
7657
7740
|
"button",
|
|
7658
7741
|
{
|
|
7659
7742
|
className: "brokr-ai-chat-thread-dropdown-item",
|
|
7660
|
-
onClick:
|
|
7743
|
+
onClick: handleRename,
|
|
7661
7744
|
type: "button"
|
|
7662
7745
|
},
|
|
7663
7746
|
/* @__PURE__ */ React35.createElement(PencilIcon, { size: 13 }),
|
|
7664
7747
|
"Rename"
|
|
7665
7748
|
), threadMenuCommands.map((cmd) => /* @__PURE__ */ React35.createElement(
|
|
7666
|
-
|
|
7749
|
+
MenuCommandItem,
|
|
7667
7750
|
{
|
|
7668
|
-
className: "brokr-ai-chat-thread-dropdown-item",
|
|
7669
7751
|
key: cmd.id,
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
type: "button"
|
|
7675
|
-
},
|
|
7676
|
-
cmd.text
|
|
7752
|
+
cmd,
|
|
7753
|
+
chatContext,
|
|
7754
|
+
onClose: closeMenu
|
|
7755
|
+
}
|
|
7677
7756
|
)), /* @__PURE__ */ React35.createElement(
|
|
7678
7757
|
"button",
|
|
7679
7758
|
{
|
|
7680
7759
|
className: "brokr-ai-chat-thread-dropdown-item",
|
|
7681
7760
|
"data-tone": "danger",
|
|
7682
|
-
onClick:
|
|
7683
|
-
setThreadMenuOpenId(null);
|
|
7684
|
-
void deleteThread(activeId);
|
|
7685
|
-
},
|
|
7761
|
+
onClick: handleDelete,
|
|
7686
7762
|
type: "button"
|
|
7687
7763
|
},
|
|
7688
7764
|
/* @__PURE__ */ React35.createElement(TrashIcon, { size: 13 }),
|
|
@@ -7691,7 +7767,11 @@ function ChatHeader({
|
|
|
7691
7767
|
}
|
|
7692
7768
|
|
|
7693
7769
|
// src/react/composites/FabAI.tsx
|
|
7694
|
-
import React36, { useCallback as
|
|
7770
|
+
import React36, { useCallback as useCallback24, useMemo as useMemo24, useState as useState19 } from "react";
|
|
7771
|
+
function StarterButton({ prompt, onSelect }) {
|
|
7772
|
+
const handleClick = useCallback24(() => onSelect(prompt), [prompt, onSelect]);
|
|
7773
|
+
return /* @__PURE__ */ React36.createElement("button", { className: "brokr-chat-starter", onClick: handleClick, type: "button" }, prompt);
|
|
7774
|
+
}
|
|
7695
7775
|
function FabAI({
|
|
7696
7776
|
model,
|
|
7697
7777
|
onSendMessage,
|
|
@@ -7713,20 +7793,20 @@ function FabAI({
|
|
|
7713
7793
|
[position]
|
|
7714
7794
|
);
|
|
7715
7795
|
const canChat = useMemo24(() => can("ai.chat"), [can]);
|
|
7716
|
-
const toggleOpen =
|
|
7796
|
+
const toggleOpen = useCallback24(() => {
|
|
7717
7797
|
if (!canChat) {
|
|
7718
7798
|
redirectTo("/pricing");
|
|
7719
7799
|
return;
|
|
7720
7800
|
}
|
|
7721
7801
|
setIsOpen((current) => !current);
|
|
7722
7802
|
}, [canChat]);
|
|
7723
|
-
const handleInputChange =
|
|
7803
|
+
const handleInputChange = useCallback24((event) => {
|
|
7724
7804
|
setInput(event.target.value);
|
|
7725
7805
|
}, []);
|
|
7726
|
-
const handleClose =
|
|
7806
|
+
const handleClose = useCallback24(() => {
|
|
7727
7807
|
setIsOpen(false);
|
|
7728
7808
|
}, []);
|
|
7729
|
-
const sendPrompt =
|
|
7809
|
+
const sendPrompt = useCallback24(async (prompt) => {
|
|
7730
7810
|
const nextPrompt = prompt.trim();
|
|
7731
7811
|
if (!nextPrompt) return;
|
|
7732
7812
|
const nextMessages = [...messages, { role: "user", content: nextPrompt }];
|
|
@@ -7759,17 +7839,17 @@ function FabAI({
|
|
|
7759
7839
|
setIsSending(false);
|
|
7760
7840
|
}
|
|
7761
7841
|
}, [messages, model, onSendMessage, systemPrompt]);
|
|
7762
|
-
const handleSubmit =
|
|
7842
|
+
const handleSubmit = useCallback24(async (event) => {
|
|
7763
7843
|
event.preventDefault();
|
|
7764
7844
|
await sendPrompt(input);
|
|
7765
7845
|
}, [input, sendPrompt]);
|
|
7766
|
-
const handleKeyDown =
|
|
7846
|
+
const handleKeyDown = useCallback24((event) => {
|
|
7767
7847
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
7768
7848
|
event.preventDefault();
|
|
7769
7849
|
void sendPrompt(input);
|
|
7770
7850
|
}
|
|
7771
7851
|
}, [input, sendPrompt]);
|
|
7772
|
-
const handleStarterPrompt =
|
|
7852
|
+
const handleStarterPrompt = useCallback24((prompt) => {
|
|
7773
7853
|
void sendPrompt(prompt);
|
|
7774
7854
|
}, [sendPrompt]);
|
|
7775
7855
|
return /* @__PURE__ */ React36.createElement(React36.Fragment, null, /* @__PURE__ */ React36.createElement("div", { className: "brokr-chat-fab", style: launcherStyle }, /* @__PURE__ */ React36.createElement(
|
|
@@ -7783,30 +7863,16 @@ function FabAI({
|
|
|
7783
7863
|
},
|
|
7784
7864
|
/* @__PURE__ */ React36.createElement(MessageIcon, { size: 16 }),
|
|
7785
7865
|
"Ask AI"
|
|
7786
|
-
)), isOpen ? /* @__PURE__ */ React36.createElement("div", { className: "brokr-panel brokr-chat-panel", role: "dialog" }, /* @__PURE__ */ React36.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ React36.createElement("div", { className: "brokr-section", style: { gap: "
|
|
7866
|
+
)), isOpen ? /* @__PURE__ */ React36.createElement("div", { className: "brokr-panel brokr-chat-panel", role: "dialog" }, /* @__PURE__ */ React36.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ React36.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ React36.createElement("strong", null, "AI Chat"), user?.name ? /* @__PURE__ */ React36.createElement("span", { className: "brokr-copy" }, user.name) : null), /* @__PURE__ */ React36.createElement("button", { className: "brokr-button-ghost", onClick: handleClose, type: "button" }, /* @__PURE__ */ React36.createElement(CloseIcon, { size: 16 }))), /* @__PURE__ */ React36.createElement(
|
|
7787
7867
|
"div",
|
|
7788
7868
|
{
|
|
7789
7869
|
className: "brokr-chat-messages",
|
|
7790
7870
|
"data-empty": messages.length === 0
|
|
7791
7871
|
},
|
|
7792
|
-
messages.length === 0 ? /* @__PURE__ */ React36.createElement("div", { className: "brokr-chat-empty" }, /* @__PURE__ */ React36.createElement(SparkIcon, { size: 18 }), /* @__PURE__ */ React36.createElement("div", { className: "brokr-section", style: { gap: "
|
|
7793
|
-
const handleClick = () => {
|
|
7794
|
-
handleStarterPrompt(prompt);
|
|
7795
|
-
};
|
|
7796
|
-
return /* @__PURE__ */ React36.createElement(
|
|
7797
|
-
"button",
|
|
7798
|
-
{
|
|
7799
|
-
className: "brokr-chat-starter",
|
|
7800
|
-
key: prompt,
|
|
7801
|
-
onClick: handleClick,
|
|
7802
|
-
type: "button"
|
|
7803
|
-
},
|
|
7804
|
-
prompt
|
|
7805
|
-
);
|
|
7806
|
-
})) : null) : null,
|
|
7872
|
+
messages.length === 0 ? /* @__PURE__ */ React36.createElement("div", { className: "brokr-chat-empty" }, /* @__PURE__ */ React36.createElement(SparkIcon, { size: 18 }), /* @__PURE__ */ React36.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ React36.createElement("strong", null, "Send a message to chat with the AI."), /* @__PURE__ */ React36.createElement("span", { className: "brokr-copy" }, "Ask a question or drop in a starter prompt below.")), starterPrompts.length > 0 ? /* @__PURE__ */ React36.createElement("div", { className: "brokr-chat-starters" }, starterPrompts.map((prompt) => /* @__PURE__ */ React36.createElement(StarterButton, { key: prompt, prompt, onSelect: handleStarterPrompt }))) : null) : null,
|
|
7807
7873
|
messages.map((message, index) => /* @__PURE__ */ React36.createElement("div", { className: "brokr-chat-bubble", "data-role": message.role, key: `${message.role}-${index}` }, contentToText(message.content))),
|
|
7808
7874
|
error ? /* @__PURE__ */ React36.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null
|
|
7809
|
-
), /* @__PURE__ */ React36.createElement("form", { className: "brokr-section", onSubmit: handleSubmit, style: { gap: "
|
|
7875
|
+
), /* @__PURE__ */ React36.createElement("form", { className: "brokr-section", onSubmit: handleSubmit, style: { gap: "var(--brokr-space-3)" } }, /* @__PURE__ */ React36.createElement(
|
|
7810
7876
|
"textarea",
|
|
7811
7877
|
{
|
|
7812
7878
|
className: "brokr-textarea brokr-chat-input",
|
|
@@ -7821,7 +7887,7 @@ function FabAI({
|
|
|
7821
7887
|
|
|
7822
7888
|
// src/react/composites/SmartUpload.tsx
|
|
7823
7889
|
import React37, {
|
|
7824
|
-
useCallback as
|
|
7890
|
+
useCallback as useCallback25,
|
|
7825
7891
|
useId as useId2,
|
|
7826
7892
|
useMemo as useMemo25,
|
|
7827
7893
|
useRef as useRef8,
|
|
@@ -7844,7 +7910,7 @@ function SmartUpload({
|
|
|
7844
7910
|
const helperText = useMemo25(() => {
|
|
7845
7911
|
return `${Math.round(maxSize / (1024 * 1024))} MB max file size.`;
|
|
7846
7912
|
}, [maxSize]);
|
|
7847
|
-
const beginUpload =
|
|
7913
|
+
const beginUpload = useCallback25((file) => {
|
|
7848
7914
|
if (file.size > maxSize) {
|
|
7849
7915
|
setError(`That file is larger than ${Math.round(maxSize / (1024 * 1024))} MB.`);
|
|
7850
7916
|
return;
|
|
@@ -7881,31 +7947,31 @@ function SmartUpload({
|
|
|
7881
7947
|
body.append("purpose", purpose);
|
|
7882
7948
|
request.send(body);
|
|
7883
7949
|
}, [maxSize, onUpload, purpose]);
|
|
7884
|
-
const handleInputChange =
|
|
7950
|
+
const handleInputChange = useCallback25((event) => {
|
|
7885
7951
|
const file = event.target.files?.[0];
|
|
7886
7952
|
event.target.value = "";
|
|
7887
7953
|
if (!file) return;
|
|
7888
7954
|
beginUpload(file);
|
|
7889
7955
|
}, [beginUpload]);
|
|
7890
|
-
const handleDrop =
|
|
7956
|
+
const handleDrop = useCallback25((event) => {
|
|
7891
7957
|
event.preventDefault();
|
|
7892
7958
|
setDragActive(false);
|
|
7893
7959
|
const file = event.dataTransfer.files?.[0];
|
|
7894
7960
|
if (!file) return;
|
|
7895
7961
|
beginUpload(file);
|
|
7896
7962
|
}, [beginUpload]);
|
|
7897
|
-
const handleDragEnter =
|
|
7963
|
+
const handleDragEnter = useCallback25((event) => {
|
|
7898
7964
|
event.preventDefault();
|
|
7899
7965
|
setDragActive(true);
|
|
7900
7966
|
}, []);
|
|
7901
|
-
const handleDragLeave =
|
|
7967
|
+
const handleDragLeave = useCallback25((event) => {
|
|
7902
7968
|
event.preventDefault();
|
|
7903
7969
|
setDragActive(false);
|
|
7904
7970
|
}, []);
|
|
7905
|
-
const handleBrowse =
|
|
7971
|
+
const handleBrowse = useCallback25(() => {
|
|
7906
7972
|
inputRef.current?.click();
|
|
7907
7973
|
}, []);
|
|
7908
|
-
return /* @__PURE__ */ React37.createElement("div", { className: "brokr-card brokr-upload-shell" }, /* @__PURE__ */ React37.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ React37.createElement("div", { className: "brokr-section", style: { gap: "
|
|
7974
|
+
return /* @__PURE__ */ React37.createElement("div", { className: "brokr-card brokr-upload-shell" }, /* @__PURE__ */ React37.createElement("div", { className: "brokr-brand-row", style: { justifyContent: "space-between" } }, /* @__PURE__ */ React37.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ React37.createElement("strong", null, "Upload files"), /* @__PURE__ */ React37.createElement("span", { className: "brokr-copy" }, "Drop a file and let Brokr handle the boring part.")), paymentsMode === "sandbox" ? /* @__PURE__ */ React37.createElement("span", { className: "brokr-badge brokr-badge-sandbox" }, "Sandbox") : null), /* @__PURE__ */ React37.createElement(
|
|
7909
7975
|
"label",
|
|
7910
7976
|
{
|
|
7911
7977
|
className: "brokr-upload-dropzone",
|
|
@@ -7930,11 +7996,11 @@ function SmartUpload({
|
|
|
7930
7996
|
ref: inputRef,
|
|
7931
7997
|
type: "file"
|
|
7932
7998
|
}
|
|
7933
|
-
), fileName ? /* @__PURE__ */ React37.createElement("div", { className: "brokr-card brokr-upload-file" }, /* @__PURE__ */ React37.createElement("div", { className: "brokr-section", style: { gap: "
|
|
7999
|
+
), fileName ? /* @__PURE__ */ React37.createElement("div", { className: "brokr-card brokr-upload-file" }, /* @__PURE__ */ React37.createElement("div", { className: "brokr-section", style: { gap: "var(--brokr-space-1)" } }, /* @__PURE__ */ React37.createElement("strong", null, fileName), /* @__PURE__ */ React37.createElement("span", { className: "brokr-copy" }, isUploading ? `Uploading ${progress}%` : progress === 100 ? "Processed" : "Queued")), /* @__PURE__ */ React37.createElement("div", { className: "brokr-meter-bar" }, /* @__PURE__ */ React37.createElement("div", { className: "brokr-meter-fill", style: { width: `${progress}%` } }))) : null, error ? /* @__PURE__ */ React37.createElement("div", { className: "brokr-inline-message", "data-tone": "error" }, error) : null);
|
|
7934
8000
|
}
|
|
7935
8001
|
|
|
7936
8002
|
// src/react/composites/FeedbackWidget.tsx
|
|
7937
|
-
import React38, { useCallback as
|
|
8003
|
+
import React38, { useCallback as useCallback26, useState as useState21 } from "react";
|
|
7938
8004
|
function FeedbackWidget({
|
|
7939
8005
|
context,
|
|
7940
8006
|
onSubmit
|
|
@@ -7945,16 +8011,16 @@ function FeedbackWidget({
|
|
|
7945
8011
|
const [error, setError] = useState21(null);
|
|
7946
8012
|
const [message, setMessage] = useState21(null);
|
|
7947
8013
|
const [isPending, setIsPending] = useState21(false);
|
|
7948
|
-
const handleTextChange =
|
|
8014
|
+
const handleTextChange = useCallback26((event) => {
|
|
7949
8015
|
setText(event.target.value);
|
|
7950
8016
|
}, []);
|
|
7951
|
-
const handleRateUp =
|
|
8017
|
+
const handleRateUp = useCallback26(() => {
|
|
7952
8018
|
setRating("up");
|
|
7953
8019
|
}, []);
|
|
7954
|
-
const handleRateDown =
|
|
8020
|
+
const handleRateDown = useCallback26(() => {
|
|
7955
8021
|
setRating("down");
|
|
7956
8022
|
}, []);
|
|
7957
|
-
const handleSubmit =
|
|
8023
|
+
const handleSubmit = useCallback26(async (event) => {
|
|
7958
8024
|
event.preventDefault();
|
|
7959
8025
|
if (!rating) {
|
|
7960
8026
|
setError("Choose a direction first.");
|
|
@@ -8270,7 +8336,7 @@ var BrokrErrorBoundary = class extends React39.Component {
|
|
|
8270
8336
|
};
|
|
8271
8337
|
|
|
8272
8338
|
// src/react/notifications/NotificationBell.tsx
|
|
8273
|
-
import React40, { useCallback as
|
|
8339
|
+
import React40, { useCallback as useCallback27, useEffect as useEffect13, useMemo as useMemo26, useRef as useRef9, useState as useState22 } from "react";
|
|
8274
8340
|
|
|
8275
8341
|
// src/react/notifications/use-notifications.ts
|
|
8276
8342
|
import { useContext as useContext4 } from "react";
|
|
@@ -8295,12 +8361,34 @@ function timeAgo(iso) {
|
|
|
8295
8361
|
const days = Math.floor(hours / 24);
|
|
8296
8362
|
return `${days}d ago`;
|
|
8297
8363
|
}
|
|
8364
|
+
function NotifDropdownItem({
|
|
8365
|
+
notif,
|
|
8366
|
+
registry,
|
|
8367
|
+
onClick
|
|
8368
|
+
}) {
|
|
8369
|
+
const handleClick = useCallback27(() => onClick(notif), [notif, onClick]);
|
|
8370
|
+
const notifData = notif.data ?? {};
|
|
8371
|
+
const notifType = notifData.type ?? "default";
|
|
8372
|
+
const resolved = resolveNotificationType(registry, notifType, notifData);
|
|
8373
|
+
return /* @__PURE__ */ React40.createElement(
|
|
8374
|
+
"button",
|
|
8375
|
+
{
|
|
8376
|
+
type: "button",
|
|
8377
|
+
className: `brokr-notif-item${notif.read ? "" : " brokr-notif-item--unread"}`,
|
|
8378
|
+
onClick: handleClick,
|
|
8379
|
+
role: "menuitem"
|
|
8380
|
+
},
|
|
8381
|
+
resolved.image ? /* @__PURE__ */ React40.createElement("img", { src: resolved.image.url, alt: resolved.image.alt, className: "brokr-notif-item-logo" }) : /* @__PURE__ */ React40.createElement("span", { className: `brokr-notif-item-dot brokr-notif-item-dot--${notif.variant}` }),
|
|
8382
|
+
/* @__PURE__ */ React40.createElement("div", { className: "brokr-notif-item-body" }, /* @__PURE__ */ React40.createElement("span", { className: "brokr-notif-item-title" }, notif.title), /* @__PURE__ */ React40.createElement("span", { className: "brokr-notif-item-message" }, notif.message)),
|
|
8383
|
+
/* @__PURE__ */ React40.createElement("span", { className: "brokr-notif-item-time" }, timeAgo(notif.createdAt))
|
|
8384
|
+
);
|
|
8385
|
+
}
|
|
8298
8386
|
function NotificationBell() {
|
|
8299
8387
|
const { notifications, unreadCount, markRead, markAllRead, isLoading, registry } = useNotifications();
|
|
8300
8388
|
const [open, setOpen] = useState22(false);
|
|
8301
8389
|
const containerRef = useRef9(null);
|
|
8302
8390
|
const markReadTimerRef = useRef9(null);
|
|
8303
|
-
const toggle =
|
|
8391
|
+
const toggle = useCallback27(() => setOpen((o) => !o), []);
|
|
8304
8392
|
useEffect13(() => {
|
|
8305
8393
|
if (markReadTimerRef.current) {
|
|
8306
8394
|
clearTimeout(markReadTimerRef.current);
|
|
@@ -8342,7 +8430,7 @@ function NotificationBell() {
|
|
|
8342
8430
|
),
|
|
8343
8431
|
[notifications]
|
|
8344
8432
|
);
|
|
8345
|
-
const handleItemClick =
|
|
8433
|
+
const handleItemClick = useCallback27((notif) => {
|
|
8346
8434
|
if (!notif.read) markRead(notif.id);
|
|
8347
8435
|
const notifData = notif.data ?? {};
|
|
8348
8436
|
const notifType = notif.type ?? notifData.type ?? "default";
|
|
@@ -8359,7 +8447,8 @@ function NotificationBell() {
|
|
|
8359
8447
|
className: "brokr-notif-bell",
|
|
8360
8448
|
onClick: toggle,
|
|
8361
8449
|
"aria-label": `Notifications${unreadCount > 0 ? ` (${unreadCount} unread)` : ""}`,
|
|
8362
|
-
"aria-expanded": open
|
|
8450
|
+
"aria-expanded": open,
|
|
8451
|
+
"aria-haspopup": "menu"
|
|
8363
8452
|
},
|
|
8364
8453
|
/* @__PURE__ */ React40.createElement("svg", { "aria-hidden": "true", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }, /* @__PURE__ */ React40.createElement("path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" }), /* @__PURE__ */ React40.createElement("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" })),
|
|
8365
8454
|
unreadCount > 0 && /* @__PURE__ */ React40.createElement("span", { className: "brokr-notif-badge" }, unreadCount > 99 ? "99+" : unreadCount)
|
|
@@ -8371,35 +8460,19 @@ function NotificationBell() {
|
|
|
8371
8460
|
onClick: markAllRead
|
|
8372
8461
|
},
|
|
8373
8462
|
"Mark all read"
|
|
8374
|
-
)), /* @__PURE__ */ React40.createElement("div", { className: "brokr-notif-dropdown-list" }, isLoading ? /* @__PURE__ */ React40.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ React40.createElement("span", { className: "brokr-notif-empty-text" }, "Loading\u2026")) : sorted.length === 0 ? /* @__PURE__ */ React40.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ React40.createElement("span", { className: "brokr-notif-empty-text" }, "No notifications yet")) : sorted.map((notif) =>
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
className: `brokr-notif-item${notif.read ? "" : " brokr-notif-item--unread"}`,
|
|
8384
|
-
onClick: () => handleItemClick(notif),
|
|
8385
|
-
role: "menuitem"
|
|
8386
|
-
},
|
|
8387
|
-
resolved.image ? /* @__PURE__ */ React40.createElement(
|
|
8388
|
-
"img",
|
|
8389
|
-
{
|
|
8390
|
-
src: resolved.image.url,
|
|
8391
|
-
alt: resolved.image.alt,
|
|
8392
|
-
className: "brokr-notif-item-logo"
|
|
8393
|
-
}
|
|
8394
|
-
) : /* @__PURE__ */ React40.createElement("span", { className: `brokr-notif-item-dot brokr-notif-item-dot--${notif.variant}` }),
|
|
8395
|
-
/* @__PURE__ */ React40.createElement("div", { className: "brokr-notif-item-body" }, /* @__PURE__ */ React40.createElement("span", { className: "brokr-notif-item-title" }, notif.title), /* @__PURE__ */ React40.createElement("span", { className: "brokr-notif-item-message" }, notif.message)),
|
|
8396
|
-
/* @__PURE__ */ React40.createElement("span", { className: "brokr-notif-item-time" }, timeAgo(notif.createdAt))
|
|
8397
|
-
);
|
|
8398
|
-
}))));
|
|
8463
|
+
)), /* @__PURE__ */ React40.createElement("div", { className: "brokr-notif-dropdown-list" }, isLoading ? /* @__PURE__ */ React40.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ React40.createElement("span", { className: "brokr-notif-empty-text" }, "Loading\u2026")) : sorted.length === 0 ? /* @__PURE__ */ React40.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ React40.createElement("span", { className: "brokr-notif-empty-text" }, "No notifications yet")) : sorted.map((notif) => /* @__PURE__ */ React40.createElement(
|
|
8464
|
+
NotifDropdownItem,
|
|
8465
|
+
{
|
|
8466
|
+
key: notif.id,
|
|
8467
|
+
notif,
|
|
8468
|
+
registry,
|
|
8469
|
+
onClick: handleItemClick
|
|
8470
|
+
}
|
|
8471
|
+
)))));
|
|
8399
8472
|
}
|
|
8400
8473
|
|
|
8401
8474
|
// src/react/notifications/NotificationList.tsx
|
|
8402
|
-
import React41, { useCallback as
|
|
8475
|
+
import React41, { useCallback as useCallback28, useMemo as useMemo27 } from "react";
|
|
8403
8476
|
function formatTimestamp(iso) {
|
|
8404
8477
|
const date = new Date(iso);
|
|
8405
8478
|
return new Intl.DateTimeFormat("en-US", {
|
|
@@ -8412,6 +8485,27 @@ function formatTimestamp(iso) {
|
|
|
8412
8485
|
function NotificationListSkeleton() {
|
|
8413
8486
|
return /* @__PURE__ */ React41.createElement("div", { className: "brokr-notif-list-items" }, [1, 2, 3].map((i) => /* @__PURE__ */ React41.createElement("div", { key: i, className: "brokr-notif-list-row brokr-notif-list-row--skeleton" }, /* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-item-dot brokr-notif-item-dot--skeleton" }), /* @__PURE__ */ React41.createElement("div", { className: "brokr-notif-item-body" }, /* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-item-title brokr-skeleton-line", style: { width: "60%" } }), /* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-item-message brokr-skeleton-line", style: { width: "80%" } })), /* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-item-time brokr-skeleton-line", style: { width: 48 } }))));
|
|
8414
8487
|
}
|
|
8488
|
+
function NotifListItem({
|
|
8489
|
+
notif,
|
|
8490
|
+
registry,
|
|
8491
|
+
onClick
|
|
8492
|
+
}) {
|
|
8493
|
+
const handleClick = useCallback28(() => onClick(notif), [notif, onClick]);
|
|
8494
|
+
const notifData = notif.data ?? {};
|
|
8495
|
+
const notifType = notif.type ?? notifData.type ?? "default";
|
|
8496
|
+
const resolved = resolveNotificationType(registry, notifType, notifData);
|
|
8497
|
+
return /* @__PURE__ */ React41.createElement(
|
|
8498
|
+
"button",
|
|
8499
|
+
{
|
|
8500
|
+
type: "button",
|
|
8501
|
+
className: `brokr-notif-list-row${notif.read ? "" : " brokr-notif-list-row--unread"}`,
|
|
8502
|
+
onClick: handleClick
|
|
8503
|
+
},
|
|
8504
|
+
resolved.image ? /* @__PURE__ */ React41.createElement("img", { src: resolved.image.url, alt: resolved.image.alt, className: "brokr-notif-item-logo" }) : /* @__PURE__ */ React41.createElement("span", { className: `brokr-notif-item-dot brokr-notif-item-dot--${notif.variant}` }),
|
|
8505
|
+
/* @__PURE__ */ React41.createElement("div", { className: "brokr-notif-item-body" }, /* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-item-title" }, notif.title), /* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-item-message" }, notif.message)),
|
|
8506
|
+
/* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-item-time" }, formatTimestamp(notif.createdAt))
|
|
8507
|
+
);
|
|
8508
|
+
}
|
|
8415
8509
|
function NotificationList() {
|
|
8416
8510
|
const { notifications, unreadCount, markRead, markAllRead, isLoading, registry } = useNotifications();
|
|
8417
8511
|
const sorted = useMemo27(
|
|
@@ -8420,7 +8514,7 @@ function NotificationList() {
|
|
|
8420
8514
|
),
|
|
8421
8515
|
[notifications]
|
|
8422
8516
|
);
|
|
8423
|
-
const handleClick =
|
|
8517
|
+
const handleClick = useCallback28((notif) => {
|
|
8424
8518
|
if (!notif.read) markRead(notif.id);
|
|
8425
8519
|
const notifData = notif.data ?? {};
|
|
8426
8520
|
const notifType = notif.type ?? notifData.type ?? "default";
|
|
@@ -8438,30 +8532,15 @@ function NotificationList() {
|
|
|
8438
8532
|
onClick: markAllRead
|
|
8439
8533
|
},
|
|
8440
8534
|
"Mark all read"
|
|
8441
|
-
)), isLoading ? /* @__PURE__ */ React41.createElement(NotificationListSkeleton, null) : sorted.length === 0 ? /* @__PURE__ */ React41.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ React41.createElement("svg", { "aria-hidden": "true", width: "40", height: "40", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round", strokeLinejoin: "round", style: { opacity: 0.3 } }, /* @__PURE__ */ React41.createElement("path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" }), /* @__PURE__ */ React41.createElement("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" })), /* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-empty-text" }, "No notifications yet")) : /* @__PURE__ */ React41.createElement("div", { className: "brokr-notif-list-items" }, sorted.map((notif) =>
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
className: `brokr-notif-list-row${notif.read ? "" : " brokr-notif-list-row--unread"}`,
|
|
8451
|
-
onClick: () => handleClick(notif)
|
|
8452
|
-
},
|
|
8453
|
-
resolved.image ? /* @__PURE__ */ React41.createElement(
|
|
8454
|
-
"img",
|
|
8455
|
-
{
|
|
8456
|
-
src: resolved.image.url,
|
|
8457
|
-
alt: resolved.image.alt,
|
|
8458
|
-
className: "brokr-notif-item-logo"
|
|
8459
|
-
}
|
|
8460
|
-
) : /* @__PURE__ */ React41.createElement("span", { className: `brokr-notif-item-dot brokr-notif-item-dot--${notif.variant}` }),
|
|
8461
|
-
/* @__PURE__ */ React41.createElement("div", { className: "brokr-notif-item-body" }, /* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-item-title" }, notif.title), /* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-item-message" }, notif.message)),
|
|
8462
|
-
/* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-item-time" }, formatTimestamp(notif.createdAt))
|
|
8463
|
-
);
|
|
8464
|
-
})));
|
|
8535
|
+
)), isLoading ? /* @__PURE__ */ React41.createElement(NotificationListSkeleton, null) : sorted.length === 0 ? /* @__PURE__ */ React41.createElement("div", { className: "brokr-notif-empty" }, /* @__PURE__ */ React41.createElement("svg", { "aria-hidden": "true", width: "40", height: "40", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1", strokeLinecap: "round", strokeLinejoin: "round", style: { opacity: 0.3 } }, /* @__PURE__ */ React41.createElement("path", { d: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" }), /* @__PURE__ */ React41.createElement("path", { d: "M10.3 21a1.94 1.94 0 0 0 3.4 0" })), /* @__PURE__ */ React41.createElement("span", { className: "brokr-notif-empty-text" }, "No notifications yet")) : /* @__PURE__ */ React41.createElement("div", { className: "brokr-notif-list-items" }, sorted.map((notif) => /* @__PURE__ */ React41.createElement(
|
|
8536
|
+
NotifListItem,
|
|
8537
|
+
{
|
|
8538
|
+
key: notif.id,
|
|
8539
|
+
notif,
|
|
8540
|
+
registry,
|
|
8541
|
+
onClick: handleClick
|
|
8542
|
+
}
|
|
8543
|
+
))));
|
|
8465
8544
|
}
|
|
8466
8545
|
|
|
8467
8546
|
// src/react/hooks/use-user.ts
|