@hanzo/ui 8.0.13 → 8.0.14

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.
@@ -1,10 +1,12 @@
1
1
  'use client';
2
2
  import { ThemeToggle } from '../chunk-42CU5GSF.js';
3
3
  export { AgnosticThemeToggle, ThemeToggle, ThemeToggleNext } from '../chunk-42CU5GSF.js';
4
- import { createContext, useRef, useState, useEffect, useCallback, useLayoutEffect, useMemo, cloneElement, useContext, useSyncExternalStore } from 'react';
5
- import { useTheme, XStack, Text, YStack, Card, Theme, useThemeName, Portal, Input, Button, Spinner, Popover, Separator, useControllableState, Label, TextArea, Switch, Slider, ScrollView } from '@hanzo/gui';
4
+ import { classifyBackend, PageHeader, BackendStateCard, DataTable, asColor } from '../chunk-YAYUPOE3.js';
5
+ export { ACCOUNT_STATUSES, BackendStateCard, COMPOSE_MODES, CampaignCard, ChannelBadge, DataTable, EmptyState, FieldRow, FieldSelect, FieldSlider, FieldSwitch, FieldText, FieldTextArea, HostProvider, POST_STATUSES, PROVIDERS, PageHeader, PostAgenda, PostCard, PostComposer, PrimaryButton, ProviderReadinessList, LG as SLIDEOVER_LG, SlideOver, SocialResource, SocialSummaryBar, StatusTag, ViewToggle, accentFor, asColor, classifyBackend, classifyRead, contrastText, createSocialApi, formatPostTime, isHexColor, normalizeAccount, normalizeAccounts, normalizePost, normalizePosts, normalizeProviderCapability, normalizeProviders, normalizeSummary, parsePostTime, postDayBucket, postPreview, resolveAccent, setOrgAccent, useAccent, useHost } from '../chunk-YAYUPOE3.js';
6
+ import { createContext, useRef, useState, useEffect, useCallback, useLayoutEffect, useMemo, cloneElement, useContext } from 'react';
7
+ import { useTheme, XStack, Text, YStack, Card, Theme, useThemeName, Portal, Input, Button, Spinner, Popover, Separator, useControllableState } from '@hanzo/gui';
6
8
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
- import { Check, ChevronRight, ChevronDown, RefreshCw, Grip, CreditCard, Users, Bot, MessageCircle, AppWindow, LayoutGrid, Sparkles, UserRound, Settings2, LogOut, ChevronsUpDown, Plus, Search, TriangleAlert, ChevronUp, Trash2, ExternalLink, ArrowRight, Cpu, Globe, Server, X, Calendar, AlertTriangle, CheckCircle2, List, Link2, Share2, Send, Pencil, Info, CircleX, CircleCheck } from '@hanzogui/lucide-icons-2';
9
+ import { Check, ChevronRight, ChevronDown, RefreshCw, Grip, CreditCard, Users, Bot, MessageCircle, AppWindow, LayoutGrid, Sparkles, UserRound, Settings2, LogOut, ChevronsUpDown, Plus, Search, Trash2, Cpu, Globe, Server, Info, CircleX, CircleCheck, X } from '@hanzogui/lucide-icons-2';
8
10
  export { Boxes as CustomModelMark } from '@hanzogui/lucide-icons-2';
9
11
  import { surfaceById } from '@hanzo/products';
10
12
  import { HanzoLogo } from '@hanzo/logo/react';
@@ -674,12 +676,12 @@ function menuKeyDown(e, onClose) {
674
676
  if (items.length === 0) return;
675
677
  e.preventDefault();
676
678
  const active = document.activeElement;
677
- const current2 = active ? items.indexOf(active) : -1;
679
+ const current = active ? items.indexOf(active) : -1;
678
680
  let next;
679
681
  if (e.key === "Home") next = 0;
680
682
  else if (e.key === "End") next = items.length - 1;
681
- else if (e.key === "ArrowDown") next = current2 < 0 ? 0 : (current2 + 1) % items.length;
682
- else next = current2 <= 0 ? items.length - 1 : current2 - 1;
683
+ else if (e.key === "ArrowDown") next = current < 0 ? 0 : (current + 1) % items.length;
684
+ else next = current <= 0 ? items.length - 1 : current - 1;
683
685
  items[next]?.focus();
684
686
  }
685
687
  var EDGE = 8;
@@ -854,8 +856,8 @@ var SURFACES = ORDER.map((id) => {
854
856
  const s = surfaceById(id);
855
857
  return { id, label: s.label, href: s.href, hint: s.domain };
856
858
  });
857
- function otherSurfaces(current2) {
858
- return current2 ? SURFACES.filter((s) => s.id !== current2) : SURFACES;
859
+ function otherSurfaces(current) {
860
+ return current ? SURFACES.filter((s) => s.id !== current) : SURFACES;
859
861
  }
860
862
  function HanzoMark({ size = 22, color = "currentColor" }) {
861
863
  return /* @__PURE__ */ jsxs(
@@ -912,7 +914,7 @@ function AppHeader({
912
914
  onBrand,
913
915
  org,
914
916
  children,
915
- current: current2,
917
+ current,
916
918
  surfaces,
917
919
  open,
918
920
  user,
@@ -925,7 +927,7 @@ function AppHeader({
925
927
  }) {
926
928
  const [appsOpen, setAppsOpen] = useState(false);
927
929
  const [menuOpen, setMenuOpen] = useState(false);
928
- const items = surfaces ?? otherSurfaces(current2);
930
+ const items = surfaces ?? otherSurfaces(current);
929
931
  const launch = (s) => {
930
932
  setAppsOpen(false);
931
933
  if (open) open(s);
@@ -1076,7 +1078,7 @@ function OrgSwitcher({ scope, orgs, pageSize = 20, current: given, create, picke
1076
1078
  const [open, setOpen] = useState(false);
1077
1079
  const [query, setQuery] = useState("");
1078
1080
  const [debounced, setDebounced] = useState("");
1079
- const [rows2, setRows] = useState([]);
1081
+ const [rows, setRows] = useState([]);
1080
1082
  const [loading, setLoading] = useState(false);
1081
1083
  const [loadingMore, setLoadingMore] = useState(false);
1082
1084
  const [hasMore, setHasMore] = useState(false);
@@ -1128,14 +1130,14 @@ function OrgSwitcher({ scope, orgs, pageSize = 20, current: given, create, picke
1128
1130
  void fetchPage(pageRef.current + 1, debounced, true);
1129
1131
  }, [loading, loadingMore, hasMore, debounced, fetchPage]);
1130
1132
  const visible = useMemo(() => {
1131
- if (orgs) return filterOrgs(rows2, query);
1133
+ if (orgs) return filterOrgs(rows, query);
1132
1134
  return [{ name: currentId, displayName: titleCase(currentId) }];
1133
- }, [orgs, rows2, query, currentId]);
1134
- const current2 = useMemo(() => {
1135
+ }, [orgs, rows, query, currentId]);
1136
+ const current = useMemo(() => {
1135
1137
  if (given && given.name === currentId) return given;
1136
- return rows2.find((o) => o.name === currentId) ?? { name: currentId, displayName: titleCase(currentId) };
1137
- }, [given, rows2, currentId]);
1138
- const currentLabel = current2.displayName || titleCase(current2.name);
1138
+ return rows.find((o) => o.name === currentId) ?? { name: currentId, displayName: titleCase(currentId) };
1139
+ }, [given, rows, currentId]);
1140
+ const currentLabel = current.displayName || titleCase(current.name);
1139
1141
  const select = useCallback(
1140
1142
  (org) => {
1141
1143
  setOpen(false);
@@ -1158,7 +1160,7 @@ function OrgSwitcher({ scope, orgs, pageSize = 20, current: given, create, picke
1158
1160
  };
1159
1161
  return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, placement: "bottom-start", children: [
1160
1162
  /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { chromeless: true, height: 44, px: "$2", justify: "flex-start", "aria-label": `${currentLabel} \xB7 switch organization`, children: /* @__PURE__ */ jsxs(XStack, { items: "center", gap: "$2.5", flex: 1, minW: 0, children: [
1161
- /* @__PURE__ */ jsx(OrgMark, { org: current2, size: 30 }),
1163
+ /* @__PURE__ */ jsx(OrgMark, { org: current, size: 30 }),
1162
1164
  /* @__PURE__ */ jsx(Text, { flex: 1, minW: 0, fontSize: "$4", fontWeight: "800", color: "$color12", numberOfLines: 1, children: currentLabel }),
1163
1165
  /* @__PURE__ */ jsx(ChevronsUpDown, { size: 15, color: "$color9" })
1164
1166
  ] }) }) }),
@@ -1589,203 +1591,6 @@ function SiteFooter({ footer, brand, tagline, meta, link = defaultLink2 }) {
1589
1591
  ] })
1590
1592
  ] });
1591
1593
  }
1592
- var HostCtx = createContext({});
1593
- var HostProvider = ({ actions, children }) => /* @__PURE__ */ jsx(HostCtx.Provider, { value: actions, children });
1594
- var useHost = () => useContext(HostCtx);
1595
- function classifyBackend(e) {
1596
- const status = typeof e?.status === "number" ? e.status : 0;
1597
- const message = e instanceof Error ? e.message : String(e);
1598
- if (status === 503) return { kind: "not-initialized", message };
1599
- if (status === 404 || status === 405) return { kind: "unavailable", message };
1600
- if (status === 501) return { kind: "not-implemented", message };
1601
- if (status === 402) return { kind: "billing", message };
1602
- if (status === 401) return { kind: "signin", message };
1603
- if (status === 403) return { kind: "access", message };
1604
- return { kind: "error", message };
1605
- }
1606
- function classifyRead(e) {
1607
- const s = classifyBackend(e);
1608
- return s.kind === "billing" ? null : s;
1609
- }
1610
- var TITLES = {
1611
- "not-initialized": "Backend not initialized",
1612
- unavailable: "Not available on this deployment yet",
1613
- "not-implemented": "Not yet available",
1614
- access: "Not enabled for your account",
1615
- signin: "Your session expired",
1616
- billing: "Add credits to continue",
1617
- error: "Could not reach the backend"
1618
- };
1619
- var BODIES = {
1620
- "not-initialized": "The /v1 route is mounted but its runtime (or the console API key it proxies to) is not configured on this deployment yet. Real data appears here once it is \u2014 no placeholder data is shown.",
1621
- unavailable: "This endpoint is not mounted at the gateway on this host yet. The view lights up automatically once the route is live.",
1622
- // 501 — a real, planned capability whose body ships in a later phase.
1623
- "not-implemented": "This capability is planned but not wired yet. The backend answers honestly rather than pretending it worked \u2014 nothing here is fabricated, and the view lights up automatically once it ships.",
1624
- // 403 for a SIGNED-IN user — never "sign in".
1625
- access: "You're signed in, but this isn't enabled for your organization on this deployment, or it's an admin-only surface. It appears here automatically once your account has access \u2014 nothing is fabricated.",
1626
- // 401 — the session itself lapsed; re-auth returns to this exact page.
1627
- signin: "Your session has expired or isn\u2019t recognized here. Sign in again to continue where you left off.",
1628
- // Empty → the card shows the backend's own message (the honest "Insufficient
1629
- // balance. Please add credits…" from the gateway billing gate).
1630
- billing: "",
1631
- error: ""
1632
- };
1633
- function BackendStateCard({
1634
- state,
1635
- onRetry,
1636
- hint
1637
- }) {
1638
- const { signIn, addCredits } = useHost();
1639
- return /* @__PURE__ */ jsxs(Card, { borderWidth: 1, borderColor: "$borderColor", p: "$4", gap: "$2", maxWidth: 640, children: [
1640
- /* @__PURE__ */ jsxs(XStack, { gap: "$2", items: "center", children: [
1641
- /* @__PURE__ */ jsx(TriangleAlert, { size: 16 }),
1642
- /* @__PURE__ */ jsx(Text, { fontSize: "$4", fontWeight: "700", children: TITLES[state.kind] })
1643
- ] }),
1644
- /* @__PURE__ */ jsx(Text, { fontSize: "$3", color: "$color11", children: BODIES[state.kind] || state.message }),
1645
- hint ? /* @__PURE__ */ jsx(Text, { fontSize: "$2", color: "$color10", children: hint }) : null,
1646
- state.kind === "signin" && signIn ? /* @__PURE__ */ jsx(Button, { size: "$2", theme: "light", self: "flex-start", onPress: signIn, children: "Sign in again" }) : state.kind === "billing" && addCredits ? (
1647
- // 402 — the org has no funded balance. Offer a top-up CTA (and keep Retry so
1648
- // a returning, funded caller can reload in place).
1649
- /* @__PURE__ */ jsxs(XStack, { gap: "$2", items: "center", flexWrap: "wrap", children: [
1650
- /* @__PURE__ */ jsx(Button, { size: "$2", theme: "light", self: "flex-start", icon: /* @__PURE__ */ jsx(CreditCard, { size: 14 }), onPress: addCredits, children: "Add credits" }),
1651
- onRetry ? /* @__PURE__ */ jsx(Button, { size: "$2", self: "flex-start", onPress: onRetry, children: "Retry" }) : null
1652
- ] })
1653
- ) : onRetry ? /* @__PURE__ */ jsx(Button, { size: "$2", self: "flex-start", onPress: onRetry, children: "Retry" }) : null
1654
- ] });
1655
- }
1656
- function PageHeader({
1657
- title,
1658
- subtitle,
1659
- actions
1660
- }) {
1661
- return (
1662
- // flexWrap lets the actions drop below the title on narrow screens; flex={1}
1663
- // minW={0} lets the title column shrink so a long subtitle WRAPS instead of
1664
- // running off the viewport (a flex child defaults to min-width:auto = content
1665
- // width, which would overflow on mobile).
1666
- /* @__PURE__ */ jsxs(XStack, { justify: "space-between", items: "flex-start", gap: "$3", flexWrap: "wrap", children: [
1667
- /* @__PURE__ */ jsxs(YStack, { gap: "$1", flex: 1, minW: 200, children: [
1668
- /* @__PURE__ */ jsx(Text, { fontSize: "$7", fontWeight: "500", letterSpacing: -0.4, children: title }),
1669
- subtitle ? /* @__PURE__ */ jsx(Text, { fontSize: "$3", color: "$color11", children: subtitle }) : null
1670
- ] }),
1671
- actions ? /* @__PURE__ */ jsx(XStack, { gap: "$2", items: "center", flexWrap: "wrap", width: "100%", $md: { width: "auto", justify: "flex-end" }, children: actions }) : null
1672
- ] })
1673
- );
1674
- }
1675
- function SkeletonRows({ columns, count = 6 }) {
1676
- return /* @__PURE__ */ jsx(YStack, { children: Array.from({ length: count }).map((_, r) => /* @__PURE__ */ jsx(XStack, { py: "$2.5", px: "$3", gap: "$3", borderTopWidth: 1, borderColor: "$borderColor", items: "center", children: columns.map((c, i) => /* @__PURE__ */ jsx(YStack, { width: c.width, flex: c.width ? void 0 : 1, minW: c.width ? void 0 : FLEX_MIN_COL_W, items: c.align === "right" ? "flex-end" : "flex-start", children: /* @__PURE__ */ jsx(
1677
- "div",
1678
- {
1679
- className: "hz-skeleton",
1680
- style: { height: 12, borderRadius: 6, width: `${[62, 40, 54, 34, 48][(i + r) % 5]}%` },
1681
- "aria-hidden": true
1682
- }
1683
- ) }, c.key)) }, r)) });
1684
- }
1685
- function DataTable({
1686
- columns,
1687
- rows: rows2,
1688
- loading,
1689
- empty = "Nothing here yet.",
1690
- rowKey,
1691
- onRowPress,
1692
- isRowExpanded,
1693
- renderExpanded,
1694
- sort,
1695
- onSortChange
1696
- }) {
1697
- const minTableW = columns.reduce((sum, c) => sum + (c.width ?? FLEX_MIN_COL_W), 0) + (columns.length + 1) * 12;
1698
- return /* @__PURE__ */ jsxs(YStack, { borderWidth: 1, borderColor: "$borderColor", rounded: "$4", overflow: "hidden", children: [
1699
- /* @__PURE__ */ jsx(YStack, { style: { overflowX: "auto", overflowY: "visible" }, children: /* @__PURE__ */ jsxs(YStack, { minW: minTableW, children: [
1700
- /* @__PURE__ */ jsx(XStack, { bg: "$color1", py: "$2.5", px: "$3", gap: "$3", borderBottomWidth: 1, borderColor: "$borderColor", role: "row", children: columns.map((c) => {
1701
- const sortable = c.sortable === true && !!onSortChange;
1702
- const active = sortable && sort?.key === c.key;
1703
- const Caret = !sortable ? null : !active ? ChevronsUpDown : sort?.dir === "asc" ? ChevronUp : ChevronDown;
1704
- return /* @__PURE__ */ jsxs(
1705
- XStack,
1706
- {
1707
- width: c.width,
1708
- flex: c.width ? void 0 : 1,
1709
- minW: c.width ? void 0 : FLEX_MIN_COL_W,
1710
- items: "center",
1711
- gap: "$1",
1712
- justify: c.align === "right" ? "flex-end" : "flex-start",
1713
- role: "columnheader",
1714
- "aria-sort": sortable ? active ? sort?.dir === "asc" ? "ascending" : "descending" : "none" : void 0,
1715
- "aria-label": sortable ? `Sort by ${c.header}` : void 0,
1716
- cursor: sortable ? "pointer" : void 0,
1717
- hoverStyle: sortable ? { opacity: 0.75 } : void 0,
1718
- onPress: sortable ? () => onSortChange?.(c.key) : void 0,
1719
- children: [
1720
- /* @__PURE__ */ jsx(
1721
- Text,
1722
- {
1723
- fontSize: "$1",
1724
- fontWeight: "500",
1725
- color: active ? "$color12" : "$color10",
1726
- text: c.align === "right" ? "right" : "left",
1727
- className: c.mono ? "hz-tnum" : void 0,
1728
- children: c.header
1729
- }
1730
- ),
1731
- Caret ? /* @__PURE__ */ jsx(Caret, { size: 12, color: active ? "$color12" : "$color9" }) : null
1732
- ]
1733
- },
1734
- c.key
1735
- );
1736
- }) }),
1737
- loading ? /* @__PURE__ */ jsx(SkeletonRows, { columns }) : rows2.length > 0 ? /* @__PURE__ */ jsx(YStack, { children: rows2.map((row) => {
1738
- const expanded = (isRowExpanded?.(row) ?? false) && !!renderExpanded;
1739
- return /* @__PURE__ */ jsxs(YStack, { children: [
1740
- /* @__PURE__ */ jsx(
1741
- XStack,
1742
- {
1743
- className: "hz-row",
1744
- py: "$2.5",
1745
- px: "$3",
1746
- gap: "$3",
1747
- borderTopWidth: 1,
1748
- borderColor: "$borderColor",
1749
- items: "center",
1750
- bg: expanded ? "$color2" : void 0,
1751
- hoverStyle: onRowPress ? { bg: "$color2" } : void 0,
1752
- cursor: onRowPress ? "pointer" : void 0,
1753
- onPress: onRowPress ? () => onRowPress(row) : void 0,
1754
- children: columns.map((c) => {
1755
- const cell = c.render ? c.render(row) : String(row[c.key] ?? "");
1756
- return /* @__PURE__ */ jsx(
1757
- YStack,
1758
- {
1759
- width: c.width,
1760
- flex: c.width ? void 0 : 1,
1761
- minW: c.width ? void 0 : FLEX_MIN_COL_W,
1762
- justify: "center",
1763
- items: c.align === "right" ? "flex-end" : "flex-start",
1764
- children: typeof cell === "string" || typeof cell === "number" ? /* @__PURE__ */ jsx(
1765
- Text,
1766
- {
1767
- fontSize: "$3",
1768
- numberOfLines: 1,
1769
- color: "$color12",
1770
- text: c.align === "right" ? "right" : "left",
1771
- className: c.mono ? "hz-mono" : void 0,
1772
- children: cell
1773
- }
1774
- ) : cell
1775
- },
1776
- c.key
1777
- );
1778
- })
1779
- }
1780
- ),
1781
- expanded && renderExpanded ? /* @__PURE__ */ jsx(YStack, { borderTopWidth: 1, borderColor: "$borderColor", bg: "$color1", children: renderExpanded(row) }) : null
1782
- ] }, rowKey(row));
1783
- }) }) : null
1784
- ] }) }),
1785
- !loading && rows2.length === 0 ? /* @__PURE__ */ jsx(YStack, { py: "$8", px: "$4", items: "center", gap: "$1", borderTopWidth: 1, borderColor: "$borderColor", children: /* @__PURE__ */ jsx(Text, { color: "$color10", fontSize: "$3", text: "center", children: empty }) }) : null
1786
- ] });
1787
- }
1788
- var FLEX_MIN_COL_W = 120;
1789
1594
  function CommerceResource({
1790
1595
  title,
1791
1596
  subtitle,
@@ -2068,131 +1873,6 @@ function AnimatedLogo({
2068
1873
  }
2069
1874
  );
2070
1875
  }
2071
- function isHexColor(v) {
2072
- return typeof v === "string" && /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(v.trim());
2073
- }
2074
- function resolveAccent(theme) {
2075
- if (!theme || !theme.isEnabled) return null;
2076
- const hex = (theme.colorPrimary ?? "").trim();
2077
- return isHexColor(hex) ? hex : null;
2078
- }
2079
- function expandHex(hex) {
2080
- const h = hex.trim().toLowerCase();
2081
- if (h.length === 4) return `#${h[1]}${h[1]}${h[2]}${h[2]}${h[3]}${h[3]}`;
2082
- return h;
2083
- }
2084
- function contrastText(hex) {
2085
- if (!isHexColor(hex)) return "#ffffff";
2086
- const h = expandHex(hex);
2087
- const r = parseInt(h.slice(1, 3), 16) / 255;
2088
- const g = parseInt(h.slice(3, 5), 16) / 255;
2089
- const b = parseInt(h.slice(5, 7), 16) / 255;
2090
- const lin = (c) => c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
2091
- const luminance = 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
2092
- return luminance > 0.5 ? "#000000" : "#ffffff";
2093
- }
2094
- function accentFor(theme) {
2095
- const hex = resolveAccent(theme);
2096
- return { accent: hex, contrast: hex ? contrastText(hex) : "#ffffff" };
2097
- }
2098
- var DEFAULT = { accent: null, contrast: "#ffffff" };
2099
- var current = DEFAULT;
2100
- var listeners = /* @__PURE__ */ new Set();
2101
- function setOrgAccent(theme) {
2102
- const next = accentFor(theme);
2103
- if (next.accent === current.accent) return;
2104
- current = next.accent ? next : DEFAULT;
2105
- for (const l of listeners) l();
2106
- }
2107
- function subscribe(cb) {
2108
- listeners.add(cb);
2109
- return () => {
2110
- listeners.delete(cb);
2111
- };
2112
- }
2113
- function useAccent() {
2114
- return useSyncExternalStore(
2115
- subscribe,
2116
- () => current,
2117
- () => DEFAULT
2118
- );
2119
- }
2120
- function PrimaryButton(props) {
2121
- const { accent, contrast } = useAccent();
2122
- if (accent) {
2123
- return /* @__PURE__ */ jsx(Button, { style: { backgroundColor: accent, color: contrast, borderColor: accent }, ...props });
2124
- }
2125
- return /* @__PURE__ */ jsx(Button, { theme: "light", ...props });
2126
- }
2127
- function openHref2(href) {
2128
- if (typeof window !== "undefined") window.open(href, "_blank", "noopener");
2129
- }
2130
- function EmptyState({
2131
- icon: Icon,
2132
- title,
2133
- description,
2134
- bullets,
2135
- primary,
2136
- secondary
2137
- }) {
2138
- return /* @__PURE__ */ jsxs(
2139
- Card,
2140
- {
2141
- borderWidth: 1,
2142
- borderColor: "$borderColor",
2143
- borderStyle: "dashed",
2144
- p: "$6",
2145
- gap: "$4",
2146
- items: "center",
2147
- maxWidth: 640,
2148
- self: "center",
2149
- width: "100%",
2150
- children: [
2151
- /* @__PURE__ */ jsx(
2152
- YStack,
2153
- {
2154
- width: 48,
2155
- height: 48,
2156
- items: "center",
2157
- justify: "center",
2158
- rounded: "$4",
2159
- bg: "$color3",
2160
- children: /* @__PURE__ */ jsx(Icon, { size: 24 })
2161
- }
2162
- ),
2163
- /* @__PURE__ */ jsxs(YStack, { gap: "$2", items: "center", maxW: 480, children: [
2164
- /* @__PURE__ */ jsx(Text, { fontSize: "$6", fontWeight: "500", text: "center", letterSpacing: -0.3, children: title }),
2165
- /* @__PURE__ */ jsx(Text, { fontSize: "$3", color: "$color11", text: "center", children: description })
2166
- ] }),
2167
- bullets && bullets.length ? /* @__PURE__ */ jsx(YStack, { gap: "$2", self: "stretch", maxW: 420, mx: "auto", children: bullets.map((b) => /* @__PURE__ */ jsxs(XStack, { gap: "$2", items: "flex-start", children: [
2168
- /* @__PURE__ */ jsx(YStack, { pt: "$1", children: /* @__PURE__ */ jsx(Check, { size: 14, color: "$color10" }) }),
2169
- /* @__PURE__ */ jsx(Text, { fontSize: "$3", color: "$color11", flex: 1, children: b })
2170
- ] }, b)) }) : null,
2171
- primary || secondary ? /* @__PURE__ */ jsxs(XStack, { gap: "$2", items: "center", flexWrap: "wrap", justify: "center", children: [
2172
- primary ? /* @__PURE__ */ jsx(
2173
- PrimaryButton,
2174
- {
2175
- icon: primary.icon,
2176
- iconAfter: primary.href ? /* @__PURE__ */ jsx(ExternalLink, { size: 15 }) : /* @__PURE__ */ jsx(ArrowRight, { size: 15 }),
2177
- onPress: () => primary.href ? openHref2(primary.href) : primary.onPress?.(),
2178
- children: primary.label
2179
- }
2180
- ) : null,
2181
- secondary ? /* @__PURE__ */ jsx(
2182
- Button,
2183
- {
2184
- chromeless: true,
2185
- icon: secondary.icon,
2186
- iconAfter: secondary.href ? /* @__PURE__ */ jsx(ExternalLink, { size: 14 }) : void 0,
2187
- onPress: () => secondary.href ? openHref2(secondary.href) : secondary.onPress?.(),
2188
- children: secondary.label
2189
- }
2190
- ) : null
2191
- ] }) : null
2192
- ]
2193
- }
2194
- );
2195
- }
2196
1876
  function FadeIn({
2197
1877
  children,
2198
1878
  index = 0,
@@ -2203,125 +1883,6 @@ function FadeIn({
2203
1883
  const delay = delayMs ?? index * step;
2204
1884
  return /* @__PURE__ */ jsx("div", { className: "hz-fade-up", style: { animationDelay: `${delay}ms`, ...style }, children });
2205
1885
  }
2206
- function FieldRow({ label, children }) {
2207
- return /* @__PURE__ */ jsxs(XStack, { gap: "$3", items: "flex-start", flexWrap: "wrap", children: [
2208
- /* @__PURE__ */ jsx(Label, { width: "100%", pt: "$2", color: "$color11", fontSize: "$3", $md: { width: 180 }, children: label }),
2209
- /* @__PURE__ */ jsx(YStack, { flex: 1, minW: 0, $md: { minW: 240 }, children })
2210
- ] });
2211
- }
2212
- function FieldText({
2213
- value,
2214
- onChange,
2215
- disabled,
2216
- secure,
2217
- placeholder
2218
- }) {
2219
- return /* @__PURE__ */ jsx(
2220
- Input,
2221
- {
2222
- value,
2223
- onChangeText: onChange,
2224
- disabled,
2225
- secureTextEntry: secure,
2226
- placeholder,
2227
- autoCapitalize: "none"
2228
- }
2229
- );
2230
- }
2231
- function FieldTextArea({
2232
- value,
2233
- onChange,
2234
- disabled,
2235
- rows: rows2 = 6
2236
- }) {
2237
- return /* @__PURE__ */ jsx(TextArea, { value, onChangeText: onChange, disabled, numberOfLines: rows2 });
2238
- }
2239
- function FieldSwitch({
2240
- checked,
2241
- onChange,
2242
- disabled
2243
- }) {
2244
- return /* @__PURE__ */ jsx(Switch, { checked, onCheckedChange: onChange, disabled, size: "$3", children: /* @__PURE__ */ jsx(Switch.Thumb, {}) });
2245
- }
2246
- var CHEVRON = `data:image/svg+xml,${encodeURIComponent(
2247
- '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#9a9a9a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>'
2248
- )}`;
2249
- function selectStyle(disabled) {
2250
- return {
2251
- width: "100%",
2252
- boxSizing: "border-box",
2253
- appearance: "none",
2254
- WebkitAppearance: "none",
2255
- MozAppearance: "none",
2256
- background: `var(--background) url("${CHEVRON}") no-repeat right 10px center`,
2257
- color: "var(--color12)",
2258
- border: "1px solid var(--borderColor)",
2259
- borderRadius: 9,
2260
- padding: "9px 34px 9px 12px",
2261
- fontSize: 14,
2262
- lineHeight: "20px",
2263
- fontFamily: "inherit",
2264
- height: 40,
2265
- outline: "none",
2266
- cursor: disabled ? "not-allowed" : "pointer",
2267
- opacity: disabled ? 0.5 : 1
2268
- };
2269
- }
2270
- var OPTION_STYLE = { background: "var(--color2)", color: "var(--color12)" };
2271
- function FieldSelect({
2272
- value,
2273
- options,
2274
- onChange,
2275
- disabled,
2276
- placeholder = "Select\u2026"
2277
- }) {
2278
- const showPlaceholder = value === "" || !options.includes(value);
2279
- return /* @__PURE__ */ jsxs(
2280
- "select",
2281
- {
2282
- value: showPlaceholder ? "" : value,
2283
- onChange: (e) => onChange(e.currentTarget.value),
2284
- disabled,
2285
- "aria-label": placeholder,
2286
- style: selectStyle(disabled),
2287
- children: [
2288
- showPlaceholder ? /* @__PURE__ */ jsx("option", { value: "", disabled: true, style: OPTION_STYLE, children: placeholder }) : null,
2289
- options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt, style: OPTION_STYLE, children: opt }, opt))
2290
- ]
2291
- }
2292
- );
2293
- }
2294
- function FieldSlider({
2295
- value,
2296
- min,
2297
- max,
2298
- step,
2299
- onChange,
2300
- disabled
2301
- }) {
2302
- return /* @__PURE__ */ jsxs(XStack, { gap: "$3", items: "center", children: [
2303
- /* @__PURE__ */ jsx(Text, { width: 56, fontSize: "$3", color: "$color11", children: value }),
2304
- /* @__PURE__ */ jsxs(
2305
- Slider,
2306
- {
2307
- flex: 1,
2308
- min,
2309
- max,
2310
- step,
2311
- value: [value],
2312
- onValueChange: (v) => onChange(v[0] ?? min),
2313
- disabled,
2314
- children: [
2315
- /* @__PURE__ */ jsx(Slider.Track, { children: /* @__PURE__ */ jsx(Slider.TrackActive, {}) }),
2316
- /* @__PURE__ */ jsx(Slider.Thumb, { index: 0, circular: true })
2317
- ]
2318
- }
2319
- )
2320
- ] });
2321
- }
2322
-
2323
- // src/product/color.ts
2324
- var asColor = (hex) => hex;
2325
1886
  function ProductIcon({
2326
1887
  icon: Icon,
2327
1888
  color,
@@ -2525,169 +2086,6 @@ function SelectMenu({
2525
2086
  }
2526
2087
  );
2527
2088
  }
2528
- var LG = 1024;
2529
- var lockCount = 0;
2530
- var savedOverflow = "";
2531
- function lockScroll() {
2532
- if (typeof document === "undefined") return;
2533
- if (lockCount === 0) {
2534
- savedOverflow = document.body.style.overflow;
2535
- document.body.style.overflow = "hidden";
2536
- }
2537
- lockCount++;
2538
- }
2539
- function unlockScroll() {
2540
- if (typeof document === "undefined") return;
2541
- lockCount = Math.max(0, lockCount - 1);
2542
- if (lockCount === 0) document.body.style.overflow = savedOverflow;
2543
- }
2544
- function SlideOver({
2545
- open,
2546
- onClose,
2547
- side = "right",
2548
- size = 420,
2549
- title,
2550
- icon: Icon,
2551
- iconColor,
2552
- headerRight,
2553
- ariaLabel,
2554
- zIndex = 1e3,
2555
- children
2556
- }) {
2557
- const panelRef = useRef(null);
2558
- const openerRef = useRef(null);
2559
- useEffect(() => {
2560
- if (!open) return;
2561
- openerRef.current = typeof document !== "undefined" ? document.activeElement : null;
2562
- lockScroll();
2563
- const t = window.setTimeout(() => {
2564
- const el = panelRef.current;
2565
- if (el && typeof el.focus === "function") el.focus();
2566
- }, 0);
2567
- return () => {
2568
- window.clearTimeout(t);
2569
- unlockScroll();
2570
- const opener = openerRef.current;
2571
- if (opener && opener instanceof HTMLElement && typeof opener.focus === "function") opener.focus();
2572
- };
2573
- }, [open]);
2574
- useEffect(() => {
2575
- if (!open) return;
2576
- const onKey = (e) => {
2577
- if (e.key === "Escape") {
2578
- e.stopPropagation();
2579
- onClose();
2580
- }
2581
- };
2582
- window.addEventListener("keydown", onKey);
2583
- return () => window.removeEventListener("keydown", onKey);
2584
- }, [open, onClose]);
2585
- const offscreen = side === "right" ? "translateX(100%)" : "translateX(-100%)";
2586
- const edge = side === "right" ? { r: 0 } : { l: 0 };
2587
- return /* @__PURE__ */ jsxs(
2588
- YStack,
2589
- {
2590
- overflow: "hidden",
2591
- pointerEvents: open ? "auto" : "none",
2592
- "aria-hidden": !open,
2593
- style: { position: "fixed", inset: 0, zIndex },
2594
- children: [
2595
- /* @__PURE__ */ jsx(
2596
- YStack,
2597
- {
2598
- position: "absolute",
2599
- t: 0,
2600
- l: 0,
2601
- r: 0,
2602
- b: 0,
2603
- bg: "rgba(0,0,0,0.55)",
2604
- className: "hz-fade",
2605
- style: { opacity: open ? 1 : 0 },
2606
- onPress: onClose
2607
- }
2608
- ),
2609
- /* @__PURE__ */ jsx(
2610
- YStack,
2611
- {
2612
- ref: panelRef,
2613
- tabIndex: -1,
2614
- role: "dialog",
2615
- "aria-modal": open ? true : void 0,
2616
- "aria-label": typeof title === "string" ? title : ariaLabel,
2617
- position: "absolute",
2618
- t: 0,
2619
- b: 0,
2620
- ...edge,
2621
- width: "100%",
2622
- $lg: { width: size, maxW: "100vw" },
2623
- bg: "$color1",
2624
- borderLeftWidth: side === "right" ? 1 : 0,
2625
- borderRightWidth: side === "left" ? 1 : 0,
2626
- borderColor: "$borderColor",
2627
- className: "hz-slide hz-elevation-4",
2628
- style: {
2629
- transform: open ? "translateX(0)" : offscreen,
2630
- height: "100dvh",
2631
- paddingTop: "env(safe-area-inset-top)",
2632
- paddingBottom: "env(safe-area-inset-bottom)"
2633
- },
2634
- children: title !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
2635
- /* @__PURE__ */ jsxs(
2636
- XStack,
2637
- {
2638
- items: "center",
2639
- gap: "$2.5",
2640
- px: "$4",
2641
- height: 56,
2642
- borderBottomWidth: 1,
2643
- borderColor: "$borderColor",
2644
- children: [
2645
- Icon ? /* @__PURE__ */ jsx(Icon, { size: 18, color: iconColor ? asColor(iconColor) : void 0 }) : null,
2646
- /* @__PURE__ */ jsx(Text, { flex: 1, fontSize: "$5", fontWeight: "700", color: "$color12", numberOfLines: 1, children: title }),
2647
- headerRight,
2648
- /* @__PURE__ */ jsx(Button, { chromeless: true, width: 44, height: 44, icon: /* @__PURE__ */ jsx(X, { size: 18 }), onPress: onClose, "aria-label": "Close" })
2649
- ]
2650
- }
2651
- ),
2652
- /* @__PURE__ */ jsx(ScrollView, { flex: 1, children: /* @__PURE__ */ jsx(YStack, { flex: 1, p: "$4", gap: "$3", children }) })
2653
- ] }) : (
2654
- // Bare mode — the caller owns the full panel layout (e.g. the nav drawer
2655
- // renders its own header + scroll + footer).
2656
- children
2657
- )
2658
- }
2659
- )
2660
- ]
2661
- }
2662
- );
2663
- }
2664
- var toneOf = (status) => {
2665
- const s = status.toLowerCase();
2666
- if (s === "green") return "green";
2667
- if (s === "yellow") return "yellow";
2668
- if (s === "red") return "red";
2669
- if (["ready", "active", "running", "available", "ok", "live", "succeeded", "connected", "synced", "imported"].includes(s)) return "green";
2670
- if (["creating", "provisioning", "pending", "updating", "attaching", "building", "deploying", "queued", "importing"].includes(s))
2671
- return "yellow";
2672
- if (["error", "failed", "degraded", "down", "canceled", "conflict"].includes(s)) return "red";
2673
- return "neutral";
2674
- };
2675
- var TONE_BG = {
2676
- green: "$color5",
2677
- yellow: "$color4",
2678
- red: "$color4",
2679
- neutral: "$color3"
2680
- };
2681
- var TONE_FG = {
2682
- green: "$color12",
2683
- yellow: "$color12",
2684
- red: "$color12",
2685
- neutral: "$color11"
2686
- };
2687
- function StatusTag({ status }) {
2688
- const tone2 = toneOf(status ?? "");
2689
- return /* @__PURE__ */ jsx(Text, { fontSize: "$1", px: "$2", py: "$1", rounded: "$2", bg: TONE_BG[tone2], color: TONE_FG[tone2], children: status || "unknown" });
2690
- }
2691
2089
  var ToastContext = createContext(null);
2692
2090
  var ACCENT3 = {
2693
2091
  success: "$green10",
@@ -2785,622 +2183,6 @@ function useToast() {
2785
2183
  return ctx;
2786
2184
  }
2787
2185
 
2788
- // src/product/social/api.ts
2789
- var enc = encodeURIComponent;
2790
- var str = (v) => typeof v === "string" ? v : v == null ? "" : String(v);
2791
- var num = (v) => {
2792
- if (typeof v === "number" && Number.isFinite(v)) return v;
2793
- if (typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v))) return Number(v);
2794
- return 0;
2795
- };
2796
- var strs = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
2797
- var asRecord = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
2798
- var rows = (payload) => {
2799
- if (Array.isArray(payload)) return payload.filter((x) => x && typeof x === "object");
2800
- if (payload && typeof payload === "object") {
2801
- for (const k of ["data", "items", "rows"]) {
2802
- const v = payload[k];
2803
- if (Array.isArray(v)) return v.filter((x) => x && typeof x === "object");
2804
- }
2805
- }
2806
- return [];
2807
- };
2808
- var PROVIDERS = ["x", "facebook", "instagram", "linkedin", "tiktok", "youtube", "threads"];
2809
- var ACCOUNT_STATUSES = ["connected", "disconnected", "error"];
2810
- var POST_STATUSES = ["draft", "scheduled", "published", "failed"];
2811
- function normalizeAccount(raw) {
2812
- const r = asRecord(raw);
2813
- return {
2814
- id: str(r.id),
2815
- provider: str(r.provider) || "x",
2816
- handle: str(r.handle),
2817
- status: str(r.status) || "connected",
2818
- createdAt: num(r.createdAt),
2819
- updatedAt: num(r.updatedAt)
2820
- };
2821
- }
2822
- function normalizePost(raw) {
2823
- const r = asRecord(raw);
2824
- return {
2825
- id: str(r.id),
2826
- content: str(r.content),
2827
- channel: str(r.channel) || "x",
2828
- status: str(r.status) || "draft",
2829
- scheduleAt: num(r.scheduleAt),
2830
- media: strs(r.media),
2831
- accountId: str(r.accountId) || void 0,
2832
- externalId: str(r.externalId) || void 0,
2833
- error: str(r.error) || void 0,
2834
- createdAt: num(r.createdAt),
2835
- updatedAt: num(r.updatedAt)
2836
- };
2837
- }
2838
- function normalizeSummary(raw) {
2839
- const r = asRecord(raw);
2840
- return { posts: num(r.posts), scheduled: num(r.scheduled), published: num(r.published), accounts: num(r.accounts) };
2841
- }
2842
- function normalizeProviderCapability(raw) {
2843
- const r = asRecord(raw);
2844
- return {
2845
- provider: str(r.provider),
2846
- credentialsConfigured: Boolean(r.credentialsConfigured),
2847
- missingCredentials: strs(r.missingCredentials)
2848
- };
2849
- }
2850
- var normalizeAccounts = (p) => rows(p).map(normalizeAccount).filter((a) => a.id);
2851
- var normalizePosts = (p) => rows(p).map(normalizePost).filter((x) => x.id);
2852
- var normalizeProviders = (p) => rows(p).map(normalizeProviderCapability).filter((c) => c.provider);
2853
- function createSocialApi(rest) {
2854
- return {
2855
- summary: () => rest.get("summary").then(normalizeSummary),
2856
- /** Publish-readiness per network (+ the exact missing OAuth-app credentials). */
2857
- providers: () => rest.get("providers").then(normalizeProviders),
2858
- accounts: {
2859
- list: (provider) => rest.get(`accounts${provider ? `?provider=${enc(provider)}` : ""}`).then(normalizeAccounts),
2860
- get: (id) => rest.get(`accounts/${enc(id)}`).then(normalizeAccount),
2861
- create: (body) => rest.post("accounts", body).then(normalizeAccount),
2862
- update: (id, body) => rest.put(`accounts/${enc(id)}`, body).then(normalizeAccount),
2863
- remove: (id) => rest.del(`accounts/${enc(id)}`)
2864
- },
2865
- posts: {
2866
- list: (status) => rest.get(`posts${status ? `?status=${enc(status)}` : ""}`).then(normalizePosts),
2867
- get: (id) => rest.get(`posts/${enc(id)}`).then(normalizePost),
2868
- create: (body) => rest.post("posts", body).then(normalizePost),
2869
- update: (id, body) => rest.put(`posts/${enc(id)}`, body).then(normalizePost),
2870
- remove: (id) => rest.del(`posts/${enc(id)}`),
2871
- /** Publish a post NOW to its channel's connected accounts. */
2872
- publish: (id) => rest.post(`posts/${enc(id)}/publish`).then(normalizePost)
2873
- }
2874
- };
2875
- }
2876
-
2877
- // src/product/social/format.ts
2878
- function formatPostTime(unix) {
2879
- if (!unix) return "\u2014";
2880
- return new Date(unix * 1e3).toLocaleString(void 0, {
2881
- month: "short",
2882
- day: "numeric",
2883
- hour: "2-digit",
2884
- minute: "2-digit"
2885
- });
2886
- }
2887
- function postDayBucket(unix) {
2888
- const d = new Date(unix * 1e3);
2889
- const key = `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
2890
- const label = d.toLocaleDateString(void 0, { weekday: "short", month: "short", day: "numeric" });
2891
- return { key, label };
2892
- }
2893
- function postPreview(s) {
2894
- const t = s.trim();
2895
- return t.length > 72 ? `${t.slice(0, 72)}\u2026` : t || "\u2014";
2896
- }
2897
- function parsePostTime(dt) {
2898
- const ms = Date.parse(dt.trim());
2899
- return Number.isFinite(ms) && ms > 0 ? Math.floor(ms / 1e3) : 0;
2900
- }
2901
- function PostAgenda({ posts, onOpen }) {
2902
- const days = useMemo(() => {
2903
- const timed = posts.filter((p) => (p.scheduleAt ?? 0) > 0).sort((a, b) => (a.scheduleAt ?? 0) - (b.scheduleAt ?? 0));
2904
- const groups = [];
2905
- const index = /* @__PURE__ */ new Map();
2906
- for (const p of timed) {
2907
- const { key, label } = postDayBucket(p.scheduleAt ?? 0);
2908
- let i = index.get(key);
2909
- if (i === void 0) {
2910
- i = groups.length;
2911
- index.set(key, i);
2912
- groups.push({ label, items: [] });
2913
- }
2914
- groups[i].items.push(p);
2915
- }
2916
- return groups;
2917
- }, [posts]);
2918
- if (days.length === 0) {
2919
- return /* @__PURE__ */ jsx(
2920
- EmptyState,
2921
- {
2922
- icon: Calendar,
2923
- title: "Nothing on the calendar",
2924
- description: "Scheduled and timed posts appear here, grouped by day. Compose a post and pick Schedule to plan ahead."
2925
- }
2926
- );
2927
- }
2928
- return /* @__PURE__ */ jsx(YStack, { gap: "$4", children: days.map((d) => /* @__PURE__ */ jsxs(YStack, { gap: "$2", children: [
2929
- /* @__PURE__ */ jsx(Text, { fontSize: "$3", fontWeight: "500", color: "$color11", children: d.label }),
2930
- d.items.map((p) => /* @__PURE__ */ jsxs(
2931
- XStack,
2932
- {
2933
- items: "center",
2934
- justify: "space-between",
2935
- gap: "$3",
2936
- borderWidth: 1,
2937
- borderColor: "$borderColor",
2938
- rounded: "$4",
2939
- px: "$4",
2940
- py: "$3",
2941
- cursor: "pointer",
2942
- hoverStyle: { bg: "$color2" },
2943
- onPress: () => onOpen(p),
2944
- children: [
2945
- /* @__PURE__ */ jsxs(YStack, { gap: "$1", flex: 1, children: [
2946
- /* @__PURE__ */ jsx(Text, { fontSize: "$3", children: postPreview(p.content) }),
2947
- /* @__PURE__ */ jsxs(XStack, { gap: "$2", items: "center", children: [
2948
- /* @__PURE__ */ jsx(Text, { fontSize: "$1", color: "$color10", children: p.channel }),
2949
- /* @__PURE__ */ jsxs(Text, { fontSize: "$1", color: "$color10", children: [
2950
- "\xB7 ",
2951
- formatPostTime(p.scheduleAt ?? 0)
2952
- ] })
2953
- ] })
2954
- ] }),
2955
- /* @__PURE__ */ jsx(StatusTag, { status: p.status })
2956
- ]
2957
- },
2958
- p.id
2959
- ))
2960
- ] }, d.label)) });
2961
- }
2962
- var COMPOSE_MODES = ["draft", "schedule", "now"];
2963
- var COMPOSE_LABEL = {
2964
- draft: "Save draft",
2965
- schedule: "Schedule",
2966
- now: "Publish now"
2967
- };
2968
- function PostComposer({
2969
- channels,
2970
- providers,
2971
- onSubmit
2972
- }) {
2973
- const [content, setContent] = useState("");
2974
- const [channel, setChannel] = useState(channels[0] ?? "x");
2975
- const [mode, setMode] = useState("draft");
2976
- const [scheduleAt, setScheduleAt] = useState("");
2977
- const [saving, setSaving] = useState(false);
2978
- const [error, setError] = useState(null);
2979
- const cap = providers.find((p) => p.provider === channel);
2980
- const unconfigured = (mode === "now" || mode === "schedule") && !!cap && !cap.credentialsConfigured;
2981
- const submit = async () => {
2982
- if (!content.trim()) {
2983
- setError("Content is required.");
2984
- return;
2985
- }
2986
- let status = "draft";
2987
- let at = 0;
2988
- if (mode === "schedule") {
2989
- at = parsePostTime(scheduleAt);
2990
- if (at <= Math.floor(Date.now() / 1e3)) {
2991
- setError("Pick a future date and time to schedule.");
2992
- return;
2993
- }
2994
- status = "scheduled";
2995
- } else if (mode === "now") {
2996
- status = "scheduled";
2997
- }
2998
- setSaving(true);
2999
- setError(null);
3000
- const message = await onSubmit({ content: content.trim(), channel, status, scheduleAt: at }, mode);
3001
- if (message) {
3002
- setError(message);
3003
- setSaving(false);
3004
- }
3005
- };
3006
- return /* @__PURE__ */ jsxs(YStack, { gap: "$3", p: "$4", children: [
3007
- /* @__PURE__ */ jsx(FieldRow, { label: "Content", children: /* @__PURE__ */ jsx(FieldTextArea, { value: content, onChange: setContent, disabled: saving }) }),
3008
- /* @__PURE__ */ jsx(FieldRow, { label: "Channel", children: /* @__PURE__ */ jsx(FieldSelect, { value: channel, options: channels, onChange: setChannel, disabled: saving }) }),
3009
- /* @__PURE__ */ jsx(FieldRow, { label: "When", children: /* @__PURE__ */ jsx(
3010
- FieldSelect,
3011
- {
3012
- value: mode,
3013
- options: [...COMPOSE_MODES],
3014
- onChange: (v) => setMode(v),
3015
- disabled: saving
3016
- }
3017
- ) }),
3018
- mode === "schedule" ? /* @__PURE__ */ jsx(FieldRow, { label: "Schedule at", children: /* @__PURE__ */ jsx(
3019
- FieldText,
3020
- {
3021
- value: scheduleAt,
3022
- onChange: setScheduleAt,
3023
- placeholder: "2026-07-15 09:00",
3024
- disabled: saving
3025
- }
3026
- ) }) : null,
3027
- unconfigured ? /* @__PURE__ */ jsxs(XStack, { items: "flex-start", gap: "$2", children: [
3028
- /* @__PURE__ */ jsx(AlertTriangle, { size: 14, color: "var(--yellow10)" }),
3029
- /* @__PURE__ */ jsxs(Text, { fontSize: "$1", color: "$color10", children: [
3030
- channel,
3031
- " isn\u2019t configured to publish yet \u2014 needs ",
3032
- cap?.missingCredentials.join(", "),
3033
- ". The post is saved and marked failed on publish until credentials are supplied."
3034
- ] })
3035
- ] }) : null,
3036
- error ? /* @__PURE__ */ jsx(Text, { fontSize: "$2", color: "$red10", children: error }) : null,
3037
- /* @__PURE__ */ jsx(PrimaryButton, { onPress: submit, disabled: saving, children: saving ? "Working\u2026" : COMPOSE_LABEL[mode] })
3038
- ] });
3039
- }
3040
- function ProviderReadinessList({ providers }) {
3041
- return /* @__PURE__ */ jsxs(YStack, { gap: "$2", children: [
3042
- /* @__PURE__ */ jsx(Text, { fontSize: "$2", color: "$color10", children: "Network publish-readiness" }),
3043
- providers.map((p) => /* @__PURE__ */ jsxs(XStack, { items: "center", justify: "space-between", gap: "$3", py: "$1", children: [
3044
- /* @__PURE__ */ jsxs(XStack, { items: "center", gap: "$2", children: [
3045
- p.credentialsConfigured ? /* @__PURE__ */ jsx(CheckCircle2, { size: 14, color: "var(--green10)" }) : /* @__PURE__ */ jsx(AlertTriangle, { size: 14, color: "var(--yellow10)" }),
3046
- /* @__PURE__ */ jsx(Text, { fontSize: "$2", children: p.provider })
3047
- ] }),
3048
- /* @__PURE__ */ jsx(Text, { fontSize: "$1", color: "$color10", children: p.credentialsConfigured ? "Ready" : `needs ${p.missingCredentials.join(", ")}` })
3049
- ] }, p.provider))
3050
- ] });
3051
- }
3052
- function SocialSummaryBar({ summary }) {
3053
- const cells = [
3054
- { label: "Posts", value: summary.posts },
3055
- { label: "Scheduled", value: summary.scheduled },
3056
- { label: "Published", value: summary.published },
3057
- { label: "Accounts", value: summary.accounts }
3058
- ];
3059
- return /* @__PURE__ */ jsx(XStack, { gap: "$3", flexWrap: "wrap", children: cells.map((c) => /* @__PURE__ */ jsxs(
3060
- YStack,
3061
- {
3062
- gap: "$1",
3063
- borderWidth: 1,
3064
- borderColor: "$borderColor",
3065
- rounded: "$4",
3066
- px: "$4",
3067
- py: "$3",
3068
- minW: 140,
3069
- children: [
3070
- /* @__PURE__ */ jsx(Text, { fontSize: "$1", color: "$color10", children: c.label }),
3071
- /* @__PURE__ */ jsx(Text, { fontSize: "$6", fontWeight: "500", className: "hz-tnum", children: c.value })
3072
- ]
3073
- },
3074
- c.label
3075
- )) });
3076
- }
3077
- var OPTIONS = [
3078
- { id: "list", label: "List", icon: List },
3079
- { id: "calendar", label: "Calendar", icon: Calendar }
3080
- ];
3081
- function ViewToggle({
3082
- view,
3083
- onChange
3084
- }) {
3085
- return /* @__PURE__ */ jsx(XStack, { borderWidth: 1, borderColor: "$borderColor", rounded: "$4", overflow: "hidden", children: OPTIONS.map((o) => {
3086
- const Icon = o.icon;
3087
- const active = view === o.id;
3088
- return /* @__PURE__ */ jsxs(
3089
- XStack,
3090
- {
3091
- items: "center",
3092
- gap: "$2",
3093
- px: "$3",
3094
- py: "$2",
3095
- cursor: "pointer",
3096
- bg: active ? "$color4" : "transparent",
3097
- hoverStyle: { bg: active ? "$color4" : "$color2" },
3098
- onPress: () => onChange(o.id),
3099
- children: [
3100
- /* @__PURE__ */ jsx(Icon, { size: 14 }),
3101
- /* @__PURE__ */ jsx(Text, { fontSize: "$2", fontWeight: active ? "500" : "400", children: o.label })
3102
- ]
3103
- },
3104
- o.id
3105
- );
3106
- }) });
3107
- }
3108
- var POST_COLUMNS = [
3109
- { key: "content", header: "Post", render: (p) => postPreview(p.content) },
3110
- { key: "channel", header: "Channel", render: (p) => p.channel || "\u2014" },
3111
- { key: "status", header: "Status", render: (p) => /* @__PURE__ */ jsx(StatusTag, { status: p.status }) },
3112
- { key: "scheduleAt", header: "Scheduled", render: (p) => formatPostTime(p.scheduleAt) }
3113
- ];
3114
- var ACCOUNT_COLUMNS = [
3115
- { key: "handle", header: "Account", render: (a) => a.handle || "\u2014" },
3116
- { key: "provider", header: "Network", render: (a) => a.provider || "\u2014" },
3117
- { key: "status", header: "Status", render: (a) => /* @__PURE__ */ jsx(StatusTag, { status: a.status }) }
3118
- ];
3119
- function PostDetail({ api, post, onChanged }) {
3120
- const [publishing, setPublishing] = useState(false);
3121
- const [error, setError] = useState(null);
3122
- const canPublish = post.status === "draft" || post.status === "scheduled" || post.status === "failed";
3123
- const publish = async () => {
3124
- setPublishing(true);
3125
- setError(null);
3126
- try {
3127
- await api.posts.publish(post.id);
3128
- onChanged();
3129
- } catch (e) {
3130
- setError(classifyBackend(e).message || "Publish failed.");
3131
- } finally {
3132
- setPublishing(false);
3133
- }
3134
- };
3135
- return /* @__PURE__ */ jsxs(YStack, { gap: "$3", p: "$4", children: [
3136
- /* @__PURE__ */ jsx(FieldRow, { label: "Content", children: /* @__PURE__ */ jsx(Text, { fontSize: "$3", children: post.content || "\u2014" }) }),
3137
- /* @__PURE__ */ jsx(FieldRow, { label: "Channel", children: /* @__PURE__ */ jsx(Text, { fontSize: "$3", children: post.channel }) }),
3138
- /* @__PURE__ */ jsx(FieldRow, { label: "Status", children: /* @__PURE__ */ jsx(StatusTag, { status: post.status }) }),
3139
- post.scheduleAt > 0 ? /* @__PURE__ */ jsx(FieldRow, { label: "Scheduled", children: /* @__PURE__ */ jsx(Text, { fontSize: "$3", children: formatPostTime(post.scheduleAt) }) }) : null,
3140
- post.media.length > 0 ? /* @__PURE__ */ jsx(FieldRow, { label: "Media", children: /* @__PURE__ */ jsx(YStack, { gap: "$1", children: post.media.map((m) => /* @__PURE__ */ jsx(Text, { fontSize: "$2", color: "$color11", children: m }, m)) }) }) : null,
3141
- post.externalId ? /* @__PURE__ */ jsx(FieldRow, { label: "External id", children: /* @__PURE__ */ jsx(Text, { fontSize: "$3", className: "hz-tnum", children: post.externalId }) }) : null,
3142
- post.error ? /* @__PURE__ */ jsx(FieldRow, { label: "Last error", children: /* @__PURE__ */ jsx(Text, { fontSize: "$2", color: "$red10", children: post.error }) }) : null,
3143
- error ? /* @__PURE__ */ jsx(Text, { fontSize: "$2", color: "$red10", children: error }) : null,
3144
- canPublish ? /* @__PURE__ */ jsx(PrimaryButton, { onPress: publish, disabled: publishing, icon: /* @__PURE__ */ jsx(Send, { size: 16 }), children: publishing ? "Publishing\u2026" : "Publish now" }) : null
3145
- ] });
3146
- }
3147
- function ConnectAccount({
3148
- api,
3149
- providers,
3150
- onCreated
3151
- }) {
3152
- const [provider, setProvider] = useState("x");
3153
- const [handle, setHandle] = useState("");
3154
- const [saving, setSaving] = useState(false);
3155
- const [error, setError] = useState(null);
3156
- const submit = async () => {
3157
- setSaving(true);
3158
- setError(null);
3159
- try {
3160
- await api.accounts.create({ provider, handle: handle.trim(), status: "connected" });
3161
- onCreated();
3162
- } catch (e) {
3163
- setError(classifyBackend(e).message || "Failed to connect account.");
3164
- } finally {
3165
- setSaving(false);
3166
- }
3167
- };
3168
- return /* @__PURE__ */ jsxs(YStack, { gap: "$4", p: "$4", children: [
3169
- /* @__PURE__ */ jsx(ProviderReadinessList, { providers }),
3170
- /* @__PURE__ */ jsxs(YStack, { gap: "$3", children: [
3171
- /* @__PURE__ */ jsx(FieldRow, { label: "Network", children: /* @__PURE__ */ jsx(FieldSelect, { value: provider, options: [...PROVIDERS], onChange: setProvider, disabled: saving }) }),
3172
- /* @__PURE__ */ jsx(FieldRow, { label: "Handle", children: /* @__PURE__ */ jsx(FieldText, { value: handle, onChange: setHandle, placeholder: "@hanzo", disabled: saving }) }),
3173
- error ? /* @__PURE__ */ jsx(Text, { fontSize: "$2", color: "$red10", children: error }) : null,
3174
- /* @__PURE__ */ jsx(PrimaryButton, { onPress: submit, disabled: saving, children: saving ? "Connecting\u2026" : "Connect account" })
3175
- ] })
3176
- ] });
3177
- }
3178
- function SocialResource({
3179
- api,
3180
- title = "Publish",
3181
- subtitle = "Compose, schedule and publish your content across networks \u2014 per org, over the native /v1/social engine."
3182
- }) {
3183
- const [state, setState] = useState({ phase: "loading" });
3184
- const [view, setView] = useState("list");
3185
- const [composing, setComposing] = useState(false);
3186
- const [connecting, setConnecting] = useState(false);
3187
- const [openPost, setOpenPost] = useState(null);
3188
- const load = useCallback(async () => {
3189
- setState({ phase: "loading" });
3190
- try {
3191
- const [summary, posts2, accounts2, providers2] = await Promise.all([
3192
- api.summary(),
3193
- api.posts.list(),
3194
- api.accounts.list(),
3195
- api.providers()
3196
- ]);
3197
- setState({ phase: "ready", data: { summary, posts: posts2, accounts: accounts2, providers: providers2 } });
3198
- } catch (e) {
3199
- setState({ phase: "error", error: classifyBackend(e) });
3200
- }
3201
- }, [api]);
3202
- useEffect(() => {
3203
- void load();
3204
- }, [load]);
3205
- const providers = state.phase === "ready" ? state.data.providers : [];
3206
- const posts = state.phase === "ready" ? state.data.posts : [];
3207
- const accounts = state.phase === "ready" ? state.data.accounts : [];
3208
- const empty = state.phase === "ready" && posts.length === 0 && accounts.length === 0;
3209
- const submitDraft = async (draft, mode) => {
3210
- try {
3211
- const created = await api.posts.create(draft);
3212
- if (mode === "now" && created.status === "failed") return created.error || "Publish failed.";
3213
- } catch (e) {
3214
- return classifyBackend(e).message || "Failed to create post.";
3215
- }
3216
- setComposing(false);
3217
- void load();
3218
- return null;
3219
- };
3220
- return /* @__PURE__ */ jsxs(YStack, { gap: "$4", p: "$4", children: [
3221
- /* @__PURE__ */ jsx(
3222
- PageHeader,
3223
- {
3224
- title,
3225
- subtitle,
3226
- actions: /* @__PURE__ */ jsxs(Fragment, { children: [
3227
- /* @__PURE__ */ jsx(PrimaryButton, { onPress: () => setComposing(true), icon: /* @__PURE__ */ jsx(Plus, { size: 16 }), children: "New post" }),
3228
- /* @__PURE__ */ jsx(PrimaryButton, { onPress: () => setConnecting(true), icon: /* @__PURE__ */ jsx(Link2, { size: 16 }), children: "Connect account" }),
3229
- /* @__PURE__ */ jsx(PrimaryButton, { onPress: () => void load(), icon: /* @__PURE__ */ jsx(RefreshCw, { size: 16 }), children: "Refresh" })
3230
- ] })
3231
- }
3232
- ),
3233
- state.phase === "error" ? /* @__PURE__ */ jsx(BackendStateCard, { state: state.error, onRetry: () => void load() }) : empty ? /* @__PURE__ */ jsxs(YStack, { gap: "$4", children: [
3234
- state.phase === "ready" ? /* @__PURE__ */ jsx(SocialSummaryBar, { summary: state.data.summary }) : null,
3235
- /* @__PURE__ */ jsx(
3236
- EmptyState,
3237
- {
3238
- icon: Share2,
3239
- title: "No posts or accounts yet",
3240
- description: "Connect a social account, then compose, schedule and publish across X, Instagram, LinkedIn, TikTok and more.",
3241
- primary: { label: "New post", onPress: () => setComposing(true) }
3242
- }
3243
- )
3244
- ] }) : /* @__PURE__ */ jsxs(YStack, { gap: "$5", children: [
3245
- state.phase === "ready" ? /* @__PURE__ */ jsx(SocialSummaryBar, { summary: state.data.summary }) : null,
3246
- /* @__PURE__ */ jsxs(YStack, { gap: "$3", children: [
3247
- /* @__PURE__ */ jsxs(XStack, { items: "center", justify: "space-between", gap: "$2", flexWrap: "wrap", children: [
3248
- /* @__PURE__ */ jsxs(XStack, { items: "center", gap: "$2", children: [
3249
- /* @__PURE__ */ jsx(Send, { size: 16 }),
3250
- /* @__PURE__ */ jsx(Text, { fontSize: "$5", fontWeight: "500", children: "Posts" })
3251
- ] }),
3252
- /* @__PURE__ */ jsx(ViewToggle, { view, onChange: setView })
3253
- ] }),
3254
- view === "list" ? /* @__PURE__ */ jsx(
3255
- DataTable,
3256
- {
3257
- columns: POST_COLUMNS,
3258
- rows: posts,
3259
- loading: state.phase === "loading",
3260
- empty: "No posts yet.",
3261
- rowKey: (p) => p.id,
3262
- onRowPress: (p) => setOpenPost(p)
3263
- }
3264
- ) : /* @__PURE__ */ jsx(PostAgenda, { posts, onOpen: (p) => setOpenPost(p) })
3265
- ] }),
3266
- /* @__PURE__ */ jsxs(YStack, { gap: "$2", children: [
3267
- /* @__PURE__ */ jsxs(XStack, { items: "center", gap: "$2", children: [
3268
- /* @__PURE__ */ jsx(Link2, { size: 16 }),
3269
- /* @__PURE__ */ jsx(Text, { fontSize: "$5", fontWeight: "500", children: "Accounts" })
3270
- ] }),
3271
- /* @__PURE__ */ jsx(
3272
- DataTable,
3273
- {
3274
- columns: ACCOUNT_COLUMNS,
3275
- rows: accounts,
3276
- loading: state.phase === "loading",
3277
- empty: "No accounts connected yet.",
3278
- rowKey: (a) => a.id
3279
- }
3280
- )
3281
- ] })
3282
- ] }),
3283
- /* @__PURE__ */ jsx(SlideOver, { open: composing, onClose: () => setComposing(false), title: "New post", icon: Send, ariaLabel: "New post", children: /* @__PURE__ */ jsx(PostComposer, { channels: [...PROVIDERS], providers, onSubmit: submitDraft }) }),
3284
- /* @__PURE__ */ jsx(
3285
- SlideOver,
3286
- {
3287
- open: connecting,
3288
- onClose: () => setConnecting(false),
3289
- title: "Connect account",
3290
- icon: Link2,
3291
- ariaLabel: "Connect account",
3292
- children: /* @__PURE__ */ jsx(
3293
- ConnectAccount,
3294
- {
3295
- api,
3296
- providers,
3297
- onCreated: () => {
3298
- setConnecting(false);
3299
- void load();
3300
- }
3301
- }
3302
- )
3303
- }
3304
- ),
3305
- /* @__PURE__ */ jsx(SlideOver, { open: openPost !== null, onClose: () => setOpenPost(null), title: "Post", icon: Send, ariaLabel: "Post detail", children: openPost ? /* @__PURE__ */ jsx(
3306
- PostDetail,
3307
- {
3308
- api,
3309
- post: openPost,
3310
- onChanged: () => {
3311
- setOpenPost(null);
3312
- void load();
3313
- }
3314
- }
3315
- ) : null })
3316
- ] });
3317
- }
3318
- var META = {
3319
- x: { label: "X", bg: "#0f0f12", fg: "#e6e6ea", mark: "\u{1D54F}" },
3320
- facebook: { label: "Facebook", bg: "#1877f2", fg: "#ffffff", mark: "f" },
3321
- instagram: { label: "Instagram", bg: "#e1306c", fg: "#ffffff", mark: "IG" },
3322
- linkedin: { label: "LinkedIn", bg: "#0a66c2", fg: "#ffffff", mark: "in" },
3323
- tiktok: { label: "TikTok", bg: "#111114", fg: "#25f4ee", mark: "TT" },
3324
- youtube: { label: "YouTube", bg: "#ff0000", fg: "#ffffff", mark: "\u25B6" },
3325
- threads: { label: "Threads", bg: "#111114", fg: "#e6e6ea", mark: "@" }
3326
- };
3327
- function ChannelBadge({
3328
- channel,
3329
- showLabel = false,
3330
- size = 22
3331
- }) {
3332
- const m = META[channel] ?? META.x;
3333
- return /* @__PURE__ */ jsxs(XStack, { items: "center", gap: "$2", children: [
3334
- /* @__PURE__ */ jsx(
3335
- YStack,
3336
- {
3337
- width: size,
3338
- height: size,
3339
- items: "center",
3340
- justify: "center",
3341
- rounded: "$2",
3342
- bg: m.bg,
3343
- children: /* @__PURE__ */ jsx(Text, { fontSize: "$1", fontWeight: "800", color: m.fg, children: m.mark })
3344
- }
3345
- ),
3346
- showLabel ? /* @__PURE__ */ jsx(Text, { fontSize: "$3", color: "$color12", children: m.label }) : null
3347
- ] });
3348
- }
3349
- var money = (cents) => `$${Math.round((cents || 0) / 100).toLocaleString()}`;
3350
- function CampaignCard({ campaign }) {
3351
- const pct = campaign.budget > 0 ? Math.min(100, campaign.spend / campaign.budget * 100) : 0;
3352
- return /* @__PURE__ */ jsxs(Card, { p: "$4", gap: "$3", borderWidth: 1, borderColor: "$borderColor", width: "100%", children: [
3353
- /* @__PURE__ */ jsxs(XStack, { items: "flex-start", justify: "space-between", gap: "$2", children: [
3354
- /* @__PURE__ */ jsxs(YStack, { gap: "$1", children: [
3355
- /* @__PURE__ */ jsx(Text, { fontSize: "$4", fontWeight: "700", children: campaign.name }),
3356
- /* @__PURE__ */ jsx(Text, { fontSize: "$2", color: "$color11", children: campaign.channel })
3357
- ] }),
3358
- /* @__PURE__ */ jsx(StatusTag, { status: campaign.status })
3359
- ] }),
3360
- campaign.objective ? /* @__PURE__ */ jsx(Text, { fontSize: "$2", color: "$color11", children: campaign.objective }) : null,
3361
- /* @__PURE__ */ jsxs(YStack, { gap: "$1.5", children: [
3362
- /* @__PURE__ */ jsxs(XStack, { justify: "space-between", children: [
3363
- /* @__PURE__ */ jsxs(Text, { fontSize: "$1", color: "$color11", children: [
3364
- money(campaign.spend),
3365
- " spent"
3366
- ] }),
3367
- /* @__PURE__ */ jsxs(Text, { fontSize: "$1", color: "$color11", children: [
3368
- money(campaign.budget),
3369
- " budget"
3370
- ] })
3371
- ] }),
3372
- /* @__PURE__ */ jsx(YStack, { height: 6, rounded: "$2", bg: "$color3", overflow: "hidden", children: /* @__PURE__ */ jsx(YStack, { height: 6, rounded: "$2", bg: "$color9", width: `${pct}%` }) })
3373
- ] })
3374
- ] });
3375
- }
3376
- function PostCard({
3377
- post,
3378
- onEdit,
3379
- onDelete
3380
- }) {
3381
- const mediaCount = post.media?.length ?? 0;
3382
- return /* @__PURE__ */ jsxs(Card, { p: "$3", gap: "$2.5", borderWidth: 1, borderColor: "$borderColor", width: "100%", children: [
3383
- /* @__PURE__ */ jsxs(XStack, { items: "center", justify: "space-between", gap: "$2", children: [
3384
- /* @__PURE__ */ jsxs(XStack, { items: "center", gap: "$2", children: [
3385
- /* @__PURE__ */ jsx(ChannelBadge, { channel: post.channel }),
3386
- /* @__PURE__ */ jsx(StatusTag, { status: post.status })
3387
- ] }),
3388
- /* @__PURE__ */ jsxs(XStack, { gap: "$1", children: [
3389
- onEdit ? /* @__PURE__ */ jsx(Button, { size: "$2", chromeless: true, icon: /* @__PURE__ */ jsx(Pencil, { size: 15 }), onPress: () => onEdit(post) }) : null,
3390
- onDelete ? /* @__PURE__ */ jsx(Button, { size: "$2", chromeless: true, icon: /* @__PURE__ */ jsx(Trash2, { size: 15 }), onPress: () => onDelete(post) }) : null
3391
- ] })
3392
- ] }),
3393
- /* @__PURE__ */ jsx(Text, { fontSize: "$3", color: "$color12", children: post.content }),
3394
- /* @__PURE__ */ jsxs(XStack, { items: "center", justify: "space-between", gap: "$2", children: [
3395
- post.scheduleAt ? /* @__PURE__ */ jsx(Text, { fontSize: "$1", color: "$color11", children: formatPostTime(post.scheduleAt) }) : /* @__PURE__ */ jsx(YStack, {}),
3396
- mediaCount ? /* @__PURE__ */ jsxs(Text, { fontSize: "$1", color: "$color10", children: [
3397
- mediaCount,
3398
- " media"
3399
- ] }) : null
3400
- ] })
3401
- ] });
3402
- }
3403
-
3404
- export { ACCOUNT_STATUSES, AnimatedLogo, AppHeader, BRANDS, BackendStateCard, BarChart, BarRows, BrandMark, CHART_OTHER, CHART_PALETTE, COMPOSE_MODES, CampaignCard, ChannelBadge, ComboBox, CommerceResource, ConfirmDelete, ContextMenu, DataTable, Donut, Donut2 as DonutRing, DropdownMenu, EmptyState, FadeIn, FieldRow, FieldSelect, FieldSlider, FieldSwitch, FieldText, FieldTextArea, FloatingMenu, GenericLogo, HANZO, HANZO_MARK_CONTENT, HanzoMark, HintButton, HostProvider, LUX, LegendDot, LineChart, MenuItemView, MenuLabelView, MenuPanel, MenuSeparatorView, MetricCard, Sparkline2 as MetricSparkline, MiniBars, OrgMark, OrgSwitcher, PARS, POST_STATUSES, PROVIDERS, PageHeader, Panel, PortalTheme, PostAgenda, PostCard, PostComposer, PrimaryButton, ProductIcon, ProviderLogo, ProviderReadinessList, Reorder, SERIES, LG as SLIDEOVER_LG, SURFACES, SearchInput, Segmented, SelectMenu, SiteFooter, SiteNav, SlideOver, SocialResource, SocialSummaryBar, Sparkline, StatusTag, ToastProvider, UtilBar, ViewToggle, ZOO, accentFor, asColor, classifyBackend, classifyRead, colorForIndex, contrastText, createSocialApi, filterOptions, filterOrgs, formatPostTime, isHexColor, isKnownOption, monogram, normalizeAccount, normalizeAccounts, normalizePost, normalizePosts, normalizeProviderCapability, normalizeProviders, normalizeSummary, orgScope, otherSurfaces, parsePostTime, postDayBucket, postPreview, providerInitials, renderMenuItems, resolveAccent, resolveBrand, rowShift, setOrgAccent, targetIndex, useAccent, useContainerWidth, useHost, useToast, utilColor };
2186
+ export { AnimatedLogo, AppHeader, BRANDS, BarChart, BarRows, BrandMark, CHART_OTHER, CHART_PALETTE, ComboBox, CommerceResource, ConfirmDelete, ContextMenu, Donut, Donut2 as DonutRing, DropdownMenu, FadeIn, FloatingMenu, GenericLogo, HANZO, HANZO_MARK_CONTENT, HanzoMark, HintButton, LUX, LegendDot, LineChart, MenuItemView, MenuLabelView, MenuPanel, MenuSeparatorView, MetricCard, Sparkline2 as MetricSparkline, MiniBars, OrgMark, OrgSwitcher, PARS, Panel, PortalTheme, ProductIcon, ProviderLogo, Reorder, SERIES, SURFACES, SearchInput, Segmented, SelectMenu, SiteFooter, SiteNav, Sparkline, ToastProvider, UtilBar, ZOO, colorForIndex, filterOptions, filterOrgs, isKnownOption, monogram, orgScope, otherSurfaces, providerInitials, renderMenuItems, resolveBrand, rowShift, targetIndex, useContainerWidth, useToast, utilColor };
3405
2187
  //# sourceMappingURL=index.js.map
3406
2188
  //# sourceMappingURL=index.js.map