@vllnt/ui 0.2.1-canary.4abeac1 → 0.2.1-canary.7fde2d1

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.
@@ -0,0 +1,104 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ forwardRef
5
+ } from "react";
6
+ import { cn } from "../../lib/utils";
7
+ const DEFAULT_LABELS = {
8
+ region: "Comment",
9
+ unreadSuffix: "unread"
10
+ };
11
+ const STATE_FILL = {
12
+ open: "bg-foreground text-background",
13
+ resolved: "bg-muted text-muted-foreground"
14
+ };
15
+ const PinBody = (props) => {
16
+ const showBadge = typeof props.unread === "number" && props.unread > 0;
17
+ const useAccent = props.accent && props.state === "open";
18
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
19
+ /* @__PURE__ */ jsx(
20
+ "span",
21
+ {
22
+ "aria-hidden": "true",
23
+ className: cn(
24
+ "flex h-7 w-7 items-center justify-center rounded-full border border-background text-[11px] font-semibold shadow-sm",
25
+ STATE_FILL[props.state]
26
+ ),
27
+ "data-comment-pin-body": true,
28
+ style: useAccent ? { backgroundColor: props.accent, color: "white" } : void 0,
29
+ children: props.authorInitial ?? "\u2022"
30
+ }
31
+ ),
32
+ showBadge ? /* @__PURE__ */ jsx(
33
+ "span",
34
+ {
35
+ "aria-hidden": "true",
36
+ className: "absolute -right-1 -top-1 inline-flex min-h-[14px] min-w-[14px] items-center justify-center rounded-full bg-red-500 px-1 text-[9px] font-medium text-white",
37
+ "data-comment-pin-unread": true,
38
+ children: props.unread
39
+ }
40
+ ) : null
41
+ ] });
42
+ };
43
+ const CommentPin = forwardRef(
44
+ (props, ref) => {
45
+ const {
46
+ authorInitial,
47
+ className,
48
+ color,
49
+ labels,
50
+ onActivate,
51
+ state = "open",
52
+ unread,
53
+ x,
54
+ y,
55
+ ...rest
56
+ } = props;
57
+ const resolvedLabels = { ...DEFAULT_LABELS, ...labels };
58
+ const showBadge = typeof unread === "number" && unread > 0;
59
+ const ariaLabel = showBadge ? `${resolvedLabels.region}, ${unread} ${resolvedLabels.unreadSuffix}` : resolvedLabels.region;
60
+ const handleClick = () => {
61
+ onActivate?.();
62
+ };
63
+ const body = /* @__PURE__ */ jsx(
64
+ PinBody,
65
+ {
66
+ accent: color,
67
+ authorInitial,
68
+ state,
69
+ unread
70
+ }
71
+ );
72
+ return /* @__PURE__ */ jsx(
73
+ "div",
74
+ {
75
+ "aria-label": ariaLabel,
76
+ className: cn(
77
+ "absolute z-30 inline-flex -translate-x-1/2 -translate-y-1/2",
78
+ className
79
+ ),
80
+ "data-comment-pin": true,
81
+ "data-comment-pin-state": state,
82
+ ref,
83
+ role: "img",
84
+ style: { left: x, top: y },
85
+ ...rest,
86
+ children: onActivate ? /* @__PURE__ */ jsx(
87
+ "button",
88
+ {
89
+ "aria-label": ariaLabel,
90
+ className: "relative inline-flex rounded-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
91
+ "data-comment-pin-trigger": true,
92
+ onClick: handleClick,
93
+ type: "button",
94
+ children: body
95
+ }
96
+ ) : /* @__PURE__ */ jsx("span", { className: "relative inline-flex", children: body })
97
+ }
98
+ );
99
+ }
100
+ );
101
+ CommentPin.displayName = "CommentPin";
102
+ export {
103
+ CommentPin
104
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ CommentPin
3
+ } from "./comment-pin";
4
+ export {
5
+ CommentPin
6
+ };
@@ -306,6 +306,9 @@ import {
306
306
  ChatDockSection
307
307
  } from "./chat-dock-section";
308
308
  import { GlassPanel } from "./glass-panel";
309
+ import {
310
+ InfinitePlane
311
+ } from "./infinite-plane";
309
312
  import { LeftRail } from "./left-rail";
310
313
  import {
311
314
  MiniMapPanel
@@ -323,6 +326,12 @@ import { Sidebar } from "./sidebar";
323
326
  import { SidebarProvider, useSidebar } from "./sidebar-provider";
324
327
  import { TableOfContents } from "./table-of-contents";
325
328
  import { TopBar } from "./top-bar";
329
+ import {
330
+ ViewportBookmarks
331
+ } from "./viewport-bookmarks";
332
+ import {
333
+ WorldBreadcrumbs
334
+ } from "./world-breadcrumbs";
326
335
  import { ZoomHUD } from "./zoom-hud";
327
336
  import {
328
337
  ActivityLog
@@ -530,15 +539,33 @@ import {
530
539
  useFlowDiagram
531
540
  } from "./flow-diagram";
532
541
  import { AnchorPort } from "./anchor-port";
542
+ import {
543
+ CommentPin
544
+ } from "./comment-pin";
533
545
  import {
534
546
  ConnectorEdge
535
547
  } from "./connector-edge";
536
548
  import { EdgeLabel } from "./edge-label";
537
549
  import { GroupHull } from "./group-hull";
550
+ import {
551
+ LiveCursor
552
+ } from "./live-cursor";
538
553
  import {
539
554
  ObjectCard
540
555
  } from "./object-card";
541
556
  import { ObjectHandle } from "./object-handle";
557
+ import {
558
+ PresenceStack
559
+ } from "./presence-stack";
560
+ import {
561
+ PresenceSyncIndicator
562
+ } from "./presence-sync-indicator";
563
+ import {
564
+ SelectionPresence
565
+ } from "./selection-presence";
566
+ import {
567
+ ThreadBubble
568
+ } from "./thread-bubble";
542
569
  import {
543
570
  ConversationEmpty,
544
571
  ConversationHeader,
@@ -633,6 +660,7 @@ export {
633
660
  CommandList,
634
661
  CommandSeparator,
635
662
  CommandShortcut,
663
+ CommentPin,
636
664
  CommonMistake,
637
665
  Comparison,
638
666
  CompletionDialog,
@@ -737,6 +765,7 @@ export {
737
765
  HoverCard,
738
766
  HoverCardContent,
739
767
  HoverCardTrigger,
768
+ InfinitePlane,
740
769
  InlineInput,
741
770
  Input,
742
771
  InputOTP,
@@ -750,6 +779,7 @@ export {
750
779
  LearningObjectives,
751
780
  LeftRail,
752
781
  LineChart,
782
+ LiveCursor,
753
783
  LiveFeed,
754
784
  MDXContent,
755
785
  MarketTreemap,
@@ -798,6 +828,8 @@ export {
798
828
  PopoverContent,
799
829
  PopoverTrigger,
800
830
  Prerequisites,
831
+ PresenceStack,
832
+ PresenceSyncIndicator,
801
833
  ProTip,
802
834
  ProfileSection,
803
835
  ProgressBar,
@@ -835,6 +867,7 @@ export {
835
867
  SelectSeparator,
836
868
  SelectTrigger,
837
869
  SelectValue,
870
+ SelectionPresence,
838
871
  Separator,
839
872
  SeverityBadge,
840
873
  ShareDialog,
@@ -890,6 +923,7 @@ export {
890
923
  ThemeProvider,
891
924
  ThemeToggle,
892
925
  ThinkingBlock,
926
+ ThreadBubble,
893
927
  TickerTape,
894
928
  Toast,
895
929
  ToastAction,
@@ -916,9 +950,11 @@ export {
916
950
  UsageBreakdown,
917
951
  VideoEmbed,
918
952
  ViewSwitcher,
953
+ ViewportBookmarks,
919
954
  WalletCard,
920
955
  Watchlist,
921
956
  WorkspaceSwitcher,
957
+ WorldBreadcrumbs,
922
958
  WorldClockBar,
923
959
  ZoomHUD,
924
960
  alertVariants,
@@ -0,0 +1,6 @@
1
+ import {
2
+ InfinitePlane
3
+ } from "./infinite-plane";
4
+ export {
5
+ InfinitePlane
6
+ };
@@ -0,0 +1,75 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import {
4
+ forwardRef
5
+ } from "react";
6
+ import { cn } from "../../lib/utils";
7
+ const DEFAULT_LABELS = {
8
+ region: "Infinite plane"
9
+ };
10
+ const safeSpacing = (value) => value < 4 ? 4 : value;
11
+ const safeZoom = (value) => {
12
+ if (value < 0.1) {
13
+ return 0.1;
14
+ }
15
+ if (value > 10) {
16
+ return 10;
17
+ }
18
+ return value;
19
+ };
20
+ const buildBackground = (input) => {
21
+ if (input.pattern === "blank") {
22
+ return {};
23
+ }
24
+ const size = safeSpacing(input.spacing) * safeZoom(input.zoom);
25
+ const pos = `${input.translate.x}px ${input.translate.y}px`;
26
+ if (input.pattern === "grid") {
27
+ return {
28
+ backgroundImage: "linear-gradient(to right, hsl(var(--border)) 1px, transparent 1px), linear-gradient(to bottom, hsl(var(--border)) 1px, transparent 1px)",
29
+ backgroundPosition: pos,
30
+ backgroundSize: `${size}px ${size}px`
31
+ };
32
+ }
33
+ return {
34
+ backgroundImage: "radial-gradient(circle, hsl(var(--border)) 1px, transparent 1px)",
35
+ backgroundPosition: pos,
36
+ backgroundSize: `${size}px ${size}px`
37
+ };
38
+ };
39
+ const InfinitePlane = forwardRef(
40
+ (props, ref) => {
41
+ const {
42
+ children,
43
+ className,
44
+ labels,
45
+ pattern = "dot",
46
+ spacing = 32,
47
+ translate = { x: 0, y: 0 },
48
+ zoom = 1,
49
+ ...rest
50
+ } = props;
51
+ const resolvedLabels = { ...DEFAULT_LABELS, ...labels };
52
+ const background = buildBackground({ pattern, spacing, translate, zoom });
53
+ return /* @__PURE__ */ jsx(
54
+ "div",
55
+ {
56
+ "aria-label": resolvedLabels.region,
57
+ className: cn(
58
+ "relative h-full w-full overflow-hidden bg-background",
59
+ className
60
+ ),
61
+ "data-infinite-plane": true,
62
+ "data-infinite-plane-pattern": pattern,
63
+ ref,
64
+ role: "region",
65
+ style: background,
66
+ ...rest,
67
+ children
68
+ }
69
+ );
70
+ }
71
+ );
72
+ InfinitePlane.displayName = "InfinitePlane";
73
+ export {
74
+ InfinitePlane
75
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ LiveCursor
3
+ } from "./live-cursor";
4
+ export {
5
+ LiveCursor
6
+ };
@@ -0,0 +1,62 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ forwardRef
5
+ } from "react";
6
+ import { cn } from "../../lib/utils";
7
+ const DEFAULT_LABELS = {
8
+ region: "Live cursor"
9
+ };
10
+ const LiveCursor = forwardRef(
11
+ (props, ref) => {
12
+ const { className, color, labels, name, status, x, y, ...rest } = props;
13
+ const resolvedLabels = { ...DEFAULT_LABELS, ...labels };
14
+ const resolvedColor = color ?? "var(--foreground)";
15
+ return /* @__PURE__ */ jsxs(
16
+ "div",
17
+ {
18
+ "aria-label": typeof name === "string" ? `${resolvedLabels.region}: ${name}` : resolvedLabels.region,
19
+ className: cn(
20
+ "pointer-events-none absolute z-30 flex items-start gap-1",
21
+ className
22
+ ),
23
+ "data-live-cursor": true,
24
+ ref,
25
+ role: "img",
26
+ style: { left: x, top: y },
27
+ ...rest,
28
+ children: [
29
+ /* @__PURE__ */ jsx(
30
+ "svg",
31
+ {
32
+ "aria-hidden": "true",
33
+ className: "-ml-1 -mt-1 drop-shadow-sm",
34
+ "data-live-cursor-pointer": true,
35
+ fill: resolvedColor,
36
+ height: 18,
37
+ viewBox: "0 0 16 18",
38
+ width: 16,
39
+ children: /* @__PURE__ */ jsx("path", { d: "M0 0 L0 14 L4 11 L7 17 L10 16 L7 10 L13 10 Z" })
40
+ }
41
+ ),
42
+ name === null || name === void 0 ? null : /* @__PURE__ */ jsxs(
43
+ "span",
44
+ {
45
+ className: "ml-2 mt-2 inline-flex flex-col rounded-md px-1.5 py-0.5 text-[10px] font-medium text-white shadow-sm",
46
+ "data-live-cursor-chip": true,
47
+ style: { backgroundColor: resolvedColor },
48
+ children: [
49
+ /* @__PURE__ */ jsx("span", { children: name }),
50
+ status ? /* @__PURE__ */ jsx("span", { className: "text-[9px] opacity-80", "data-live-cursor-status": true, children: status }) : null
51
+ ]
52
+ }
53
+ )
54
+ ]
55
+ }
56
+ );
57
+ }
58
+ );
59
+ LiveCursor.displayName = "LiveCursor";
60
+ export {
61
+ LiveCursor
62
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ PresenceStack
3
+ } from "./presence-stack";
4
+ export {
5
+ PresenceStack
6
+ };
@@ -0,0 +1,108 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ forwardRef
5
+ } from "react";
6
+ import { cn } from "../../lib/utils";
7
+ const STATUS_DOT = {
8
+ active: "bg-emerald-500",
9
+ away: "bg-amber-500",
10
+ idle: "bg-muted-foreground",
11
+ offline: "bg-muted-foreground/40"
12
+ };
13
+ const DEFAULT_LABELS = {
14
+ overflowSuffix: "more",
15
+ region: "Live presence"
16
+ };
17
+ const Avatar = (props) => {
18
+ const { user } = props;
19
+ const status = user.status ?? "active";
20
+ return /* @__PURE__ */ jsxs(
21
+ "span",
22
+ {
23
+ className: "relative -ml-2 inline-flex h-7 w-7 items-center justify-center rounded-full border-2 border-background text-[11px] font-semibold text-white shadow-sm first:ml-0",
24
+ "data-presence-stack-status": status,
25
+ "data-presence-stack-user": user.id,
26
+ style: { backgroundColor: user.color ?? "var(--foreground)" },
27
+ title: user.name,
28
+ children: [
29
+ user.initial,
30
+ /* @__PURE__ */ jsx(
31
+ "span",
32
+ {
33
+ "aria-hidden": "true",
34
+ className: cn(
35
+ "absolute -bottom-0.5 -right-0.5 h-2 w-2 rounded-full border border-background",
36
+ STATUS_DOT[status]
37
+ ),
38
+ "data-presence-stack-dot": true
39
+ }
40
+ )
41
+ ]
42
+ }
43
+ );
44
+ };
45
+ const PresenceStack = forwardRef(
46
+ (props, ref) => {
47
+ const {
48
+ className,
49
+ labels,
50
+ max = 5,
51
+ onOverflowActivate,
52
+ users,
53
+ ...rest
54
+ } = props;
55
+ const resolvedLabels = { ...DEFAULT_LABELS, ...labels };
56
+ const visible = max >= users.length ? users : users.slice(0, max);
57
+ const hidden = users.length - visible.length;
58
+ const handleOverflow = () => {
59
+ onOverflowActivate?.();
60
+ };
61
+ return /* @__PURE__ */ jsxs(
62
+ "div",
63
+ {
64
+ "aria-label": resolvedLabels.region,
65
+ className: cn("inline-flex items-center pl-2", className),
66
+ "data-presence-stack": true,
67
+ ref,
68
+ role: "group",
69
+ ...rest,
70
+ children: [
71
+ visible.map((user) => /* @__PURE__ */ jsx(Avatar, { user }, user.id)),
72
+ hidden > 0 ? renderOverflow({
73
+ count: hidden,
74
+ handleClick: handleOverflow,
75
+ handlerProvided: Boolean(onOverflowActivate),
76
+ labels: resolvedLabels
77
+ }) : null
78
+ ]
79
+ }
80
+ );
81
+ }
82
+ );
83
+ PresenceStack.displayName = "PresenceStack";
84
+ const renderOverflow = (input) => {
85
+ const text = `+${input.count}`;
86
+ const aria = `${input.count} ${input.labels.overflowSuffix}`;
87
+ const className = "relative -ml-2 inline-flex h-7 min-w-7 items-center justify-center rounded-full border-2 border-background bg-muted px-1.5 text-[10px] font-semibold text-muted-foreground shadow-sm";
88
+ if (input.handlerProvided) {
89
+ return /* @__PURE__ */ jsx(
90
+ "button",
91
+ {
92
+ "aria-label": aria,
93
+ className: cn(
94
+ className,
95
+ "transition-colors hover:bg-muted/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
96
+ ),
97
+ "data-presence-stack-overflow": true,
98
+ onClick: input.handleClick,
99
+ type: "button",
100
+ children: text
101
+ }
102
+ );
103
+ }
104
+ return /* @__PURE__ */ jsx("span", { "aria-label": aria, className, "data-presence-stack-overflow": true, children: text });
105
+ };
106
+ export {
107
+ PresenceStack
108
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ PresenceSyncIndicator
3
+ } from "./presence-sync-indicator";
4
+ export {
5
+ PresenceSyncIndicator
6
+ };
@@ -0,0 +1,73 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import {
4
+ forwardRef
5
+ } from "react";
6
+ import { cn } from "../../lib/utils";
7
+ const STATE_LABEL = {
8
+ error: "Sync error",
9
+ live: "Live",
10
+ offline: "Offline",
11
+ reconnecting: "Reconnecting",
12
+ syncing: "Syncing"
13
+ };
14
+ const STATE_DOT = {
15
+ error: "bg-red-500",
16
+ live: "bg-emerald-500",
17
+ offline: "bg-muted-foreground",
18
+ reconnecting: "bg-amber-500 animate-pulse",
19
+ syncing: "bg-blue-500 animate-pulse"
20
+ };
21
+ const STATE_TEXT = {
22
+ error: "text-red-700 dark:text-red-300",
23
+ live: "text-emerald-700 dark:text-emerald-300",
24
+ offline: "text-muted-foreground",
25
+ reconnecting: "text-amber-700 dark:text-amber-300",
26
+ syncing: "text-blue-700 dark:text-blue-300"
27
+ };
28
+ const DEFAULT_LABELS = {
29
+ region: "Presence sync"
30
+ };
31
+ const PresenceSyncIndicator = forwardRef((props, ref) => {
32
+ const { className, label, labels, state, status, ...rest } = props;
33
+ const resolvedLabels = { ...DEFAULT_LABELS, ...labels };
34
+ const text = label ?? STATE_LABEL[state];
35
+ return /* @__PURE__ */ jsxs(
36
+ "div",
37
+ {
38
+ "aria-label": `${resolvedLabels.region}: ${STATE_LABEL[state]}`,
39
+ className: cn(
40
+ "inline-flex items-center gap-1.5 rounded-full border border-border bg-background px-2 py-1 text-[11px] shadow-sm",
41
+ className
42
+ ),
43
+ "data-presence-state": state,
44
+ "data-presence-sync": true,
45
+ ref,
46
+ role: "status",
47
+ ...rest,
48
+ children: [
49
+ /* @__PURE__ */ jsx(
50
+ "span",
51
+ {
52
+ "aria-hidden": "true",
53
+ className: cn("h-1.5 w-1.5 rounded-full", STATE_DOT[state]),
54
+ "data-presence-sync-dot": true
55
+ }
56
+ ),
57
+ /* @__PURE__ */ jsx("span", { className: cn("font-medium", STATE_TEXT[state]), children: text }),
58
+ status ? /* @__PURE__ */ jsx(
59
+ "span",
60
+ {
61
+ className: "text-[10px] text-muted-foreground",
62
+ "data-presence-sync-status": true,
63
+ children: status
64
+ }
65
+ ) : null
66
+ ]
67
+ }
68
+ );
69
+ });
70
+ PresenceSyncIndicator.displayName = "PresenceSyncIndicator";
71
+ export {
72
+ PresenceSyncIndicator
73
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ SelectionPresence
3
+ } from "./selection-presence";
4
+ export {
5
+ SelectionPresence
6
+ };
@@ -0,0 +1,50 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import {
4
+ forwardRef
5
+ } from "react";
6
+ import { cn } from "../../lib/utils";
7
+ const DEFAULT_LABELS = {
8
+ region: "Selection presence"
9
+ };
10
+ const SelectionPresence = forwardRef((props, ref) => {
11
+ const { className, color, height, labels, name, width, x, y, ...rest } = props;
12
+ const resolvedLabels = { ...DEFAULT_LABELS, ...labels };
13
+ const accent = color ?? "var(--foreground)";
14
+ const ariaLabel = typeof name === "string" ? `${resolvedLabels.region}: ${name}` : resolvedLabels.region;
15
+ return /* @__PURE__ */ jsx(
16
+ "div",
17
+ {
18
+ "aria-label": ariaLabel,
19
+ className: cn(
20
+ "pointer-events-none absolute z-20 rounded-md border-2 border-dashed",
21
+ className
22
+ ),
23
+ "data-selection-presence": true,
24
+ ref,
25
+ role: "img",
26
+ style: {
27
+ backgroundColor: `color-mix(in srgb, ${accent} 10%, transparent)`,
28
+ borderColor: accent,
29
+ height,
30
+ left: x,
31
+ top: y,
32
+ width
33
+ },
34
+ ...rest,
35
+ children: name === null || name === void 0 ? null : /* @__PURE__ */ jsx(
36
+ "span",
37
+ {
38
+ className: "absolute -top-5 left-0 inline-flex items-center rounded-md px-1.5 py-0.5 text-[10px] font-medium text-white shadow-sm",
39
+ "data-selection-presence-chip": true,
40
+ style: { backgroundColor: accent },
41
+ children: name
42
+ }
43
+ )
44
+ }
45
+ );
46
+ });
47
+ SelectionPresence.displayName = "SelectionPresence";
48
+ export {
49
+ SelectionPresence
50
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ ThreadBubble
3
+ } from "./thread-bubble";
4
+ export {
5
+ ThreadBubble
6
+ };