@meetreeve/ui 0.11.0 → 0.13.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/README.md CHANGED
@@ -158,6 +158,35 @@ single-org case stays a flat list. `collapsed` swaps the trigger for an
158
158
  icon-only button (56px nav rail); `footer` adds a slot below the list (e.g.
159
159
  an "Add brand" CTA).
160
160
 
161
+ ## InfoTip (DEV-11387)
162
+
163
+ A "?" circle that reveals a short explanation, so a page can keep caveats and
164
+ definitions one hover away instead of as paragraphs of body copy.
165
+
166
+ ```tsx
167
+ import { InfoTip } from "@meetreeve/ui";
168
+
169
+ <h2>Human review required</h2>
170
+ <InfoTip label="About human review">
171
+ These networks are withheld from buying groups until a person checks the evidence.
172
+ </InfoTip>;
173
+ ```
174
+
175
+ Built on Base UI's Popover, not a tooltip, because a tooltip never opens on
176
+ touch: hover opens it for mouse users, click/tap and Enter/Space open it
177
+ everywhere, and Escape or an outside click closes it. `side`/`align` set the
178
+ preferred placement and the bubble flips near a viewport edge.
179
+
180
+ The trigger keeps the 44px `MIN_SIZES.touchTarget` floor while its glyph is
181
+ 16px. The extra height is cancelled so it sits inline in a heading without
182
+ changing the line height, but the full 44px of width stays in the layout — the
183
+ hit area never overlaps the text beside it, so expect the glyph to look
184
+ generously spaced rather than tight against its heading.
185
+ The bubble is portalled to `<body>` and styles from the host's theme tokens, so
186
+ the host must define `--color-popover`, `--color-popover-foreground`,
187
+ `--color-border` and `--color-ring`, and Tailwind consumers must include this
188
+ package's `dist` as a `@source` (see ResponsiveHeader above).
189
+
161
190
  ## Tokens
162
191
 
163
192
  ```ts
package/dist/index.d.mts CHANGED
@@ -206,6 +206,35 @@ declare function ResponsiveHeader({ brand, search, nav, brandHref, linkComponent
206
206
  */
207
207
  declare function useResponsivePlaceholder(desktop: string, mobile?: string): string;
208
208
 
209
+ interface InfoTipProps {
210
+ /** The explanation the tip reveals. Keep it to a sentence or two. */
211
+ children: ReactNode;
212
+ /** Accessible name for the "?" trigger. Say what it explains, e.g. "About human review". */
213
+ label?: string;
214
+ /** Preferred side for the bubble; it flips when that side would leave the viewport. */
215
+ side?: "top" | "bottom" | "left" | "right";
216
+ align?: "start" | "center" | "end";
217
+ className?: string;
218
+ }
219
+ /**
220
+ * A "?" circle that reveals a short explanation (DEV-11387), so a page can keep
221
+ * caveats and definitions one hover away instead of as paragraphs of body copy.
222
+ *
223
+ * Built on Base UI's Popover, not a tooltip: a tooltip never opens on touch,
224
+ * and these explanations must be reachable on a phone. Hover opens it for mouse
225
+ * users; click/tap and Enter/Space open it everywhere; Escape and an outside
226
+ * click close it. The bubble is portalled and collision-aware, so a tip near a
227
+ * page edge stays on screen, and it styles from the host's theme tokens.
228
+ *
229
+ * The visible glyph is 16px but the button keeps the 44px touch-target floor.
230
+ * The negative margin is VERTICAL ONLY: it cancels the extra height so the tip
231
+ * sits inline in a heading without changing its line height, while the full
232
+ * 44px of inline width stays in the layout. A horizontal cancel would let the
233
+ * hit area reach ~14px into whatever sits beside it, swallowing hovers and
234
+ * clicks meant for that text.
235
+ */
236
+ declare function InfoTip({ children, label, side, align, className }: InfoTipProps): react.JSX.Element;
237
+
209
238
  /**
210
239
  * SidebarLadder — the per-tenant JSON artifact (DEV-4351) that pre-calculates
211
240
  * every viewport-driven collapse step for AppSidebar. Agent-authored at spawn
@@ -719,6 +748,19 @@ interface ConnectorCredentialTestResult {
719
748
  */
720
749
  permissions_note?: string | null;
721
750
  }
751
+ /**
752
+ * Connector health as the DEV-1964 probe classifies it — Reeve.Connects-wide
753
+ * vocabulary, not provider-specific (the same shape the adbuyer surfaces
754
+ * already read off `GET /api/connects/v1/connections`). Deliberately
755
+ * tri-state, never a `needs_reconnect` boolean (Matt's call, DEV-7873): a
756
+ * probe that has not run yet ("unknown") or has not run at all (the whole
757
+ * field absent) is not the same claim as a probe that ran and failed.
758
+ */
759
+ interface ConnectorConnectionHealth {
760
+ status: "healthy" | "unhealthy" | "unknown";
761
+ error_code?: string | null;
762
+ checked_at?: string | null;
763
+ }
722
764
  interface ConnectableEntry {
723
765
  slug: string;
724
766
  name: string;
@@ -749,6 +791,21 @@ interface ConnectableEntry {
749
791
  } | null;
750
792
  /** true = the viewer owns this connection (enables manage-sharing). */
751
793
  owned_by_viewer?: boolean;
794
+ /**
795
+ * Live health probe for this connection (DEV-1964 / DEV-7873), when the
796
+ * backend has one. Absent/undefined is NOT "healthy" — it means no probe
797
+ * has run; the picker only ever reacts to an explicit "unhealthy"
798
+ * status, so "unknown" and absent both render as a plain connected
799
+ * tile, same as before this field existed.
800
+ */
801
+ health?: ConnectorConnectionHealth | null;
802
+ /**
803
+ * Human-readable identity of the external account this connection
804
+ * authenticated as (an email, a workspace name, whatever the provider's
805
+ * own identity claim resolves to). Optional and provider-agnostic — the
806
+ * picker never assumes an email shape or synthesizes this itself.
807
+ */
808
+ account_label?: string | null;
752
809
  };
753
810
  /** true = tenant has a live connection but the entry left the allowlist. */
754
811
  deprecated: boolean;
@@ -766,6 +823,15 @@ interface ConnectableEntry {
766
823
  * connect button renders, exactly as before.
767
824
  */
768
825
  credential_fields?: ConnectorCredentialField[] | null;
826
+ /**
827
+ * Plain-language description of what a LIVE connection actually reads or
828
+ * writes (e.g. "Reads recent activity to build your weekly summary") —
829
+ * entirely server-authored copy, same posture as `category`/`name`.
830
+ * Rendered only once connected (it describes a live grant, not the
831
+ * catalog listing); absent renders nothing. This file must never
832
+ * synthesize this text itself for a specific provider.
833
+ */
834
+ access_summary?: string | null;
769
835
  }
770
836
  interface ConnectorPickerClient {
771
837
  listConnectable(opts: {
@@ -829,4 +895,4 @@ interface ConnectorPickerProps {
829
895
  }
830
896
  declare function ConnectorPicker({ client, purpose, lens, layout, onConnected, }: ConnectorPickerProps): react.JSX.Element | null;
831
897
 
832
- export { type AppRungItem, AppSidebar, type AppSidebarBrand, type AppSidebarModuleDef, type AppSidebarProps, type AppSidebarTopItem, type Brand, BrandGlyph, type BrandGlyphProps, type ConnectableCapability, type ConnectableEntry, type ConnectableTransport, type ConnectionKind, type ConnectorCredentialField, type ConnectorCredentialTestResult, type ConnectorGrant, type ConnectorGrantInput, type ConnectorGranteeType, type ConnectorGuideStep, ConnectorPicker, type ConnectorPickerClient, type ConnectorPickerLens, type ConnectorPickerProps, type ConnectorRoleOption, type ConnectorSetupGuide, type ContextOrgGroup, ContextSwitcher, type ContextSwitcherItem, type ContextSwitcherProps, type FallbackModuleDef, Flyout, type FlyoutChild, type FlyoutProps, GLYPH_CANVAS_FILL, type GroupRungItem, type HeaderNavItem, LOCKUP_GAP, LOCKUP_ROW, MARK_CAP_RATIO, MARK_WEIGHT, type OrgConnectPolicy, REEVE_ACCENT, ResponsiveHeader, type ResponsiveHeaderProps, type RungItem, type SidebarLadder, type SidebarLadderParsed, type SidebarRung, type UseLadderRungOptions, WORDMARK_WEIGHT, deriveFallbackLadder, faviconUrl, groupByOrg, reconcileLadder, resolveLadder, useLadderRung, useResponsivePlaceholder, zSidebarLadder };
898
+ export { type AppRungItem, AppSidebar, type AppSidebarBrand, type AppSidebarModuleDef, type AppSidebarProps, type AppSidebarTopItem, type Brand, BrandGlyph, type BrandGlyphProps, type ConnectableCapability, type ConnectableEntry, type ConnectableTransport, type ConnectionKind, type ConnectorConnectionHealth, type ConnectorCredentialField, type ConnectorCredentialTestResult, type ConnectorGrant, type ConnectorGrantInput, type ConnectorGranteeType, type ConnectorGuideStep, ConnectorPicker, type ConnectorPickerClient, type ConnectorPickerLens, type ConnectorPickerProps, type ConnectorRoleOption, type ConnectorSetupGuide, type ContextOrgGroup, ContextSwitcher, type ContextSwitcherItem, type ContextSwitcherProps, type FallbackModuleDef, Flyout, type FlyoutChild, type FlyoutProps, GLYPH_CANVAS_FILL, type GroupRungItem, type HeaderNavItem, InfoTip, type InfoTipProps, LOCKUP_GAP, LOCKUP_ROW, MARK_CAP_RATIO, MARK_WEIGHT, type OrgConnectPolicy, REEVE_ACCENT, ResponsiveHeader, type ResponsiveHeaderProps, type RungItem, type SidebarLadder, type SidebarLadderParsed, type SidebarRung, type UseLadderRungOptions, WORDMARK_WEIGHT, deriveFallbackLadder, faviconUrl, groupByOrg, reconcileLadder, resolveLadder, useLadderRung, useResponsivePlaceholder, zSidebarLadder };
package/dist/index.d.ts CHANGED
@@ -206,6 +206,35 @@ declare function ResponsiveHeader({ brand, search, nav, brandHref, linkComponent
206
206
  */
207
207
  declare function useResponsivePlaceholder(desktop: string, mobile?: string): string;
208
208
 
209
+ interface InfoTipProps {
210
+ /** The explanation the tip reveals. Keep it to a sentence or two. */
211
+ children: ReactNode;
212
+ /** Accessible name for the "?" trigger. Say what it explains, e.g. "About human review". */
213
+ label?: string;
214
+ /** Preferred side for the bubble; it flips when that side would leave the viewport. */
215
+ side?: "top" | "bottom" | "left" | "right";
216
+ align?: "start" | "center" | "end";
217
+ className?: string;
218
+ }
219
+ /**
220
+ * A "?" circle that reveals a short explanation (DEV-11387), so a page can keep
221
+ * caveats and definitions one hover away instead of as paragraphs of body copy.
222
+ *
223
+ * Built on Base UI's Popover, not a tooltip: a tooltip never opens on touch,
224
+ * and these explanations must be reachable on a phone. Hover opens it for mouse
225
+ * users; click/tap and Enter/Space open it everywhere; Escape and an outside
226
+ * click close it. The bubble is portalled and collision-aware, so a tip near a
227
+ * page edge stays on screen, and it styles from the host's theme tokens.
228
+ *
229
+ * The visible glyph is 16px but the button keeps the 44px touch-target floor.
230
+ * The negative margin is VERTICAL ONLY: it cancels the extra height so the tip
231
+ * sits inline in a heading without changing its line height, while the full
232
+ * 44px of inline width stays in the layout. A horizontal cancel would let the
233
+ * hit area reach ~14px into whatever sits beside it, swallowing hovers and
234
+ * clicks meant for that text.
235
+ */
236
+ declare function InfoTip({ children, label, side, align, className }: InfoTipProps): react.JSX.Element;
237
+
209
238
  /**
210
239
  * SidebarLadder — the per-tenant JSON artifact (DEV-4351) that pre-calculates
211
240
  * every viewport-driven collapse step for AppSidebar. Agent-authored at spawn
@@ -719,6 +748,19 @@ interface ConnectorCredentialTestResult {
719
748
  */
720
749
  permissions_note?: string | null;
721
750
  }
751
+ /**
752
+ * Connector health as the DEV-1964 probe classifies it — Reeve.Connects-wide
753
+ * vocabulary, not provider-specific (the same shape the adbuyer surfaces
754
+ * already read off `GET /api/connects/v1/connections`). Deliberately
755
+ * tri-state, never a `needs_reconnect` boolean (Matt's call, DEV-7873): a
756
+ * probe that has not run yet ("unknown") or has not run at all (the whole
757
+ * field absent) is not the same claim as a probe that ran and failed.
758
+ */
759
+ interface ConnectorConnectionHealth {
760
+ status: "healthy" | "unhealthy" | "unknown";
761
+ error_code?: string | null;
762
+ checked_at?: string | null;
763
+ }
722
764
  interface ConnectableEntry {
723
765
  slug: string;
724
766
  name: string;
@@ -749,6 +791,21 @@ interface ConnectableEntry {
749
791
  } | null;
750
792
  /** true = the viewer owns this connection (enables manage-sharing). */
751
793
  owned_by_viewer?: boolean;
794
+ /**
795
+ * Live health probe for this connection (DEV-1964 / DEV-7873), when the
796
+ * backend has one. Absent/undefined is NOT "healthy" — it means no probe
797
+ * has run; the picker only ever reacts to an explicit "unhealthy"
798
+ * status, so "unknown" and absent both render as a plain connected
799
+ * tile, same as before this field existed.
800
+ */
801
+ health?: ConnectorConnectionHealth | null;
802
+ /**
803
+ * Human-readable identity of the external account this connection
804
+ * authenticated as (an email, a workspace name, whatever the provider's
805
+ * own identity claim resolves to). Optional and provider-agnostic — the
806
+ * picker never assumes an email shape or synthesizes this itself.
807
+ */
808
+ account_label?: string | null;
752
809
  };
753
810
  /** true = tenant has a live connection but the entry left the allowlist. */
754
811
  deprecated: boolean;
@@ -766,6 +823,15 @@ interface ConnectableEntry {
766
823
  * connect button renders, exactly as before.
767
824
  */
768
825
  credential_fields?: ConnectorCredentialField[] | null;
826
+ /**
827
+ * Plain-language description of what a LIVE connection actually reads or
828
+ * writes (e.g. "Reads recent activity to build your weekly summary") —
829
+ * entirely server-authored copy, same posture as `category`/`name`.
830
+ * Rendered only once connected (it describes a live grant, not the
831
+ * catalog listing); absent renders nothing. This file must never
832
+ * synthesize this text itself for a specific provider.
833
+ */
834
+ access_summary?: string | null;
769
835
  }
770
836
  interface ConnectorPickerClient {
771
837
  listConnectable(opts: {
@@ -829,4 +895,4 @@ interface ConnectorPickerProps {
829
895
  }
830
896
  declare function ConnectorPicker({ client, purpose, lens, layout, onConnected, }: ConnectorPickerProps): react.JSX.Element | null;
831
897
 
832
- export { type AppRungItem, AppSidebar, type AppSidebarBrand, type AppSidebarModuleDef, type AppSidebarProps, type AppSidebarTopItem, type Brand, BrandGlyph, type BrandGlyphProps, type ConnectableCapability, type ConnectableEntry, type ConnectableTransport, type ConnectionKind, type ConnectorCredentialField, type ConnectorCredentialTestResult, type ConnectorGrant, type ConnectorGrantInput, type ConnectorGranteeType, type ConnectorGuideStep, ConnectorPicker, type ConnectorPickerClient, type ConnectorPickerLens, type ConnectorPickerProps, type ConnectorRoleOption, type ConnectorSetupGuide, type ContextOrgGroup, ContextSwitcher, type ContextSwitcherItem, type ContextSwitcherProps, type FallbackModuleDef, Flyout, type FlyoutChild, type FlyoutProps, GLYPH_CANVAS_FILL, type GroupRungItem, type HeaderNavItem, LOCKUP_GAP, LOCKUP_ROW, MARK_CAP_RATIO, MARK_WEIGHT, type OrgConnectPolicy, REEVE_ACCENT, ResponsiveHeader, type ResponsiveHeaderProps, type RungItem, type SidebarLadder, type SidebarLadderParsed, type SidebarRung, type UseLadderRungOptions, WORDMARK_WEIGHT, deriveFallbackLadder, faviconUrl, groupByOrg, reconcileLadder, resolveLadder, useLadderRung, useResponsivePlaceholder, zSidebarLadder };
898
+ export { type AppRungItem, AppSidebar, type AppSidebarBrand, type AppSidebarModuleDef, type AppSidebarProps, type AppSidebarTopItem, type Brand, BrandGlyph, type BrandGlyphProps, type ConnectableCapability, type ConnectableEntry, type ConnectableTransport, type ConnectionKind, type ConnectorConnectionHealth, type ConnectorCredentialField, type ConnectorCredentialTestResult, type ConnectorGrant, type ConnectorGrantInput, type ConnectorGranteeType, type ConnectorGuideStep, ConnectorPicker, type ConnectorPickerClient, type ConnectorPickerLens, type ConnectorPickerProps, type ConnectorRoleOption, type ConnectorSetupGuide, type ContextOrgGroup, ContextSwitcher, type ContextSwitcherItem, type ContextSwitcherProps, type FallbackModuleDef, Flyout, type FlyoutChild, type FlyoutProps, GLYPH_CANVAS_FILL, type GroupRungItem, type HeaderNavItem, InfoTip, type InfoTipProps, LOCKUP_GAP, LOCKUP_ROW, MARK_CAP_RATIO, MARK_WEIGHT, type OrgConnectPolicy, REEVE_ACCENT, ResponsiveHeader, type ResponsiveHeaderProps, type RungItem, type SidebarLadder, type SidebarLadderParsed, type SidebarRung, type UseLadderRungOptions, WORDMARK_WEIGHT, deriveFallbackLadder, faviconUrl, groupByOrg, reconcileLadder, resolveLadder, useLadderRung, useResponsivePlaceholder, zSidebarLadder };