@parallelworks/ui 0.52.0 → 0.53.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.
Files changed (55) hide show
  1. package/README.md +42 -3
  2. package/dist/ai/ai.css +5 -3
  3. package/dist/ai/components/agent/AgentMessageParts.js +1 -1
  4. package/dist/ai/strings.js +0 -1
  5. package/dist/ai/ui/sidebar.js +1 -1
  6. package/dist/components/Field.d.ts +5 -4
  7. package/dist/components/Field.js +27 -4
  8. package/dist/components/InfoTip.d.ts +12 -4
  9. package/dist/components/InfoTip.js +13 -3
  10. package/dist/components/MarkdownImpl.d.ts +1 -0
  11. package/dist/components/MarkdownImpl.js +1 -0
  12. package/dist/components/Popover.d.ts +4 -1
  13. package/dist/components/Popover.js +2 -1
  14. package/dist/components/Provider.d.ts +2 -0
  15. package/dist/components/Provider.js +1 -0
  16. package/dist/components/focus.d.ts +5 -0
  17. package/dist/components/focus.js +21 -1
  18. package/dist/editor/Editor.js +13 -3
  19. package/dist/editor/Monaco.d.ts +8 -1
  20. package/dist/editor/Monaco.js +16 -3
  21. package/dist/editor/editorModel.d.ts +1 -1
  22. package/dist/editor/editorModel.js +1 -1
  23. package/dist/editor/index.d.ts +1 -0
  24. package/dist/editor/index.js +2 -1
  25. package/dist/editor/languages.d.ts +24 -0
  26. package/dist/editor/languages.js +31 -0
  27. package/dist/editor/monacoFeatures.d.ts +7 -0
  28. package/dist/editor/monacoFeatures.js +19 -0
  29. package/dist/editor/themes.js +7 -2
  30. package/dist/editor/workers.d.ts +3 -3
  31. package/dist/editor/workers.js +8 -4
  32. package/dist/editor/yamlLanguage.js +55 -38
  33. package/dist/file-explorer/FileExplorer.d.ts +18 -4
  34. package/dist/file-explorer/FileExplorer.js +62 -19
  35. package/dist/file-explorer/FilePreview/Viewer.js +12 -8
  36. package/dist/file-explorer/FileRow.d.ts +6 -2
  37. package/dist/file-explorer/FileRow.js +35 -17
  38. package/dist/file-explorer/FileRowsWindow.d.ts +2 -1
  39. package/dist/file-explorer/FileRowsWindow.js +2 -1
  40. package/dist/file-explorer/FileTable.d.ts +3 -1
  41. package/dist/file-explorer/FileTable.js +3 -2
  42. package/dist/file-explorer/TreeView.d.ts +5 -1
  43. package/dist/file-explorer/TreeView.js +49 -25
  44. package/dist/file-explorer/helpers.js +3 -3
  45. package/dist/file-explorer/lib/utils.d.ts +3 -0
  46. package/dist/file-explorer/lib/utils.js +6 -1
  47. package/dist/form/Wizard/utils.js +2 -1
  48. package/dist/list/ActionToolbar.js +3 -2
  49. package/dist/list/ListPage.js +1 -1
  50. package/dist/list/ListTable.d.ts +5 -0
  51. package/dist/list/ListTable.js +6 -2
  52. package/dist/styles.css +1 -1
  53. package/package.json +5 -2
  54. package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +0 -6
  55. package/dist/file-explorer/FilePreview/CodePreviewEditor.js +0 -64
@@ -12,7 +12,7 @@ import { useVirtualizer } from "@tanstack/react-virtual";
12
12
  /** The file table. Give it a `key` of the folder path: a folder change must reset
13
13
  * the cursor, the scroll offset and the virtualizer's measurements, and a remount
14
14
  * does all three without a synchronising effect. */
15
- function FileTable({ nodes, checkedItems, allSelected, someSelected, onSelectAll, getItems, openMenu, onOpen, onToggleCheck, onPreview, loadMore }) {
15
+ function FileTable({ nodes, checkedItems, allSelected, someSelected, onSelectAll, getItems, openMenu, onOpen, onToggleCheck, onPreview, pathHref, loadMore }) {
16
16
  const [scrollEl, setScrollEl] = useState(null);
17
17
  const [activeIndex, setActiveIndex] = useState(-1);
18
18
  const [theadHeight, setTheadHeight] = useState(0);
@@ -165,7 +165,8 @@ function FileTable({ nodes, checkedItems, allSelected, someSelected, onSelectAll
165
165
  openMenu,
166
166
  onOpen: handleOpen,
167
167
  onToggleCheck,
168
- onPreview
168
+ onPreview,
169
+ pathHref
169
170
  })]
170
171
  })
171
172
  });
@@ -13,6 +13,10 @@ interface TreeViewProps {
13
13
  onDropToFolder: (folderPath: string, files: FileList | DataTransferItemList) => void;
14
14
  onContextMenu: (e: React.MouseEvent, node: TreeNode) => void;
15
15
  onPreviewFile: (node: TreeNode) => void;
16
+ /** The URL of a path; set, each row is a link to its path. */
17
+ pathHref?: ((path: string) => string) | undefined;
18
+ /** A plain click on a row's link, which moves to its path on its own. */
19
+ onFollowLink?: ((node: TreeNode) => void) | undefined;
16
20
  /** Directories with pages left to fetch, and how to fetch them. */
17
21
  paging?: {
18
22
  incompletePaths: ReadonlySet<string>;
@@ -23,5 +27,5 @@ interface TreeViewProps {
23
27
  }
24
28
  /** The sidebar tree, flattened and windowed. The flat array is the single source
25
29
  * of truth for rendering, arrow keys and ARIA. */
26
- export declare function TreeView({ rootNodes, parentToChildrenMap, expandedPaths, selectedPath, loadingPaths, onToggleExpand, onSelect, onDropToFolder, onContextMenu, onPreviewFile, paging, }: TreeViewProps): import("react").JSX.Element;
30
+ export declare function TreeView({ rootNodes, parentToChildrenMap, expandedPaths, selectedPath, loadingPaths, onToggleExpand, onSelect, onDropToFolder, onContextMenu, onPreviewFile, pathHref, onFollowLink, paging, }: TreeViewProps): import("react").JSX.Element;
27
31
  export {};
@@ -3,8 +3,9 @@ import { ChevronRightIcon, FolderIcon, FolderOpenIcon } from "../icons.js";
3
3
  import { isDev } from "../dev.js";
4
4
  import { positionKeys } from "../components/keys.js";
5
5
  import { useStrings } from "../components/Provider.js";
6
+ import { AppLink, isPlainClick } from "../components/AppLink.js";
6
7
  import { Skeleton } from "../components/Skeleton.js";
7
- import { getParentPath } from "./lib/utils.js";
8
+ import { carriesFiles, getParentPath } from "./lib/utils.js";
8
9
  import { canPreview } from "./FilePreview/previewType.js";
9
10
  import { getNodeIcon } from "./helpers.js";
10
11
  import { edgeRow, findRowIndex, firstChildRow, flattenTreeRows, nextFileLimit, parentRow, stepRow } from "./treeRows.js";
@@ -23,7 +24,7 @@ function rowHeight(row) {
23
24
  }
24
25
  /** The sidebar tree, flattened and windowed. The flat array is the single source
25
26
  * of truth for rendering, arrow keys and ARIA. */
26
- function TreeView({ rootNodes, parentToChildrenMap, expandedPaths, selectedPath, loadingPaths, onToggleExpand, onSelect, onDropToFolder, onContextMenu, onPreviewFile, paging }) {
27
+ function TreeView({ rootNodes, parentToChildrenMap, expandedPaths, selectedPath, loadingPaths, onToggleExpand, onSelect, onDropToFolder, onContextMenu, onPreviewFile, pathHref, onFollowLink, paging }) {
27
28
  const [scrollEl, setScrollEl] = useState(null);
28
29
  const treeLabel = useStrings().fileExplorer.chrome.folders;
29
30
  const [fileLimits, setFileLimits] = useState(() => /* @__PURE__ */ new Map());
@@ -151,6 +152,8 @@ function TreeView({ rootNodes, parentToChildrenMap, expandedPaths, selectedPath,
151
152
  }) : /* @__PURE__ */ jsx(TreeRowItem, {
152
153
  row,
153
154
  isSelected: row.node.path === selectedPath,
155
+ href: pathHref?.(row.node.path),
156
+ onFollowLink,
154
157
  onToggleExpand,
155
158
  onSelect,
156
159
  onDropToFolder,
@@ -269,6 +272,7 @@ function useSpringLoadedDrop({ node, dropPath, isDirectory, isExpanded, onToggle
269
272
  dragHandlers: {
270
273
  onDragEnter: (e) => {
271
274
  e.preventDefault();
275
+ if (!carriesFiles(e.dataTransfer)) return;
272
276
  e.stopPropagation();
273
277
  hoverCount.current += 1;
274
278
  setDragActive(true);
@@ -280,6 +284,7 @@ function useSpringLoadedDrop({ node, dropPath, isDirectory, isExpanded, onToggle
280
284
  onDragOver: (e) => e.preventDefault(),
281
285
  onDragLeave: (e) => {
282
286
  e.preventDefault();
287
+ if (!carriesFiles(e.dataTransfer)) return;
283
288
  e.stopPropagation();
284
289
  hoverCount.current -= 1;
285
290
  if (hoverCount.current > 0) return;
@@ -287,8 +292,9 @@ function useSpringLoadedDrop({ node, dropPath, isDirectory, isExpanded, onToggle
287
292
  clear();
288
293
  },
289
294
  onDrop: (e) => {
290
- e.stopPropagation();
291
295
  e.preventDefault();
296
+ if (!carriesFiles(e.dataTransfer)) return;
297
+ e.stopPropagation();
292
298
  hoverCount.current = 0;
293
299
  setDragActive(false);
294
300
  clear();
@@ -300,8 +306,9 @@ function useSpringLoadedDrop({ node, dropPath, isDirectory, isExpanded, onToggle
300
306
  /** Keys a row handles itself: Enter, Space, and Right or Left on a folder that
301
307
  * can open or close. The keys that move between rows delegate upward, where
302
308
  * the flat array is. There is no typeahead. */
303
- function dispatchRowKey(e, { node, isDirectory, isExpanded, onSelect, onToggleExpand, onDelegate }) {
309
+ function dispatchRowKey(e, { node, isDirectory, isExpanded, isLink, onSelect, onToggleExpand, onDelegate }) {
304
310
  if (e.key === "Enter") {
311
+ if (isLink && (e.metaKey || e.ctrlKey || e.shiftKey)) return;
305
312
  e.preventDefault();
306
313
  onSelect(e);
307
314
  return;
@@ -319,7 +326,7 @@ function dispatchRowKey(e, { node, isDirectory, isExpanded, onSelect, onToggleEx
319
326
  }
320
327
  onDelegate(e, node);
321
328
  }
322
- var TreeRowItem = memo(function TreeRowItem({ row, isSelected, onToggleExpand, onSelect, onDropToFolder, onContextMenu, onKeyDown }) {
329
+ var TreeRowItem = memo(function TreeRowItem({ row, isSelected, href, onFollowLink, onToggleExpand, onSelect, onDropToFolder, onContextMenu, onKeyDown }) {
323
330
  const { node, depth, isExpanded } = row;
324
331
  const isDirectory = node.type === "directory";
325
332
  const { dragActive, dragHandlers } = useSpringLoadedDrop({
@@ -335,40 +342,57 @@ var TreeRowItem = memo(function TreeRowItem({ row, isSelected, onToggleExpand, o
335
342
  onSelect(node.path, node);
336
343
  if (isDirectory) onToggleExpand(node.path);
337
344
  };
345
+ const handleLinkClick = (e) => {
346
+ if (!isPlainClick(e)) return;
347
+ onFollowLink?.(node);
348
+ if (isDirectory) onToggleExpand(node.path);
349
+ };
338
350
  const handleKeyDown = (e) => dispatchRowKey(e, {
339
351
  node,
340
352
  isDirectory,
341
353
  isExpanded,
354
+ isLink: !!href,
342
355
  onSelect: handleSelect,
343
356
  onToggleExpand,
344
357
  onDelegate: onKeyDown
345
358
  });
346
359
  const customIcon = getNodeIcon(node);
347
360
  const label = isDirectory && node.storageId && node.displayName ? node.displayName : node.name;
361
+ const tabIndex = isSelected ? 0 : -1;
362
+ const itemProps = {
363
+ className: cx("group relative flex items-center gap-1.5 pr-2 py-1 rounded-md cursor-pointer", "transition-colors duration-150", "focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-(--theme-link)", isSelected ? "bg-(--theme-accent)/15 font-medium" : dragActive ? "theme-hover" : "hover:theme-hover"),
364
+ style: indentStyle(depth, isDirectory),
365
+ onContextMenu: (e) => onContextMenu(e, node),
366
+ "aria-level": depth + 1,
367
+ "aria-posinset": row.posInSet,
368
+ "aria-setsize": row.setSize,
369
+ "aria-selected": isSelected,
370
+ ...isDirectory && { "aria-expanded": isExpanded },
371
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(RowIcons, {
372
+ isDirectory,
373
+ isExpanded,
374
+ customIcon
375
+ }), /* @__PURE__ */ jsx("span", {
376
+ className: "text-sm truncate",
377
+ children: label
378
+ })] })
379
+ };
348
380
  return /* @__PURE__ */ jsxs("div", {
349
381
  className: cx("relative h-full rounded-md transition-[box-shadow,background-color] duration-150", dragActive && "ring-1 ring-(--theme-link)/60"),
350
382
  ...dragHandlers,
351
- children: [/* @__PURE__ */ jsx(IndentGuides, { depth }), /* @__PURE__ */ jsxs("div", {
352
- className: cx("group relative flex items-center gap-1.5 pr-2 py-1 rounded-md cursor-pointer", "transition-colors duration-150", "focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-(--theme-link)", isSelected ? "bg-(--theme-accent)/15 font-medium" : dragActive ? "theme-hover" : "hover:theme-hover"),
353
- style: indentStyle(depth, isDirectory),
354
- onClick: handleSelect,
355
- onKeyDown: handleKeyDown,
356
- onContextMenu: (e) => onContextMenu(e, node),
383
+ children: [/* @__PURE__ */ jsx(IndentGuides, { depth }), href ? /* @__PURE__ */ jsx(AppLink, {
384
+ ...itemProps,
357
385
  role: "treeitem",
358
- "aria-level": depth + 1,
359
- "aria-posinset": row.posInSet,
360
- "aria-setsize": row.setSize,
361
- "aria-selected": isSelected,
362
- ...isDirectory && { "aria-expanded": isExpanded },
363
- tabIndex: isSelected ? 0 : -1,
364
- children: [/* @__PURE__ */ jsx(RowIcons, {
365
- isDirectory,
366
- isExpanded,
367
- customIcon
368
- }), /* @__PURE__ */ jsx("span", {
369
- className: "text-sm truncate",
370
- children: label
371
- })]
386
+ tabIndex,
387
+ href,
388
+ onClick: handleLinkClick,
389
+ onKeyDown: handleKeyDown
390
+ }) : /* @__PURE__ */ jsx("div", {
391
+ ...itemProps,
392
+ role: "treeitem",
393
+ tabIndex,
394
+ onClick: handleSelect,
395
+ onKeyDown: handleKeyDown
372
396
  })]
373
397
  });
374
398
  });
@@ -9,7 +9,7 @@ import { Skeleton } from "../components/Skeleton.js";
9
9
  import { formatBytes } from "../format.js";
10
10
  import { useElapsed } from "../components/relativeTime.js";
11
11
  import { ListSkeleton } from "../list/ListTable.js";
12
- import { getFileExtension } from "./lib/utils.js";
12
+ import { carriesFiles, getFileExtension } from "./lib/utils.js";
13
13
  import { CorsError } from "./lib/errors.js";
14
14
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
15
  import { useState, useTransition } from "react";
@@ -467,13 +467,13 @@ function DragDropZone({ onDropFiles, children, className = "" }) {
467
467
  className: cx("transition-[box-shadow,background-color] duration-150", className, isDragging && "ring-1 ring-(--theme-link) ring-inset bg-(--theme-link)/5"),
468
468
  onDragOver: (e) => {
469
469
  e.preventDefault();
470
- if (onDropFiles) setIsDragging(true);
470
+ if (onDropFiles && carriesFiles(e.dataTransfer)) setIsDragging(true);
471
471
  },
472
472
  onDragLeave: () => setIsDragging(false),
473
473
  onDrop: (e) => {
474
474
  e.preventDefault();
475
475
  setIsDragging(false);
476
- if (!onDropFiles) return;
476
+ if (!onDropFiles || !carriesFiles(e.dataTransfer)) return;
477
477
  onDropFiles(e.dataTransfer.items.length ? e.dataTransfer.items : e.dataTransfer.files);
478
478
  },
479
479
  children
@@ -32,6 +32,9 @@ export declare function attachmentDisposition(filename: string): string;
32
32
  export declare function getDirectoryPrefixFromNode(node: TreeNode): string;
33
33
  export declare function pruneNodesInsideSelectedDirectories(nodes: TreeNode[]): TreeNode[];
34
34
  export declare function collectObjectKeysToDelete(nodes: TreeNode[], listKeysUnderPrefix: (prefix: string) => Promise<string[]>): Promise<string[]>;
35
+ /** True when a drag carries files or folders, not a link or text, such as a
36
+ * row's own link dragged across the explorer. */
37
+ export declare function carriesFiles(dataTransfer: DataTransfer): boolean;
35
38
  export declare function getUriScheme(uri: string): string;
36
39
  export declare function removeLeadingSlash(path: string): string;
37
40
  export declare function removeLeadingAndTrailingSlashes(path: string): string;
@@ -229,6 +229,11 @@ async function collectObjectKeysToDelete(nodes, listKeysUnderPrefix) {
229
229
  }
230
230
  return Array.from(keys);
231
231
  }
232
+ /** True when a drag carries files or folders, not a link or text, such as a
233
+ * row's own link dragged across the explorer. */
234
+ function carriesFiles(dataTransfer) {
235
+ return Array.from(dataTransfer.types).includes("Files");
236
+ }
232
237
  function getUriScheme(uri) {
233
238
  return uri.match(/^([a-z0-9+.-]+):\/\//i)?.[1] ?? "";
234
239
  }
@@ -290,4 +295,4 @@ function getUploadSessionETA(totalLoadedBytes, totalSizeBytes, lastProgressTime,
290
295
  };
291
296
  }
292
297
  //#endregion
293
- export { attachmentDisposition, calculateUploadNodesTotalSize, collectObjectKeysToDelete, createTreeBuilder, ensureTrailingSlash, getDirectoryNameError, getDirectoryObjectPath, getDirectoryPrefixFromNode, getFileExtension, getNodeChildren, getNodeName, getObjectKeyFromNode, getParentPath, getUploadNodesFromDataTransferItems, getUploadSessionETA, getUriScheme, isClientValid, pruneNodesInsideSelectedDirectories, removeLeadingAndTrailingSlashes, removeLeadingSlash };
298
+ export { attachmentDisposition, calculateUploadNodesTotalSize, carriesFiles, collectObjectKeysToDelete, createTreeBuilder, ensureTrailingSlash, getDirectoryNameError, getDirectoryObjectPath, getDirectoryPrefixFromNode, getFileExtension, getNodeChildren, getNodeName, getObjectKeyFromNode, getParentPath, getUploadNodesFromDataTransferItems, getUploadSessionETA, getUriScheme, isClientValid, pruneNodesInsideSelectedDirectories, removeLeadingAndTrailingSlashes, removeLeadingSlash };
@@ -1,3 +1,4 @@
1
+ import { isDev } from "../../dev.js";
1
2
  //#region src/form/Wizard/utils.ts
2
3
  function isWizardMeta(value) {
3
4
  return typeof value === "object" && value !== null && "wizard" in value;
@@ -16,7 +17,7 @@ function parseWizardConfig(options) {
16
17
  stepOrder.push(key);
17
18
  }
18
19
  if (stepOrder.length === 0) {
19
- if (process.env.NODE_ENV !== "production") console.warn("Wizard mode enabled but no steps found");
20
+ if (isDev()) console.warn("Wizard mode enabled but no steps found");
20
21
  return null;
21
22
  }
22
23
  return {
@@ -2,6 +2,7 @@ import { cx } from "../cx.js";
2
2
  import { buttonClasses } from "../components/buttonClasses.js";
3
3
  import { MoreIcon } from "../icons.js";
4
4
  import { MenuPopup, MenuSeparator } from "../components/Menu.js";
5
+ import { isDev } from "../dev.js";
5
6
  import { Tooltip } from "../components/Tooltip.js";
6
7
  import { useStrings } from "../components/Provider.js";
7
8
  import { AppLink } from "../components/AppLink.js";
@@ -321,7 +322,7 @@ var warnedPrimary = /* @__PURE__ */ new Set();
321
322
  /** Warns in development when more than one action is primary: the fill marks
322
323
  * the one next step, so two of them mark none. */
323
324
  function warnIfManyPrimary(items) {
324
- if (process.env.NODE_ENV === "production") return;
325
+ if (!isDev()) return;
325
326
  const labels = items.flatMap((item) => "label" in item && item.primary ? [item.label] : []);
326
327
  const names = labels.map((label) => `"${label}"`).join(", ");
327
328
  if (labels.length < 2 || warnedPrimary.has(names)) return;
@@ -332,7 +333,7 @@ var warnedIcons = /* @__PURE__ */ new Set();
332
333
  /** Warns in development when two actions share an icon: folded to their icons
333
334
  * in a narrow toolbar, they would look the same. */
334
335
  function warnIfIconsRepeat(items) {
335
- if (process.env.NODE_ENV === "production") return;
336
+ if (!isDev()) return;
336
337
  const byIcon = /* @__PURE__ */ new Map();
337
338
  for (const item of items) {
338
339
  if ("element" in item || !isValidElement(item.icon) || typeof item.icon.type === "string") continue;
@@ -89,7 +89,7 @@ function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selec
89
89
  const pinnedLabels = new Set((pinnedActions ?? []).map((a) => a.label));
90
90
  const hasOverflowItems = items.some((item) => !isMenuDivider(item) && (isMenuSubmenu(item) || !pinnedLabels.has(item.label)));
91
91
  return /* @__PURE__ */ jsxs("tr", {
92
- className: cx("group", selected ? "bg-(--theme-accent-subtle)/60" : menuActive ? "theme-hover" : "hover:theme-hover", (href || onActivate || selectionActive) && "cursor-pointer", stretch && "relative [&_:is(a,button,input,label):not([data-row-link])]:relative [&_:is(a,button,input,label):not([data-row-link])]:z-[1]", className),
92
+ className: cx("group", selected ? "bg-(--theme-accent-subtle)/60" : menuActive ? "theme-hover" : "hover:theme-hover", (href || onActivate || selectionActive) && "cursor-pointer", stretch && "relative [&_:is(a,button,input,label,[role=checkbox]):not([data-row-link])]:relative [&_:is(a,button,input,label,[role=checkbox]):not([data-row-link])]:z-[1]", className),
93
93
  onClick: handleRowClick,
94
94
  ...rowContextMenuProps(openRowMenu, items),
95
95
  children: [
@@ -28,6 +28,11 @@ export declare const listTableFixedProps: {
28
28
  /** True inside a `ListRow` whose name link should take the whole row's
29
29
  * clicks: it navigates, and no selection claims plain clicks. */
30
30
  export declare const StretchRowLinkContext: import("react").Context<boolean>;
31
+ export declare const STRETCHED_LINK = "after:absolute after:inset-0 after:content-[''] focus-visible:outline-none focus-visible:after:outline-2 focus-visible:after:-outline-offset-2 focus-visible:after:outline-(--theme-link)";
32
+ /** The row a `STRETCHED_LINK` covers: its box, with the row's other controls
33
+ * raised above the link so they keep their own clicks. A checkbox is a
34
+ * `role="checkbox"` span, not an input, so the role names it. */
35
+ export declare const STRETCHED_LINK_ROW = "relative [&_:is(a,button,input,label,[role=checkbox]):not([data-row-link])]:relative [&_:is(a,button,input,label,[role=checkbox]):not([data-row-link])]:z-[1]";
31
36
  export declare function NameCell({ icon, name, subtitle, href, badge, title, children, }: {
32
37
  icon: ReactNode;
33
38
  name: string;
@@ -37,6 +37,10 @@ var listTableFixedProps = {
37
37
  * clicks: it navigates, and no selection claims plain clicks. */
38
38
  var StretchRowLinkContext = createContext(false);
39
39
  var STRETCHED_LINK = "after:absolute after:inset-0 after:content-[''] focus-visible:outline-none focus-visible:after:outline-2 focus-visible:after:-outline-offset-2 focus-visible:after:outline-(--theme-link)";
40
+ /** The row a `STRETCHED_LINK` covers: its box, with the row's other controls
41
+ * raised above the link so they keep their own clicks. A checkbox is a
42
+ * `role="checkbox"` span, not an input, so the role names it. */
43
+ var STRETCHED_LINK_ROW = "relative [&_:is(a,button,input,label,[role=checkbox]):not([data-row-link])]:relative [&_:is(a,button,input,label,[role=checkbox]):not([data-row-link])]:z-[1]";
40
44
  function NameCell({ icon, name, subtitle, href, badge, title, children }) {
41
45
  const stretch = useContext(StretchRowLinkContext);
42
46
  const inner = /* @__PURE__ */ jsxs(Fragment, { children: [icon, /* @__PURE__ */ jsxs("div", {
@@ -58,7 +62,7 @@ function NameCell({ icon, name, subtitle, href, badge, title, children }) {
58
62
  children: [href ? /* @__PURE__ */ jsx(AppLink, {
59
63
  href,
60
64
  "data-row-link": stretch || void 0,
61
- className: cx("group/namecell flex items-center gap-2.5 min-w-0 cursor-pointer", stretch && STRETCHED_LINK),
65
+ className: cx("group/namecell flex items-center gap-2.5 min-w-0 cursor-pointer", stretch && "after:absolute after:inset-0 after:content-[''] focus-visible:outline-none focus-visible:after:outline-2 focus-visible:after:-outline-offset-2 focus-visible:after:outline-(--theme-link)"),
62
66
  children: inner
63
67
  }) : /* @__PURE__ */ jsx("div", {
64
68
  className: "flex items-center gap-2.5 min-w-0",
@@ -203,4 +207,4 @@ function ListActionsHeader({ view, actionCount = 0, className }) {
203
207
  }
204
208
  ListActionsHeader.isTableHeader = true;
205
209
  //#endregion
206
- export { GroupRow, HEADERS_OFF, ListActionsHeader, ListError, ListSelectAllHeader, ListSkeleton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, StretchRowLinkContext, actionsColumnWidth, listTableFixedProps, listTableProps };
210
+ export { GroupRow, HEADERS_OFF, ListActionsHeader, ListError, ListSelectAllHeader, ListSkeleton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, STRETCHED_LINK, STRETCHED_LINK_ROW, StretchRowLinkContext, actionsColumnWidth, listTableFixedProps, listTableProps };