@agent-native/toolkit 0.2.0 → 0.4.1

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.
Files changed (55) hide show
  1. package/README.md +17 -5
  2. package/dist/collab-ui/AgentPresenceChip.d.ts +12 -0
  3. package/dist/collab-ui/AgentPresenceChip.d.ts.map +1 -0
  4. package/dist/collab-ui/AgentPresenceChip.js +42 -0
  5. package/dist/collab-ui/AgentPresenceChip.js.map +1 -0
  6. package/dist/collab-ui/LiveCursorOverlay.d.ts +46 -0
  7. package/dist/collab-ui/LiveCursorOverlay.d.ts.map +1 -0
  8. package/dist/collab-ui/LiveCursorOverlay.js +124 -0
  9. package/dist/collab-ui/LiveCursorOverlay.js.map +1 -0
  10. package/dist/collab-ui/PresenceBar.d.ts +27 -0
  11. package/dist/collab-ui/PresenceBar.d.ts.map +1 -0
  12. package/dist/collab-ui/PresenceBar.js +165 -0
  13. package/dist/collab-ui/PresenceBar.js.map +1 -0
  14. package/dist/collab-ui/RecentEditHighlights.d.ts +44 -0
  15. package/dist/collab-ui/RecentEditHighlights.d.ts.map +1 -0
  16. package/dist/collab-ui/RecentEditHighlights.js +146 -0
  17. package/dist/collab-ui/RecentEditHighlights.js.map +1 -0
  18. package/dist/collab-ui/RemoteSelectionRings.d.ts +53 -0
  19. package/dist/collab-ui/RemoteSelectionRings.d.ts.map +1 -0
  20. package/dist/collab-ui/RemoteSelectionRings.js +130 -0
  21. package/dist/collab-ui/RemoteSelectionRings.js.map +1 -0
  22. package/dist/collab-ui/index.d.ts +7 -0
  23. package/dist/collab-ui/index.d.ts.map +1 -0
  24. package/dist/collab-ui/index.js +7 -0
  25. package/dist/collab-ui/index.js.map +1 -0
  26. package/dist/collab-ui/types.d.ts +48 -0
  27. package/dist/collab-ui/types.d.ts.map +1 -0
  28. package/dist/collab-ui/types.js +43 -0
  29. package/dist/collab-ui/types.js.map +1 -0
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +3 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/provider.d.ts +14 -0
  35. package/dist/provider.d.ts.map +1 -0
  36. package/dist/provider.js +15 -0
  37. package/dist/provider.js.map +1 -0
  38. package/dist/sharing/VisibilityBadge.d.ts +11 -0
  39. package/dist/sharing/VisibilityBadge.d.ts.map +1 -0
  40. package/dist/sharing/VisibilityBadge.js +19 -0
  41. package/dist/sharing/VisibilityBadge.js.map +1 -0
  42. package/dist/sharing/index.d.ts +2 -0
  43. package/dist/sharing/index.d.ts.map +1 -0
  44. package/dist/sharing/index.js +2 -0
  45. package/dist/sharing/index.js.map +1 -0
  46. package/dist/styles.css +19 -0
  47. package/dist/ui/button.d.ts +2 -1
  48. package/dist/ui/button.d.ts.map +1 -1
  49. package/dist/ui/button.js +14 -2
  50. package/dist/ui/button.js.map +1 -1
  51. package/dist/ui/dropdown-menu.d.ts +3 -1
  52. package/dist/ui/dropdown-menu.d.ts.map +1 -1
  53. package/dist/ui/dropdown-menu.js +1 -1
  54. package/dist/ui/dropdown-menu.js.map +1 -1
  55. package/package.json +34 -9
@@ -0,0 +1,146 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * RecentEditHighlights — lingering, fading highlights over regions another
4
+ * participant (human or agent) just edited, with their name/avatar flag.
5
+ *
6
+ * The Google-Docs/Figma feel: when a collaborator or the AI edits something,
7
+ * the changed region glows in their color and the flag identifies them; the
8
+ * highlight fades out over the last portion of its lifetime instead of
9
+ * vanishing.
10
+ *
11
+ * Feed it `useRecentEdits(others)` (which reads participants' `recentEdits`
12
+ * awareness rings) and a `resolveRect` that maps an edit descriptor to a
13
+ * viewport DOMRect for your surface:
14
+ *
15
+ * const others = usePresence(awareness, ydoc?.clientID).others;
16
+ * const edits = useRecentEdits(others);
17
+ * <RecentEditHighlights
18
+ * edits={edits}
19
+ * resolveRect={(edit) =>
20
+ * edit.descriptor.kind === "selector"
21
+ * ? container.querySelector(edit.descriptor.selector)?.getBoundingClientRect() ?? null
22
+ * : null
23
+ * }
24
+ * containerRef={containerRef}
25
+ * />
26
+ */
27
+ import { memo, useEffect, useLayoutEffect, useRef, useState, } from "react";
28
+ import { RECENT_EDIT_TTL_MS } from "./types.js";
29
+ const HighlightItem = memo(function HighlightItem({ h }) {
30
+ return (_jsx("div", { "aria-label": `${h.label} edited this`, style: {
31
+ position: "absolute",
32
+ top: h.rect.top,
33
+ left: h.rect.left,
34
+ width: h.rect.width,
35
+ height: h.rect.height,
36
+ borderRadius: 4,
37
+ pointerEvents: "none",
38
+ zIndex: 9997,
39
+ opacity: h.opacity,
40
+ transition: "opacity 400ms ease-out",
41
+ outline: `2px solid ${h.color}`,
42
+ outlineOffset: 2,
43
+ backgroundColor: `${h.color}1A`,
44
+ boxShadow: `0 0 0 1px ${h.color}33, 0 0 12px ${h.color}40`,
45
+ }, children: _jsxs("div", { style: {
46
+ position: "absolute",
47
+ top: -22,
48
+ left: 0,
49
+ display: "flex",
50
+ alignItems: "center",
51
+ gap: 4,
52
+ backgroundColor: h.color,
53
+ color: "#fff",
54
+ fontSize: 10,
55
+ fontWeight: 600,
56
+ padding: "2px 6px",
57
+ borderRadius: 3,
58
+ whiteSpace: "nowrap",
59
+ maxWidth: 180,
60
+ overflow: "hidden",
61
+ textOverflow: "ellipsis",
62
+ }, children: [h.avatarUrl ? (_jsx("img", { src: h.avatarUrl, alt: "", style: {
63
+ width: 12,
64
+ height: 12,
65
+ borderRadius: "50%",
66
+ flexShrink: 0,
67
+ } })) : null, h.label] }) }));
68
+ });
69
+ export function RecentEditHighlights({ edits, resolveRect, containerRef, ttlMs = RECENT_EDIT_TTL_MS, className, }) {
70
+ const [highlights, setHighlights] = useState([]);
71
+ const editsRef = useRef(edits);
72
+ editsRef.current = edits;
73
+ const resolveRef = useRef(resolveRect);
74
+ resolveRef.current = resolveRect;
75
+ const recompute = () => {
76
+ const container = containerRef.current;
77
+ if (!container) {
78
+ setHighlights([]);
79
+ return;
80
+ }
81
+ const containerRect = container.getBoundingClientRect();
82
+ const now = Date.now();
83
+ const next = [];
84
+ for (const edit of editsRef.current) {
85
+ const domRect = resolveRef.current(edit);
86
+ if (!domRect)
87
+ continue;
88
+ const top = domRect.top - containerRect.top;
89
+ const left = domRect.left - containerRect.left;
90
+ if (left + domRect.width < 0 ||
91
+ top + domRect.height < 0 ||
92
+ left > containerRect.width ||
93
+ top > containerRect.height) {
94
+ continue;
95
+ }
96
+ // Fade over the final 40% of the lifetime.
97
+ const age = now - edit.at;
98
+ const fadeStart = ttlMs * 0.6;
99
+ const opacity = age <= fadeStart
100
+ ? 1
101
+ : Math.max(0, 1 - (age - fadeStart) / (ttlMs - fadeStart));
102
+ next.push({
103
+ key: `${edit.clientId}:${edit.at}`,
104
+ color: edit.user.color || "#94a3b8",
105
+ label: edit.isAgent
106
+ ? edit.label
107
+ ? `AI — ${edit.label}`
108
+ : "AI edited"
109
+ : edit.label
110
+ ? `${edit.user.name} — ${edit.label}`
111
+ : edit.user.name,
112
+ avatarUrl: edit.user.avatarUrl,
113
+ isAgent: edit.isAgent,
114
+ opacity,
115
+ rect: { top, left, width: domRect.width, height: domRect.height },
116
+ });
117
+ }
118
+ setHighlights(next);
119
+ };
120
+ useLayoutEffect(() => {
121
+ recompute();
122
+ // eslint-disable-next-line react-hooks/exhaustive-deps
123
+ }, [edits, ttlMs]);
124
+ useEffect(() => {
125
+ const container = containerRef.current;
126
+ if (!container)
127
+ return;
128
+ const observer = new ResizeObserver(() => recompute());
129
+ observer.observe(container);
130
+ container.addEventListener("scroll", recompute, { passive: true });
131
+ window.addEventListener("scroll", recompute, { passive: true });
132
+ return () => {
133
+ observer.disconnect();
134
+ container.removeEventListener("scroll", recompute);
135
+ window.removeEventListener("scroll", recompute);
136
+ };
137
+ // eslint-disable-next-line react-hooks/exhaustive-deps
138
+ }, [containerRef]);
139
+ return (_jsx("div", { "aria-hidden": true, style: {
140
+ position: "absolute",
141
+ inset: 0,
142
+ pointerEvents: "none",
143
+ overflow: "hidden",
144
+ }, className: className, children: highlights.map((h) => (_jsx(HighlightItem, { h: h }, h.key))) }));
145
+ }
146
+ //# sourceMappingURL=RecentEditHighlights.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecentEditHighlights.js","sourceRoot":"","sources":["../../src/collab-ui/RecentEditHighlights.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * RemoteSelectionRings — renders colored outline rings + name tags over
3
+ * elements selected by remote participants.
4
+ *
5
+ * Each participant's presence payload may contain a `selection` key with an
6
+ * opaque descriptor (e.g. a CSS selector). The `resolveRect` callback maps
7
+ * a descriptor to a DOMRect (or null when the element isn't found). Rings
8
+ * are rendered as absolutely-positioned outlines anchored to the container.
9
+ *
10
+ * Usage:
11
+ * <div style={{ position: "relative" }}>
12
+ * {content}
13
+ * <RemoteSelectionRings
14
+ * others={others}
15
+ * resolveRect={(selector) => document.querySelector(selector)?.getBoundingClientRect() ?? null}
16
+ * containerRef={containerRef}
17
+ * />
18
+ * </div>
19
+ */
20
+ import { type RefObject } from "react";
21
+ import type { OtherPresence } from "./types.js";
22
+ /**
23
+ * Selection descriptors may be a plain string (treated as the resolver
24
+ * input) or an object carrying a resolver input plus a human label
25
+ * ("Editing hero section").
26
+ */
27
+ export type SelectionDescriptor = string | {
28
+ selector: string;
29
+ label?: string;
30
+ };
31
+ export interface RemoteSelectionRingsProps {
32
+ /** Remote participants. */
33
+ others: OtherPresence[];
34
+ /**
35
+ * Key inside presence payload that carries the selection descriptor.
36
+ * Default: "selection"
37
+ */
38
+ selectionKey?: string;
39
+ /**
40
+ * Resolver: maps a selection descriptor to a DOMRect relative to the
41
+ * viewport. Return null when the element is not found.
42
+ */
43
+ resolveRect: (descriptor: string) => DOMRect | null;
44
+ /**
45
+ * Container element ref. Rings are positioned relative to this element's
46
+ * bounding box.
47
+ */
48
+ containerRef: RefObject<HTMLElement | null>;
49
+ /** Additional CSS class for the overlay div. */
50
+ className?: string;
51
+ }
52
+ export declare function RemoteSelectionRings({ others, selectionKey, resolveRect, containerRef, className, }: RemoteSelectionRingsProps): import("react").JSX.Element;
53
+ //# sourceMappingURL=RemoteSelectionRings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RemoteSelectionRings.d.ts","sourceRoot":"","sources":["../../src/collab-ui/RemoteSelectionRings.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhF,MAAM,WAAW,yBAAyB;IACxC,2BAA2B;IAC3B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IACpD;;;OAGG;IACH,YAAY,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC5C,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAoED,wBAAgB,oBAAoB,CAAC,EACnC,MAAM,EACN,YAA0B,EAC1B,WAAW,EACX,YAAY,EACZ,SAAS,GACV,EAAE,yBAAyB,+BA8F3B"}
@@ -0,0 +1,130 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * RemoteSelectionRings — renders colored outline rings + name tags over
4
+ * elements selected by remote participants.
5
+ *
6
+ * Each participant's presence payload may contain a `selection` key with an
7
+ * opaque descriptor (e.g. a CSS selector). The `resolveRect` callback maps
8
+ * a descriptor to a DOMRect (or null when the element isn't found). Rings
9
+ * are rendered as absolutely-positioned outlines anchored to the container.
10
+ *
11
+ * Usage:
12
+ * <div style={{ position: "relative" }}>
13
+ * {content}
14
+ * <RemoteSelectionRings
15
+ * others={others}
16
+ * resolveRect={(selector) => document.querySelector(selector)?.getBoundingClientRect() ?? null}
17
+ * containerRef={containerRef}
18
+ * />
19
+ * </div>
20
+ */
21
+ import { useState, useEffect, useRef, useLayoutEffect, memo, } from "react";
22
+ const RingItem = memo(function RingItem({ ring }) {
23
+ return (_jsx("div", { "aria-label": `${ring.label} selection`, style: {
24
+ position: "absolute",
25
+ top: ring.rect.top,
26
+ left: ring.rect.left,
27
+ width: ring.rect.width,
28
+ height: ring.rect.height,
29
+ outline: `2px solid ${ring.color}`,
30
+ outlineOffset: 2,
31
+ borderRadius: 3,
32
+ pointerEvents: "none",
33
+ boxShadow: `0 0 0 1px ${ring.color}40`,
34
+ zIndex: 9998,
35
+ }, children: _jsxs("div", { style: {
36
+ position: "absolute",
37
+ top: -20,
38
+ left: 0,
39
+ display: "flex",
40
+ alignItems: "center",
41
+ gap: 4,
42
+ backgroundColor: ring.color,
43
+ color: "#fff",
44
+ fontSize: 10,
45
+ fontWeight: 600,
46
+ padding: "1px 5px",
47
+ borderRadius: 3,
48
+ whiteSpace: "nowrap",
49
+ maxWidth: 160,
50
+ overflow: "hidden",
51
+ textOverflow: "ellipsis",
52
+ }, children: [ring.avatarUrl ? (_jsx("img", { src: ring.avatarUrl, alt: "", style: {
53
+ width: 12,
54
+ height: 12,
55
+ borderRadius: "50%",
56
+ flexShrink: 0,
57
+ } })) : null, ring.label] }) }));
58
+ });
59
+ export function RemoteSelectionRings({ others, selectionKey = "selection", resolveRect, containerRef, className, }) {
60
+ const overlayRef = useRef(null);
61
+ const [rings, setRings] = useState([]);
62
+ // Recompute rings whenever others change or on animation frame.
63
+ const recompute = () => {
64
+ const container = containerRef.current;
65
+ if (!container) {
66
+ setRings([]);
67
+ return;
68
+ }
69
+ const containerRect = container.getBoundingClientRect();
70
+ const next = [];
71
+ for (const other of others) {
72
+ const raw = other.presence[selectionKey];
73
+ const selector = typeof raw === "string" ? raw : raw ? raw.selector : undefined;
74
+ if (!selector || typeof selector !== "string")
75
+ continue;
76
+ const selectionLabel = raw && typeof raw === "object" ? raw.label : undefined;
77
+ const domRect = resolveRect(selector);
78
+ if (!domRect)
79
+ continue;
80
+ // Convert viewport-relative rect to container-relative.
81
+ const top = domRect.top - containerRect.top;
82
+ const left = domRect.left - containerRect.left;
83
+ if (left + domRect.width < 0 ||
84
+ top + domRect.height < 0 ||
85
+ left > containerRect.width ||
86
+ top > containerRect.height) {
87
+ continue; // Out of container bounds — skip.
88
+ }
89
+ const baseName = other.isAgent
90
+ ? "AI"
91
+ : other.user.name || other.user.email;
92
+ next.push({
93
+ clientId: other.clientId,
94
+ color: other.user.color || "#94a3b8",
95
+ label: selectionLabel ? `${baseName} — ${selectionLabel}` : baseName,
96
+ avatarUrl: other.user.avatarUrl,
97
+ isAgent: other.isAgent,
98
+ rect: { top, left, width: domRect.width, height: domRect.height },
99
+ });
100
+ }
101
+ setRings(next);
102
+ };
103
+ // Recompute on scroll/resize of the container to keep rings in sync.
104
+ useLayoutEffect(() => {
105
+ recompute();
106
+ // eslint-disable-next-line react-hooks/exhaustive-deps
107
+ }, [others, selectionKey]);
108
+ useEffect(() => {
109
+ const container = containerRef.current;
110
+ if (!container)
111
+ return;
112
+ const observer = new ResizeObserver(() => recompute());
113
+ observer.observe(container);
114
+ container.addEventListener("scroll", recompute, { passive: true });
115
+ window.addEventListener("scroll", recompute, { passive: true });
116
+ return () => {
117
+ observer.disconnect();
118
+ container.removeEventListener("scroll", recompute);
119
+ window.removeEventListener("scroll", recompute);
120
+ };
121
+ // eslint-disable-next-line react-hooks/exhaustive-deps
122
+ }, [containerRef]);
123
+ return (_jsx("div", { ref: overlayRef, "aria-hidden": true, style: {
124
+ position: "absolute",
125
+ inset: 0,
126
+ pointerEvents: "none",
127
+ overflow: "hidden",
128
+ }, className: className, children: rings.map((ring) => (_jsx(RingItem, { ring: ring }, ring.clientId))) }));
129
+ }
130
+ //# sourceMappingURL=RemoteSelectionRings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RemoteSelectionRings.js","sourceRoot":"","sources":["../../src/collab-ui/RemoteSelectionRings.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { AgentPresenceChip, type AgentPresenceChipProps, } from "./AgentPresenceChip.js";
2
+ export { LiveCursorOverlay, type CursorMapFn, type LiveCursorOverlayProps, } from "./LiveCursorOverlay.js";
3
+ export { PresenceBar, type PresenceBarProps } from "./PresenceBar.js";
4
+ export { RecentEditHighlights, type RecentEditHighlightsProps, } from "./RecentEditHighlights.js";
5
+ export { RemoteSelectionRings, type RemoteSelectionRingsProps, type SelectionDescriptor, } from "./RemoteSelectionRings.js";
6
+ export { RECENT_EDITS_MAX, RECENT_EDIT_TTL_MS, dedupeCollabUsersByEmail, emailToColor, emailToName, type AttributedRecentEdit, type CollabUser, type NormalizedPoint, type OtherPresence, type PresencePayload, type RecentEdit, type RecentEditDescriptor, } from "./types.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/collab-ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,GAC5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,sBAAsB,GAC5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACL,oBAAoB,EACpB,KAAK,yBAAyB,GAC/B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,oBAAoB,EACpB,KAAK,yBAAyB,EAC9B,KAAK,mBAAmB,GACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,YAAY,EACZ,WAAW,EACX,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,oBAAoB,GAC1B,MAAM,YAAY,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { AgentPresenceChip, } from "./AgentPresenceChip.js";
2
+ export { LiveCursorOverlay, } from "./LiveCursorOverlay.js";
3
+ export { PresenceBar } from "./PresenceBar.js";
4
+ export { RecentEditHighlights, } from "./RecentEditHighlights.js";
5
+ export { RemoteSelectionRings, } from "./RemoteSelectionRings.js";
6
+ export { RECENT_EDITS_MAX, RECENT_EDIT_TTL_MS, dedupeCollabUsersByEmail, emailToColor, emailToName, } from "./types.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/collab-ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAElB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,iBAAiB,GAGlB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,WAAW,EAAyB,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACL,oBAAoB,GAErB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,oBAAoB,GAGrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,YAAY,EACZ,WAAW,GAQZ,MAAM,YAAY,CAAC"}
@@ -0,0 +1,48 @@
1
+ export interface CollabUser {
2
+ name: string;
3
+ email: string;
4
+ color: string;
5
+ avatarUrl?: string;
6
+ }
7
+ export type PresencePayload = Record<string, unknown>;
8
+ export interface OtherPresence {
9
+ clientId: number;
10
+ user: CollabUser;
11
+ presence: PresencePayload;
12
+ isAgent: boolean;
13
+ }
14
+ export interface NormalizedPoint {
15
+ x: number;
16
+ y: number;
17
+ }
18
+ export type RecentEditDescriptor = {
19
+ kind: "text";
20
+ quote: string;
21
+ } | {
22
+ kind: "selector";
23
+ selector: string;
24
+ } | {
25
+ kind: "paths";
26
+ paths: string[];
27
+ } | {
28
+ kind: "doc";
29
+ } | {
30
+ kind: string;
31
+ [key: string]: unknown;
32
+ };
33
+ export interface RecentEdit {
34
+ descriptor: RecentEditDescriptor;
35
+ label?: string;
36
+ at: number;
37
+ }
38
+ export interface AttributedRecentEdit extends RecentEdit {
39
+ clientId: number;
40
+ user: OtherPresence["user"];
41
+ isAgent: boolean;
42
+ }
43
+ export declare const RECENT_EDITS_MAX = 5;
44
+ export declare const RECENT_EDIT_TTL_MS = 10000;
45
+ export declare function emailToColor(email: string): string;
46
+ export declare function emailToName(email: string): string;
47
+ export declare function dedupeCollabUsersByEmail(users: CollabUser[]): CollabUser[];
48
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/collab-ui/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,eAAe,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GACf;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,oBAAoB,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,oBAAqB,SAAQ,UAAU;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAezC,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD;AAMD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAY1E"}
@@ -0,0 +1,43 @@
1
+ export const RECENT_EDITS_MAX = 5;
2
+ export const RECENT_EDIT_TTL_MS = 10_000;
3
+ const CURSOR_COLORS = [
4
+ "#f87171",
5
+ "#fb923c",
6
+ "#fbbf24",
7
+ "#a3e635",
8
+ "#34d399",
9
+ "#22d3ee",
10
+ "#60a5fa",
11
+ "#14b8a6",
12
+ "#f472b6",
13
+ "#e879f9",
14
+ ];
15
+ export function emailToColor(email) {
16
+ let hash = 0;
17
+ for (let i = 0; i < email.length; i++) {
18
+ hash = ((hash << 5) - hash + email.charCodeAt(i)) | 0;
19
+ }
20
+ return CURSOR_COLORS[Math.abs(hash) % CURSOR_COLORS.length];
21
+ }
22
+ export function emailToName(email) {
23
+ const local = email.split("@")[0] || email;
24
+ return local.charAt(0).toUpperCase() + local.slice(1);
25
+ }
26
+ function normalizeCollabEmail(email) {
27
+ return email.trim().toLowerCase();
28
+ }
29
+ export function dedupeCollabUsersByEmail(users) {
30
+ const byEmail = new Map();
31
+ for (const user of users) {
32
+ const email = normalizeCollabEmail(user.email);
33
+ if (!email || byEmail.has(email))
34
+ continue;
35
+ byEmail.set(email, {
36
+ name: user.name || emailToName(email),
37
+ email,
38
+ color: user.color || emailToColor(email),
39
+ });
40
+ }
41
+ return Array.from(byEmail.values());
42
+ }
43
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/collab-ui/types.ts"],"names":[],"mappings":"AAwCA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAClC,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAEzC,MAAM,aAAa,GAAG;IACpB,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;CACV,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;IAC3C,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAa;IACzC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,KAAmB;IAC1D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC;YACrC,KAAK;YACL,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC,KAAK,CAAC;SACzC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AACtC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  export * from "./app-shell/index.js";
2
+ export * from "./collab-ui/index.js";
2
3
  export * from "./hooks/index.js";
3
4
  export * from "./onboarding/index.js";
5
+ export * from "./provider.js";
6
+ export * from "./sharing/index.js";
4
7
  export * from "./ui/index.js";
5
8
  export * from "./utils.js";
6
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  export * from "./app-shell/index.js";
2
+ export * from "./collab-ui/index.js";
2
3
  export * from "./hooks/index.js";
3
4
  export * from "./onboarding/index.js";
5
+ export * from "./provider.js";
6
+ export * from "./sharing/index.js";
4
7
  export * from "./ui/index.js";
5
8
  export * from "./utils.js";
6
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type ReactNode, type ComponentType } from "react";
2
+ import type { ButtonProps } from "./ui/button.js";
3
+ export interface ToolkitComponents {
4
+ Button?: ComponentType<ButtonProps>;
5
+ }
6
+ interface ToolkitProviderProps {
7
+ children: ReactNode;
8
+ components?: ToolkitComponents;
9
+ }
10
+ export declare function ToolkitProvider({ children, components, }: ToolkitProviderProps): import("react").JSX.Element;
11
+ export declare function useToolkitComponents(): ToolkitComponents;
12
+ export declare function useToolkitComponent<Name extends keyof ToolkitComponents>(name: Name): ToolkitComponents[Name];
13
+ export {};
14
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;CACrC;AAED,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAID,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,UAAU,GACX,EAAE,oBAAoB,+BAYtB;AAED,wBAAgB,oBAAoB,IAAI,iBAAiB,CAExD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,SAAS,MAAM,iBAAiB,EACtE,IAAI,EAAE,IAAI,GACT,iBAAiB,CAAC,IAAI,CAAC,CAEzB"}
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useMemo, } from "react";
3
+ const ToolkitComponentsContext = createContext({});
4
+ export function ToolkitProvider({ children, components, }) {
5
+ const parent = useContext(ToolkitComponentsContext);
6
+ const value = useMemo(() => ({ ...parent, ...components }), [parent, components]);
7
+ return (_jsx(ToolkitComponentsContext.Provider, { value: value, children: children }));
8
+ }
9
+ export function useToolkitComponents() {
10
+ return useContext(ToolkitComponentsContext);
11
+ }
12
+ export function useToolkitComponent(name) {
13
+ return useToolkitComponents()[name];
14
+ }
15
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,aAAa,EACb,UAAU,EACV,OAAO,GAGR,MAAM,OAAO,CAAC;AAaf,MAAM,wBAAwB,GAAG,aAAa,CAAoB,EAAE,CAAC,CAAC;AAEtE,MAAM,UAAU,eAAe,CAAC,EAC9B,QAAQ,EACR,UAAU,GACW;IACrB,MAAM,MAAM,GAAG,UAAU,CAAC,wBAAwB,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC,EACpC,CAAC,MAAM,EAAE,UAAU,CAAC,CACrB,CAAC;IAEF,OAAO,CACL,KAAC,wBAAwB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAC5C,QAAQ,GACyB,CACrC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,UAAU,CAAC,wBAAwB,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,IAAU;IAEV,OAAO,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface VisibilityBadgeProps {
2
+ visibility: "private" | "org" | "public" | null | undefined;
3
+ size?: number;
4
+ className?: string;
5
+ }
6
+ /**
7
+ * Tiny visibility chip for list views. Renders a small icon + label so users
8
+ * can spot shared/public resources at a glance.
9
+ */
10
+ export declare function VisibilityBadge({ visibility, size, className, }: VisibilityBadgeProps): import("react").JSX.Element;
11
+ //# sourceMappingURL=VisibilityBadge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VisibilityBadge.d.ts","sourceRoot":"","sources":["../../src/sharing/VisibilityBadge.tsx"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,UAAU,EACV,IAAS,EACT,SAAS,GACV,EAAE,oBAAoB,+BAoBtB"}
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { IconLock, IconBuilding, IconWorld } from "@tabler/icons-react";
3
+ /**
4
+ * Tiny visibility chip for list views. Renders a small icon + label so users
5
+ * can spot shared/public resources at a glance.
6
+ */
7
+ export function VisibilityBadge({ visibility, size = 12, className, }) {
8
+ const v = visibility ?? "private";
9
+ const Icon = v === "public" ? IconWorld : v === "org" ? IconBuilding : IconLock;
10
+ const label = v === "public" ? "Public" : v === "org" ? "Org" : "Private";
11
+ return (_jsxs("span", { className: className, style: {
12
+ display: "inline-flex",
13
+ alignItems: "center",
14
+ gap: 4,
15
+ fontSize: size,
16
+ color: "hsl(var(--muted-foreground))",
17
+ }, children: [_jsx(Icon, { size: size + 2 }), label] }));
18
+ }
19
+ //# sourceMappingURL=VisibilityBadge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VisibilityBadge.js","sourceRoot":"","sources":["../../src/sharing/VisibilityBadge.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAQxE;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,UAAU,EACV,IAAI,GAAG,EAAE,EACT,SAAS,GACY;IACrB,MAAM,CAAC,GAAG,UAAU,IAAI,SAAS,CAAC;IAClC,MAAM,IAAI,GACR,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;IACrE,MAAM,KAAK,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1E,OAAO,CACL,gBACE,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE;YACL,OAAO,EAAE,aAAa;YACtB,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,CAAC;YACN,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,8BAA8B;SACtC,aAED,KAAC,IAAI,IAAC,IAAI,EAAE,IAAI,GAAG,CAAC,GAAI,EACvB,KAAK,IACD,CACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { VisibilityBadge, type VisibilityBadgeProps, } from "./VisibilityBadge.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sharing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { VisibilityBadge, } from "./VisibilityBadge.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sharing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,GAEhB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,19 @@
1
+ /*
2
+ * Registers @agent-native/toolkit's compiled components with Tailwind so apps
3
+ * that render toolkit UI (dropdowns, dialogs, popovers, etc.) generate the
4
+ * classes those components use. Without this, classes that appear ONLY inside
5
+ * toolkit components (e.g. the dropdown content's `z-[250]` and enter/exit
6
+ * animations) are never generated, and the components render unstyled/invisible.
7
+ *
8
+ * Import in an app's `app/global.css` AFTER `@import "tailwindcss";`, alongside
9
+ * the core stylesheet:
10
+ *
11
+ * @import "tailwindcss";
12
+ * @import "@agent-native/core/styles/agent-native.css";
13
+ * @import "@agent-native/toolkit/styles.css";
14
+ *
15
+ * The @source path is self-relative to this file's shipped location in `dist/`,
16
+ * so it is robust to install layout — mirroring @agent-native/core's
17
+ * agent-native.css. Do NOT reach into node_modules from app CSS instead.
18
+ */
19
+ @source "./**/*.js";