@parallelworks/ui 0.52.0 → 0.54.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 (92) hide show
  1. package/README.md +97 -8
  2. package/dist/access/AccessDrawer.d.ts +55 -0
  3. package/dist/access/AccessDrawer.js +445 -0
  4. package/dist/access/AccessList.d.ts +58 -0
  5. package/dist/access/AccessList.js +382 -0
  6. package/dist/access/GrantView.d.ts +35 -0
  7. package/dist/access/GrantView.js +188 -0
  8. package/dist/access/GroupPicker.d.ts +35 -0
  9. package/dist/access/GroupPicker.js +336 -0
  10. package/dist/access/focus.d.ts +10 -0
  11. package/dist/access/focus.js +27 -0
  12. package/dist/access/index.d.ts +3 -0
  13. package/dist/access/index.js +3 -0
  14. package/dist/access/model.d.ts +49 -0
  15. package/dist/access/model.js +129 -0
  16. package/dist/access/strings.d.ts +122 -0
  17. package/dist/access/strings.js +151 -0
  18. package/dist/access/types.d.ts +56 -0
  19. package/dist/ai/ai.css +5 -3
  20. package/dist/ai/components/SlashMenu.js +1 -1
  21. package/dist/ai/components/agent/AgentMessageParts.js +1 -1
  22. package/dist/ai/strings.js +0 -1
  23. package/dist/ai/ui/sidebar.js +1 -1
  24. package/dist/components/Combobox.d.ts +19 -0
  25. package/dist/components/Combobox.js +101 -50
  26. package/dist/components/Drawer.d.ts +6 -1
  27. package/dist/components/Drawer.js +25 -16
  28. package/dist/components/Field.d.ts +5 -4
  29. package/dist/components/Field.js +27 -4
  30. package/dist/components/InfoTip.d.ts +12 -4
  31. package/dist/components/InfoTip.js +13 -3
  32. package/dist/components/MarkdownImpl.d.ts +1 -0
  33. package/dist/components/MarkdownImpl.js +1 -0
  34. package/dist/components/Menu.js +4 -4
  35. package/dist/components/MenuEntries.js +1 -1
  36. package/dist/components/OptionDescription.d.ts +7 -0
  37. package/dist/components/OptionDescription.js +19 -0
  38. package/dist/components/Popover.d.ts +4 -1
  39. package/dist/components/Popover.js +2 -1
  40. package/dist/components/Provider.d.ts +9 -0
  41. package/dist/components/Provider.js +4 -0
  42. package/dist/components/Select.js +13 -11
  43. package/dist/components/comboboxItems.d.ts +10 -0
  44. package/dist/components/comboboxItems.js +8 -1
  45. package/dist/components/floating.d.ts +5 -2
  46. package/dist/components/floating.js +2 -2
  47. package/dist/components/focus.d.ts +5 -0
  48. package/dist/components/focus.js +21 -1
  49. package/dist/editor/Editor.js +13 -3
  50. package/dist/editor/Monaco.d.ts +8 -1
  51. package/dist/editor/Monaco.js +16 -3
  52. package/dist/editor/editorModel.d.ts +1 -1
  53. package/dist/editor/editorModel.js +1 -1
  54. package/dist/editor/index.d.ts +1 -0
  55. package/dist/editor/index.js +2 -1
  56. package/dist/editor/languages.d.ts +24 -0
  57. package/dist/editor/languages.js +31 -0
  58. package/dist/editor/monacoFeatures.d.ts +7 -0
  59. package/dist/editor/monacoFeatures.js +19 -0
  60. package/dist/editor/themes.d.ts +5 -0
  61. package/dist/editor/themes.js +24 -4
  62. package/dist/editor/workers.d.ts +3 -3
  63. package/dist/editor/workers.js +8 -4
  64. package/dist/editor/yamlLanguage.js +55 -38
  65. package/dist/file-explorer/FileExplorer.d.ts +18 -4
  66. package/dist/file-explorer/FileExplorer.js +64 -20
  67. package/dist/file-explorer/FilePreview/Viewer.js +12 -8
  68. package/dist/file-explorer/FileRow.d.ts +6 -2
  69. package/dist/file-explorer/FileRow.js +35 -17
  70. package/dist/file-explorer/FileRowsWindow.d.ts +2 -1
  71. package/dist/file-explorer/FileRowsWindow.js +2 -1
  72. package/dist/file-explorer/FileTable.d.ts +3 -1
  73. package/dist/file-explorer/FileTable.js +3 -2
  74. package/dist/file-explorer/TreeView.d.ts +5 -1
  75. package/dist/file-explorer/TreeView.js +49 -25
  76. package/dist/file-explorer/helpers.js +3 -3
  77. package/dist/file-explorer/lib/paging.d.ts +1 -0
  78. package/dist/file-explorer/lib/paging.js +5 -1
  79. package/dist/file-explorer/lib/utils.d.ts +3 -0
  80. package/dist/file-explorer/lib/utils.js +6 -1
  81. package/dist/form/Wizard/utils.js +2 -1
  82. package/dist/list/ActionToolbar.js +3 -2
  83. package/dist/list/ListPage.js +1 -1
  84. package/dist/list/ListTable.d.ts +5 -0
  85. package/dist/list/ListTable.js +6 -2
  86. package/dist/styles/theme.css +82 -62
  87. package/dist/styles.css +1 -1
  88. package/dist/theme/derive.d.ts +5 -3
  89. package/dist/theme/derive.js +61 -3
  90. package/package.json +9 -2
  91. package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +0 -6
  92. package/dist/file-explorer/FilePreview/CodePreviewEditor.js +0 -64
@@ -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
@@ -47,6 +47,7 @@ export declare function recordListingError(listings: TListings, path: string, er
47
47
  /** Keeps the cursor and pages, so a retry resumes paging instead of starting over. */
48
48
  export declare function clearListingError(listings: TListings, path: string): TListings;
49
49
  export declare function clearListingsUnder(listings: TListings, path: string): TListings;
50
+ export declare function retainListings(listings: TListings, paths: ReadonlySet<string>): TListings;
50
51
  /** Tree paths whose children should keep arrival order, since sorting them would
51
52
  * reshuffle rows under the user mid-scroll. */
52
53
  export declare function incompletePaths(listings: TListings): Set<string>;
@@ -83,6 +83,10 @@ function clearListingsUnder(listings, path) {
83
83
  for (const key of listings.keys()) if (key === path || key.startsWith(prefix)) next.delete(key);
84
84
  return next;
85
85
  }
86
+ function retainListings(listings, paths) {
87
+ if ([...listings.keys()].every((path) => paths.has(path))) return listings;
88
+ return new Map([...listings].filter(([path]) => paths.has(path)));
89
+ }
86
90
  /** Tree paths whose children should keep arrival order, since sorting them would
87
91
  * reshuffle rows under the user mid-scroll. */
88
92
  function incompletePaths(listings) {
@@ -121,4 +125,4 @@ function nextHydrationStep({ targetResolved, ancestors, isListableDir, listings,
121
125
  };
122
126
  }
123
127
  //#endregion
124
- export { LIST_PAGE_SIZE, advanceListing, beginLoadingMore, canAutoLoadMore, clearListingError, clearListingsUnder, hasMore, incompletePaths, isListed, isLoadingMore, loadMoreError, nextHydrationStep, recordListingError, replaceListing };
128
+ export { LIST_PAGE_SIZE, advanceListing, beginLoadingMore, canAutoLoadMore, clearListingError, clearListingsUnder, hasMore, incompletePaths, isListed, isLoadingMore, loadMoreError, nextHydrationStep, recordListingError, replaceListing, retainListings };
@@ -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 };
@@ -1,8 +1,9 @@
1
1
  /* The theme contract: `theme-*` utilities over the `--theme-*` tokens, which
2
2
  * src/theme generates from a scheme of three choices (base, accent, contrast).
3
3
  * Hosts set the tokens at runtime with applyTheme; the defaults below are the
4
- * default theme's light scheme, for standalone use, with display-p3 values for
5
- * wide-gamut screens.
4
+ * default theme's light and dark schemes, for standalone use and for any token
5
+ * a host leaves unset, with display-p3 values for wide-gamut screens. Each pairs
6
+ * its modes with light-dark(), so it follows the CSS color-scheme a host sets.
6
7
  *
7
8
  * Sidebar tokens (--theme-sidebar-*) are part of the contract but have no
8
9
  * defaults here: hosts supply per-site fallbacks at the use sites, and a global
@@ -10,75 +11,94 @@
10
11
 
11
12
  /* generated:start (src/theme/derive.test.ts checks this; UPDATE_THEME_CSS=1 rewrites it) */
12
13
  :root {
13
- --theme-app-bg: #f3f4f6;
14
- --theme-panel-bg: #fcfeff;
15
- --theme-panel-hover: #f2f5f9;
16
- --theme-muted-panel-bg: #e7eaee;
17
- --theme-hover: #e3e5e9;
18
- --theme-input-bg: #fafcfe;
19
- --theme-input-disabled-bg: #ebeef1;
20
- --theme-app: #0a101b;
21
- --theme-muted-text-color: #4e5664;
22
- --theme-placeholder: #7e8796;
23
- --theme-link: #06354f;
24
- --theme-border: #cacdd0;
25
- --theme-border-strong: #a3a6a9;
26
- --theme-accent: #06354f;
27
- --theme-accent-text: #ffffff;
28
- --theme-accent-hover: #002841;
29
- --theme-accent-subtle: #d3ebfc;
30
- --theme-focus: #06354f;
31
- --theme-focus-ring: rgba(6, 53, 79, 0.25);
32
- --theme-success: #00973d;
33
- --theme-success-text: #006226;
14
+ --theme-app-bg: light-dark(#f3f4f6, #111418);
15
+ --theme-panel-bg: light-dark(#fcfeff, #151c25);
16
+ --theme-panel-hover: light-dark(#f2f5f9, #1e262e);
17
+ --theme-muted-panel-bg: light-dark(#e7eaee, #1c242c);
18
+ --theme-hover: light-dark(#e3e5e9, #1f2730);
19
+ --theme-input-bg: light-dark(#fafcfe, #182028);
20
+ --theme-input-disabled-bg: light-dark(#ebeef1, #131a22);
21
+ --theme-app: light-dark(#0a101b, #e2eaf3);
22
+ --theme-muted-text-color: light-dark(#4e5664, #c1c9d2);
23
+ --theme-placeholder: light-dark(#7e8796, #9da5ad);
24
+ --theme-link: light-dark(#06354f, #8dcfff);
25
+ --theme-border: light-dark(#cacdd0, #30363d);
26
+ --theme-border-strong: light-dark(#a3a6a9, #4f565d);
27
+ --theme-accent: light-dark(#06354f, #5b9ccf);
28
+ --theme-accent-text: light-dark(#ffffff, #000000);
29
+ --theme-accent-hover: light-dark(#002841, #6aace0);
30
+ --theme-accent-subtle: light-dark(#d3ebfc, #0f2638);
31
+ --theme-focus: light-dark(#06354f, #5b9ccf);
32
+ --theme-focus-ring: light-dark(rgba(6, 53, 79, 0.25), rgba(91, 156, 207, 0.35));
33
+ --theme-success: light-dark(#00973d, #00bf54);
34
+ --theme-success-text: light-dark(#006226, #65e387);
34
35
  --theme-success-solid: #00873c;
35
- --theme-success-muted: rgba(0, 151, 61, 0.1);
36
- --theme-error: #ea4841;
37
- --theme-error-text: #a11a1b;
36
+ --theme-success-muted: light-dark(rgba(0, 151, 61, 0.1), rgba(0, 191, 84, 0.15));
37
+ --theme-error: light-dark(#ea4841, #ff6056);
38
+ --theme-error-text: light-dark(#a11a1b, #ffb8af);
38
39
  --theme-error-solid: #db3934;
39
- --theme-error-muted: rgba(234, 72, 65, 0.1);
40
- --theme-warning: #bd7100;
41
- --theme-warning-text: #7b4a00;
40
+ --theme-error-muted: light-dark(rgba(234, 72, 65, 0.1), rgba(255, 96, 86, 0.15));
41
+ --theme-warning: light-dark(#bd7100, #dd8900);
42
+ --theme-warning-text: light-dark(#7b4a00, #ffbe6a);
42
43
  --theme-warning-solid: #a76900;
43
- --theme-warning-muted: rgba(189, 113, 0, 0.1);
44
- --theme-info: #0681f8;
45
- --theme-info-text: #0050af;
46
- --theme-info-solid: #0073e8;
47
- --theme-info-muted: rgba(6, 129, 248, 0.1);
48
- --theme-favorite: #e7457a;
49
- --theme-favorite-text: #9e174b;
44
+ --theme-warning-muted: light-dark(rgba(189, 113, 0, 0.1), rgba(221, 137, 0, 0.15));
45
+ --theme-info: light-dark(#0681f8, #499fff);
46
+ --theme-info-text: light-dark(#0050af, #a6cfff);
47
+ --theme-info-solid: light-dark(#0073e8, #0073e9);
48
+ --theme-info-muted: light-dark(rgba(6, 129, 248, 0.1), rgba(73, 159, 255, 0.15));
49
+ --theme-favorite: light-dark(#e7457a, #fe5c8e);
50
+ --theme-favorite-text: light-dark(#9e174b, #ffb7c7);
50
51
  --theme-favorite-solid: #d7366e;
51
- --theme-favorite-muted: rgba(231, 69, 122, 0.1);
52
- --theme-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.07);
53
- --theme-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.07), 0 2px 4px -2px rgba(0, 0, 0, 0.07);
54
- --theme-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.07), 0 4px 6px -4px rgba(0, 0, 0, 0.07);
55
- --theme-shadow-xl: 0 25px 80px -20px rgba(0, 0, 0, 0.2), 0 10px 30px -10px rgba(0, 0, 0, 0.1);
56
- --theme-code-bg: #e7eaee;
57
- --theme-code-text: #1c2330;
58
- --theme-code-comment: #555d6c;
59
- --theme-code-keyword: #36617d;
60
- --theme-code-string: #196a24;
61
- --theme-code-number: #944500;
62
- --theme-code-function: #6c4b9e;
63
- --theme-code-type: #006565;
64
- --theme-code-property: #5a51a5;
65
- --theme-ansi-black: #1c2330;
66
- --theme-ansi-red: #a3322d;
67
- --theme-ansi-green: #006a12;
68
- --theme-ansi-yellow: #755800;
69
- --theme-ansi-blue: #0b5aae;
70
- --theme-ansi-magenta: #8d3a88;
71
- --theme-ansi-cyan: #00666c;
72
- --theme-ansi-white: #555d6c;
52
+ --theme-favorite-muted: light-dark(rgba(231, 69, 122, 0.1), rgba(254, 92, 142, 0.15));
53
+ --theme-shadow-sm: 0 1px 2px light-dark(rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.35));
54
+ --theme-shadow:
55
+ 0 4px 6px -1px light-dark(rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.35)),
56
+ 0 2px 4px -2px light-dark(rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.35));
57
+ --theme-shadow-lg:
58
+ 0 10px 15px -3px light-dark(rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.35)),
59
+ 0 4px 6px -4px light-dark(rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0.35));
60
+ --theme-shadow-xl:
61
+ 0 25px 80px -20px light-dark(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.6)),
62
+ 0 10px 30px -10px light-dark(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.4));
63
+ --theme-code-bg: light-dark(#e7eaee, #1c242c);
64
+ --theme-code-text: light-dark(#1c2330, #e1e9f2);
65
+ --theme-code-comment: light-dark(#555d6c, #c0c8d1);
66
+ --theme-code-keyword: light-dark(#36617d, #8cceff);
67
+ --theme-code-string: light-dark(#196a24, #8bd98d);
68
+ --theme-code-number: light-dark(#944500, #ffb882);
69
+ --theme-code-function: light-dark(#6c4b9e, #d3bcff);
70
+ --theme-code-type: light-dark(#006565, #31dbdb);
71
+ --theme-code-property: light-dark(#5a51a5, #31dbdb);
72
+ --theme-ansi-black: light-dark(#1c2330, #c0c8d1);
73
+ --theme-ansi-red: light-dark(#a3322d, #ffb5ab);
74
+ --theme-ansi-green: light-dark(#006a12, #7fdb83);
75
+ --theme-ansi-yellow: light-dark(#755800, #edc23e);
76
+ --theme-ansi-blue: light-dark(#0b5aae, #9ecbff);
77
+ --theme-ansi-magenta: light-dark(#8d3a88, #ffaafe);
78
+ --theme-ansi-cyan: light-dark(#00666c, #00dbe5);
79
+ --theme-ansi-white: light-dark(#555d6c, #e1e9f2);
73
80
  }
74
81
 
75
82
  @media (color-gamut: p3) {
76
83
  :root {
77
- --theme-success: color(display-p3 0.1559 0.5942 0.2459);
84
+ --theme-success: light-dark(color(display-p3 0.1559 0.5942 0.2459), #00bf54);
78
85
  --theme-success-solid: color(display-p3 0.0738 0.5422 0.1959);
79
- --theme-success-muted: color(display-p3 0.1559 0.5942 0.2459 / 0.1);
80
- --theme-warning-solid: color(display-p3 0.6474 0.4089 0);
81
- --theme-ansi-cyan: color(display-p3 0 0.4024 0.4329);
86
+ --theme-success-muted: light-dark(
87
+ color(display-p3 0.1559 0.5942 0.2459 / 0.1),
88
+ rgba(0, 191, 84, 0.15)
89
+ );
90
+ --theme-warning: light-dark(#bd7100, color(display-p3 0.8343 0.5429 0));
91
+ --theme-warning-solid: light-dark(
92
+ color(display-p3 0.6474 0.4089 0),
93
+ color(display-p3 0.6478 0.4092 0)
94
+ );
95
+ --theme-warning-muted: light-dark(
96
+ rgba(189, 113, 0, 0.1),
97
+ color(display-p3 0.8343 0.5429 0 / 0.15)
98
+ );
99
+ --theme-code-number: light-dark(#944500, color(display-p3 1 0.7209 0.5024));
100
+ --theme-ansi-red: light-dark(#a3322d, color(display-p3 1 0.7032 0.6565));
101
+ --theme-ansi-cyan: light-dark(color(display-p3 0 0.4024 0.4329), #00dbe5);
82
102
  }
83
103
  }
84
104
  /* generated:end */