@arbidocs/blocks 0.3.128 → 0.3.130

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
@@ -1058,7 +1058,6 @@ function MetricCard({
1058
1058
  ] });
1059
1059
  }
1060
1060
  var MAX_AVATARS = 3;
1061
- var ON_HOVER = "opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100";
1062
1061
  function WorkspaceCard({
1063
1062
  name,
1064
1063
  matterRef,
@@ -1074,6 +1073,7 @@ function WorkspaceCard({
1074
1073
  onOpen,
1075
1074
  icon: Icon = lucideReact.FolderLock,
1076
1075
  iconSlot,
1076
+ tooltipEntitySlot,
1077
1077
  cornerSlot,
1078
1078
  accent = "default",
1079
1079
  testId,
@@ -1083,24 +1083,57 @@ function WorkspaceCard({
1083
1083
  const totalMembers = memberCount ?? members.length;
1084
1084
  const shownMembers = membersHidden ? [] : members.slice(0, MAX_AVATARS);
1085
1085
  const extraMembers = totalMembers - shownMembers.length;
1086
- const btnTestId = buttonTestId ?? (testId ? `${testId}-open` : void 0);
1086
+ const actionTestId = buttonTestId ?? (testId ? `${testId}-open` : void 0);
1087
+ const canOpen = Boolean(onOpen) && !busy;
1088
+ const [isHoverPointerActive, setIsHoverPointerActive] = react$1.useState(false);
1089
+ const [isKeyboardFocused, setIsKeyboardFocused] = react$1.useState(false);
1090
+ const revealInteractiveContent = isHoverPointerActive || isKeyboardFocused;
1091
+ const showOpenAction = busy || revealInteractiveContent;
1087
1092
  const hue = accent && accent !== "default" ? `var(--color-${accent})` : null;
1088
1093
  const tileStyle = hue ? { backgroundColor: `color-mix(in oklab, ${hue} 14%, transparent)`, color: hue } : void 0;
1089
- const buttonStyle = hue ? { backgroundColor: hue, color: "var(--color-primary-foreground)" } : void 0;
1094
+ const openStyle = hue ? { backgroundColor: hue, color: "var(--color-background)" } : void 0;
1095
+ const handleKeyDown = (event) => {
1096
+ if (!canOpen || event.target !== event.currentTarget) return;
1097
+ if (event.key === "Enter" || event.key === " ") {
1098
+ event.preventDefault();
1099
+ onOpen?.();
1100
+ }
1101
+ };
1102
+ const handleFocusCapture = (event) => {
1103
+ setIsKeyboardFocused(event.target instanceof Element && event.target.matches(":focus-visible"));
1104
+ };
1105
+ const handleBlurCapture = (event) => {
1106
+ if (!event.currentTarget.contains(event.relatedTarget)) {
1107
+ setIsKeyboardFocused(false);
1108
+ }
1109
+ };
1090
1110
  return /* @__PURE__ */ jsxRuntime.jsxs(
1091
1111
  react.Card,
1092
1112
  {
1093
- variant: "outline",
1113
+ variant: "flat",
1094
1114
  className: react.cn(
1095
- "card-hover group flex flex-col gap-3 p-4",
1096
- // The current workspace is marked by a ring, not a badge — the footer
1097
- // already says "Current workspace" in words.
1098
- active && "ring-1 ring-primary",
1115
+ "card-hover relative flex h-48 w-full flex-col gap-3 overflow-hidden rounded-xl bg-card p-4 shadow-sm",
1116
+ canOpen && "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2",
1117
+ active && "bg-primary/10 shadow-md",
1099
1118
  className
1100
1119
  ),
1101
1120
  "data-testid": testId,
1121
+ "data-active": active || void 0,
1122
+ role: canOpen ? "button" : void 0,
1123
+ tabIndex: canOpen ? 0 : void 0,
1124
+ "aria-current": active ? "page" : void 0,
1125
+ "aria-label": canOpen ? `Open workspace ${name}` : void 0,
1126
+ "aria-busy": busy || void 0,
1127
+ onClick: canOpen ? onOpen : void 0,
1128
+ onKeyDown: handleKeyDown,
1129
+ onPointerEnter: (event) => {
1130
+ if (event.pointerType !== "touch") setIsHoverPointerActive(true);
1131
+ },
1132
+ onPointerLeave: () => setIsHoverPointerActive(false),
1133
+ onFocusCapture: handleFocusCapture,
1134
+ onBlurCapture: handleBlurCapture,
1102
1135
  children: [
1103
- /* @__PURE__ */ jsxRuntime.jsxs(react.CardHeader, { className: "flex flex-row items-start gap-3 p-0", children: [
1136
+ /* @__PURE__ */ jsxRuntime.jsxs(react.CardHeader, { className: "flex flex-row items-center gap-3 space-y-0 p-0", children: [
1104
1137
  iconSlot ?? /* @__PURE__ */ jsxRuntime.jsx(
1105
1138
  "div",
1106
1139
  {
@@ -1113,97 +1146,125 @@ function WorkspaceCard({
1113
1146
  /* @__PURE__ */ jsxRuntime.jsx(
1114
1147
  react.CardTitle,
1115
1148
  {
1116
- className: "line-clamp-2 text-base leading-tight",
1149
+ className: "line-clamp-2 text-base font-bold leading-tight",
1117
1150
  "data-testid": testId && `${testId}-title`,
1118
1151
  children: name
1119
1152
  }
1120
1153
  ),
1121
1154
  matterRef && /* @__PURE__ */ jsxRuntime.jsx(react.CardDescription, { className: "mt-0.5 truncate text-xs font-medium uppercase tracking-wide text-muted-foreground", children: matterRef })
1122
1155
  ] }),
1123
- cornerSlot && /* @__PURE__ */ jsxRuntime.jsx("div", { className: react.cn("shrink-0", ON_HOVER), children: cornerSlot })
1156
+ cornerSlot && /* @__PURE__ */ jsxRuntime.jsx(
1157
+ "div",
1158
+ {
1159
+ className: react.cn(
1160
+ "shrink-0 opacity-0 transition-opacity",
1161
+ revealInteractiveContent && "opacity-100"
1162
+ ),
1163
+ children: cornerSlot
1164
+ }
1165
+ )
1124
1166
  ] }),
1125
- /* @__PURE__ */ jsxRuntime.jsxs(react.CardContent, { className: "flex flex-1 flex-col gap-2 p-0", children: [
1126
- description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-2 text-sm text-muted-foreground", children: description }),
1127
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3 text-sm", children: [
1128
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-foreground", title: "Documents", children: [
1129
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-3.5 text-muted-foreground" }),
1130
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium tabular-nums", children: docCount.toLocaleString() })
1131
- ] }),
1132
- chatCount !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-foreground", title: "Chats", children: [
1133
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessagesSquare, { className: "size-3.5 text-muted-foreground" }),
1134
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium tabular-nums", children: chatCount.toLocaleString() })
1135
- ] }),
1136
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-foreground", title: "Members", children: [
1137
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { className: "size-3.5 text-muted-foreground" }),
1138
- /* @__PURE__ */ jsxRuntime.jsx(
1167
+ /* @__PURE__ */ jsxRuntime.jsxs(react.CardContent, { className: "relative flex min-h-0 flex-1 flex-col p-0", children: [
1168
+ description && /* @__PURE__ */ jsxRuntime.jsxs(react.Tooltip, { children: [
1169
+ /* @__PURE__ */ jsxRuntime.jsx(react.TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
1170
+ "p",
1171
+ {
1172
+ className: react.cn(
1173
+ "line-clamp-2 text-sm text-muted-foreground opacity-100 transition-opacity",
1174
+ showOpenAction && "opacity-0"
1175
+ ),
1176
+ children: description
1177
+ }
1178
+ ) }),
1179
+ /* @__PURE__ */ jsxRuntime.jsx(react.TooltipContent, { side: "top", className: "max-w-sm p-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-md", children: [
1180
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center bg-muted/70 px-3 py-2.5", children: tooltipEntitySlot ?? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: name }) }),
1181
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 py-3 text-sm leading-relaxed text-foreground/90", children: description })
1182
+ ] }) })
1183
+ ] }),
1184
+ /* @__PURE__ */ jsxRuntime.jsx(
1185
+ "span",
1186
+ {
1187
+ className: react.cn(
1188
+ "pointer-events-none absolute inset-0 z-10 inline-flex items-center justify-center whitespace-nowrap opacity-0 transition-opacity",
1189
+ showOpenAction && "opacity-100"
1190
+ ),
1191
+ "data-testid": actionTestId,
1192
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1139
1193
  "span",
1140
1194
  {
1141
- className: "font-medium tabular-nums",
1142
- "data-testid": testId && `${testId}-member-count`,
1143
- children: membersHidden ? "\u2014" : totalMembers
1195
+ className: react.cn(
1196
+ "inline-flex w-full items-center justify-center gap-2 rounded-md px-4 py-2 text-base font-semibold shadow-md",
1197
+ active ? "bg-muted-foreground text-background" : "bg-primary text-primary-foreground"
1198
+ ),
1199
+ style: active ? void 0 : openStyle,
1200
+ children: active ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1201
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "size-4" }),
1202
+ " Current workspace"
1203
+ ] }) : busy ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1204
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-4 animate-spin" }),
1205
+ " Opening"
1206
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1207
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeftRight, { className: "size-4" }),
1208
+ " Open"
1209
+ ] })
1144
1210
  }
1145
1211
  )
1146
- ] }),
1147
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex shrink-0 -space-x-2", children: [
1148
- shownMembers.map((m, i) => /* @__PURE__ */ jsxRuntime.jsxs(react.Avatar, { className: "size-6 border-2 border-card", title: m.name, children: [
1149
- m.picture && /* @__PURE__ */ jsxRuntime.jsx(react.AvatarImage, { src: m.picture, alt: m.name }),
1150
- /* @__PURE__ */ jsxRuntime.jsx(react.AvatarFallback, { className: "bg-foreground text-[9px] font-medium text-background", children: chunkAHWIZJ4M_cjs.initials(m.name || "?") })
1151
- ] }, i)),
1152
- !membersHidden && extraMembers > 0 && /* @__PURE__ */ jsxRuntime.jsx(react.Avatar, { className: "size-6 border-2 border-card", children: /* @__PURE__ */ jsxRuntime.jsxs(react.AvatarFallback, { className: "bg-accent text-[9px] font-medium text-muted-foreground", children: [
1153
- "+",
1154
- extraMembers
1155
- ] }) })
1156
- ] })
1157
- ] })
1158
- ] }),
1159
- /* @__PURE__ */ jsxRuntime.jsx(react.CardFooter, { className: "grid min-h-8 place-items-center p-0", children: active ? (
1160
- // Reads as a statement, not a call to action — but stays clickable, so
1161
- // re-entering the workspace you're already in still works.
1162
- /* @__PURE__ */ jsxRuntime.jsxs(
1163
- react.Button,
1164
- {
1165
- variant: "ghost",
1166
- size: "sm",
1167
- className: "col-start-1 row-start-1 h-8 whitespace-nowrap px-2 text-xs font-medium text-primary hover:bg-primary/10",
1168
- onClick: onOpen,
1169
- "data-testid": btnTestId,
1170
- children: [
1171
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "size-3.5" }),
1172
- " Current workspace"
1173
- ]
1174
1212
  }
1175
1213
  )
1176
- ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1214
+ ] }),
1215
+ /* @__PURE__ */ jsxRuntime.jsxs(react.CardFooter, { className: "mt-auto flex w-full min-w-0 flex-col items-stretch gap-3 overflow-hidden p-0", children: [
1216
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-x-3 text-sm", children: [
1217
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
1218
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-foreground", title: "Documents", children: [
1219
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { className: "size-3.5 text-muted-foreground" }),
1220
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium tabular-nums", children: docCount.toLocaleString() })
1221
+ ] }),
1222
+ chatCount !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-foreground", title: "Chats", children: [
1223
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessagesSquare, { className: "size-3.5 text-muted-foreground" }),
1224
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium tabular-nums", children: chatCount.toLocaleString() })
1225
+ ] }),
1226
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-foreground", title: "Members", children: [
1227
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Users, { className: "size-3.5 text-muted-foreground" }),
1228
+ /* @__PURE__ */ jsxRuntime.jsx(
1229
+ "span",
1230
+ {
1231
+ className: "font-medium tabular-nums",
1232
+ "data-testid": testId && `${testId}-member-count`,
1233
+ children: membersHidden ? "\u2014" : totalMembers
1234
+ }
1235
+ )
1236
+ ] })
1237
+ ] }),
1238
+ /* @__PURE__ */ jsxRuntime.jsxs(
1239
+ "div",
1240
+ {
1241
+ className: "ml-auto flex shrink-0 -space-x-2",
1242
+ "data-testid": testId && `${testId}-member-avatars`,
1243
+ children: [
1244
+ shownMembers.map((m, i) => /* @__PURE__ */ jsxRuntime.jsxs(react.Avatar, { className: "size-6 border-2 border-card", title: m.name, children: [
1245
+ m.picture && /* @__PURE__ */ jsxRuntime.jsx(react.AvatarImage, { src: m.picture, alt: m.name }),
1246
+ /* @__PURE__ */ jsxRuntime.jsx(react.AvatarFallback, { className: "bg-foreground text-[9px] font-medium text-background", children: chunkAHWIZJ4M_cjs.initials(m.name || "?") })
1247
+ ] }, i)),
1248
+ !membersHidden && extraMembers > 0 && /* @__PURE__ */ jsxRuntime.jsx(react.Avatar, { className: "size-6 border-2 border-card", children: /* @__PURE__ */ jsxRuntime.jsxs(react.AvatarFallback, { className: "bg-accent text-[9px] font-medium text-muted-foreground", children: [
1249
+ "+",
1250
+ extraMembers
1251
+ ] }) })
1252
+ ]
1253
+ }
1254
+ )
1255
+ ] }),
1177
1256
  updatedAt && /* @__PURE__ */ jsxRuntime.jsxs(
1178
1257
  "span",
1179
1258
  {
1180
- className: react.cn(
1181
- "col-start-1 row-start-1 whitespace-nowrap text-xs text-muted-foreground",
1182
- "transition-opacity group-hover:opacity-0 group-focus-within:opacity-0"
1183
- ),
1259
+ className: "min-w-0 max-w-full self-start truncate text-left text-xs text-muted-foreground",
1184
1260
  title: chunkAHWIZJ4M_cjs.fmtDate(updatedAt),
1185
1261
  children: [
1186
1262
  "Updated ",
1187
1263
  chunkAHWIZJ4M_cjs.fromNow(updatedAt)
1188
1264
  ]
1189
1265
  }
1190
- ),
1191
- /* @__PURE__ */ jsxRuntime.jsxs(
1192
- react.Button,
1193
- {
1194
- size: "sm",
1195
- className: react.cn("col-start-1 row-start-1 whitespace-nowrap", ON_HOVER),
1196
- style: buttonStyle,
1197
- onClick: onOpen,
1198
- disabled: busy,
1199
- "data-testid": btnTestId,
1200
- children: [
1201
- busy ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeftRight, { className: "size-3.5" }),
1202
- "Open"
1203
- ]
1204
- }
1205
1266
  )
1206
- ] }) })
1267
+ ] })
1207
1268
  ]
1208
1269
  }
1209
1270
  );