@proteos/ui 0.50.1 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -610,7 +610,7 @@ function IconPicker({
610
610
  const [query, setQuery] = react.useState("");
611
611
  const [limit, setLimit] = react.useState(GRID_PAGE);
612
612
  const triggerRef = react.useRef(null);
613
- const styles3 = fieldControlStyles({ size, invalid: isInvalid, appearance });
613
+ const styles4 = fieldControlStyles({ size, invalid: isInvalid, appearance });
614
614
  const selectedName = resolveLucideIconName(value);
615
615
  const SelectedIcon = selectedName ? lucideReact.icons[selectedName] : null;
616
616
  const matches2 = react.useMemo(() => {
@@ -655,7 +655,7 @@ function IconPicker({
655
655
  onClick: () => open(!isOpen),
656
656
  "data-invalid": isInvalid || void 0,
657
657
  className: chunkMWAXK66H_cjs.cn(
658
- styles3.box(),
658
+ styles4.box(),
659
659
  "flex shrink-0 items-center justify-center cursor-pointer",
660
660
  appearance === "cell" ? "size-[29px]" : COMPACT_SIZE[size],
661
661
  "disabled:cursor-not-allowed disabled:opacity-45"
@@ -676,8 +676,8 @@ function IconPicker({
676
676
  className: chunkMWAXK66H_cjs.cn(
677
677
  // box carries no padding by contract — content is what gives a
678
678
  // single-element control its interior (padding, font, text-size).
679
- styles3.box(),
680
- styles3.content(),
679
+ styles4.box(),
680
+ styles4.content(),
681
681
  "flex w-full items-center gap-2 text-left cursor-pointer",
682
682
  "disabled:cursor-not-allowed disabled:opacity-45"
683
683
  ),
@@ -809,9 +809,7 @@ var badgeStyles = tailwindVariants.tv({
809
809
  base: [
810
810
  "inline-flex items-center gap-1.5",
811
811
  "font-mono text-[11.5px] tracking-[-0.005em]",
812
- "px-2.5 py-0.5 rounded-pill border",
813
- // Leading dot
814
- 'before:content-[""] before:block before:size-1.5 before:rounded-full'
812
+ "px-2.5 py-0.5 border"
815
813
  ],
816
814
  variants: {
817
815
  variant: {
@@ -845,9 +843,18 @@ var badgeStyles = tailwindVariants.tv({
845
843
  "border-[color-mix(in_oklab,var(--badge-color)_35%,var(--color-rule))]",
846
844
  "bg-[color-mix(in_oklab,var(--badge-color)_12%,var(--color-surface))]"
847
845
  ]
846
+ },
847
+ shape: {
848
+ pill: "rounded-pill",
849
+ rounded: "rounded-chip"
850
+ },
851
+ // Leading dot — its color comes from the register's `before:bg-*`.
852
+ hasDot: {
853
+ true: 'before:content-[""] before:block before:size-1.5 before:rounded-full',
854
+ false: ""
848
855
  }
849
856
  },
850
- defaultVariants: { variant: "default" }
857
+ defaultVariants: { variant: "default", shape: "pill", hasDot: true }
851
858
  });
852
859
  var ICON_TONE = {
853
860
  default: "text-ink-4",
@@ -858,16 +865,31 @@ var ICON_TONE = {
858
865
  danger: "text-danger",
859
866
  custom: "text-[var(--badge-color)]"
860
867
  };
861
- function Badge({ variant, color, icon, className, style, children, ...props }) {
868
+ function Badge({
869
+ variant,
870
+ shape,
871
+ hasDot,
872
+ color,
873
+ icon,
874
+ className,
875
+ style,
876
+ children,
877
+ ...props
878
+ }) {
862
879
  const Icon = icon ? resolveLucideIcon(icon) : null;
863
880
  const register2 = color ? "custom" : variant ?? "default";
864
881
  const mergedStyle = color ? { ...style, "--badge-color": color } : style;
882
+ const showDot = hasDot !== false && !Icon;
865
883
  return /* @__PURE__ */ jsxRuntime.jsxs(
866
884
  "span",
867
885
  {
868
886
  ...props,
869
887
  style: mergedStyle,
870
- className: chunkMWAXK66H_cjs.cn(badgeStyles({ variant: register2 }), Icon ? "before:hidden" : null, className),
888
+ className: chunkMWAXK66H_cjs.cn(
889
+ badgeStyles({ variant: register2, shape, hasDot }),
890
+ showDot ? null : "before:hidden",
891
+ className
892
+ ),
871
893
  children: [
872
894
  Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { "aria-hidden": true, className: chunkMWAXK66H_cjs.cn("size-3 shrink-0", ICON_TONE[register2]) }) : null,
873
895
  children
@@ -878,6 +900,8 @@ function Badge({ variant, color, icon, className, style, children, ...props }) {
878
900
  function badgeChrome(option) {
879
901
  return {
880
902
  ...option.variant ? { variant: option.variant } : {},
903
+ ...option.shape ? { shape: option.shape } : {},
904
+ ...option.hasDot !== void 0 ? { hasDot: option.hasDot } : {},
881
905
  ...option.color ? { color: option.color } : {},
882
906
  ...option.icon ? { icon: option.icon } : {}
883
907
  };
@@ -898,7 +922,7 @@ function BadgeMultiSelect({
898
922
  autoFocus = false,
899
923
  className
900
924
  }) {
901
- const styles3 = fieldControlStyles({ size, invalid: isInvalid, appearance });
925
+ const styles4 = fieldControlStyles({ size, invalid: isInvalid, appearance });
902
926
  const focusWithin = appearance === "cell" ? "focus-within:border-accent focus-within:shadow-none" : "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]";
903
927
  const minHeight = appearance === "cell" ? "min-h-[29px]" : fieldMinHeight[size];
904
928
  const [isOpen, setIsOpen] = react.useState(false);
@@ -938,7 +962,7 @@ function BadgeMultiSelect({
938
962
  "data-invalid": isInvalid || void 0,
939
963
  "data-disabled": isDisabled || void 0,
940
964
  className: chunkMWAXK66H_cjs.cn(
941
- styles3.box(),
965
+ styles4.box(),
942
966
  "flex flex-wrap items-center gap-1.5 cursor-pointer",
943
967
  minHeight,
944
968
  fieldChipPadding[size],
@@ -1024,13 +1048,11 @@ function BadgeMultiSelect({
1024
1048
  }
1025
1049
  function RemovableBadge({
1026
1050
  children,
1027
- variant,
1028
- color,
1029
- icon,
1030
1051
  onRemove,
1031
- isDisabled
1052
+ isDisabled,
1053
+ ...chrome
1032
1054
  }) {
1033
- return /* @__PURE__ */ jsxRuntime.jsxs(Badge, { ...badgeChrome({ variant, color, icon }), children: [
1055
+ return /* @__PURE__ */ jsxRuntime.jsxs(Badge, { ...badgeChrome(chrome), children: [
1034
1056
  /* @__PURE__ */ jsxRuntime.jsx("span", { children }),
1035
1057
  /* @__PURE__ */ jsxRuntime.jsx(
1036
1058
  "button",
@@ -1384,7 +1406,7 @@ function ColorInput({
1384
1406
  }, [committed]);
1385
1407
  const isDraftInvalid = draft.trim() !== "" && normalizeHexColor(draft) === null;
1386
1408
  const invalid = isInvalid || isDraftInvalid;
1387
- const styles3 = fieldControlStyles({ size, invalid, appearance });
1409
+ const styles4 = fieldControlStyles({ size, invalid, appearance });
1388
1410
  const focusWithin = appearance === "cell" ? "focus-within:border-accent focus-within:shadow-none" : "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]";
1389
1411
  const edit = (next) => {
1390
1412
  setDraft(next);
@@ -1425,7 +1447,7 @@ function ColorInput({
1425
1447
  {
1426
1448
  "data-disabled": isDisabled || void 0,
1427
1449
  className: chunkMWAXK66H_cjs.cn(
1428
- styles3.box(),
1450
+ styles4.box(),
1429
1451
  "flex items-center gap-2",
1430
1452
  size === "sm" ? "pl-2" : "pl-2.5",
1431
1453
  focusWithin
@@ -1472,7 +1494,7 @@ function ColorInput({
1472
1494
  spellCheck: false,
1473
1495
  autoComplete: "off",
1474
1496
  className: chunkMWAXK66H_cjs.cn(
1475
- styles3.content(),
1497
+ styles4.content(),
1476
1498
  "min-w-0 flex-1 bg-transparent font-mono outline-none",
1477
1499
  "pl-0",
1478
1500
  fieldTextStyles[size]
@@ -1505,7 +1527,7 @@ function Combobox({
1505
1527
  allowsEmptyCollection = true,
1506
1528
  ...props
1507
1529
  }) {
1508
- const styles3 = fieldControlStyles({ size, appearance });
1530
+ const styles4 = fieldControlStyles({ size, appearance });
1509
1531
  const focusWithin = appearance === "cell" ? "focus-within:border-accent focus-within:shadow-none" : "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]";
1510
1532
  return /* @__PURE__ */ jsxRuntime.jsxs(
1511
1533
  reactAriaComponents.ComboBox,
@@ -1524,7 +1546,7 @@ function Combobox({
1524
1546
  className: chunkMWAXK66H_cjs.cn(
1525
1547
  // Box chrome on the wrapper; the inner <input> carries the padding
1526
1548
  // + font so the chevron button sits inside the same border + ring.
1527
- styles3.box(),
1549
+ styles4.box(),
1528
1550
  "flex items-center gap-1 pr-2",
1529
1551
  focusWithin,
1530
1552
  inputWrapperClassName
@@ -1536,7 +1558,7 @@ function Combobox({
1536
1558
  placeholder,
1537
1559
  className: chunkMWAXK66H_cjs.cn(
1538
1560
  "flex-1 min-w-0 bg-transparent outline-none",
1539
- styles3.content(),
1561
+ styles4.content(),
1540
1562
  inputClassName
1541
1563
  )
1542
1564
  }
@@ -1904,46 +1926,509 @@ function Command({ combo, target, className, children }) {
1904
1926
  discoveryActive ? /* @__PURE__ */ jsxRuntime.jsx(
1905
1927
  "div",
1906
1928
  {
1907
- "aria-hidden": true,
1908
- className: "absolute -inset-2 rounded-md bg-[color-mix(in_oklab,var(--color-ink)_28%,transparent)] pointer-events-none transition-opacity z-40",
1909
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-2.5 -left-2 pointer-events-none z-50", children: /* @__PURE__ */ jsxRuntime.jsx(CommandHint, { combo, tone: "prominent" }) })
1929
+ "aria-hidden": true,
1930
+ className: "absolute -inset-2 rounded-md bg-[color-mix(in_oklab,var(--color-ink)_28%,transparent)] pointer-events-none transition-opacity z-40",
1931
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-2.5 -left-2 pointer-events-none z-50", children: /* @__PURE__ */ jsxRuntime.jsx(CommandHint, { combo, tone: "prominent" }) })
1932
+ }
1933
+ ) : null
1934
+ ] });
1935
+ }
1936
+ var stack = [];
1937
+ var listenerInstalled2 = false;
1938
+ function onWindowKeyDown2(event) {
1939
+ if (event.key !== "Escape") return;
1940
+ if (isEditableTarget(event.target)) return;
1941
+ const top = stack[stack.length - 1];
1942
+ if (!top) return;
1943
+ top.handler(event);
1944
+ }
1945
+ function ensureListener2() {
1946
+ if (listenerInstalled2) return;
1947
+ if (typeof window === "undefined") return;
1948
+ window.addEventListener("keydown", onWindowKeyDown2, { capture: true });
1949
+ listenerInstalled2 = true;
1950
+ }
1951
+ function useEscapeKey(handler, options) {
1952
+ const enabled = options?.enabled ?? true;
1953
+ const handlerRef = react.useRef(handler);
1954
+ react.useEffect(() => {
1955
+ handlerRef.current = handler;
1956
+ });
1957
+ react.useEffect(() => {
1958
+ if (!enabled) return void 0;
1959
+ ensureListener2();
1960
+ const entry = {
1961
+ handler: (event) => handlerRef.current(event)
1962
+ };
1963
+ stack.push(entry);
1964
+ return () => {
1965
+ const idx = stack.lastIndexOf(entry);
1966
+ if (idx >= 0) stack.splice(idx, 1);
1967
+ };
1968
+ }, [enabled]);
1969
+ }
1970
+ var conversationBriefCardStyles = tailwindVariants.tv({
1971
+ slots: {
1972
+ root: [
1973
+ "flex items-center gap-2.5 rounded-md border border-accent/40 px-3 py-2",
1974
+ "bg-[color-mix(in_oklab,var(--color-accent)_6%,var(--color-surface))]"
1975
+ ],
1976
+ icon: [
1977
+ "grid size-8 shrink-0 place-items-center rounded-full text-accent",
1978
+ "bg-[color-mix(in_oklab,var(--color-accent)_12%,transparent)]"
1979
+ ],
1980
+ body: "min-w-0 flex-1",
1981
+ eyebrow: "font-mono text-[10px] uppercase tracking-[0.08em] text-accent",
1982
+ title: "truncate text-[13px] font-medium text-ink",
1983
+ summary: "truncate text-[12px] text-ink-3",
1984
+ action: [
1985
+ "shrink-0 cursor-pointer rounded-sm border border-accent/50 px-2.5 py-1",
1986
+ "font-mono text-[11px] text-accent outline-none",
1987
+ "hover:bg-[color-mix(in_oklab,var(--color-accent)_12%,transparent)]",
1988
+ "focus-visible:shadow-[var(--shadow-focus)]",
1989
+ "disabled:cursor-default disabled:opacity-50"
1990
+ ],
1991
+ outcome: "shrink-0 font-mono text-[11px] text-ink-3"
1992
+ }
1993
+ });
1994
+ var styles = conversationBriefCardStyles();
1995
+ var CONVERSATION_BRIEF_OUTCOME_LABEL = {
1996
+ used: "Call held",
1997
+ discarded: "Discarded"
1998
+ };
1999
+ function ConversationBriefCard({
2000
+ title,
2001
+ summary,
2002
+ eyebrow = "Conversation brief \u2014 prepared",
2003
+ openLabel = "Open Brief",
2004
+ outcome,
2005
+ onOpen,
2006
+ isOpenDisabled = false,
2007
+ className
2008
+ }) {
2009
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn(styles.root(), className), children: [
2010
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.icon(), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { className: "size-4", "aria-hidden": true }) }),
2011
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.body(), children: [
2012
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles.eyebrow(), children: eyebrow }),
2013
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles.title(), children: title }),
2014
+ summary ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles.summary(), children: summary }) : null
2015
+ ] }),
2016
+ outcome ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.outcome(), children: CONVERSATION_BRIEF_OUTCOME_LABEL[outcome] }) : /* @__PURE__ */ jsxRuntime.jsx(
2017
+ reactAriaComponents.Button,
2018
+ {
2019
+ onPress: onOpen ?? (() => {
2020
+ }),
2021
+ isDisabled: isOpenDisabled,
2022
+ className: styles.action(),
2023
+ children: openLabel
2024
+ }
2025
+ )
2026
+ ] });
2027
+ }
2028
+ function Select({
2029
+ label,
2030
+ description,
2031
+ errorMessage,
2032
+ placeholder = "Select\u2026",
2033
+ options,
2034
+ renderItem,
2035
+ size,
2036
+ appearance,
2037
+ triggerClassName,
2038
+ popoverClassName,
2039
+ className,
2040
+ ...props
2041
+ }) {
2042
+ const styles4 = fieldControlStyles({ size, appearance });
2043
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2044
+ reactAriaComponents.Select,
2045
+ {
2046
+ ...props,
2047
+ className: (renderProps) => chunkMWAXK66H_cjs.cn(
2048
+ "grid grid-cols-1 gap-1.5",
2049
+ typeof className === "function" ? className(renderProps) : className
2050
+ ),
2051
+ children: [
2052
+ label ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Label, { className: fieldLabelStyles, children: label }) : null,
2053
+ /* @__PURE__ */ jsxRuntime.jsxs(
2054
+ reactAriaComponents.Button,
2055
+ {
2056
+ className: chunkMWAXK66H_cjs.cn(
2057
+ styles4.box(),
2058
+ styles4.content(),
2059
+ "flex items-center justify-between gap-3 text-left cursor-pointer",
2060
+ triggerClassName
2061
+ ),
2062
+ children: [
2063
+ /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.SelectValue, { className: "truncate", children: ({ defaultChildren, isPlaceholder }) => isPlaceholder ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-4", children: placeholder }) : defaultChildren }),
2064
+ /* @__PURE__ */ jsxRuntime.jsx(FieldCaret, {})
2065
+ ]
2066
+ }
2067
+ ),
2068
+ description ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Text, { slot: "description", className: fieldHintStyles, children: description }) : null,
2069
+ errorMessage && appearance !== "cell" ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.FieldError, { className: fieldErrorStyles, children: errorMessage }) : null,
2070
+ /* @__PURE__ */ jsxRuntime.jsxs(
2071
+ reactAriaComponents.Popover,
2072
+ {
2073
+ offset: 6,
2074
+ className: chunkMWAXK66H_cjs.cn(
2075
+ // Match the trigger width exactly (RAC exposes --trigger-width on
2076
+ // the Popover when anchored to a Select button).
2077
+ "w-[var(--trigger-width)]",
2078
+ // Float above modals + full-screen editors (e.g. agent-studio's
2079
+ // .as-editor z-1000 / a raised modal overlay), matching Menu's z-[1200].
2080
+ "z-[1300]",
2081
+ "rounded-md border border-rule bg-surface p-1",
2082
+ "shadow-[var(--shadow-raised)]",
2083
+ "entering:animate-in entering:fade-in-0 entering:slide-in-from-top-1",
2084
+ "exiting:animate-out exiting:fade-out-0 exiting:slide-out-to-top-1",
2085
+ popoverClassName
2086
+ ),
2087
+ children: [
2088
+ /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.ListBox, { className: "outline-none max-h-72 overflow-auto", children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
2089
+ SelectItem,
2090
+ {
2091
+ id: option.id,
2092
+ ...option.textValue ? { textValue: option.textValue } : {},
2093
+ ...option.isDisabled ? { isDisabled: true } : {},
2094
+ children: renderItem ? renderItem(option) : option.label
2095
+ },
2096
+ option.id
2097
+ )) }),
2098
+ options.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkMWAXK66H_cjs.cn("px-3 py-2", fieldHintStyles), children: placeholder }) : null
2099
+ ]
2100
+ }
2101
+ )
2102
+ ]
2103
+ }
2104
+ );
2105
+ }
2106
+ function SelectItem(props) {
2107
+ return /* @__PURE__ */ jsxRuntime.jsx(
2108
+ reactAriaComponents.ListBoxItem,
2109
+ {
2110
+ ...props,
2111
+ className: chunkMWAXK66H_cjs.cn(
2112
+ "flex items-center justify-between gap-3",
2113
+ "rounded-[6px] px-3 py-2 text-[14px] text-ink-2",
2114
+ "cursor-pointer outline-none select-none",
2115
+ "data-[hovered]:bg-surface-2 data-[hovered]:text-ink",
2116
+ "data-[focused]:bg-surface-2 data-[focused]:text-ink",
2117
+ "data-[selected]:bg-surface-3 data-[selected]:text-ink",
2118
+ "data-[disabled]:opacity-45 data-[disabled]:cursor-not-allowed"
2119
+ )
2120
+ }
2121
+ );
2122
+ }
2123
+
2124
+ // src/components/conversation-brief-card/types.ts
2125
+ function conversationBriefOutcomeFor(status) {
2126
+ if (status === "used" || status === "discarded") return status;
2127
+ return null;
2128
+ }
2129
+ function isDialableConversationBrief(brief) {
2130
+ return !brief.channel || brief.channel === "phone";
2131
+ }
2132
+ function contactPhoneNumbers(contact) {
2133
+ const numbers = [];
2134
+ for (const address of contact?.addresses ?? []) {
2135
+ if (address.kind !== "phone" || !address.value) continue;
2136
+ if (!numbers.includes(address.value)) numbers.push(address.value);
2137
+ }
2138
+ return numbers;
2139
+ }
2140
+ function ConversationBriefPreview({
2141
+ brief,
2142
+ contacts,
2143
+ onCall,
2144
+ isCallDisabled = false,
2145
+ callDisabledReason,
2146
+ controls,
2147
+ isCallButtonHidden = false,
2148
+ onSelectionChange,
2149
+ callLabel = "Call",
2150
+ className,
2151
+ contentClassName
2152
+ }) {
2153
+ const [pickedContactId, setPickedContactId] = react.useState("");
2154
+ const contact = contacts.find((entry) => entry.id === pickedContactId) ?? contacts[0] ?? null;
2155
+ const numbers = react.useMemo(() => contactPhoneNumbers(contact), [contact]);
2156
+ const [pickedNumber, setPickedNumber] = react.useState("");
2157
+ const phoneNumber = numbers.includes(pickedNumber) ? pickedNumber : numbers[0] || "";
2158
+ const isOpen = brief.status === "prepared";
2159
+ const names = contacts.map((entry) => entry.name).filter(Boolean).join(", ");
2160
+ const onSelectionChangeRef = react.useRef(onSelectionChange);
2161
+ onSelectionChangeRef.current = onSelectionChange;
2162
+ react.useEffect(() => {
2163
+ onSelectionChangeRef.current?.(contact, phoneNumber);
2164
+ }, [contact, phoneNumber]);
2165
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn("flex flex-col gap-3", className), children: [
2166
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
2167
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[14px] font-semibold text-ink", children: brief.subject || names || "Prepared conversation" }),
2168
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-[10.5px] text-ink-4", children: [
2169
+ brief.subject ? names : "",
2170
+ brief.channel ? `Channel ${brief.channel}` : "Any channel",
2171
+ brief.type_key ? `Type ${brief.type_key}` : "",
2172
+ brief.status === "prepared" ? "Prepared" : brief.status === "used" ? "Call held" : "Discarded"
2173
+ ].filter(Boolean).join(" \xB7 ") })
2174
+ ] }),
2175
+ /* @__PURE__ */ jsxRuntime.jsx(
2176
+ "div",
2177
+ {
2178
+ className: chunkMWAXK66H_cjs.cn(
2179
+ "whitespace-pre-wrap rounded-md border border-rule-2 bg-surface-2/60 px-3 py-2.5",
2180
+ "text-[13px] leading-relaxed text-ink-2 overflow-y-auto [scrollbar-width:thin]",
2181
+ contentClassName
2182
+ ),
2183
+ children: brief.content
2184
+ }
2185
+ ),
2186
+ onCall ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 border-t border-rule-2 pt-3", children: [
2187
+ contacts.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
2188
+ Select,
2189
+ {
2190
+ "aria-label": "Who to call",
2191
+ selectedKey: contact?.id ?? "",
2192
+ onSelectionChange: (key) => {
2193
+ setPickedContactId(String(key));
2194
+ setPickedNumber("");
2195
+ },
2196
+ options: contacts.map((entry) => ({ id: entry.id, label: entry.name || entry.id }))
2197
+ }
2198
+ ) : null,
2199
+ numbers.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(
2200
+ Select,
2201
+ {
2202
+ "aria-label": "Number to call",
2203
+ selectedKey: phoneNumber,
2204
+ onSelectionChange: (key) => setPickedNumber(String(key)),
2205
+ options: numbers.map((number) => ({ id: number, label: number }))
2206
+ }
2207
+ ) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-[12px] text-ink-3", children: phoneNumber || (contact ? "This contact has no phone number on file." : "No contact to call.") }),
2208
+ controls,
2209
+ callDisabledReason ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[12px] text-warning", children: callDisabledReason }) : null,
2210
+ isCallButtonHidden ? null : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(
2211
+ chunkMWAXK66H_cjs.Button,
2212
+ {
2213
+ isDisabled: isCallDisabled || !isOpen || phoneNumber === "" || !contact,
2214
+ onPress: () => contact && onCall(contact, phoneNumber),
2215
+ children: [
2216
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { className: "size-3.5", "aria-hidden": true }),
2217
+ callLabel
2218
+ ]
2219
+ }
2220
+ ) })
2221
+ ] }) : null
2222
+ ] });
2223
+ }
2224
+ function Modal(props) {
2225
+ return /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.DialogTrigger, { ...props });
2226
+ }
2227
+ function ModalContent({
2228
+ children,
2229
+ className,
2230
+ modalClassName,
2231
+ isDismissable = true,
2232
+ ...props
2233
+ }) {
2234
+ return /* @__PURE__ */ jsxRuntime.jsx(
2235
+ reactAriaComponents.ModalOverlay,
2236
+ {
2237
+ isDismissable,
2238
+ ...props,
2239
+ className: (renderProps) => chunkMWAXK66H_cjs.cn(
2240
+ "fixed inset-0 z-50 flex items-center justify-center p-4",
2241
+ // Warm ink scrim — stays in the Proteos palette (no pure black).
2242
+ "bg-[color-mix(in_oklab,var(--color-ink)_40%,transparent)]",
2243
+ "entering:animate-in entering:fade-in-0 entering:duration-150",
2244
+ "exiting:animate-out exiting:fade-out-0 exiting:duration-100",
2245
+ typeof className === "function" ? className(renderProps) : className
2246
+ ),
2247
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2248
+ reactAriaComponents.Modal,
2249
+ {
2250
+ className: chunkMWAXK66H_cjs.cn(
2251
+ "w-full max-w-lg",
2252
+ // Cap the panel at the viewport (minus the overlay's p-4) and lay it
2253
+ // out as a column so a tall body scrolls instead of overflowing the
2254
+ // screen. Short modals are unaffected — height still tracks content.
2255
+ "flex flex-col max-h-[calc(100dvh-2rem)]",
2256
+ "bg-surface border border-rule rounded-lg",
2257
+ "shadow-[var(--shadow-float)]",
2258
+ "entering:animate-in entering:zoom-in-95 entering:slide-in-from-top-2 entering:duration-150",
2259
+ "exiting:animate-out exiting:zoom-out-95 exiting:duration-100",
2260
+ modalClassName
2261
+ ),
2262
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Dialog, { className: "outline-none flex flex-col min-h-0 overflow-hidden", children })
2263
+ }
2264
+ )
2265
+ }
2266
+ );
2267
+ }
2268
+ function ModalHeader({ className, ...props }) {
2269
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ...props, className: chunkMWAXK66H_cjs.cn("shrink-0 px-5 pt-5 pb-3 flex flex-col gap-1.5", className) });
2270
+ }
2271
+ function ModalTitle({ className, ...props }) {
2272
+ return /* @__PURE__ */ jsxRuntime.jsx(
2273
+ reactAriaComponents.Heading,
2274
+ {
2275
+ slot: "title",
2276
+ ...props,
2277
+ className: chunkMWAXK66H_cjs.cn(
2278
+ "font-sans font-medium text-[20px] leading-[1.25] tracking-[-0.015em] text-ink",
2279
+ className
2280
+ )
2281
+ }
2282
+ );
2283
+ }
2284
+ function ModalDescription({ className, ...props }) {
2285
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { ...props, className: chunkMWAXK66H_cjs.cn("text-[14px] leading-[1.55] text-ink-3", className) });
2286
+ }
2287
+ function ModalBody({ className, ...props }) {
2288
+ return /* @__PURE__ */ jsxRuntime.jsx(
2289
+ "div",
2290
+ {
2291
+ ...props,
2292
+ className: chunkMWAXK66H_cjs.cn(
2293
+ // The scroll region: caps at the panel's spare height and scrolls when
2294
+ // the content is taller, leaving header + footer pinned.
2295
+ "min-h-0 overflow-y-auto px-5 py-3 flex flex-col gap-3 text-[14px] text-ink-2",
2296
+ className
2297
+ )
2298
+ }
2299
+ );
2300
+ }
2301
+ function ModalFooter({ className, ...props }) {
2302
+ return /* @__PURE__ */ jsxRuntime.jsx(
2303
+ "div",
2304
+ {
2305
+ ...props,
2306
+ className: chunkMWAXK66H_cjs.cn("shrink-0 flex justify-end items-center gap-2", "px-5 pt-3 pb-5", className)
2307
+ }
2308
+ );
2309
+ }
2310
+ function ConversationBriefReview({
2311
+ conversationBriefId,
2312
+ client,
2313
+ onOpenCall,
2314
+ onCall,
2315
+ isCallDisabled = false,
2316
+ callDisabledReason,
2317
+ onOutcome,
2318
+ onLoadError,
2319
+ modalTitle = "Prepared conversation",
2320
+ modalClassName = "max-w-2xl",
2321
+ overlayClassName,
2322
+ openLabel,
2323
+ className
2324
+ }) {
2325
+ const [brief, setBrief] = react.useState(null);
2326
+ const [contacts, setContacts] = react.useState([]);
2327
+ const [isOpen, setIsOpen] = react.useState(false);
2328
+ const [outcome, setOutcome] = react.useState(null);
2329
+ const onOutcomeRef = react.useRef(onOutcome);
2330
+ onOutcomeRef.current = onOutcome;
2331
+ const onLoadErrorRef = react.useRef(onLoadError);
2332
+ onLoadErrorRef.current = onLoadError;
2333
+ const hasSettledRef = react.useRef(false);
2334
+ const settle = react.useCallback((next, settled) => {
2335
+ setOutcome(next);
2336
+ setIsOpen(false);
2337
+ if (hasSettledRef.current) return;
2338
+ hasSettledRef.current = true;
2339
+ onOutcomeRef.current?.(next, settled);
2340
+ }, []);
2341
+ react.useEffect(() => {
2342
+ let cancelled = false;
2343
+ void (async () => {
2344
+ try {
2345
+ const loaded = await client.getConversationBrief(conversationBriefId);
2346
+ if (cancelled) return;
2347
+ setBrief(loaded);
2348
+ const terminal = conversationBriefOutcomeFor(loaded.status);
2349
+ if (terminal) settle(terminal, loaded);
2350
+ const people = await Promise.all(
2351
+ loaded.contact_ids.map((contactId) => client.getContact(contactId).catch(() => null))
2352
+ );
2353
+ if (!cancelled) setContacts(people.filter((person) => person !== null));
2354
+ } catch (error) {
2355
+ if (cancelled) return;
2356
+ onLoadErrorRef.current?.(error instanceof Error ? error : new Error(String(error)));
2357
+ }
2358
+ })();
2359
+ return () => {
2360
+ cancelled = true;
2361
+ };
2362
+ }, [client, conversationBriefId, settle]);
2363
+ const open = () => {
2364
+ if (onOpenCall) {
2365
+ onOpenCall(conversationBriefId);
2366
+ return;
2367
+ }
2368
+ setIsOpen(true);
2369
+ };
2370
+ if (!brief) return null;
2371
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2372
+ /* @__PURE__ */ jsxRuntime.jsx(
2373
+ ConversationBriefCard,
2374
+ {
2375
+ title: brief.subject || namesOf(contacts) || "Prepared conversation",
2376
+ summary: summaryFor(brief, contacts),
2377
+ outcome,
2378
+ onOpen: open,
2379
+ ...openLabel !== void 0 ? { openLabel } : {},
2380
+ ...className !== void 0 ? { className } : {}
2381
+ }
2382
+ ),
2383
+ onOpenCall ? null : /* @__PURE__ */ jsxRuntime.jsxs(
2384
+ ModalContent,
2385
+ {
2386
+ isOpen,
2387
+ onOpenChange: setIsOpen,
2388
+ modalClassName,
2389
+ ...overlayClassName !== void 0 ? { className: overlayClassName } : {},
2390
+ children: [
2391
+ /* @__PURE__ */ jsxRuntime.jsx(ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: modalTitle }) }),
2392
+ /* @__PURE__ */ jsxRuntime.jsx(ModalBody, { className: "min-h-0 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
2393
+ ConversationBriefPreview,
2394
+ {
2395
+ brief,
2396
+ contacts,
2397
+ contentClassName: "max-h-[50dvh]",
2398
+ isCallDisabled,
2399
+ ...callDisabledReason !== void 0 ? { callDisabledReason } : {},
2400
+ ...onCall && isDialableConversationBrief(brief) ? {
2401
+ onCall: (contact, phoneNumber) => {
2402
+ setIsOpen(false);
2403
+ onCall(brief, contact, phoneNumber);
2404
+ }
2405
+ } : {}
2406
+ }
2407
+ ) })
2408
+ ]
1910
2409
  }
1911
- ) : null
2410
+ )
1912
2411
  ] });
1913
2412
  }
1914
- var stack = [];
1915
- var listenerInstalled2 = false;
1916
- function onWindowKeyDown2(event) {
1917
- if (event.key !== "Escape") return;
1918
- if (isEditableTarget(event.target)) return;
1919
- const top = stack[stack.length - 1];
1920
- if (!top) return;
1921
- top.handler(event);
2413
+ function namesOf(contacts) {
2414
+ return contacts.map((contact) => contact.name).filter(Boolean).join(", ");
1922
2415
  }
1923
- function ensureListener2() {
1924
- if (listenerInstalled2) return;
1925
- if (typeof window === "undefined") return;
1926
- window.addEventListener("keydown", onWindowKeyDown2, { capture: true });
1927
- listenerInstalled2 = true;
2416
+ function summaryFor(brief, contacts) {
2417
+ const firstLine = brief.content.split("\n").find((line) => line.trim() !== "")?.trim() ?? "";
2418
+ return [
2419
+ brief.subject ? namesOf(contacts) : "",
2420
+ brief.channel ?? "",
2421
+ brief.type_key ?? "",
2422
+ firstLine
2423
+ ].filter(Boolean).join(" \xB7 ");
1928
2424
  }
1929
- function useEscapeKey(handler, options) {
1930
- const enabled = options?.enabled ?? true;
1931
- const handlerRef = react.useRef(handler);
1932
- react.useEffect(() => {
1933
- handlerRef.current = handler;
1934
- });
1935
- react.useEffect(() => {
1936
- if (!enabled) return void 0;
1937
- ensureListener2();
1938
- const entry = {
1939
- handler: (event) => handlerRef.current(event)
1940
- };
1941
- stack.push(entry);
1942
- return () => {
1943
- const idx = stack.lastIndexOf(entry);
1944
- if (idx >= 0) stack.splice(idx, 1);
1945
- };
1946
- }, [enabled]);
2425
+
2426
+ // src/components/conversation-brief-card/create-conversation-brief-client.ts
2427
+ function createConversationBriefClient(conversation) {
2428
+ return {
2429
+ getConversationBrief: (conversationBriefId) => conversation.conversationBriefs.get(conversationBriefId),
2430
+ getContact: (contactId) => conversation.contacts.get(contactId)
2431
+ };
1947
2432
  }
1948
2433
  function CurrencyInput({
1949
2434
  value,
@@ -1976,16 +2461,16 @@ function CurrencyInput({
1976
2461
  onChange({ amount: nextAmount, currency_code: nextCode });
1977
2462
  };
1978
2463
  const selectedSymbol = currencyOptions.find((option) => option.code === code)?.symbol ?? code;
1979
- const styles3 = fieldControlStyles({ size, appearance, ...isInvalid ? { invalid: true } : {} });
2464
+ const styles4 = fieldControlStyles({ size, appearance, ...isInvalid ? { invalid: true } : {} });
1980
2465
  const focusWithin = appearance === "cell" ? "focus-within:border-accent focus-within:shadow-none" : "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]";
1981
2466
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn("grid grid-cols-1 gap-1.5", className), children: [
1982
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn(styles3.box(), "flex items-center gap-1 pr-1", focusWithin), children: [
2467
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn(styles4.box(), "flex items-center gap-1 pr-1", focusWithin), children: [
1983
2468
  /* @__PURE__ */ jsxRuntime.jsx(
1984
2469
  "input",
1985
2470
  {
1986
2471
  className: chunkMWAXK66H_cjs.cn(
1987
2472
  "min-w-0 flex-1 bg-transparent text-ink outline-none tabular-nums",
1988
- styles3.content(),
2473
+ styles4.content(),
1989
2474
  // Sit a touch lower than a standard field by trimming the vertical
1990
2475
  // padding (cell mode keeps the fixed 29px row-editor height).
1991
2476
  appearance === "cell" ? "" : size === "sm" ? "py-1" : "py-1.5"
@@ -2651,7 +3136,9 @@ function DataTable({
2651
3136
  selectionMode = "none",
2652
3137
  selectedIds,
2653
3138
  onSelectionChange,
2654
- columnBorders = false
3139
+ columnBorders = false,
3140
+ groupBy,
3141
+ groupHeaderHeight
2655
3142
  }) {
2656
3143
  const rows = react.useMemo(() => {
2657
3144
  const pages = query.data?.pages;
@@ -2770,6 +3257,24 @@ function DataTable({
2770
3257
  });
2771
3258
  const tableRows = table.getRowModel().rows;
2772
3259
  const tableRowCount = tableRows.length;
3260
+ const listItems = react.useMemo(() => {
3261
+ if (!groupBy) {
3262
+ return tableRows.map((row, dataIndex) => ({ kind: "row", row, dataIndex }));
3263
+ }
3264
+ const items = [];
3265
+ let currentGroupId = null;
3266
+ tableRows.forEach((row, dataIndex) => {
3267
+ const group = groupBy(row.original);
3268
+ if (group && group.id !== currentGroupId) {
3269
+ currentGroupId = group.id;
3270
+ items.push({ kind: "group", id: group.id, label: group.label });
3271
+ } else if (!group) {
3272
+ currentGroupId = null;
3273
+ }
3274
+ items.push({ kind: "row", row, dataIndex });
3275
+ });
3276
+ return items;
3277
+ }, [tableRows, groupBy]);
2773
3278
  const scrollerRef = react.useRef(null);
2774
3279
  react.useEffect(() => {
2775
3280
  scrollerRef.current?.scrollTo({ top: 0 });
@@ -2780,10 +3285,11 @@ function DataTable({
2780
3285
  const top = listRef.current?.offsetTop ?? 0;
2781
3286
  setListOffset((prev) => prev === top ? prev : top);
2782
3287
  });
3288
+ const headingHeight = groupHeaderHeight ?? rowHeight;
2783
3289
  const virtualizer = reactVirtual.useVirtualizer({
2784
- count: tableRowCount,
3290
+ count: listItems.length,
2785
3291
  getScrollElement: () => scrollerRef.current,
2786
- estimateSize: () => rowHeight,
3292
+ estimateSize: (index) => listItems[index]?.kind === "group" ? headingHeight : rowHeight,
2787
3293
  overscan,
2788
3294
  scrollMargin: listOffset
2789
3295
  });
@@ -2890,8 +3396,8 @@ function DataTable({
2890
3396
  role: "presentation",
2891
3397
  style: { height: totalSize, position: "relative", width: "100%" },
2892
3398
  children: virtualItems.map((vRow) => {
2893
- const row = tableRows[vRow.index];
2894
- if (!row) return null;
3399
+ const item = listItems[vRow.index];
3400
+ if (!item) return null;
2895
3401
  const rowStyle = {
2896
3402
  // Items' `start` includes the virtualizer's scrollMargin
2897
3403
  // (the list's offset below the sticky header); subtract
@@ -2899,18 +3405,21 @@ function DataTable({
2899
3405
  transform: `translateY(${vRow.start - listOffset}px)`,
2900
3406
  height: vRow.size
2901
3407
  };
3408
+ if (item.kind === "group") {
3409
+ return /* @__PURE__ */ jsxRuntime.jsx(GroupHeaderRow, { style: rowStyle, children: item.label }, `group:${item.id}`);
3410
+ }
2902
3411
  return /* @__PURE__ */ jsxRuntime.jsx(
2903
3412
  DataRow,
2904
3413
  {
2905
- row,
2906
- index: vRow.index,
3414
+ row: item.row,
3415
+ index: item.dataIndex,
2907
3416
  zebra,
2908
3417
  onRowClick,
2909
3418
  style: rowStyle,
2910
3419
  columnBorders,
2911
3420
  ...rowWrapper ? { rowWrapper } : {}
2912
3421
  },
2913
- row.id
3422
+ item.row.id
2914
3423
  );
2915
3424
  })
2916
3425
  }
@@ -2924,6 +3433,20 @@ function DataTable({
2924
3433
  }
2925
3434
  );
2926
3435
  }
3436
+ function GroupHeaderRow({ style, children }) {
3437
+ return /* @__PURE__ */ jsxRuntime.jsx(
3438
+ TableRow,
3439
+ {
3440
+ absolute: true,
3441
+ style,
3442
+ className: chunkMWAXK66H_cjs.cn(
3443
+ "bg-surface-2 border-b border-rule",
3444
+ "font-mono text-[11px] uppercase tracking-[0.06em] text-ink-3"
3445
+ ),
3446
+ children: /* @__PURE__ */ jsxRuntime.jsx(TableCell, { className: "gap-2 text-inherit", children })
3447
+ }
3448
+ );
3449
+ }
2927
3450
  function DataRow({
2928
3451
  row,
2929
3452
  index,
@@ -3156,7 +3679,7 @@ function DatePicker({
3156
3679
  className,
3157
3680
  ...props
3158
3681
  }) {
3159
- const styles3 = fieldControlStyles({ size, appearance });
3682
+ const styles4 = fieldControlStyles({ size, appearance });
3160
3683
  const focusWithin = appearance === "cell" ? "focus-within:border-accent focus-within:shadow-none" : "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]";
3161
3684
  return /* @__PURE__ */ jsxRuntime.jsxs(
3162
3685
  reactAriaComponents.DatePicker,
@@ -3174,7 +3697,7 @@ function DatePicker({
3174
3697
  className: chunkMWAXK66H_cjs.cn(
3175
3698
  // Box chrome on the wrapper; the DateInput inside carries padding +
3176
3699
  // font so the calendar trigger sits inside the same border + ring.
3177
- styles3.box(),
3700
+ styles4.box(),
3178
3701
  "flex items-center gap-1 pr-1",
3179
3702
  focusWithin
3180
3703
  ),
@@ -3184,7 +3707,7 @@ function DatePicker({
3184
3707
  {
3185
3708
  className: chunkMWAXK66H_cjs.cn(
3186
3709
  "flex-1 flex items-center min-w-0 text-ink",
3187
- styles3.content(),
3710
+ styles4.content(),
3188
3711
  // Tabular alignment for date segments — overrides content's
3189
3712
  // font-sans on purpose.
3190
3713
  "font-mono"
@@ -3306,7 +3829,7 @@ function DateTimePicker({
3306
3829
  shouldCloseOnSelect = false,
3307
3830
  ...props
3308
3831
  }) {
3309
- const styles3 = fieldControlStyles({ size, appearance });
3832
+ const styles4 = fieldControlStyles({ size, appearance });
3310
3833
  const focusWithin = appearance === "cell" ? "focus-within:border-accent focus-within:shadow-none" : "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]";
3311
3834
  const timeGranularity = granularity === "day" ? "minute" : granularity;
3312
3835
  const { hourCycle } = props;
@@ -3329,7 +3852,7 @@ function DateTimePicker({
3329
3852
  className: chunkMWAXK66H_cjs.cn(
3330
3853
  // Box chrome on the wrapper; the DateInput inside carries padding +
3331
3854
  // font so the calendar trigger sits inside the same border + ring.
3332
- styles3.box(),
3855
+ styles4.box(),
3333
3856
  "flex items-center gap-1 pr-1",
3334
3857
  focusWithin
3335
3858
  ),
@@ -3339,7 +3862,7 @@ function DateTimePicker({
3339
3862
  {
3340
3863
  className: chunkMWAXK66H_cjs.cn(
3341
3864
  "flex-1 flex items-center min-w-0 text-ink",
3342
- styles3.content(),
3865
+ styles4.content(),
3343
3866
  // Tabular alignment for date/time segments — overrides content's
3344
3867
  // font-sans on purpose.
3345
3868
  "font-mono"
@@ -3423,7 +3946,7 @@ var draftMessageCardStyles = tailwindVariants.tv({
3423
3946
  outcome: "shrink-0 font-mono text-[11px] text-ink-3"
3424
3947
  }
3425
3948
  });
3426
- var styles = draftMessageCardStyles();
3949
+ var styles2 = draftMessageCardStyles();
3427
3950
  var DRAFT_OUTCOME_LABEL = {
3428
3951
  sent: "Sent",
3429
3952
  rejected: "Rejected",
@@ -3440,23 +3963,23 @@ function DraftMessageCard({
3440
3963
  isPreviewDisabled = false,
3441
3964
  className
3442
3965
  }) {
3443
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn(styles.root(), className), children: [
3444
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.icon(), children: /* @__PURE__ */ jsxRuntime.jsx(ChannelIcon, { channel }) }),
3445
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.body(), children: [
3446
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles.eyebrow(), children: eyebrow }),
3447
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles.title(), children: title }),
3448
- recipients && recipients.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: styles.recipients(), children: [
3966
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn(styles2.root(), className), children: [
3967
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles2.icon(), children: /* @__PURE__ */ jsxRuntime.jsx(ChannelIcon, { channel }) }),
3968
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles2.body(), children: [
3969
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles2.eyebrow(), children: eyebrow }),
3970
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles2.title(), children: title }),
3971
+ recipients && recipients.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: styles2.recipients(), children: [
3449
3972
  "To ",
3450
3973
  recipients.join(", ")
3451
3974
  ] }) : null
3452
3975
  ] }),
3453
- outcome ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.outcome(), children: DRAFT_OUTCOME_LABEL[outcome] }) : /* @__PURE__ */ jsxRuntime.jsx(
3976
+ outcome ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles2.outcome(), children: DRAFT_OUTCOME_LABEL[outcome] }) : /* @__PURE__ */ jsxRuntime.jsx(
3454
3977
  reactAriaComponents.Button,
3455
3978
  {
3456
3979
  onPress: onPreview ?? (() => {
3457
3980
  }),
3458
3981
  isDisabled: isPreviewDisabled,
3459
- className: styles.action(),
3982
+ className: styles2.action(),
3460
3983
  children: previewLabel
3461
3984
  }
3462
3985
  )
@@ -3531,7 +4054,7 @@ function MultiSelect({
3531
4054
  appearance,
3532
4055
  className
3533
4056
  }) {
3534
- const styles3 = fieldControlStyles({ size, invalid: isInvalid, appearance });
4057
+ const styles4 = fieldControlStyles({ size, invalid: isInvalid, appearance });
3535
4058
  const focusWithin = appearance === "cell" ? "focus-within:border-accent focus-within:shadow-none" : "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]";
3536
4059
  const minHeight = appearance === "cell" ? "min-h-[29px]" : fieldMinHeight[size];
3537
4060
  const [isOpen, setIsOpen] = react.useState(false);
@@ -3578,7 +4101,7 @@ function MultiSelect({
3578
4101
  "data-invalid": isInvalid || void 0,
3579
4102
  "data-disabled": isDisabled || void 0,
3580
4103
  className: chunkMWAXK66H_cjs.cn(
3581
- styles3.box(),
4104
+ styles4.box(),
3582
4105
  "flex flex-wrap items-center gap-1.5 cursor-pointer",
3583
4106
  minHeight,
3584
4107
  fieldChipPadding[size],
@@ -3814,101 +4337,6 @@ function RecipientSelect({
3814
4337
  }
3815
4338
  );
3816
4339
  }
3817
- function Select({
3818
- label,
3819
- description,
3820
- errorMessage,
3821
- placeholder = "Select\u2026",
3822
- options,
3823
- renderItem,
3824
- size,
3825
- appearance,
3826
- triggerClassName,
3827
- popoverClassName,
3828
- className,
3829
- ...props
3830
- }) {
3831
- const styles3 = fieldControlStyles({ size, appearance });
3832
- return /* @__PURE__ */ jsxRuntime.jsxs(
3833
- reactAriaComponents.Select,
3834
- {
3835
- ...props,
3836
- className: (renderProps) => chunkMWAXK66H_cjs.cn(
3837
- "grid grid-cols-1 gap-1.5",
3838
- typeof className === "function" ? className(renderProps) : className
3839
- ),
3840
- children: [
3841
- label ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Label, { className: fieldLabelStyles, children: label }) : null,
3842
- /* @__PURE__ */ jsxRuntime.jsxs(
3843
- reactAriaComponents.Button,
3844
- {
3845
- className: chunkMWAXK66H_cjs.cn(
3846
- styles3.box(),
3847
- styles3.content(),
3848
- "flex items-center justify-between gap-3 text-left cursor-pointer",
3849
- triggerClassName
3850
- ),
3851
- children: [
3852
- /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.SelectValue, { className: "truncate", children: ({ defaultChildren, isPlaceholder }) => isPlaceholder ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ink-4", children: placeholder }) : defaultChildren }),
3853
- /* @__PURE__ */ jsxRuntime.jsx(FieldCaret, {})
3854
- ]
3855
- }
3856
- ),
3857
- description ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Text, { slot: "description", className: fieldHintStyles, children: description }) : null,
3858
- errorMessage && appearance !== "cell" ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.FieldError, { className: fieldErrorStyles, children: errorMessage }) : null,
3859
- /* @__PURE__ */ jsxRuntime.jsxs(
3860
- reactAriaComponents.Popover,
3861
- {
3862
- offset: 6,
3863
- className: chunkMWAXK66H_cjs.cn(
3864
- // Match the trigger width exactly (RAC exposes --trigger-width on
3865
- // the Popover when anchored to a Select button).
3866
- "w-[var(--trigger-width)]",
3867
- // Float above modals + full-screen editors (e.g. agent-studio's
3868
- // .as-editor z-1000 / a raised modal overlay), matching Menu's z-[1200].
3869
- "z-[1300]",
3870
- "rounded-md border border-rule bg-surface p-1",
3871
- "shadow-[var(--shadow-raised)]",
3872
- "entering:animate-in entering:fade-in-0 entering:slide-in-from-top-1",
3873
- "exiting:animate-out exiting:fade-out-0 exiting:slide-out-to-top-1",
3874
- popoverClassName
3875
- ),
3876
- children: [
3877
- /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.ListBox, { className: "outline-none max-h-72 overflow-auto", children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
3878
- SelectItem,
3879
- {
3880
- id: option.id,
3881
- ...option.textValue ? { textValue: option.textValue } : {},
3882
- ...option.isDisabled ? { isDisabled: true } : {},
3883
- children: renderItem ? renderItem(option) : option.label
3884
- },
3885
- option.id
3886
- )) }),
3887
- options.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkMWAXK66H_cjs.cn("px-3 py-2", fieldHintStyles), children: placeholder }) : null
3888
- ]
3889
- }
3890
- )
3891
- ]
3892
- }
3893
- );
3894
- }
3895
- function SelectItem(props) {
3896
- return /* @__PURE__ */ jsxRuntime.jsx(
3897
- reactAriaComponents.ListBoxItem,
3898
- {
3899
- ...props,
3900
- className: chunkMWAXK66H_cjs.cn(
3901
- "flex items-center justify-between gap-3",
3902
- "rounded-[6px] px-3 py-2 text-[14px] text-ink-2",
3903
- "cursor-pointer outline-none select-none",
3904
- "data-[hovered]:bg-surface-2 data-[hovered]:text-ink",
3905
- "data-[focused]:bg-surface-2 data-[focused]:text-ink",
3906
- "data-[selected]:bg-surface-3 data-[selected]:text-ink",
3907
- "data-[disabled]:opacity-45 data-[disabled]:cursor-not-allowed"
3908
- )
3909
- }
3910
- );
3911
- }
3912
4340
  var MAX_COMPOSER_ATTACHMENT_BYTES = 25 * 1024 * 1024;
3913
4341
  var messageComposerStyles = tailwindVariants.tv({
3914
4342
  base: [
@@ -4275,7 +4703,7 @@ var draftMessageComposerStyles = tailwindVariants.tv({
4275
4703
  error: "px-[18px] font-mono text-[11px] text-danger"
4276
4704
  }
4277
4705
  });
4278
- var styles2 = draftMessageComposerStyles();
4706
+ var styles3 = draftMessageComposerStyles();
4279
4707
  function sendRecipientsFromMessage(message, role) {
4280
4708
  return (message.recipients ?? []).filter((recipient) => recipient.role === role && !!recipient.external_id).map((recipient) => ({
4281
4709
  kind: "contact-address",
@@ -4491,10 +4919,10 @@ function DraftMessageComposer({
4491
4919
  [message?.attachments]
4492
4920
  );
4493
4921
  if (phase === "loading") {
4494
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkMWAXK66H_cjs.cn(styles2.root(), className), children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles2.terminal(), children: "Loading draft\u2026" }) });
4922
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkMWAXK66H_cjs.cn(styles3.root(), className), children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles3.terminal(), children: "Loading draft\u2026" }) });
4495
4923
  }
4496
4924
  if (phase === "load-error") {
4497
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkMWAXK66H_cjs.cn(styles2.root(), className), children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: styles2.terminal(), children: [
4925
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkMWAXK66H_cjs.cn(styles3.root(), className), children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: styles3.terminal(), children: [
4498
4926
  loadError ?? "Loading the draft failed.",
4499
4927
  " ",
4500
4928
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -4509,12 +4937,12 @@ function DraftMessageComposer({
4509
4937
  }
4510
4938
  if (phase === "terminal" || !message) {
4511
4939
  const line = terminalKind === "sent" ? "This draft was sent." : terminalKind === "rejected" ? "This draft was rejected." : terminalKind === "failed" ? `Sending failed${message?.error ? ` \u2014 ${message.error}` : ""}.` : "This message is not a reviewable draft.";
4512
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkMWAXK66H_cjs.cn(styles2.root(), className), "data-draft-terminal": terminalKind, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles2.terminal(), children: line }) });
4940
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkMWAXK66H_cjs.cn(styles3.root(), className), "data-draft-terminal": terminalKind, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: styles3.terminal(), children: line }) });
4513
4941
  }
4514
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn(styles2.root(), className), children: [
4515
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles2.header(), children: [
4516
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles2.badge(), children: "Draft \xB7 awaiting review" }),
4517
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles2.sender(), children: [
4942
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn(styles3.root(), className), children: [
4943
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles3.header(), children: [
4944
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles3.badge(), children: "Draft \xB7 awaiting review" }),
4945
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles3.sender(), children: [
4518
4946
  "from ",
4519
4947
  message.sender.name
4520
4948
  ] })
@@ -4545,11 +4973,11 @@ function DraftMessageComposer({
4545
4973
  showSendButton: showActions
4546
4974
  }
4547
4975
  ),
4548
- actionError ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: styles2.error(), children: [
4976
+ actionError ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: styles3.error(), children: [
4549
4977
  actionError,
4550
4978
  " \u2014 your edits are kept."
4551
4979
  ] }) : null,
4552
- showActions ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles2.actions(), children: [
4980
+ showActions ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles3.actions(), children: [
4553
4981
  isConfirmingReject ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
4554
4982
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[12.5px] text-ink-3", children: "Reject draft?" }),
4555
4983
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -4586,92 +5014,6 @@ function DraftMessageComposer({
4586
5014
  ] }) : null
4587
5015
  ] });
4588
5016
  }
4589
- function Modal(props) {
4590
- return /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.DialogTrigger, { ...props });
4591
- }
4592
- function ModalContent({
4593
- children,
4594
- className,
4595
- modalClassName,
4596
- isDismissable = true,
4597
- ...props
4598
- }) {
4599
- return /* @__PURE__ */ jsxRuntime.jsx(
4600
- reactAriaComponents.ModalOverlay,
4601
- {
4602
- isDismissable,
4603
- ...props,
4604
- className: (renderProps) => chunkMWAXK66H_cjs.cn(
4605
- "fixed inset-0 z-50 flex items-center justify-center p-4",
4606
- // Warm ink scrim — stays in the Proteos palette (no pure black).
4607
- "bg-[color-mix(in_oklab,var(--color-ink)_40%,transparent)]",
4608
- "entering:animate-in entering:fade-in-0 entering:duration-150",
4609
- "exiting:animate-out exiting:fade-out-0 exiting:duration-100",
4610
- typeof className === "function" ? className(renderProps) : className
4611
- ),
4612
- children: /* @__PURE__ */ jsxRuntime.jsx(
4613
- reactAriaComponents.Modal,
4614
- {
4615
- className: chunkMWAXK66H_cjs.cn(
4616
- "w-full max-w-lg",
4617
- // Cap the panel at the viewport (minus the overlay's p-4) and lay it
4618
- // out as a column so a tall body scrolls instead of overflowing the
4619
- // screen. Short modals are unaffected — height still tracks content.
4620
- "flex flex-col max-h-[calc(100dvh-2rem)]",
4621
- "bg-surface border border-rule rounded-lg",
4622
- "shadow-[var(--shadow-float)]",
4623
- "entering:animate-in entering:zoom-in-95 entering:slide-in-from-top-2 entering:duration-150",
4624
- "exiting:animate-out exiting:zoom-out-95 exiting:duration-100",
4625
- modalClassName
4626
- ),
4627
- children: /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Dialog, { className: "outline-none flex flex-col min-h-0 overflow-hidden", children })
4628
- }
4629
- )
4630
- }
4631
- );
4632
- }
4633
- function ModalHeader({ className, ...props }) {
4634
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ...props, className: chunkMWAXK66H_cjs.cn("shrink-0 px-5 pt-5 pb-3 flex flex-col gap-1.5", className) });
4635
- }
4636
- function ModalTitle({ className, ...props }) {
4637
- return /* @__PURE__ */ jsxRuntime.jsx(
4638
- reactAriaComponents.Heading,
4639
- {
4640
- slot: "title",
4641
- ...props,
4642
- className: chunkMWAXK66H_cjs.cn(
4643
- "font-sans font-medium text-[20px] leading-[1.25] tracking-[-0.015em] text-ink",
4644
- className
4645
- )
4646
- }
4647
- );
4648
- }
4649
- function ModalDescription({ className, ...props }) {
4650
- return /* @__PURE__ */ jsxRuntime.jsx("p", { ...props, className: chunkMWAXK66H_cjs.cn("text-[14px] leading-[1.55] text-ink-3", className) });
4651
- }
4652
- function ModalBody({ className, ...props }) {
4653
- return /* @__PURE__ */ jsxRuntime.jsx(
4654
- "div",
4655
- {
4656
- ...props,
4657
- className: chunkMWAXK66H_cjs.cn(
4658
- // The scroll region: caps at the panel's spare height and scrolls when
4659
- // the content is taller, leaving header + footer pinned.
4660
- "min-h-0 overflow-y-auto px-5 py-3 flex flex-col gap-3 text-[14px] text-ink-2",
4661
- className
4662
- )
4663
- }
4664
- );
4665
- }
4666
- function ModalFooter({ className, ...props }) {
4667
- return /* @__PURE__ */ jsxRuntime.jsx(
4668
- "div",
4669
- {
4670
- ...props,
4671
- className: chunkMWAXK66H_cjs.cn("shrink-0 flex justify-end items-center gap-2", "px-5 pt-3 pb-5", className)
4672
- }
4673
- );
4674
- }
4675
5017
  function DraftMessageReview({
4676
5018
  messageId,
4677
5019
  client,
@@ -4817,12 +5159,12 @@ function EmptyState({
4817
5159
  size,
4818
5160
  className
4819
5161
  }) {
4820
- const styles3 = emptyStateStyles({ size });
4821
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn(styles3.root(), className), children: [
4822
- icon ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles3.art(), children: icon }) : null,
4823
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles3.title(), children: title }),
4824
- description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles3.description(), children: description }) : null,
4825
- action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles3.actions(), children: action }) : null
5162
+ const styles4 = emptyStateStyles({ size });
5163
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn(styles4.root(), className), children: [
5164
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles4.art(), children: icon }) : null,
5165
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles4.title(), children: title }),
5166
+ description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles4.description(), children: description }) : null,
5167
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles4.actions(), children: action }) : null
4826
5168
  ] });
4827
5169
  }
4828
5170
  function ErrorAnimation({ className }) {
@@ -5063,7 +5405,7 @@ function Input({
5063
5405
  className,
5064
5406
  ...props
5065
5407
  }) {
5066
- const styles3 = fieldControlStyles({ size, appearance, hasFocusRing });
5408
+ const styles4 = fieldControlStyles({ size, appearance, hasFocusRing });
5067
5409
  return /* @__PURE__ */ jsxRuntime.jsxs(
5068
5410
  reactAriaComponents.TextField,
5069
5411
  {
@@ -5079,7 +5421,7 @@ function Input({
5079
5421
  {
5080
5422
  ...inputProps,
5081
5423
  placeholder: placeholder ?? "",
5082
- className: chunkMWAXK66H_cjs.cn(styles3.box(), styles3.content(), inputClassName)
5424
+ className: chunkMWAXK66H_cjs.cn(styles4.box(), styles4.content(), inputClassName)
5083
5425
  }
5084
5426
  ),
5085
5427
  description ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Text, { slot: "description", className: fieldHintStyles, children: description }) : null,
@@ -5589,6 +5931,8 @@ function ChipItem({
5589
5931
  Badge,
5590
5932
  {
5591
5933
  variant: option?.variant,
5934
+ shape: "rounded",
5935
+ hasDot: false,
5592
5936
  ...option?.color ? { color: option.color } : {},
5593
5937
  ...option?.icon ? { icon: option.icon } : {},
5594
5938
  children: option?.label ?? value
@@ -5665,7 +6009,7 @@ function SegmentedControl({
5665
6009
  orientation = "horizontal",
5666
6010
  ...props
5667
6011
  }) {
5668
- const styles3 = segmentedControlStyles({ size });
6012
+ const styles4 = segmentedControlStyles({ size });
5669
6013
  return /* @__PURE__ */ jsxRuntime.jsx(
5670
6014
  reactAriaComponents.RadioGroup,
5671
6015
  {
@@ -5673,14 +6017,14 @@ function SegmentedControl({
5673
6017
  orientation,
5674
6018
  value: String(value),
5675
6019
  onChange: (next) => onChange(next),
5676
- className: chunkMWAXK66H_cjs.cn(styles3.group(), className),
6020
+ className: chunkMWAXK66H_cjs.cn(styles4.group(), className),
5677
6021
  children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
5678
6022
  reactAriaComponents.Radio,
5679
6023
  {
5680
6024
  value: String(option.id),
5681
6025
  ...option.isDisabled ? { isDisabled: true } : {},
5682
6026
  ...autoFocus && option.id === value ? { autoFocus: true } : {},
5683
- className: styles3.segment(),
6027
+ className: styles4.segment(),
5684
6028
  children: option.label
5685
6029
  },
5686
6030
  String(option.id)
@@ -5703,7 +6047,7 @@ function TagInput({
5703
6047
  autoFocus = false,
5704
6048
  className
5705
6049
  }) {
5706
- const styles3 = fieldControlStyles({ size, invalid: isInvalid, appearance });
6050
+ const styles4 = fieldControlStyles({ size, invalid: isInvalid, appearance });
5707
6051
  const focusWithin = appearance === "cell" ? "focus-within:border-accent focus-within:shadow-none" : "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]";
5708
6052
  const minHeight = appearance === "cell" ? "min-h-[29px]" : fieldMinHeight[size];
5709
6053
  const inputRef = react.useRef(null);
@@ -5744,7 +6088,7 @@ function TagInput({
5744
6088
  "data-invalid": isInvalid || void 0,
5745
6089
  "data-disabled": isDisabled || void 0,
5746
6090
  className: chunkMWAXK66H_cjs.cn(
5747
- styles3.box(),
6091
+ styles4.box(),
5748
6092
  "flex flex-wrap items-center gap-1",
5749
6093
  minHeight,
5750
6094
  fieldChipPadding[size],
@@ -7494,45 +7838,45 @@ var tabsStyles = tailwindVariants.tv({
7494
7838
  defaultVariants: { size: "md" }
7495
7839
  });
7496
7840
  function Root({ size, className, children, ...props }) {
7497
- const styles3 = tabsStyles({ size });
7841
+ const styles4 = tabsStyles({ size });
7498
7842
  return /* @__PURE__ */ jsxRuntime.jsx(
7499
7843
  reactAriaComponents.Tabs,
7500
7844
  {
7501
7845
  ...props,
7502
- className: (rp) => chunkMWAXK66H_cjs.cn(styles3.root(), typeof className === "function" ? className(rp) : className),
7846
+ className: (rp) => chunkMWAXK66H_cjs.cn(styles4.root(), typeof className === "function" ? className(rp) : className),
7503
7847
  children
7504
7848
  }
7505
7849
  );
7506
7850
  }
7507
7851
  function List({ size, className, children, ...props }) {
7508
- const styles3 = tabsStyles({ size });
7852
+ const styles4 = tabsStyles({ size });
7509
7853
  return /* @__PURE__ */ jsxRuntime.jsx(
7510
7854
  reactAriaComponents.TabList,
7511
7855
  {
7512
7856
  ...props,
7513
- className: (rp) => chunkMWAXK66H_cjs.cn(styles3.list(), typeof className === "function" ? className(rp) : className),
7857
+ className: (rp) => chunkMWAXK66H_cjs.cn(styles4.list(), typeof className === "function" ? className(rp) : className),
7514
7858
  children
7515
7859
  }
7516
7860
  );
7517
7861
  }
7518
7862
  function Trigger({ size, className, children, ...props }) {
7519
- const styles3 = tabsStyles({ size });
7863
+ const styles4 = tabsStyles({ size });
7520
7864
  return /* @__PURE__ */ jsxRuntime.jsx(
7521
7865
  reactAriaComponents.Tab,
7522
7866
  {
7523
7867
  ...props,
7524
- className: (rp) => chunkMWAXK66H_cjs.cn(styles3.trigger(), typeof className === "function" ? className(rp) : className),
7868
+ className: (rp) => chunkMWAXK66H_cjs.cn(styles4.trigger(), typeof className === "function" ? className(rp) : className),
7525
7869
  children
7526
7870
  }
7527
7871
  );
7528
7872
  }
7529
7873
  function Panel({ className, children, ...props }) {
7530
- const styles3 = tabsStyles({});
7874
+ const styles4 = tabsStyles({});
7531
7875
  return /* @__PURE__ */ jsxRuntime.jsx(
7532
7876
  reactAriaComponents.TabPanel,
7533
7877
  {
7534
7878
  ...props,
7535
- className: (rp) => chunkMWAXK66H_cjs.cn(styles3.panel(), typeof className === "function" ? className(rp) : className),
7879
+ className: (rp) => chunkMWAXK66H_cjs.cn(styles4.panel(), typeof className === "function" ? className(rp) : className),
7536
7880
  children
7537
7881
  }
7538
7882
  );
@@ -7556,7 +7900,7 @@ function Textarea({
7556
7900
  className,
7557
7901
  ...props
7558
7902
  }) {
7559
- const styles3 = fieldControlStyles({ size, appearance });
7903
+ const styles4 = fieldControlStyles({ size, appearance });
7560
7904
  return /* @__PURE__ */ jsxRuntime.jsxs(
7561
7905
  reactAriaComponents.TextField,
7562
7906
  {
@@ -7576,8 +7920,8 @@ function Textarea({
7576
7920
  className: chunkMWAXK66H_cjs.cn(
7577
7921
  // Same hairline chrome as Input, but allow vertical resize and set a
7578
7922
  // sensible minimum height so short content doesn't collapse.
7579
- styles3.box(),
7580
- styles3.content(),
7923
+ styles4.box(),
7924
+ styles4.content(),
7581
7925
  "min-h-[100px] resize-y",
7582
7926
  textareaClassName
7583
7927
  )
@@ -7598,7 +7942,7 @@ function TimeField({
7598
7942
  className,
7599
7943
  ...props
7600
7944
  }) {
7601
- const styles3 = fieldControlStyles({ size, appearance });
7945
+ const styles4 = fieldControlStyles({ size, appearance });
7602
7946
  const focusWithin = appearance === "cell" ? "focus-within:border-accent focus-within:shadow-none" : "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]";
7603
7947
  return /* @__PURE__ */ jsxRuntime.jsxs(
7604
7948
  reactAriaComponents.TimeField,
@@ -7614,8 +7958,8 @@ function TimeField({
7614
7958
  reactAriaComponents.DateInput,
7615
7959
  {
7616
7960
  className: chunkMWAXK66H_cjs.cn(
7617
- styles3.box(),
7618
- styles3.content(),
7961
+ styles4.box(),
7962
+ styles4.content(),
7619
7963
  "flex items-center min-w-0 text-ink",
7620
7964
  // Tabular alignment for time segments — overrides content's
7621
7965
  // font-sans on purpose.
@@ -7771,6 +8115,7 @@ exports.BadgeMultiSelect = BadgeMultiSelect;
7771
8115
  exports.BooleanCell = BooleanCell;
7772
8116
  exports.Breadcrumbs = Breadcrumbs;
7773
8117
  exports.COLUMN_DRAG_KIND = COLUMN_DRAG_KIND;
8118
+ exports.CONVERSATION_BRIEF_OUTCOME_LABEL = CONVERSATION_BRIEF_OUTCOME_LABEL;
7774
8119
  exports.Card = Card;
7775
8120
  exports.CardBody = CardBody;
7776
8121
  exports.CardContent = CardContent;
@@ -7787,6 +8132,9 @@ exports.ColorInput = ColorInput;
7787
8132
  exports.Combobox = Combobox;
7788
8133
  exports.Command = Command;
7789
8134
  exports.CommandHint = CommandHint;
8135
+ exports.ConversationBriefCard = ConversationBriefCard;
8136
+ exports.ConversationBriefPreview = ConversationBriefPreview;
8137
+ exports.ConversationBriefReview = ConversationBriefReview;
7790
8138
  exports.CurrencyInput = CurrencyInput;
7791
8139
  exports.DRAFT_OUTCOME_LABEL = DRAFT_OUTCOME_LABEL;
7792
8140
  exports.DataTable = DataTable;
@@ -7887,7 +8235,11 @@ exports.avatarStyles = avatarStyles;
7887
8235
  exports.badgeStyles = badgeStyles;
7888
8236
  exports.cardStyles = cardStyles2;
7889
8237
  exports.channelIcon = channelIcon;
8238
+ exports.contactPhoneNumbers = contactPhoneNumbers;
8239
+ exports.conversationBriefCardStyles = conversationBriefCardStyles;
8240
+ exports.conversationBriefOutcomeFor = conversationBriefOutcomeFor;
7890
8241
  exports.countLeaves = countLeaves;
8242
+ exports.createConversationBriefClient = createConversationBriefClient;
7891
8243
  exports.createDraftMessageClient = createDraftMessageClient;
7892
8244
  exports.createToastQueue = createToastQueue;
7893
8245
  exports.defaultValueFor = defaultValueFor;
@@ -7907,12 +8259,14 @@ exports.iconForContentType = iconForContentType;
7907
8259
  exports.imageAttachmentStyles = imageAttachmentStyles;
7908
8260
  exports.imageLightboxStyles = imageLightboxStyles;
7909
8261
  exports.isColumnDragData = isColumnDragData;
8262
+ exports.isDialableConversationBrief = isDialableConversationBrief;
7910
8263
  exports.isDraftReviewOutcome = isDraftReviewOutcome;
7911
8264
  exports.isEditableTarget = isEditableTarget;
7912
8265
  exports.isPreviewableImageName = isPreviewableImageName;
7913
8266
  exports.joinFieldLabel = joinFieldLabel;
7914
8267
  exports.makeActionsColumn = makeActionsColumn;
7915
8268
  exports.messageComposerStyles = messageComposerStyles;
8269
+ exports.namesOf = namesOf;
7916
8270
  exports.navItemStyles = navItemStyles;
7917
8271
  exports.normalizeHexColor = normalizeHexColor;
7918
8272
  exports.operatorById = operatorById;
@@ -7931,6 +8285,7 @@ exports.resolveLucideIconName = resolveLucideIconName;
7931
8285
  exports.segmentedControlStyles = segmentedControlStyles;
7932
8286
  exports.setJoiner = setJoiner;
7933
8287
  exports.subscribeDraftMessageOutcome = subscribeDraftMessageOutcome;
8288
+ exports.summaryFor = summaryFor;
7934
8289
  exports.tableCellStyles = tableCellStyles;
7935
8290
  exports.tableHeaderCellStyles = tableHeaderCellStyles;
7936
8291
  exports.tabsStyles = tabsStyles;