@arbidocs/blocks 0.3.115 → 0.3.117
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 +542 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +182 -55
- package/dist/index.d.ts +182 -55
- package/dist/index.js +541 -33
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -604,7 +604,25 @@ function ConnectionProvider({
|
|
|
604
604
|
await arbi.selectWorkspace(target.external_id);
|
|
605
605
|
setWorkspaceId(target.external_id);
|
|
606
606
|
}
|
|
607
|
-
|
|
607
|
+
let resolved = { name: email.split("@")[0], email };
|
|
608
|
+
try {
|
|
609
|
+
const me = arbi.user.identity();
|
|
610
|
+
const members = await arbi.workspaces.listUsers();
|
|
611
|
+
const self = members.find((m) => m.user.external_id === me?.externalId)?.user;
|
|
612
|
+
if (self) {
|
|
613
|
+
const fullName = [self.given_name, self.family_name].filter(Boolean).join(" ").trim();
|
|
614
|
+
resolved = {
|
|
615
|
+
name: fullName || email.split("@")[0],
|
|
616
|
+
email: self.email || email,
|
|
617
|
+
externalId: self.external_id,
|
|
618
|
+
picture: self.picture ?? null
|
|
619
|
+
};
|
|
620
|
+
} else if (me?.externalId) {
|
|
621
|
+
resolved.externalId = me.externalId;
|
|
622
|
+
}
|
|
623
|
+
} catch {
|
|
624
|
+
}
|
|
625
|
+
setUser(resolved);
|
|
608
626
|
setStatus("authenticated");
|
|
609
627
|
} catch (e) {
|
|
610
628
|
setError(e instanceof Error ? e.message : "Sign-in failed. Check your credentials.");
|
|
@@ -2298,6 +2316,390 @@ function TestimonialGrid({ items, columns = "3", testId }) {
|
|
|
2298
2316
|
i
|
|
2299
2317
|
)) });
|
|
2300
2318
|
}
|
|
2319
|
+
function NavItemLink({ item, onNavigate }) {
|
|
2320
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2321
|
+
reactRouterDom.NavLink,
|
|
2322
|
+
{
|
|
2323
|
+
to: item.to,
|
|
2324
|
+
end: item.end,
|
|
2325
|
+
onClick: onNavigate,
|
|
2326
|
+
"data-testid": tid("sidebar-nav", item.id),
|
|
2327
|
+
className: ({ isActive }) => react.cn(
|
|
2328
|
+
"group flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors",
|
|
2329
|
+
isActive ? "bg-sidebar-accent text-sidebar-accent-foreground" : "text-sidebar-foreground hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground"
|
|
2330
|
+
),
|
|
2331
|
+
children: [
|
|
2332
|
+
/* @__PURE__ */ jsxRuntime.jsx(item.icon, { className: "size-[18px] shrink-0" }),
|
|
2333
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: item.label }),
|
|
2334
|
+
item.arbi && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "size-3.5 text-sidebar-primary", "aria-label": "Powered by ARBI" })
|
|
2335
|
+
]
|
|
2336
|
+
}
|
|
2337
|
+
);
|
|
2338
|
+
}
|
|
2339
|
+
function SidebarBody({
|
|
2340
|
+
sections,
|
|
2341
|
+
footerItems,
|
|
2342
|
+
logo,
|
|
2343
|
+
logoHref,
|
|
2344
|
+
logoLabel,
|
|
2345
|
+
sidebarFooter,
|
|
2346
|
+
onNavigate
|
|
2347
|
+
}) {
|
|
2348
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2349
|
+
logo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-16 items-center border-b border-sidebar-border px-5", children: logoHref ? /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { to: logoHref, "aria-label": logoLabel, onClick: onNavigate, children: logo }) : logo }),
|
|
2350
|
+
/* @__PURE__ */ jsxRuntime.jsx("nav", { className: "flex-1 space-y-6 overflow-y-auto px-3 py-5", children: sections.map((section) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2351
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-sidebar-foreground/55", children: section.heading }),
|
|
2352
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-0.5", children: section.items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(NavItemLink, { item, onNavigate }, item.id)) })
|
|
2353
|
+
] }, section.heading)) }),
|
|
2354
|
+
(footerItems?.length || sidebarFooter) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-sidebar-border px-3 py-3", children: [
|
|
2355
|
+
footerItems?.map((item) => /* @__PURE__ */ jsxRuntime.jsx(NavItemLink, { item, onNavigate }, item.id)),
|
|
2356
|
+
sidebarFooter
|
|
2357
|
+
] })
|
|
2358
|
+
] });
|
|
2359
|
+
}
|
|
2360
|
+
function AppShell({
|
|
2361
|
+
sections,
|
|
2362
|
+
footerItems,
|
|
2363
|
+
logo,
|
|
2364
|
+
logoHref,
|
|
2365
|
+
logoLabel,
|
|
2366
|
+
sidebarFooter,
|
|
2367
|
+
topbar,
|
|
2368
|
+
rightRail,
|
|
2369
|
+
children,
|
|
2370
|
+
mainClassName,
|
|
2371
|
+
testIdPrefix = "app"
|
|
2372
|
+
}) {
|
|
2373
|
+
const [open, setOpen] = react$1.useState(false);
|
|
2374
|
+
const location = reactRouterDom.useLocation();
|
|
2375
|
+
react$1.useEffect(() => {
|
|
2376
|
+
setOpen(false);
|
|
2377
|
+
}, [location.pathname]);
|
|
2378
|
+
const body = (onNavigate) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2379
|
+
SidebarBody,
|
|
2380
|
+
{
|
|
2381
|
+
sections,
|
|
2382
|
+
footerItems,
|
|
2383
|
+
logo,
|
|
2384
|
+
logoHref,
|
|
2385
|
+
logoLabel,
|
|
2386
|
+
sidebarFooter,
|
|
2387
|
+
onNavigate
|
|
2388
|
+
}
|
|
2389
|
+
);
|
|
2390
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2391
|
+
"div",
|
|
2392
|
+
{
|
|
2393
|
+
className: "flex h-screen overflow-hidden bg-background",
|
|
2394
|
+
"data-testid": `${testIdPrefix}-shell`,
|
|
2395
|
+
children: [
|
|
2396
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2397
|
+
"aside",
|
|
2398
|
+
{
|
|
2399
|
+
className: "hidden h-full w-64 shrink-0 flex-col border-r border-sidebar-border bg-sidebar lg:flex",
|
|
2400
|
+
"data-testid": `${testIdPrefix}-sidebar`,
|
|
2401
|
+
children: body()
|
|
2402
|
+
}
|
|
2403
|
+
),
|
|
2404
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2405
|
+
"div",
|
|
2406
|
+
{
|
|
2407
|
+
className: "fixed inset-0 z-50 lg:hidden",
|
|
2408
|
+
"data-testid": `${testIdPrefix}-sidebar-mobile`,
|
|
2409
|
+
children: [
|
|
2410
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2411
|
+
"div",
|
|
2412
|
+
{
|
|
2413
|
+
className: "absolute inset-0 bg-black/60 backdrop-blur-sm",
|
|
2414
|
+
onClick: () => setOpen(false),
|
|
2415
|
+
"aria-hidden": true
|
|
2416
|
+
}
|
|
2417
|
+
),
|
|
2418
|
+
/* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "absolute inset-y-0 left-0 flex w-64 max-w-[82%] flex-col border-r border-sidebar-border bg-sidebar shadow-xl", children: [
|
|
2419
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2420
|
+
"button",
|
|
2421
|
+
{
|
|
2422
|
+
type: "button",
|
|
2423
|
+
onClick: () => setOpen(false),
|
|
2424
|
+
className: "absolute right-3 top-4 z-10 flex size-8 items-center justify-center rounded-md text-sidebar-foreground/70 hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground",
|
|
2425
|
+
"aria-label": "Close menu",
|
|
2426
|
+
"data-testid": `${testIdPrefix}-sidebar-close`,
|
|
2427
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-5" })
|
|
2428
|
+
}
|
|
2429
|
+
),
|
|
2430
|
+
body(() => setOpen(false))
|
|
2431
|
+
] })
|
|
2432
|
+
]
|
|
2433
|
+
}
|
|
2434
|
+
),
|
|
2435
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
2436
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2437
|
+
"header",
|
|
2438
|
+
{
|
|
2439
|
+
className: "flex h-16 shrink-0 items-center gap-4 border-b border-border bg-card/80 px-6 backdrop-blur",
|
|
2440
|
+
"data-testid": `${testIdPrefix}-topbar`,
|
|
2441
|
+
children: [
|
|
2442
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2443
|
+
"button",
|
|
2444
|
+
{
|
|
2445
|
+
type: "button",
|
|
2446
|
+
onClick: () => setOpen(true),
|
|
2447
|
+
className: "flex size-9 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground lg:hidden",
|
|
2448
|
+
"data-testid": `${testIdPrefix}-nav-toggle`,
|
|
2449
|
+
"aria-label": "Open menu",
|
|
2450
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
|
|
2451
|
+
}
|
|
2452
|
+
),
|
|
2453
|
+
topbar
|
|
2454
|
+
]
|
|
2455
|
+
}
|
|
2456
|
+
),
|
|
2457
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2458
|
+
"main",
|
|
2459
|
+
{
|
|
2460
|
+
className: react.cn("flex-1 overflow-y-auto", mainClassName),
|
|
2461
|
+
"data-testid": `${testIdPrefix}-main`,
|
|
2462
|
+
children
|
|
2463
|
+
}
|
|
2464
|
+
)
|
|
2465
|
+
] }),
|
|
2466
|
+
rightRail
|
|
2467
|
+
]
|
|
2468
|
+
}
|
|
2469
|
+
);
|
|
2470
|
+
}
|
|
2471
|
+
function AppHeader({
|
|
2472
|
+
onSearch,
|
|
2473
|
+
onAsk,
|
|
2474
|
+
searchPlaceholder = "Ask AI or search\u2026",
|
|
2475
|
+
searchKbd = "\u2318K",
|
|
2476
|
+
askLabel = "Ask AI",
|
|
2477
|
+
leading,
|
|
2478
|
+
actions,
|
|
2479
|
+
user,
|
|
2480
|
+
userItems,
|
|
2481
|
+
onLogout,
|
|
2482
|
+
onNotificationNavigate,
|
|
2483
|
+
notificationTones,
|
|
2484
|
+
classNames,
|
|
2485
|
+
testIdPrefix = "app"
|
|
2486
|
+
}) {
|
|
2487
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2488
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2489
|
+
"button",
|
|
2490
|
+
{
|
|
2491
|
+
type: "button",
|
|
2492
|
+
onClick: onSearch,
|
|
2493
|
+
className: classNames?.search ?? "relative hidden max-w-md flex-1 items-center rounded-md border border-input bg-background py-2 pl-9 pr-3 text-left text-sm text-muted-foreground transition-colors hover:bg-accent md:flex",
|
|
2494
|
+
"data-testid": tid(testIdPrefix, "global-search"),
|
|
2495
|
+
children: [
|
|
2496
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" }),
|
|
2497
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: searchPlaceholder }),
|
|
2498
|
+
/* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "rounded border border-border px-1.5 py-0.5 text-[10px]", children: searchKbd })
|
|
2499
|
+
]
|
|
2500
|
+
}
|
|
2501
|
+
),
|
|
2502
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex items-center gap-3", children: [
|
|
2503
|
+
leading,
|
|
2504
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2505
|
+
react.Button,
|
|
2506
|
+
{
|
|
2507
|
+
size: "sm",
|
|
2508
|
+
onClick: onAsk ?? onSearch,
|
|
2509
|
+
className: classNames?.askButton,
|
|
2510
|
+
"data-testid": tid(testIdPrefix, "ask-ai"),
|
|
2511
|
+
children: [
|
|
2512
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "size-4" }),
|
|
2513
|
+
askLabel
|
|
2514
|
+
]
|
|
2515
|
+
}
|
|
2516
|
+
),
|
|
2517
|
+
actions,
|
|
2518
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2519
|
+
react.NotificationBell,
|
|
2520
|
+
{
|
|
2521
|
+
testId: tid(testIdPrefix, "notifications"),
|
|
2522
|
+
onNavigate: onNotificationNavigate,
|
|
2523
|
+
toneClassNames: notificationTones
|
|
2524
|
+
}
|
|
2525
|
+
),
|
|
2526
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2527
|
+
react.UserMenu,
|
|
2528
|
+
{
|
|
2529
|
+
user,
|
|
2530
|
+
items: userItems,
|
|
2531
|
+
onLogout,
|
|
2532
|
+
testId: tid(testIdPrefix, "user-menu"),
|
|
2533
|
+
logoutTestId: tid(testIdPrefix, "logout")
|
|
2534
|
+
}
|
|
2535
|
+
)
|
|
2536
|
+
] })
|
|
2537
|
+
] });
|
|
2538
|
+
}
|
|
2539
|
+
var LiveDataContext = react$1.createContext(false);
|
|
2540
|
+
function useLiveDataActive() {
|
|
2541
|
+
return react$1.useContext(LiveDataContext);
|
|
2542
|
+
}
|
|
2543
|
+
function LiveDataProvider({ children }) {
|
|
2544
|
+
return /* @__PURE__ */ jsxRuntime.jsx(LiveDataContext.Provider, { value: true, children });
|
|
2545
|
+
}
|
|
2546
|
+
function WidgetPlaceholder({
|
|
2547
|
+
label,
|
|
2548
|
+
icon: Icon = lucideReact.Sparkles,
|
|
2549
|
+
testId
|
|
2550
|
+
}) {
|
|
2551
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2552
|
+
"div",
|
|
2553
|
+
{
|
|
2554
|
+
className: "flex items-center gap-3 rounded-xl border border-dashed border-border bg-muted/30 px-5 py-6 text-sm text-muted-foreground",
|
|
2555
|
+
"data-testid": testId,
|
|
2556
|
+
children: [
|
|
2557
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "size-4" }) }),
|
|
2558
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2559
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: label }),
|
|
2560
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", children: "\xB7 live in the app" })
|
|
2561
|
+
] })
|
|
2562
|
+
]
|
|
2563
|
+
}
|
|
2564
|
+
);
|
|
2565
|
+
}
|
|
2566
|
+
function useActiveWorkspaceId() {
|
|
2567
|
+
const { workspaceId, fallbackWorkspaceId } = useConnection();
|
|
2568
|
+
return workspaceId ?? fallbackWorkspaceId ?? void 0;
|
|
2569
|
+
}
|
|
2570
|
+
function timeAgo(iso) {
|
|
2571
|
+
if (!iso) return "";
|
|
2572
|
+
const then = new Date(iso).getTime();
|
|
2573
|
+
if (Number.isNaN(then)) return "";
|
|
2574
|
+
const s = Math.max(0, Math.round((Date.now() - then) / 1e3));
|
|
2575
|
+
if (s < 60) return "just now";
|
|
2576
|
+
const m = Math.round(s / 60);
|
|
2577
|
+
if (m < 60) return `${m}m ago`;
|
|
2578
|
+
const h = Math.round(m / 60);
|
|
2579
|
+
if (h < 24) return `${h}h ago`;
|
|
2580
|
+
return `${Math.round(h / 24)}d ago`;
|
|
2581
|
+
}
|
|
2582
|
+
var METRIC_SOURCES = {
|
|
2583
|
+
documents: { label: "Documents", icon: lucideReact.FileText },
|
|
2584
|
+
conversations: { label: "Agent threads", icon: lucideReact.Bot }
|
|
2585
|
+
};
|
|
2586
|
+
var asMetricSource = (s) => s in METRIC_SOURCES ? s : "documents";
|
|
2587
|
+
function AgentActivityLive({
|
|
2588
|
+
title,
|
|
2589
|
+
limit,
|
|
2590
|
+
testId
|
|
2591
|
+
}) {
|
|
2592
|
+
const wsId = useActiveWorkspaceId();
|
|
2593
|
+
const { data, isLoading } = react.useConversations(wsId);
|
|
2594
|
+
const rows = [...data ?? []].sort((a, b) => +new Date(b.updated_at ?? 0) - +new Date(a.updated_at ?? 0)).slice(0, limit);
|
|
2595
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(react.Card, { variant: "elevated", className: "rounded-xl p-5", "data-testid": testId, children: [
|
|
2596
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 flex items-center gap-2", children: [
|
|
2597
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bot, { className: "size-4 text-muted-foreground" }),
|
|
2598
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: title })
|
|
2599
|
+
] }),
|
|
2600
|
+
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", "data-testid": `${testId}-loading`, children: "Loading agent threads\u2026" }) : rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", "data-testid": `${testId}-empty`, children: "No agent threads yet." }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-2", "data-testid": `${testId}-list`, children: rows.map((c, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2601
|
+
"li",
|
|
2602
|
+
{
|
|
2603
|
+
className: "flex items-center justify-between gap-3",
|
|
2604
|
+
"data-testid": `${testId}-item-${i}`,
|
|
2605
|
+
children: [
|
|
2606
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2 truncate", children: [
|
|
2607
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessagesSquare, { className: "size-3.5 shrink-0 text-muted-foreground" }),
|
|
2608
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm text-foreground", children: c.title?.trim() || "Untitled thread" })
|
|
2609
|
+
] }),
|
|
2610
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: timeAgo(c.updated_at) })
|
|
2611
|
+
]
|
|
2612
|
+
},
|
|
2613
|
+
c.external_id ?? i
|
|
2614
|
+
)) })
|
|
2615
|
+
] });
|
|
2616
|
+
}
|
|
2617
|
+
function LiveMetricInner({
|
|
2618
|
+
label,
|
|
2619
|
+
source,
|
|
2620
|
+
accent,
|
|
2621
|
+
testId
|
|
2622
|
+
}) {
|
|
2623
|
+
const wsId = useActiveWorkspaceId();
|
|
2624
|
+
const docs = react.useDocuments(wsId, { enabled: source === "documents" });
|
|
2625
|
+
const convos = react.useConversations(wsId, { enabled: source === "conversations" });
|
|
2626
|
+
const query = source === "documents" ? docs : convos;
|
|
2627
|
+
const count = Array.isArray(query.data) ? query.data.length : 0;
|
|
2628
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2629
|
+
MetricCard,
|
|
2630
|
+
{
|
|
2631
|
+
label: label || METRIC_SOURCES[source].label,
|
|
2632
|
+
value: query.isLoading ? "\u2014" : String(count),
|
|
2633
|
+
accent,
|
|
2634
|
+
icon: METRIC_SOURCES[source].icon,
|
|
2635
|
+
testId
|
|
2636
|
+
}
|
|
2637
|
+
);
|
|
2638
|
+
}
|
|
2639
|
+
function AgentActivityBlock({
|
|
2640
|
+
title,
|
|
2641
|
+
limit,
|
|
2642
|
+
testId
|
|
2643
|
+
}) {
|
|
2644
|
+
return useLiveDataActive() ? /* @__PURE__ */ jsxRuntime.jsx(AgentActivityLive, { title, limit, testId }) : /* @__PURE__ */ jsxRuntime.jsx(WidgetPlaceholder, { label: String(title || "Agent activity"), icon: lucideReact.Bot, testId });
|
|
2645
|
+
}
|
|
2646
|
+
function LiveMetricBlock({
|
|
2647
|
+
label,
|
|
2648
|
+
source,
|
|
2649
|
+
accent,
|
|
2650
|
+
testId
|
|
2651
|
+
}) {
|
|
2652
|
+
const src = asMetricSource(source);
|
|
2653
|
+
return useLiveDataActive() ? /* @__PURE__ */ jsxRuntime.jsx(LiveMetricInner, { label, source: src, accent, testId }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2654
|
+
WidgetPlaceholder,
|
|
2655
|
+
{
|
|
2656
|
+
label: String(label || METRIC_SOURCES[src].label),
|
|
2657
|
+
icon: METRIC_SOURCES[src].icon,
|
|
2658
|
+
testId
|
|
2659
|
+
}
|
|
2660
|
+
);
|
|
2661
|
+
}
|
|
2662
|
+
function createLiveWidgets(kit) {
|
|
2663
|
+
const { blockTestId } = kit;
|
|
2664
|
+
const AgentActivityWidget = {
|
|
2665
|
+
label: "Agent activity (live)",
|
|
2666
|
+
fields: {
|
|
2667
|
+
title: { type: "text", label: "Title" },
|
|
2668
|
+
limit: { type: "number", label: "Rows", min: 1, max: 8 }
|
|
2669
|
+
},
|
|
2670
|
+
defaultProps: { title: "Recent agent activity", limit: 4 },
|
|
2671
|
+
render: ({ id, title, limit }) => /* @__PURE__ */ jsxRuntime.jsx(AgentActivityBlock, { title, limit, testId: blockTestId(id) })
|
|
2672
|
+
};
|
|
2673
|
+
const LiveMetricWidget = {
|
|
2674
|
+
label: "Live metric",
|
|
2675
|
+
fields: {
|
|
2676
|
+
label: { type: "text", label: "Label" },
|
|
2677
|
+
source: {
|
|
2678
|
+
type: "select",
|
|
2679
|
+
label: "Source",
|
|
2680
|
+
options: [
|
|
2681
|
+
{ label: "Documents", value: "documents" },
|
|
2682
|
+
{ label: "Agent threads", value: "conversations" }
|
|
2683
|
+
]
|
|
2684
|
+
},
|
|
2685
|
+
accent: {
|
|
2686
|
+
type: "radio",
|
|
2687
|
+
label: "Accent",
|
|
2688
|
+
options: [
|
|
2689
|
+
{ label: "Default", value: "default" },
|
|
2690
|
+
{ label: "Primary", value: "primary" },
|
|
2691
|
+
{ label: "Success", value: "success" }
|
|
2692
|
+
]
|
|
2693
|
+
}
|
|
2694
|
+
},
|
|
2695
|
+
defaultProps: { label: "", source: "documents", accent: "primary" },
|
|
2696
|
+
render: ({ id, label, source, accent }) => /* @__PURE__ */ jsxRuntime.jsx(LiveMetricBlock, { label, source, accent, testId: blockTestId(id) })
|
|
2697
|
+
};
|
|
2698
|
+
return {
|
|
2699
|
+
AgentActivity: AgentActivityWidget,
|
|
2700
|
+
LiveMetric: LiveMetricWidget
|
|
2701
|
+
};
|
|
2702
|
+
}
|
|
2301
2703
|
|
|
2302
2704
|
// src/studio/publish.ts
|
|
2303
2705
|
function blobToDataUrl(blob) {
|
|
@@ -2572,34 +2974,36 @@ function PageRenderer({
|
|
|
2572
2974
|
live,
|
|
2573
2975
|
slug: slugProp,
|
|
2574
2976
|
emptyState,
|
|
2575
|
-
testIdPrefix = "studio"
|
|
2977
|
+
testIdPrefix = "studio",
|
|
2978
|
+
liveData = false,
|
|
2979
|
+
initialData,
|
|
2980
|
+
applyTheme = true
|
|
2576
2981
|
}) {
|
|
2577
2982
|
const params = reactRouterDom.useParams();
|
|
2578
2983
|
const slug = slugProp ?? params.slug ?? "home";
|
|
2579
2984
|
const arbi = react.useArbi();
|
|
2580
|
-
const [data, setData] = react$1.useState(null);
|
|
2581
|
-
const [loading, setLoading] = react$1.useState(
|
|
2985
|
+
const [data, setData] = react$1.useState(initialData ?? null);
|
|
2986
|
+
const [loading, setLoading] = react$1.useState(!initialData);
|
|
2582
2987
|
react$1.useEffect(() => {
|
|
2583
2988
|
let cancelled = false;
|
|
2584
|
-
setLoading(
|
|
2989
|
+
setLoading(!initialData);
|
|
2585
2990
|
void (async () => {
|
|
2586
|
-
const
|
|
2587
|
-
persistence.loadPublished(arbi, live, slug),
|
|
2588
|
-
persistence.loadTheme(arbi, live)
|
|
2589
|
-
]);
|
|
2991
|
+
const theme = applyTheme ? (await persistence.loadTheme(arbi, live)).data : void 0;
|
|
2590
2992
|
if (cancelled) return;
|
|
2591
|
-
const page =
|
|
2993
|
+
const page = initialData ?? (await persistence.loadPublished(arbi, live, slug)).data ?? (await persistence.loadPage(arbi, live, slug)).data;
|
|
2592
2994
|
if (cancelled) return;
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2995
|
+
if (applyTheme) {
|
|
2996
|
+
applyThemeVars(
|
|
2997
|
+
theme ? { ...defaultTheme, ...theme, colors: { ...defaultTheme.colors, ...theme.colors } } : defaultTheme
|
|
2998
|
+
);
|
|
2999
|
+
}
|
|
2596
3000
|
setData(page);
|
|
2597
3001
|
setLoading(false);
|
|
2598
3002
|
})();
|
|
2599
3003
|
return () => {
|
|
2600
3004
|
cancelled = true;
|
|
2601
3005
|
};
|
|
2602
|
-
}, [arbi, live, slug, persistence, defaultTheme]);
|
|
3006
|
+
}, [arbi, live, slug, persistence, defaultTheme, initialData, applyTheme]);
|
|
2603
3007
|
if (loading) {
|
|
2604
3008
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2605
3009
|
"div",
|
|
@@ -2625,7 +3029,8 @@ function PageRenderer({
|
|
|
2625
3029
|
}
|
|
2626
3030
|
);
|
|
2627
3031
|
}
|
|
2628
|
-
|
|
3032
|
+
const rendered = /* @__PURE__ */ jsxRuntime.jsx(puck.Render, { config, data });
|
|
3033
|
+
return /* @__PURE__ */ jsxRuntime.jsx("main", { "data-testid": `page-${testIdPrefix}-render`, children: liveData ? /* @__PURE__ */ jsxRuntime.jsx(LiveDataProvider, { children: rendered }) : rendered });
|
|
2629
3034
|
}
|
|
2630
3035
|
|
|
2631
3036
|
// src/studio/persistence.ts
|
|
@@ -2900,6 +3305,9 @@ function useImageGen() {
|
|
|
2900
3305
|
reset: task.reset
|
|
2901
3306
|
};
|
|
2902
3307
|
}
|
|
3308
|
+
function toJpgName(name) {
|
|
3309
|
+
return name.replace(/\.[^.]+$/, "") + ".jpg";
|
|
3310
|
+
}
|
|
2903
3311
|
var IMAGE_EXT = /\.(png|jpe?g|webp|gif|avif|svg)$/i;
|
|
2904
3312
|
function ImageFieldControl({
|
|
2905
3313
|
value,
|
|
@@ -2913,9 +3321,12 @@ function ImageFieldControl({
|
|
|
2913
3321
|
const [url, setUrl] = react$1.useState("");
|
|
2914
3322
|
const [prompt, setPrompt] = react$1.useState("");
|
|
2915
3323
|
const [busy, setBusy] = react$1.useState(false);
|
|
3324
|
+
const [cropSrc, setCropSrc] = react$1.useState(null);
|
|
3325
|
+
const [cropName, setCropName] = react$1.useState("image.jpg");
|
|
2916
3326
|
const arbi = react.useArbi();
|
|
2917
3327
|
const gen = useImageGen();
|
|
2918
3328
|
const queryClient = reactQuery.useQueryClient();
|
|
3329
|
+
const currentAssetImage = useAssetImage(isAssetRef(value) ? assetRefId(value) : "");
|
|
2919
3330
|
const tp = (...q) => tid(`${testIdPrefix}-image`, name, ...q);
|
|
2920
3331
|
const refreshAssets = () => queryClient.invalidateQueries({ queryKey: ["arbi", "documents", workspaceId] });
|
|
2921
3332
|
const { data: docs } = react.useDocuments(workspaceId);
|
|
@@ -2930,13 +3341,24 @@ function ImageFieldControl({
|
|
|
2930
3341
|
[imageDocs]
|
|
2931
3342
|
);
|
|
2932
3343
|
const { data: thumbs } = react.useThumbnails(imageIds);
|
|
2933
|
-
const onUpload =
|
|
3344
|
+
const onUpload = (e) => {
|
|
2934
3345
|
const file = e.target.files?.[0];
|
|
2935
3346
|
if (!file) return;
|
|
3347
|
+
setCropName(toJpgName(file.name));
|
|
3348
|
+
setCropSrc(URL.createObjectURL(file));
|
|
3349
|
+
e.target.value = "";
|
|
3350
|
+
};
|
|
3351
|
+
const openReframe = () => {
|
|
3352
|
+
if (!currentAssetImage) return;
|
|
3353
|
+
setCropName("reframe.jpg");
|
|
3354
|
+
setCropSrc(currentAssetImage);
|
|
3355
|
+
};
|
|
3356
|
+
const uploadBlobAsAsset = async (blob, name2) => {
|
|
2936
3357
|
setBusy(true);
|
|
2937
3358
|
try {
|
|
2938
3359
|
await arbi.selectWorkspace(workspaceId);
|
|
2939
|
-
const
|
|
3360
|
+
const file = new File([blob], name2, { type: blob.type });
|
|
3361
|
+
const res = await arbi.documents.uploadFile(file, name2, { folder });
|
|
2940
3362
|
const id = res.doc_ext_ids?.[0];
|
|
2941
3363
|
if (id) {
|
|
2942
3364
|
onChange(asAssetRef(id));
|
|
@@ -2946,6 +3368,12 @@ function ImageFieldControl({
|
|
|
2946
3368
|
setBusy(false);
|
|
2947
3369
|
}
|
|
2948
3370
|
};
|
|
3371
|
+
const onCropComplete = async (result) => {
|
|
3372
|
+
const src = cropSrc;
|
|
3373
|
+
setCropSrc(null);
|
|
3374
|
+
await uploadBlobAsAsset(result.blob, cropName);
|
|
3375
|
+
if (src?.startsWith("blob:")) URL.revokeObjectURL(src);
|
|
3376
|
+
};
|
|
2949
3377
|
const onGenerate = async () => {
|
|
2950
3378
|
if (!prompt.trim() || gen.isGenerating) return;
|
|
2951
3379
|
const id = await gen.generate(prompt);
|
|
@@ -2963,7 +3391,22 @@ function ImageFieldControl({
|
|
|
2963
3391
|
const inputClass = "w-full rounded-md border border-border bg-card px-2.5 py-1.5 text-sm text-foreground outline-none focus:border-primary";
|
|
2964
3392
|
const tabClass = (on) => `inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs font-medium ${on ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground"}`;
|
|
2965
3393
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", "data-testid": tp(), children: [
|
|
2966
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3394
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
3395
|
+
/* @__PURE__ */ jsxRuntime.jsx(BlockImage, { src: value, aspect: "16:9", rounded: "md", testId: tp("preview") }),
|
|
3396
|
+
currentAssetImage ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3397
|
+
"button",
|
|
3398
|
+
{
|
|
3399
|
+
type: "button",
|
|
3400
|
+
onClick: openReframe,
|
|
3401
|
+
className: "absolute right-1.5 top-1.5 inline-flex items-center gap-1 rounded-md bg-background/85 px-2 py-1 text-xs font-medium text-foreground shadow-sm backdrop-blur hover:bg-background",
|
|
3402
|
+
"data-testid": tp("reframe"),
|
|
3403
|
+
children: [
|
|
3404
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Crop, { className: "size-3" }),
|
|
3405
|
+
" Crop"
|
|
3406
|
+
]
|
|
3407
|
+
}
|
|
3408
|
+
) : null
|
|
3409
|
+
] }),
|
|
2967
3410
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: MODES.map((m) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2968
3411
|
"button",
|
|
2969
3412
|
{
|
|
@@ -3080,6 +3523,19 @@ function ImageFieldControl({
|
|
|
3080
3523
|
"data-testid": tp("clear"),
|
|
3081
3524
|
children: "Clear"
|
|
3082
3525
|
}
|
|
3526
|
+
),
|
|
3527
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3528
|
+
react.ImageCropModal,
|
|
3529
|
+
{
|
|
3530
|
+
open: !!cropSrc,
|
|
3531
|
+
image: cropSrc,
|
|
3532
|
+
title: "Frame your image",
|
|
3533
|
+
aspectOptions: react.DEFAULT_ASPECT_OPTIONS,
|
|
3534
|
+
cropShape: "rect",
|
|
3535
|
+
output: { maxSize: 1600 },
|
|
3536
|
+
onComplete: onCropComplete,
|
|
3537
|
+
onCancel: () => setCropSrc(null)
|
|
3538
|
+
}
|
|
3083
3539
|
)
|
|
3084
3540
|
] });
|
|
3085
3541
|
}
|
|
@@ -4233,6 +4689,13 @@ function createSiteBlocks(kit) {
|
|
|
4233
4689
|
TestimonialGrid: TestimonialGridBlock
|
|
4234
4690
|
};
|
|
4235
4691
|
}
|
|
4692
|
+
var emptySlot2 = [];
|
|
4693
|
+
var METRIC_COLS = {
|
|
4694
|
+
"2": "sm:grid-cols-2",
|
|
4695
|
+
"3": "sm:grid-cols-2 lg:grid-cols-3",
|
|
4696
|
+
"4": "sm:grid-cols-2 lg:grid-cols-4"
|
|
4697
|
+
};
|
|
4698
|
+
var METRIC_GAP = { sm: "gap-3", md: "gap-4", lg: "gap-6" };
|
|
4236
4699
|
function createArbiBlocksConfig(opts = {}) {
|
|
4237
4700
|
const kit = createBlockKit(opts.aiFields, opts.imageField, opts.eyebrowClassName);
|
|
4238
4701
|
const { textField, textareaField, boolRadio, iconField, resolveIcon, blockTestId } = kit;
|
|
@@ -4270,16 +4733,19 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4270
4733
|
fields: {
|
|
4271
4734
|
title: textField("Title"),
|
|
4272
4735
|
eyebrow: textField("Eyebrow"),
|
|
4273
|
-
description: textareaField("Description", void 0, "description")
|
|
4736
|
+
description: textareaField("Description", void 0, "description"),
|
|
4737
|
+
// `actions` is a slot so the top band can host real buttons/badges authored
|
|
4738
|
+
// as blocks (drop a Button in), while the interactive body stays bespoke.
|
|
4739
|
+
actions: { type: "slot", allow: ["Button", "Badge"] }
|
|
4274
4740
|
},
|
|
4275
|
-
defaultProps: { title: "Page title" },
|
|
4276
|
-
|
|
4277
|
-
render: ({ id, title, eyebrow, description }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4741
|
+
defaultProps: { title: "Page title", actions: emptySlot2 },
|
|
4742
|
+
render: ({ id, title, eyebrow, description, actions: Actions }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4278
4743
|
PageHeader,
|
|
4279
4744
|
{
|
|
4280
4745
|
title,
|
|
4281
4746
|
eyebrow,
|
|
4282
4747
|
description,
|
|
4748
|
+
actions: /* @__PURE__ */ jsxRuntime.jsx(Actions, { className: "flex items-center gap-2" }),
|
|
4283
4749
|
testId: blockTestId(id)
|
|
4284
4750
|
}
|
|
4285
4751
|
)
|
|
@@ -4289,16 +4755,18 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4289
4755
|
fields: {
|
|
4290
4756
|
title: textField("Title"),
|
|
4291
4757
|
description: textareaField("Description", void 0, "description"),
|
|
4292
|
-
icon: iconField()
|
|
4758
|
+
icon: iconField(),
|
|
4759
|
+
// `action` is a slot so an empty state can offer a real call-to-action button.
|
|
4760
|
+
action: { type: "slot", allow: ["Button"] }
|
|
4293
4761
|
},
|
|
4294
|
-
defaultProps: { title: "Nothing here yet" },
|
|
4295
|
-
|
|
4296
|
-
render: ({ id, title, description, icon }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4762
|
+
defaultProps: { title: "Nothing here yet", action: emptySlot2 },
|
|
4763
|
+
render: ({ id, title, description, icon, action: Action }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4297
4764
|
EmptyState,
|
|
4298
4765
|
{
|
|
4299
4766
|
title,
|
|
4300
4767
|
description,
|
|
4301
4768
|
icon: resolveIcon(icon),
|
|
4769
|
+
action: /* @__PURE__ */ jsxRuntime.jsx(Action, {}),
|
|
4302
4770
|
testId: blockTestId(id)
|
|
4303
4771
|
}
|
|
4304
4772
|
)
|
|
@@ -4351,6 +4819,42 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4351
4819
|
}
|
|
4352
4820
|
)
|
|
4353
4821
|
};
|
|
4822
|
+
const MetricRowBlock = {
|
|
4823
|
+
label: "Metric row",
|
|
4824
|
+
fields: {
|
|
4825
|
+
columns: {
|
|
4826
|
+
type: "radio",
|
|
4827
|
+
label: "Columns",
|
|
4828
|
+
options: [
|
|
4829
|
+
{ label: "2", value: "2" },
|
|
4830
|
+
{ label: "3", value: "3" },
|
|
4831
|
+
{ label: "4", value: "4" }
|
|
4832
|
+
]
|
|
4833
|
+
},
|
|
4834
|
+
gap: {
|
|
4835
|
+
type: "radio",
|
|
4836
|
+
label: "Gap",
|
|
4837
|
+
options: [
|
|
4838
|
+
{ label: "S", value: "sm" },
|
|
4839
|
+
{ label: "M", value: "md" },
|
|
4840
|
+
{ label: "L", value: "lg" }
|
|
4841
|
+
]
|
|
4842
|
+
},
|
|
4843
|
+
// Static KPI tiles and (when registered) live metric widgets both belong in a band.
|
|
4844
|
+
items: { type: "slot", allow: ["MetricCard", "LiveMetric"] }
|
|
4845
|
+
},
|
|
4846
|
+
defaultProps: { columns: "3", gap: "md", items: emptySlot2 },
|
|
4847
|
+
render: ({ id, columns, gap, items: Items }) => /* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": blockTestId(id), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4848
|
+
Items,
|
|
4849
|
+
{
|
|
4850
|
+
className: react.cn(
|
|
4851
|
+
"grid grid-cols-1",
|
|
4852
|
+
METRIC_COLS[columns] ?? METRIC_COLS["3"],
|
|
4853
|
+
METRIC_GAP[gap] ?? METRIC_GAP.md
|
|
4854
|
+
)
|
|
4855
|
+
}
|
|
4856
|
+
) })
|
|
4857
|
+
};
|
|
4354
4858
|
const DataTableBlockConfig = {
|
|
4355
4859
|
label: "Data table",
|
|
4356
4860
|
fields: {
|
|
@@ -4549,11 +5053,13 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4549
5053
|
};
|
|
4550
5054
|
const website = createWebsiteBlocks(kit);
|
|
4551
5055
|
const site = createSiteBlocks(kit);
|
|
5056
|
+
const widgets = opts.liveWidgets ? createLiveWidgets(kit) : {};
|
|
4552
5057
|
const components = {
|
|
4553
5058
|
SectionHeading: SectionHeadingBlock,
|
|
4554
5059
|
PageHeader: PageHeaderBlock,
|
|
4555
5060
|
EmptyState: EmptyStateBlock,
|
|
4556
5061
|
MetricCard: MetricCardBlock,
|
|
5062
|
+
MetricRow: MetricRowBlock,
|
|
4557
5063
|
DataTable: DataTableBlockConfig,
|
|
4558
5064
|
Section: SectionBlock,
|
|
4559
5065
|
Card: CardBlock,
|
|
@@ -4561,7 +5067,8 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4561
5067
|
Badge: BadgeBlock,
|
|
4562
5068
|
Separator: SeparatorBlock,
|
|
4563
5069
|
...website,
|
|
4564
|
-
...site
|
|
5070
|
+
...site,
|
|
5071
|
+
...widgets
|
|
4565
5072
|
};
|
|
4566
5073
|
const config = {
|
|
4567
5074
|
categories: {
|
|
@@ -4595,7 +5102,8 @@ function createArbiBlocksConfig(opts = {}) {
|
|
|
4595
5102
|
Commerce: { title: "Commerce", components: ["Pricing"] },
|
|
4596
5103
|
Forms: { title: "Forms", components: ["ContactForm"] },
|
|
4597
5104
|
Navigation: { title: "Navigation", components: ["Navbar", "Footer"] },
|
|
4598
|
-
Data: { title: "Data", components: ["MetricCard", "DataTable"] },
|
|
5105
|
+
Data: { title: "Data", components: ["MetricRow", "MetricCard", "DataTable"] },
|
|
5106
|
+
...opts.liveWidgets ? { Widgets: { title: "Widgets", components: ["AgentActivity", "LiveMetric"] } } : {},
|
|
4599
5107
|
Primitives: { title: "Primitives", components: ["Button", "Badge", "Separator"] }
|
|
4600
5108
|
},
|
|
4601
5109
|
components,
|
|
@@ -5119,6 +5627,8 @@ Object.defineProperty(exports, "toRedlineMarkdown", {
|
|
|
5119
5627
|
exports.ASSET_REF_PREFIX = ASSET_REF_PREFIX;
|
|
5120
5628
|
exports.Accordion = Accordion;
|
|
5121
5629
|
exports.AgentsPanel = AgentsPanel;
|
|
5630
|
+
exports.AppHeader = AppHeader;
|
|
5631
|
+
exports.AppShell = AppShell;
|
|
5122
5632
|
exports.AssetResolverProvider = AssetResolverProvider;
|
|
5123
5633
|
exports.AvatarBlock = AvatarBlock;
|
|
5124
5634
|
exports.Banner = Banner;
|
|
@@ -5140,6 +5650,7 @@ exports.GridView = GridView;
|
|
|
5140
5650
|
exports.Hero = Hero;
|
|
5141
5651
|
exports.LegalArbiProvider = LegalArbiProvider;
|
|
5142
5652
|
exports.ListBlock = ListBlock;
|
|
5653
|
+
exports.LiveDataProvider = LiveDataProvider;
|
|
5143
5654
|
exports.LogoCloud = LogoCloud;
|
|
5144
5655
|
exports.MediaText = MediaText;
|
|
5145
5656
|
exports.MetricCard = MetricCard;
|
|
@@ -5164,6 +5675,7 @@ exports.ThemeEditor = ThemeEditor;
|
|
|
5164
5675
|
exports.Toolbar = Toolbar;
|
|
5165
5676
|
exports.VerticalBuilder = VerticalBuilder;
|
|
5166
5677
|
exports.VideoEmbed = VideoEmbed;
|
|
5678
|
+
exports.WidgetPlaceholder = WidgetPlaceholder;
|
|
5167
5679
|
exports.applyStoredTheme = applyStoredTheme;
|
|
5168
5680
|
exports.applyThemeVars = applyThemeVars;
|
|
5169
5681
|
exports.asAssetRef = asAssetRef;
|
|
@@ -5175,6 +5687,7 @@ exports.createArbiBlocksConfig = createArbiBlocksConfig;
|
|
|
5175
5687
|
exports.createArbiMaterializer = createArbiMaterializer;
|
|
5176
5688
|
exports.createBlockKit = createBlockKit;
|
|
5177
5689
|
exports.createImageField = createImageField;
|
|
5690
|
+
exports.createLiveWidgets = createLiveWidgets;
|
|
5178
5691
|
exports.createModuleRegistry = createModuleRegistry;
|
|
5179
5692
|
exports.createModuleStore = createModuleStore;
|
|
5180
5693
|
exports.createPromptLibrary = createPromptLibrary;
|
|
@@ -5203,6 +5716,7 @@ exports.useAssetResolverActive = useAssetResolverActive;
|
|
|
5203
5716
|
exports.useConnection = useConnection;
|
|
5204
5717
|
exports.useFirmAiTask = useFirmAiTask;
|
|
5205
5718
|
exports.useImageGen = useImageGen;
|
|
5719
|
+
exports.useLiveDataActive = useLiveDataActive;
|
|
5206
5720
|
exports.useSemanticSearch = useSemanticSearch;
|
|
5207
5721
|
exports.useWorkspaceDocs = useWorkspaceDocs;
|
|
5208
5722
|
//# sourceMappingURL=index.cjs.map
|