@parallelworks/ui 0.51.0 → 0.52.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.
- package/README.md +155 -14
- package/dist/ai/agent/toolStrings.d.ts +2 -0
- package/dist/ai/agent/toolStrings.js +20 -18
- package/dist/ai/ai.css +12 -0
- package/dist/ai/components/AllocationSelector.js +5 -1
- package/dist/ai/components/AttachmentManager.js +51 -42
- package/dist/ai/components/AttachmentUpload.d.ts +4 -2
- package/dist/ai/components/AttachmentUpload.js +9 -9
- package/dist/ai/components/BlockedGroupBanner.js +8 -14
- package/dist/ai/components/BranchNavigator.js +11 -12
- package/dist/ai/components/ChatEmptyState.js +12 -19
- package/dist/ai/components/ChatInput.d.ts +4 -3
- package/dist/ai/components/ChatInput.js +27 -13
- package/dist/ai/components/ChatMessage.js +45 -121
- package/dist/ai/components/ChatMessageList.d.ts +5 -2
- package/dist/ai/components/ChatMessageList.js +89 -51
- package/dist/ai/components/ChatSidebar.js +11 -7
- package/dist/ai/components/ChatThread.js +1 -13
- package/dist/ai/components/DragOverlay.js +3 -3
- package/dist/ai/components/MessageAttachments.d.ts +10 -0
- package/dist/ai/components/MessageAttachments.js +78 -0
- package/dist/ai/components/ModelSelector.js +3 -3
- package/dist/ai/components/PastedText.js +2 -2
- package/dist/ai/components/ProviderIssueBanner.js +19 -23
- package/dist/ai/components/ShareDialog.js +2 -2
- package/dist/ai/components/agent/ActivityLine.d.ts +0 -2
- package/dist/ai/components/agent/ActivityLine.js +8 -51
- package/dist/ai/components/agent/AgentMessageParts.js +114 -53
- package/dist/ai/core/ChatProvider.d.ts +16 -5
- package/dist/ai/core/ChatProvider.js +41 -8
- package/dist/ai/core/config.js +4 -3
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.js +3 -3
- package/dist/ai/strings.d.ts +29 -3
- package/dist/ai/strings.js +81 -26
- package/dist/ai/types.d.ts +4 -0
- package/dist/ai/ui/Notice.d.ts +2 -2
- package/dist/ai/ui/Notice.js +29 -62
- package/dist/ai/ui/sidebar.d.ts +5 -3
- package/dist/ai/ui/sidebar.js +21 -9
- package/dist/components/ActionMenu.d.ts +1 -0
- package/dist/components/ActionMenu.js +6 -1
- package/dist/components/AppLink.d.ts +26 -0
- package/dist/components/AppLink.js +51 -0
- package/dist/components/Avatar.d.ts +2 -1
- package/dist/components/Avatar.js +4 -2
- package/dist/components/Button.d.ts +15 -5
- package/dist/components/Button.js +47 -40
- package/dist/components/Callout.d.ts +31 -7
- package/dist/components/Callout.js +50 -19
- package/dist/components/Card.d.ts +11 -6
- package/dist/components/Card.js +14 -8
- package/dist/components/Checkbox.js +2 -1
- package/dist/components/ColorInput.js +5 -3
- package/dist/components/Combobox.js +49 -19
- package/dist/components/ConfirmModal.d.ts +19 -8
- package/dist/components/ConfirmModal.js +31 -53
- package/dist/components/CopyButton.d.ts +38 -0
- package/dist/components/CopyButton.js +68 -0
- package/dist/components/CreateModal.js +118 -111
- package/dist/components/DatePicker.js +12 -8
- package/dist/components/DescriptionList.d.ts +25 -5
- package/dist/components/DescriptionList.js +56 -22
- package/dist/components/Disclosure.js +1 -1
- package/dist/components/Drawer.js +10 -16
- package/dist/components/Field.d.ts +15 -5
- package/dist/components/Field.js +40 -8
- package/dist/components/IconButton.d.ts +14 -5
- package/dist/components/IconButton.js +25 -14
- package/dist/components/InfoTip.d.ts +4 -1
- package/dist/components/InfoTip.js +2 -1
- package/dist/components/Input.d.ts +14 -8
- package/dist/components/Input.js +46 -31
- package/dist/components/Loader.js +1 -1
- package/dist/components/MenuEntries.d.ts +4 -0
- package/dist/components/MenuEntries.js +11 -12
- package/dist/components/Meter.js +5 -4
- package/dist/components/Modal.d.ts +28 -4
- package/dist/components/Modal.js +37 -14
- package/dist/components/Overview.d.ts +20 -12
- package/dist/components/Overview.js +14 -9
- package/dist/components/PageHeader.d.ts +47 -65
- package/dist/components/PageHeader.js +275 -153
- package/dist/components/PageHeaderAction.d.ts +67 -0
- package/dist/components/PageHeaderAction.js +107 -0
- package/dist/components/Pagination.js +6 -16
- package/dist/components/Popover.js +3 -2
- package/dist/components/Provider.d.ts +77 -19
- package/dist/components/Provider.js +139 -130
- package/dist/components/Radio.js +2 -1
- package/dist/components/RefreshButton.js +7 -8
- package/dist/components/RequiredMark.js +1 -1
- package/dist/components/Section.js +1 -1
- package/dist/components/Select.d.ts +4 -9
- package/dist/components/Select.js +24 -11
- package/dist/components/SettingModeOption.d.ts +1 -1
- package/dist/components/SettingModeOption.js +7 -1
- package/dist/components/SettingsCard.d.ts +5 -3
- package/dist/components/SettingsCard.js +27 -20
- package/dist/components/Slider.js +1 -1
- package/dist/components/StatusBadge.js +2 -2
- package/dist/components/Switch.js +5 -4
- package/dist/components/Table.d.ts +30 -20
- package/dist/components/Table.js +50 -73
- package/dist/components/Tabs.d.ts +3 -7
- package/dist/components/Tabs.js +6 -10
- package/dist/components/ThemeEditor.js +18 -8
- package/dist/components/Toast.d.ts +11 -3
- package/dist/components/Toast.js +45 -20
- package/dist/components/buttonClasses.js +1 -1
- package/dist/components/comboboxItems.d.ts +4 -0
- package/dist/components/comboboxItems.js +6 -1
- package/dist/components/dismiss.d.ts +12 -0
- package/dist/components/dismiss.js +19 -0
- package/dist/components/fieldBox.d.ts +4 -0
- package/dist/components/fieldBox.js +7 -3
- package/dist/components/floating.d.ts +3 -3
- package/dist/components/floating.js +1 -1
- package/dist/components/markdownCodeBreaks.js +3 -4
- package/dist/components/pageHeaderStore.d.ts +41 -0
- package/dist/components/pageHeaderStore.js +67 -0
- package/dist/components/pathBreaks.d.ts +8 -0
- package/dist/components/pathBreaks.js +28 -0
- package/dist/components/segmented.js +1 -1
- package/dist/components/shortcutKey.d.ts +2 -1
- package/dist/components/shortcutKey.js +19 -2
- package/dist/components/splitter.js +1 -1
- package/dist/components/useCssIsDark.js +40 -18
- package/dist/components/useTheme.js +9 -10
- package/dist/dev.d.ts +9 -0
- package/dist/dev.js +14 -0
- package/dist/editor/Editor.d.ts +3 -2
- package/dist/editor/Editor.js +11 -2
- package/dist/editor/EditorField.d.ts +2 -1
- package/dist/editor/EditorField.js +11 -29
- package/dist/editor/FormCodePanel.d.ts +7 -3
- package/dist/editor/FormCodePanel.js +14 -7
- package/dist/editor/Monaco.d.ts +14 -5
- package/dist/editor/Monaco.js +163 -112
- package/dist/editor/index.d.ts +5 -5
- package/dist/editor/index.js +3 -3
- package/dist/editor/themes.d.ts +8 -5
- package/dist/editor/themes.js +58 -30
- package/dist/editor/yaml.d.ts +6 -2
- package/dist/editor/yaml.js +11 -2
- package/dist/file-explorer/FileExplorer.js +143 -124
- package/dist/file-explorer/FileExplorerContext.js +1 -1
- package/dist/file-explorer/FilePreview/StreamedBadge.js +3 -1
- package/dist/file-explorer/FilePreview/Viewer.js +2 -2
- package/dist/file-explorer/FilePreview/index.js +4 -4
- package/dist/file-explorer/FileRow.js +1 -1
- package/dist/file-explorer/FileRowsWindow.js +34 -3
- package/dist/file-explorer/FileTable.js +3 -1
- package/dist/file-explorer/TreeView.js +37 -14
- package/dist/file-explorer/helpers.d.ts +2 -1
- package/dist/file-explorer/helpers.js +21 -20
- package/dist/file-explorer/toasts.js +27 -19
- package/dist/file-explorer/treeRows.d.ts +6 -0
- package/dist/file-explorer/treeRows.js +19 -1
- package/dist/file-explorer/useNearEnd.js +3 -6
- package/dist/form/Fields/CheckboxGroupField.js +12 -5
- package/dist/form/Fields/DurationField.js +1 -1
- package/dist/form/Fields/LabelField.js +1 -1
- package/dist/form/Fields/ObjectField.d.ts +1 -1
- package/dist/form/Fields/ObjectField.js +3 -2
- package/dist/form/Fields/StringField.js +16 -29
- package/dist/form/Fields/TextAreaField.js +3 -4
- package/dist/form/Form.js +3 -8
- package/dist/form/Wizard/WizardNavigation.js +0 -3
- package/dist/form/Wizard/utils.js +1 -1
- package/dist/form/fieldFrame.d.ts +1 -1
- package/dist/form/fieldFrame.js +2 -2
- package/dist/form/types/fieldComponentTypes.d.ts +2 -1
- package/dist/graph/AnnotationBanner.d.ts +1 -2
- package/dist/graph/AnnotationBanner.js +30 -32
- package/dist/graph/Connectors.js +4 -1
- package/dist/graph/DependencyGraph.js +2 -2
- package/dist/graph/GraphEditor.js +11 -9
- package/dist/graph/GraphEditorDialogs.js +1 -1
- package/dist/graph/GraphNode.js +7 -4
- package/dist/graph/InputDialog.js +1 -1
- package/dist/graph/InputsEditor.js +14 -11
- package/dist/graph/MatrixGroup.js +9 -3
- package/dist/graph/Reveal.js +18 -10
- package/dist/graph/ShortcutsButton.d.ts +11 -2
- package/dist/graph/ShortcutsButton.js +14 -3
- package/dist/graph/TreeView.js +35 -18
- package/dist/graph/WorkflowSettingsDialog.js +1 -1
- package/dist/graph/editorFields.js +1 -1
- package/dist/graph/editorRows.js +16 -10
- package/dist/graph/editorStrings.d.ts +7 -0
- package/dist/graph/editorStrings.js +8 -1
- package/dist/graph/inputRefs.js +1 -1
- package/dist/graph/settingsViews.js +11 -18
- package/dist/graph/stepWith.js +1 -1
- package/dist/icons.d.ts +2 -0
- package/dist/icons.js +4 -2
- package/dist/index.d.ts +12 -12
- package/dist/index.js +16 -16
- package/dist/list/ActionToolbar.d.ts +42 -6
- package/dist/list/ActionToolbar.js +297 -101
- package/dist/list/ListPage.d.ts +15 -23
- package/dist/list/ListPage.js +42 -43
- package/dist/list/ListTable.d.ts +32 -7
- package/dist/list/ListTable.js +48 -12
- package/dist/list/ListViewControls.js +1 -1
- package/dist/list/UserHoverCard.js +7 -15
- package/dist/list/index.d.ts +2 -2
- package/dist/list/index.js +2 -2
- package/dist/list/listSearch.js +12 -10
- package/dist/list/listView.d.ts +10 -1
- package/dist/list/listView.js +15 -1
- package/dist/logviewer/LogViewer.d.ts +4 -2
- package/dist/logviewer/LogViewer.js +87 -69
- package/dist/logviewer/logviewer.css +3 -2
- package/dist/reducedMotion.d.ts +5 -0
- package/dist/reducedMotion.js +20 -0
- package/dist/safeUrl.d.ts +1 -1
- package/dist/safeUrl.js +4 -2
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/dist/components/Breadcrumbs.d.ts +0 -37
- package/dist/components/Breadcrumbs.js +0 -90
- package/dist/components/CopyToClipboard.d.ts +0 -17
- package/dist/components/CopyToClipboard.js +0 -66
- package/dist/components/Sort.d.ts +0 -9
- package/dist/components/Sort.js +0 -42
package/dist/list/ListPage.d.ts
CHANGED
|
@@ -1,40 +1,29 @@
|
|
|
1
1
|
import type { MouseEvent as ReactMouseEvent, ReactNode } from 'react';
|
|
2
2
|
import type { OpenMenu } from '../components/ContextMenu.js';
|
|
3
3
|
import { type MenuEntry } from '../components/MenuEntries.js';
|
|
4
|
-
import { type PageHeaderBreadcrumb } from '../components/PageHeader.js';
|
|
5
4
|
import type { ListView, ListViewChrome } from './listView.js';
|
|
6
5
|
import { type RowAction } from './rowMenu.js';
|
|
7
|
-
/** Negative offsets (admin/org) cancel the shell's pt-4 so rows don't peek through the gap above the pinned header. */
|
|
8
|
-
declare const SECTION_STICKY_TOP: {
|
|
9
|
-
readonly main: 'top-0';
|
|
10
|
-
readonly kubernetes: 'top-0';
|
|
11
|
-
readonly admin: '-top-4';
|
|
12
|
-
readonly org: '-top-4';
|
|
13
|
-
};
|
|
14
|
-
export type ListSection = keyof typeof SECTION_STICKY_TOP;
|
|
15
6
|
export declare function ListRowActionsProvider({ view, children, }: {
|
|
16
7
|
view?: ListViewChrome | undefined;
|
|
17
8
|
children: ReactNode;
|
|
18
9
|
}): import("react").JSX.Element;
|
|
19
10
|
export interface ListPageProps {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
*
|
|
26
|
-
embedded?: boolean;
|
|
27
|
-
breadcrumbs?: PageHeaderBreadcrumb[] | undefined;
|
|
28
|
-
title?: ReactNode;
|
|
29
|
-
titleAction?: ReactNode;
|
|
30
|
-
actions?: ReactNode;
|
|
11
|
+
/** Reaches past the host's content padding (`p-4`) to the container's
|
|
12
|
+
* edges, for a host whose page container is padded. A list runs edge to
|
|
13
|
+
* edge so its rows' hover and dividers span the page. */
|
|
14
|
+
bleed?: boolean | undefined;
|
|
15
|
+
/** The list's search, filters and view controls, above the rows. The page's
|
|
16
|
+
* trail and actions go in its `PageHeader`. */
|
|
31
17
|
toolbar?: ReactNode;
|
|
32
18
|
/** Omit on pages without a list view — rows show all actions by default. */
|
|
33
19
|
view?: ListViewChrome | undefined;
|
|
34
20
|
children: ReactNode;
|
|
35
21
|
}
|
|
36
|
-
|
|
22
|
+
/** A list filling the page: its toolbar stays put while only the rows scroll. */
|
|
23
|
+
export declare function ListPage({ bleed, toolbar, view, children }: ListPageProps): import("react").JSX.Element;
|
|
37
24
|
export declare function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selected, selectionActive, onRowSelect, leading, className, children, }: {
|
|
25
|
+
/** Where the row goes. Its `NameCell` with the same href becomes a link
|
|
26
|
+
* covering the row; a click the link doesn't catch still goes there. */
|
|
38
27
|
href: string | null;
|
|
39
28
|
/** Plain-click handler for rows that open something in place instead of navigating. */
|
|
40
29
|
onActivate?: (() => void) | undefined;
|
|
@@ -53,7 +42,11 @@ export declare function ListRow({ href, onActivate, items, goTo, openMenu, pinne
|
|
|
53
42
|
leading?: ReactNode;
|
|
54
43
|
children: ReactNode;
|
|
55
44
|
}): import("react").JSX.Element;
|
|
56
|
-
/** Name column min-width is by role, not position, so a leading checkbox
|
|
45
|
+
/** Name column min-width is by role, not position, so a leading checkbox
|
|
46
|
+
* doesn't shift it. A column with an `orderBy` the view offers sorts by it.
|
|
47
|
+
* While the view's column headers are off, the header row collapses: its
|
|
48
|
+
* cells still size the columns, but nobody sees or hears them, as with any
|
|
49
|
+
* other display option that is off. */
|
|
57
50
|
export declare function ListColumns<T>({ view }: {
|
|
58
51
|
view: ListView<T>;
|
|
59
52
|
}): import("react").JSX.Element;
|
|
@@ -62,4 +55,3 @@ export declare namespace ListColumns {
|
|
|
62
55
|
}
|
|
63
56
|
/** Stable `goTo` for whole-row navigation (`rowNavProps`, `ListRow`). */
|
|
64
57
|
export declare function useListNavigate(): (to: string) => void;
|
|
65
|
-
export {};
|
package/dist/list/ListPage.js
CHANGED
|
@@ -1,28 +1,14 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
2
|
import { Tooltip } from "../components/Tooltip.js";
|
|
3
|
-
import {
|
|
3
|
+
import { useNavigation } from "../components/Provider.js";
|
|
4
|
+
import { AppLink, isPlainClick } from "../components/AppLink.js";
|
|
4
5
|
import { isMenuDivider, isMenuSubmenu, useRunAction, warnIfInert } from "../components/MenuEntries.js";
|
|
5
|
-
import { PageHeader } from "../components/PageHeader.js";
|
|
6
6
|
import { Table } from "../components/Table.js";
|
|
7
|
-
import { ListActionsHeader } from "./ListTable.js";
|
|
7
|
+
import { ListActionsHeader, StretchRowLinkContext } from "./ListTable.js";
|
|
8
8
|
import { MoreButton, rowContextMenuProps, useRowMenuActive } from "./rowMenu.js";
|
|
9
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
import { Children, cloneElement, createContext, isValidElement, useContext, useMemo } from "react";
|
|
11
11
|
//#region src/list/ListPage.tsx
|
|
12
|
-
/** Negative offsets (admin/org) cancel the shell's pt-4 so rows don't peek through the gap above the pinned header. */
|
|
13
|
-
var SECTION_STICKY_TOP = {
|
|
14
|
-
main: "top-0",
|
|
15
|
-
kubernetes: "top-0",
|
|
16
|
-
admin: "-top-4",
|
|
17
|
-
org: "-top-4"
|
|
18
|
-
};
|
|
19
|
-
/** Whether the shell adds pt-4 padding that the edge-to-edge list must cancel with a negative margin. */
|
|
20
|
-
var SECTION_SHELL_PADDED = {
|
|
21
|
-
main: false,
|
|
22
|
-
kubernetes: false,
|
|
23
|
-
admin: true,
|
|
24
|
-
org: true
|
|
25
|
-
};
|
|
26
12
|
/** Defaults mean rows outside a ListView fully show actions (no view = show everything). */
|
|
27
13
|
var RowActionsContext = createContext({
|
|
28
14
|
show: true,
|
|
@@ -50,20 +36,13 @@ function ListRowActionsProvider({ view, children }) {
|
|
|
50
36
|
children
|
|
51
37
|
});
|
|
52
38
|
}
|
|
53
|
-
|
|
54
|
-
|
|
39
|
+
/** A list filling the page: its toolbar stays put while only the rows scroll. */
|
|
40
|
+
function ListPage({ bleed = false, toolbar, view, children }) {
|
|
55
41
|
return /* @__PURE__ */ jsxs("div", {
|
|
56
|
-
className: cx("flex h-full min-h-0 flex-col",
|
|
57
|
-
children: [
|
|
58
|
-
className: "px-4
|
|
42
|
+
className: cx("flex h-full min-h-0 flex-col", bleed && "-m-4"),
|
|
43
|
+
children: [toolbar && /* @__PURE__ */ jsx("div", {
|
|
44
|
+
className: "shrink-0 px-4",
|
|
59
45
|
children: toolbar
|
|
60
|
-
}) : /* @__PURE__ */ jsx(PageHeader, {
|
|
61
|
-
stickyTopClassName: SECTION_STICKY_TOP[section],
|
|
62
|
-
breadcrumbs,
|
|
63
|
-
title,
|
|
64
|
-
titleAction,
|
|
65
|
-
actions,
|
|
66
|
-
toolbar
|
|
67
46
|
}), /* @__PURE__ */ jsx("div", {
|
|
68
47
|
className: "relative @container min-h-0 flex-1 overflow-auto",
|
|
69
48
|
children: /* @__PURE__ */ jsx(ListRowActionsProvider, {
|
|
@@ -96,24 +75,29 @@ function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selec
|
|
|
96
75
|
});
|
|
97
76
|
return cloneElement(el, { className: cx(el.props.className, cls) });
|
|
98
77
|
});
|
|
78
|
+
const stretch = !!href && !selectionActive;
|
|
99
79
|
const handleRowClick = (e) => {
|
|
100
80
|
if (e.target.closest("a,button,input,label")) return;
|
|
101
81
|
if (selectionActive && onRowSelect) {
|
|
102
82
|
onRowSelect(e);
|
|
103
83
|
return;
|
|
104
84
|
}
|
|
105
|
-
if (href)
|
|
106
|
-
|
|
85
|
+
if (href) {
|
|
86
|
+
if (isPlainClick(e)) goTo(href);
|
|
87
|
+
} else onActivate?.();
|
|
107
88
|
};
|
|
108
89
|
const pinnedLabels = new Set((pinnedActions ?? []).map((a) => a.label));
|
|
109
90
|
const hasOverflowItems = items.some((item) => !isMenuDivider(item) && (isMenuSubmenu(item) || !pinnedLabels.has(item.label)));
|
|
110
91
|
return /* @__PURE__ */ jsxs("tr", {
|
|
111
|
-
className: cx("group", selected ? "bg-
|
|
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),
|
|
112
93
|
onClick: handleRowClick,
|
|
113
94
|
...rowContextMenuProps(openRowMenu, items),
|
|
114
95
|
children: [
|
|
115
96
|
leading,
|
|
116
|
-
|
|
97
|
+
/* @__PURE__ */ jsx(StretchRowLinkContext.Provider, {
|
|
98
|
+
value: stretch,
|
|
99
|
+
children: styledCells
|
|
100
|
+
}),
|
|
117
101
|
showActions && /* @__PURE__ */ jsx(Table.Item, {
|
|
118
102
|
className: "relative py-2.5",
|
|
119
103
|
children: /* @__PURE__ */ jsxs("div", {
|
|
@@ -137,18 +121,20 @@ function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selec
|
|
|
137
121
|
}
|
|
138
122
|
function PinnedActionButton({ action, visible }) {
|
|
139
123
|
warnIfInert(action, "ListPage pinned action");
|
|
140
|
-
const Link = useLink();
|
|
141
124
|
const runAction = useRunAction();
|
|
142
125
|
const reason = action.disabled ? action.disabledReason : void 0;
|
|
143
126
|
const props = {
|
|
144
127
|
"aria-label": reason ? `${action.label}. ${reason}` : action.label,
|
|
145
|
-
className: cx("rounded p-1 cursor-pointer text-(--theme-muted-text-color) transition-colors hover:bg-(--theme-muted-panel-bg) hover:text-(--theme-app) aria-disabled:cursor-not-allowed aria-disabled:opacity-20 aria-disabled:hover:bg-transparent aria-disabled:hover:text-(--theme-muted-text-color) [&>svg]:h-4 [&>svg]:w-4", visible ? "opacity-100" : "opacity-0 group-hover:opacity-100 focus-visible:opacity-100")
|
|
128
|
+
className: cx("rounded p-1 cursor-pointer text-(--theme-muted-text-color) transition-colors hover:bg-(--theme-muted-panel-bg) hover:text-(--theme-app) focus-visible:outline-2 focus-visible:outline-(--theme-link) aria-disabled:cursor-not-allowed aria-disabled:opacity-20 aria-disabled:hover:bg-transparent aria-disabled:hover:text-(--theme-muted-text-color) [&>svg]:h-4 [&>svg]:w-4", visible ? "opacity-100" : "opacity-0 group-hover:opacity-100 focus-visible:opacity-100")
|
|
146
129
|
};
|
|
147
130
|
return /* @__PURE__ */ jsx(Tooltip, {
|
|
148
131
|
content: reason ?? action.label,
|
|
149
132
|
side: "bottom",
|
|
150
|
-
children: action.href
|
|
133
|
+
children: action.href ? /* @__PURE__ */ jsx(AppLink, {
|
|
151
134
|
href: action.href,
|
|
135
|
+
reloadDocument: action.reloadDocument,
|
|
136
|
+
target: action.target,
|
|
137
|
+
disabled: action.disabled,
|
|
152
138
|
...props,
|
|
153
139
|
children: action.icon
|
|
154
140
|
}) : /* @__PURE__ */ jsx("button", {
|
|
@@ -163,14 +149,27 @@ function PinnedActionButton({ action, visible }) {
|
|
|
163
149
|
})
|
|
164
150
|
});
|
|
165
151
|
}
|
|
166
|
-
|
|
152
|
+
function columnSort(view, orderBy) {
|
|
153
|
+
if (view.orderBy !== orderBy) return "none";
|
|
154
|
+
return view.orderDir === "asc" ? "ascending" : "descending";
|
|
155
|
+
}
|
|
156
|
+
/** Name column min-width is by role, not position, so a leading checkbox
|
|
157
|
+
* doesn't shift it. A column with an `orderBy` the view offers sorts by it.
|
|
158
|
+
* While the view's column headers are off, the header row collapses: its
|
|
159
|
+
* cells still size the columns, but nobody sees or hears them, as with any
|
|
160
|
+
* other display option that is off. */
|
|
167
161
|
function ListColumns({ view }) {
|
|
168
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [view.visibleColumns.map((col, i) =>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
162
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [view.visibleColumns.map((col, i) => {
|
|
163
|
+
const orderBy = view.orderBys.some((o) => o.value === col.orderBy) ? col.orderBy : void 0;
|
|
164
|
+
return /* @__PURE__ */ jsx(Table.Header, {
|
|
165
|
+
caps: false,
|
|
166
|
+
className: cx(col.headerClassName, view.columnClasses[i], !view.showColumnHeaders && "list-headers-off"),
|
|
167
|
+
style: col.alwaysVisible ? { minWidth: 200 } : void 0,
|
|
168
|
+
sort: orderBy === void 0 ? void 0 : columnSort(view, orderBy),
|
|
169
|
+
onSort: orderBy === void 0 ? void 0 : () => view.sortBy(orderBy),
|
|
170
|
+
children: col.label
|
|
171
|
+
}, col.key);
|
|
172
|
+
}), /* @__PURE__ */ jsx(ListActionsHeader, { view })] });
|
|
174
173
|
}
|
|
175
174
|
ListColumns.isTableHeader = true;
|
|
176
175
|
/** Stable `goTo` for whole-row navigation (`rowNavProps`, `ListRow`). */
|
package/dist/list/ListTable.d.ts
CHANGED
|
@@ -1,27 +1,39 @@
|
|
|
1
|
-
import type
|
|
2
|
-
/**
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/** Marks a header cell of a list whose column headers are off; see `listTableProps`. */
|
|
3
|
+
export declare const HEADERS_OFF = "list-headers-off";
|
|
4
|
+
/** table-auto; the name column has a min-width floor so it can't be crushed.
|
|
5
|
+
* The header row sticks as the rows scroll, so the list's scrolling box
|
|
6
|
+
* (`ListPage`'s body) scrolls it sideways too. */
|
|
3
7
|
export declare const listTableProps: {
|
|
4
8
|
readonly borderless: true;
|
|
9
|
+
readonly stickyHeader: true;
|
|
5
10
|
readonly panel: false;
|
|
6
11
|
readonly rounded: false;
|
|
7
|
-
readonly theadClassName: 'text-(--theme-muted-text-color)';
|
|
12
|
+
readonly theadClassName: 'bg-(--theme-app-bg) text-(--theme-muted-text-color) has-[.list-headers-off]:collapse';
|
|
8
13
|
readonly tbodyClassName: 'divide-y border-b border-(--theme-border) divide-(--theme-border)';
|
|
9
14
|
readonly className: 'table-auto w-full [&_td:first-child]:pl-4 [&_th:first-child]:pl-4 [&_td:last-child]:pr-4 [&_th:last-child]:pr-4';
|
|
10
15
|
};
|
|
11
16
|
/** Widths come only from the header row, so a windowed body cannot shift the
|
|
12
|
-
* columns as different content scrolls into view.
|
|
17
|
+
* columns as different content scrolls into view. The windowed table scrolls
|
|
18
|
+
* in its own box, so its header doesn't stick. */
|
|
13
19
|
export declare const listTableFixedProps: {
|
|
14
20
|
readonly borderless: true;
|
|
15
21
|
readonly panel: false;
|
|
16
22
|
readonly rounded: false;
|
|
17
|
-
readonly theadClassName: 'text-(--theme-muted-text-color)';
|
|
23
|
+
readonly theadClassName: 'bg-(--theme-app-bg) text-(--theme-muted-text-color) has-[.list-headers-off]:collapse';
|
|
18
24
|
readonly tbodyClassName: 'divide-y border-b border-(--theme-border) divide-(--theme-border)';
|
|
25
|
+
readonly stickyHeader: false;
|
|
19
26
|
readonly className: string;
|
|
20
27
|
};
|
|
28
|
+
/** True inside a `ListRow` whose name link should take the whole row's
|
|
29
|
+
* clicks: it navigates, and no selection claims plain clicks. */
|
|
30
|
+
export declare const StretchRowLinkContext: import("react").Context<boolean>;
|
|
21
31
|
export declare function NameCell({ icon, name, subtitle, href, badge, title, children, }: {
|
|
22
32
|
icon: ReactNode;
|
|
23
33
|
name: string;
|
|
24
34
|
subtitle?: string | undefined;
|
|
35
|
+
/** The name's link. Inside a `ListRow` with an `href`, the whole row is
|
|
36
|
+
* this link, so give both the same URL. */
|
|
25
37
|
href: string | null;
|
|
26
38
|
badge?: ReactNode;
|
|
27
39
|
title?: string | undefined;
|
|
@@ -34,9 +46,10 @@ export declare function GroupRow({ label, count, colSpan, }: {
|
|
|
34
46
|
count: number;
|
|
35
47
|
colSpan: number;
|
|
36
48
|
}): import("react").JSX.Element;
|
|
37
|
-
export declare function ListError({ error, noun }: {
|
|
49
|
+
export declare function ListError({ error, noun, }: {
|
|
38
50
|
error: unknown;
|
|
39
|
-
|
|
51
|
+
/** What failed to load, as the heading names it: "Couldn't load clusters". */
|
|
52
|
+
noun?: string | undefined;
|
|
40
53
|
}): import("react").JSX.Element;
|
|
41
54
|
export declare function ListSkeleton({ rows }: {
|
|
42
55
|
rows?: number;
|
|
@@ -54,6 +67,18 @@ export declare function RowSelectCheckbox({ checked, label, onToggle, }: {
|
|
|
54
67
|
/** Gets the press, a click or a key, so a host can extend a range on Shift. */
|
|
55
68
|
onToggle: (event: Event) => void;
|
|
56
69
|
}): import("react").JSX.Element;
|
|
70
|
+
/** The selection column's header: a checkbox that ticks every row, mixed while
|
|
71
|
+
* only some are. `onToggle` selects them all, or clears them once all are. */
|
|
72
|
+
export declare function ListSelectAllHeader({ selected, total, onToggle, }: {
|
|
73
|
+
/** How many rows are selected. */
|
|
74
|
+
selected: number;
|
|
75
|
+
/** How many rows there are to select. */
|
|
76
|
+
total: number;
|
|
77
|
+
onToggle: () => void;
|
|
78
|
+
}): import("react").JSX.Element;
|
|
79
|
+
export declare namespace ListSelectAllHeader {
|
|
80
|
+
var isTableHeader: boolean;
|
|
81
|
+
}
|
|
57
82
|
/** Sizes to fit pinned buttons + ⋯; below ~44rem only ⋯ remains. Pass a view's
|
|
58
83
|
* chrome (structurally: showActions + actionsWidth) or actionCount. */
|
|
59
84
|
export declare function ListActionsHeader({ view, actionCount, className, }: {
|
package/dist/list/ListTable.js
CHANGED
|
@@ -1,31 +1,44 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
2
|
import { ErrorIcon } from "../icons.js";
|
|
3
3
|
import { positionKeys } from "../components/keys.js";
|
|
4
|
-
import {
|
|
4
|
+
import { useStrings } from "../components/Provider.js";
|
|
5
|
+
import { AppLink } from "../components/AppLink.js";
|
|
5
6
|
import { Checkbox } from "../components/Checkbox.js";
|
|
6
7
|
import { LoadingRegion, Skeleton } from "../components/Skeleton.js";
|
|
7
8
|
import { Table } from "../components/Table.js";
|
|
8
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { createContext, useContext } from "react";
|
|
9
11
|
//#region src/list/ListTable.tsx
|
|
10
12
|
var NAME_TEXT = "font-medium text-[13px] leading-tight text-(--theme-app) truncate";
|
|
11
13
|
var SUBTITLE_TEXT = "text-xs leading-tight text-(--theme-muted-text-color) truncate";
|
|
12
|
-
/**
|
|
14
|
+
/** Marks a header cell of a list whose column headers are off; see `listTableProps`. */
|
|
15
|
+
var HEADERS_OFF = "list-headers-off";
|
|
16
|
+
/** table-auto; the name column has a min-width floor so it can't be crushed.
|
|
17
|
+
* The header row sticks as the rows scroll, so the list's scrolling box
|
|
18
|
+
* (`ListPage`'s body) scrolls it sideways too. */
|
|
13
19
|
var listTableProps = {
|
|
14
20
|
borderless: true,
|
|
21
|
+
stickyHeader: true,
|
|
15
22
|
panel: false,
|
|
16
23
|
rounded: false,
|
|
17
|
-
theadClassName: "text-(--theme-muted-text-color)",
|
|
24
|
+
theadClassName: "bg-(--theme-app-bg) text-(--theme-muted-text-color) has-[.list-headers-off]:collapse",
|
|
18
25
|
tbodyClassName: "divide-y border-b border-(--theme-border) divide-(--theme-border)",
|
|
19
26
|
className: "table-auto w-full [&_td:first-child]:pl-4 [&_th:first-child]:pl-4 [&_td:last-child]:pr-4 [&_th:last-child]:pr-4"
|
|
20
27
|
};
|
|
21
28
|
/** Widths come only from the header row, so a windowed body cannot shift the
|
|
22
|
-
* columns as different content scrolls into view.
|
|
29
|
+
* columns as different content scrolls into view. The windowed table scrolls
|
|
30
|
+
* in its own box, so its header doesn't stick. */
|
|
23
31
|
var listTableFixedProps = {
|
|
24
32
|
...listTableProps,
|
|
33
|
+
stickyHeader: false,
|
|
25
34
|
className: listTableProps.className.replace("table-auto", "table-fixed")
|
|
26
35
|
};
|
|
36
|
+
/** True inside a `ListRow` whose name link should take the whole row's
|
|
37
|
+
* clicks: it navigates, and no selection claims plain clicks. */
|
|
38
|
+
var StretchRowLinkContext = createContext(false);
|
|
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)";
|
|
27
40
|
function NameCell({ icon, name, subtitle, href, badge, title, children }) {
|
|
28
|
-
const
|
|
41
|
+
const stretch = useContext(StretchRowLinkContext);
|
|
29
42
|
const inner = /* @__PURE__ */ jsxs(Fragment, { children: [icon, /* @__PURE__ */ jsxs("div", {
|
|
30
43
|
className: "min-w-0",
|
|
31
44
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -42,9 +55,10 @@ function NameCell({ icon, name, subtitle, href, badge, title, children }) {
|
|
|
42
55
|
})] });
|
|
43
56
|
return /* @__PURE__ */ jsxs(Table.Item, {
|
|
44
57
|
className: "py-2.5",
|
|
45
|
-
children: [href ? /* @__PURE__ */ jsx(
|
|
58
|
+
children: [href ? /* @__PURE__ */ jsx(AppLink, {
|
|
46
59
|
href,
|
|
47
|
-
|
|
60
|
+
"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),
|
|
48
62
|
children: inner
|
|
49
63
|
}) : /* @__PURE__ */ jsx("div", {
|
|
50
64
|
className: "flex items-center gap-2.5 min-w-0",
|
|
@@ -75,16 +89,20 @@ function GroupRow({ label, count, colSpan }) {
|
|
|
75
89
|
]
|
|
76
90
|
}) });
|
|
77
91
|
}
|
|
78
|
-
function ListError({ error, noun
|
|
92
|
+
function ListError({ error, noun }) {
|
|
79
93
|
const { list: t } = useStrings();
|
|
80
94
|
const message = error && typeof error === "object" && "message" in error ? String(error.message) : void 0;
|
|
81
95
|
return /* @__PURE__ */ jsxs("div", {
|
|
96
|
+
role: "alert",
|
|
82
97
|
className: "flex flex-col items-center justify-center gap-3 py-20 text-center",
|
|
83
|
-
children: [/* @__PURE__ */ jsx(ErrorIcon, {
|
|
98
|
+
children: [/* @__PURE__ */ jsx(ErrorIcon, {
|
|
99
|
+
"aria-hidden": "true",
|
|
100
|
+
className: "h-10 w-10 text-(--theme-error)"
|
|
101
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
84
102
|
className: "space-y-1",
|
|
85
103
|
children: [/* @__PURE__ */ jsx("p", {
|
|
86
104
|
className: "text-sm font-medium text-(--theme-app)",
|
|
87
|
-
children: t.couldNotLoad(noun)
|
|
105
|
+
children: t.couldNotLoad(noun ?? t.data)
|
|
88
106
|
}), message && /* @__PURE__ */ jsx("p", {
|
|
89
107
|
className: "max-w-md text-xs text-(--theme-muted-text-color)",
|
|
90
108
|
children: message
|
|
@@ -146,6 +164,24 @@ function RowSelectCheckbox({ checked, label, onToggle }) {
|
|
|
146
164
|
}
|
|
147
165
|
});
|
|
148
166
|
}
|
|
167
|
+
/** The selection column's header: a checkbox that ticks every row, mixed while
|
|
168
|
+
* only some are. `onToggle` selects them all, or clears them once all are. */
|
|
169
|
+
function ListSelectAllHeader({ selected, total, onToggle }) {
|
|
170
|
+
const t = useStrings().list;
|
|
171
|
+
const all = total > 0 && selected >= total;
|
|
172
|
+
return /* @__PURE__ */ jsx(Table.Header, {
|
|
173
|
+
caps: false,
|
|
174
|
+
className: "w-10",
|
|
175
|
+
children: /* @__PURE__ */ jsx(Checkbox, {
|
|
176
|
+
"aria-label": t.selectAll,
|
|
177
|
+
checked: all,
|
|
178
|
+
indeterminate: selected > 0 && !all,
|
|
179
|
+
disabled: total === 0,
|
|
180
|
+
onCheckedChange: () => onToggle()
|
|
181
|
+
})
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
ListSelectAllHeader.isTableHeader = true;
|
|
149
185
|
/** Sizes to fit pinned buttons + ⋯; below ~44rem only ⋯ remains. Pass a view's
|
|
150
186
|
* chrome (structurally: showActions + actionsWidth) or actionCount. */
|
|
151
187
|
function ListActionsHeader({ view, actionCount = 0, className }) {
|
|
@@ -158,7 +194,7 @@ function ListActionsHeader({ view, actionCount = 0, className }) {
|
|
|
158
194
|
width,
|
|
159
195
|
minWidth: width
|
|
160
196
|
},
|
|
161
|
-
className: cx("relative py-2 text-right @max-[
|
|
197
|
+
className: cx("relative py-2 text-right @max-[44rem]:w-[52px]! @max-[44rem]:min-w-[52px]!", className),
|
|
162
198
|
children: /* @__PURE__ */ jsx("span", {
|
|
163
199
|
className: "sr-only",
|
|
164
200
|
children: common.actions
|
|
@@ -167,4 +203,4 @@ function ListActionsHeader({ view, actionCount = 0, className }) {
|
|
|
167
203
|
}
|
|
168
204
|
ListActionsHeader.isTableHeader = true;
|
|
169
205
|
//#endregion
|
|
170
|
-
export { GroupRow, ListActionsHeader, ListError, ListSkeleton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, actionsColumnWidth, listTableFixedProps, listTableProps };
|
|
206
|
+
export { GroupRow, HEADERS_OFF, ListActionsHeader, ListError, ListSelectAllHeader, ListSkeleton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, StretchRowLinkContext, actionsColumnWidth, listTableFixedProps, listTableProps };
|
|
@@ -4,10 +4,10 @@ import { MenuCheckboxItem, MenuPopup, MenuSubmenuTrigger } from "../components/M
|
|
|
4
4
|
import { Tooltip } from "../components/Tooltip.js";
|
|
5
5
|
import { useStrings } from "../components/Provider.js";
|
|
6
6
|
import { useQueryMatch } from "../components/search.js";
|
|
7
|
-
import { Switch } from "../components/Switch.js";
|
|
8
7
|
import { IconButton } from "../components/IconButton.js";
|
|
9
8
|
import { Popover } from "../components/Popover.js";
|
|
10
9
|
import { InfoTip } from "../components/InfoTip.js";
|
|
10
|
+
import { Switch } from "../components/Switch.js";
|
|
11
11
|
import { Select } from "../components/Select.js";
|
|
12
12
|
import { Menu } from "@base-ui/react/menu";
|
|
13
13
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
|
-
import { CopyIcon } from "../icons.js";
|
|
3
|
-
import { Tooltip } from "../components/Tooltip.js";
|
|
4
2
|
import { useLink, useStrings } from "../components/Provider.js";
|
|
5
|
-
import { useCopy } from "../components/useCopy.js";
|
|
6
3
|
import { Avatar } from "../components/Avatar.js";
|
|
4
|
+
import { CopyButton } from "../components/CopyButton.js";
|
|
7
5
|
import { LoadingRegion, Skeleton } from "../components/Skeleton.js";
|
|
8
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
7
|
//#region src/list/UserHoverCard.tsx
|
|
10
8
|
function UserHoverCard({ username, name, avatarSrc, badge, href, linkComponent, loading = false, children }) {
|
|
11
|
-
const {
|
|
12
|
-
const { copy } = useCopy();
|
|
9
|
+
const { list: t } = useStrings();
|
|
13
10
|
const SlotLink = useLink();
|
|
14
11
|
const Link = linkComponent ?? SlotLink;
|
|
15
12
|
const displayName = name || username;
|
|
@@ -36,7 +33,6 @@ function UserHoverCard({ username, name, avatarSrc, badge, href, linkComponent,
|
|
|
36
33
|
})]
|
|
37
34
|
})] });
|
|
38
35
|
const copyLabel = EMAIL.test(username) ? t.labelEmail : t.labelUsername;
|
|
39
|
-
const onCopy = () => void copy(username, { label: copyLabel });
|
|
40
36
|
return /* @__PURE__ */ jsxs("div", {
|
|
41
37
|
className: "w-64 p-3",
|
|
42
38
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -48,15 +44,11 @@ function UserHoverCard({ username, name, avatarSrc, badge, href, linkComponent,
|
|
|
48
44
|
}) : /* @__PURE__ */ jsx("div", {
|
|
49
45
|
className: "flex min-w-0 flex-1 items-start gap-3",
|
|
50
46
|
children: header
|
|
51
|
-
}), username && /* @__PURE__ */ jsx(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
onClick: onCopy,
|
|
57
|
-
className: cx("shrink-0 cursor-pointer rounded p-0.5 text-(--theme-muted-text-color) opacity-0 transition hover:bg-(--theme-muted-panel-bg) hover:text-(--theme-app) [&>svg]:h-3.5 [&>svg]:w-3.5", "hover:opacity-100 group-has-[[data-copy-value]:hover]/copy:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--theme-link) pointer-coarse:opacity-100"),
|
|
58
|
-
children: /* @__PURE__ */ jsx(CopyIcon, { "aria-hidden": "true" })
|
|
59
|
-
})
|
|
47
|
+
}), username && /* @__PURE__ */ jsx(CopyButton, {
|
|
48
|
+
text: username,
|
|
49
|
+
label: copyLabel,
|
|
50
|
+
size: "xs",
|
|
51
|
+
className: cx("-mr-1 opacity-0", "hover:opacity-100 group-has-[[data-copy-value]:hover]/copy:opacity-100 focus-visible:opacity-100 pointer-coarse:opacity-100")
|
|
60
52
|
})]
|
|
61
53
|
}), loading ? /* @__PURE__ */ jsxs(LoadingRegion, {
|
|
62
54
|
className: "mt-3 space-y-2 border-t border-(--theme-border) pt-3",
|
package/dist/list/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ActionToolbar, stickyToolbarClasses, type ToolbarAction, ToolbarButton, type ToolbarItem, } from './ActionToolbar.js';
|
|
2
|
-
export { ListColumns, ListPage, type ListPageProps, ListRow, ListRowActionsProvider,
|
|
3
|
-
export { actionsColumnWidth, GroupRow, ListActionsHeader, ListError, ListSkeleton, listTableFixedProps, listTableProps, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, } from './ListTable.js';
|
|
2
|
+
export { ListColumns, ListPage, type ListPageProps, ListRow, ListRowActionsProvider, useListNavigate, } from './ListPage.js';
|
|
3
|
+
export { actionsColumnWidth, GroupRow, ListActionsHeader, ListError, ListSelectAllHeader, ListSkeleton, listTableFixedProps, listTableProps, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, } from './ListTable.js';
|
|
4
4
|
export { ListDisplayMenu, ListFilterMenu } from './ListViewControls.js';
|
|
5
5
|
export { ListCount, type ListSearch, ListSearchControl, useListSearch, } from './listSearch.js';
|
|
6
6
|
export { type ActionDef, type ColumnDef, DEFAULT_ORDER, FAVORITE_ORDER, type FilterFacet, type ListView, type ListViewChrome, type ListViewConfig, type OrderByOption, useListView, } from './listView.js';
|
package/dist/list/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ActionToolbar, ToolbarButton, stickyToolbarClasses } from "./ActionToolbar.js";
|
|
2
|
-
import { GroupRow, ListActionsHeader, ListError, ListSkeleton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, actionsColumnWidth, listTableFixedProps, listTableProps } from "./ListTable.js";
|
|
2
|
+
import { GroupRow, ListActionsHeader, ListError, ListSelectAllHeader, ListSkeleton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, actionsColumnWidth, listTableFixedProps, listTableProps } from "./ListTable.js";
|
|
3
3
|
import { MoreButton, assembleRowMenu, rowContextMenuProps, useCopySubmenu, useRowMenuActive } from "./rowMenu.js";
|
|
4
4
|
import { ListColumns, ListPage, ListRow, ListRowActionsProvider, useListNavigate } from "./ListPage.js";
|
|
5
5
|
import { ListDisplayMenu, ListFilterMenu } from "./ListViewControls.js";
|
|
6
6
|
import { ListCount, ListSearchControl, useListSearch } from "./listSearch.js";
|
|
7
7
|
import { DEFAULT_ORDER, FAVORITE_ORDER, useListView } from "./listView.js";
|
|
8
8
|
import { HoverCardRow, UserHoverCard } from "./UserHoverCard.js";
|
|
9
|
-
export { ActionToolbar, DEFAULT_ORDER, FAVORITE_ORDER, GroupRow, HoverCardRow, ListActionsHeader, ListColumns, ListCount, ListDisplayMenu, ListError, ListFilterMenu, ListPage, ListRow, ListRowActionsProvider, ListSearchControl, ListSkeleton, MoreButton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, ToolbarButton, UserHoverCard, actionsColumnWidth, assembleRowMenu, listTableFixedProps, listTableProps, rowContextMenuProps, stickyToolbarClasses, useCopySubmenu, useListNavigate, useListSearch, useListView, useRowMenuActive };
|
|
9
|
+
export { ActionToolbar, DEFAULT_ORDER, FAVORITE_ORDER, GroupRow, HoverCardRow, ListActionsHeader, ListColumns, ListCount, ListDisplayMenu, ListError, ListFilterMenu, ListPage, ListRow, ListRowActionsProvider, ListSearchControl, ListSelectAllHeader, ListSkeleton, MoreButton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, ToolbarButton, UserHoverCard, actionsColumnWidth, assembleRowMenu, listTableFixedProps, listTableProps, rowContextMenuProps, stickyToolbarClasses, useCopySubmenu, useListNavigate, useListSearch, useListView, useRowMenuActive };
|
package/dist/list/listSearch.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CloseIcon, RemoveIcon, SearchIcon } from "../icons.js";
|
|
2
1
|
import { buttonClasses } from "../components/buttonClasses.js";
|
|
2
|
+
import { CloseIcon, RemoveIcon, SearchIcon } from "../icons.js";
|
|
3
3
|
import { Tooltip } from "../components/Tooltip.js";
|
|
4
4
|
import { usePersistedState, useStrings } from "../components/Provider.js";
|
|
5
5
|
import { isTextEntryContext } from "../components/shortcutKey.js";
|
|
@@ -7,6 +7,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
7
7
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
8
8
|
//#region src/list/listSearch.tsx
|
|
9
9
|
var NO_TERMS = [];
|
|
10
|
+
var COUNT = new Intl.NumberFormat();
|
|
10
11
|
/** Pass `enabled: false` to suspend the global ⌘F/`/` hijack (e.g. when search isn't shown and browser Find should stay active). */
|
|
11
12
|
function useListSearch(enabled = true, storageKey) {
|
|
12
13
|
const [filter, setFilter] = useState("");
|
|
@@ -20,11 +21,6 @@ function useListSearch(enabled = true, storageKey) {
|
|
|
20
21
|
useEffect(() => {
|
|
21
22
|
if (!enabled) return;
|
|
22
23
|
const onKey = (e) => {
|
|
23
|
-
if (e.key === "Escape" && searchOpen) {
|
|
24
|
-
setSearchOpen(false);
|
|
25
|
-
setFilter("");
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
24
|
if (isTextEntryContext(e.target)) return;
|
|
29
25
|
if ((e.key === "f" || e.key === "F") && (e.metaKey || e.ctrlKey)) {
|
|
30
26
|
e.preventDefault();
|
|
@@ -36,7 +32,7 @@ function useListSearch(enabled = true, storageKey) {
|
|
|
36
32
|
};
|
|
37
33
|
window.addEventListener("keydown", onKey);
|
|
38
34
|
return () => window.removeEventListener("keydown", onKey);
|
|
39
|
-
}, [
|
|
35
|
+
}, [enabled]);
|
|
40
36
|
const openSearch = useCallback(() => setSearchOpen(true), []);
|
|
41
37
|
const closeSearch = useCallback(() => {
|
|
42
38
|
setSearchOpen(false);
|
|
@@ -94,8 +90,12 @@ function ListSearchControl({ search, placeholder, label: labelProp }) {
|
|
|
94
90
|
value: search.filter,
|
|
95
91
|
onChange: (e) => search.setFilter(e.target.value),
|
|
96
92
|
onFocus: search.openSearch,
|
|
93
|
+
"aria-label": label,
|
|
97
94
|
onKeyDown: (e) => {
|
|
98
|
-
if (e.key === "
|
|
95
|
+
if (e.key === "Escape" && search.searchOpen) {
|
|
96
|
+
e.preventDefault();
|
|
97
|
+
search.closeSearch();
|
|
98
|
+
} else if (e.key === "Enter") {
|
|
99
99
|
e.preventDefault();
|
|
100
100
|
search.addTerm(search.filter);
|
|
101
101
|
} else if (e.key === "Backspace" && !search.filter) {
|
|
@@ -117,7 +117,7 @@ function ListSearchControl({ search, placeholder, label: labelProp }) {
|
|
|
117
117
|
});
|
|
118
118
|
return /* @__PURE__ */ jsx(Tooltip, {
|
|
119
119
|
content: label,
|
|
120
|
-
shortcut: "
|
|
120
|
+
shortcut: "/",
|
|
121
121
|
children: /* @__PURE__ */ jsx("button", {
|
|
122
122
|
type: "button",
|
|
123
123
|
onClick: search.openSearch,
|
|
@@ -132,11 +132,13 @@ function ListSearchControl({ search, placeholder, label: labelProp }) {
|
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
134
|
function ListCount({ total, matches, filterActive, noun, nounPlural }) {
|
|
135
|
+
const { list: t } = useStrings();
|
|
135
136
|
return /* @__PURE__ */ jsx("div", {
|
|
136
137
|
className: "flex items-center h-9",
|
|
137
138
|
children: /* @__PURE__ */ jsx("span", {
|
|
139
|
+
role: "status",
|
|
138
140
|
className: "text-[13px] text-(--theme-muted-text-color)",
|
|
139
|
-
children: filterActive ?
|
|
141
|
+
children: filterActive ? t.matchCount(COUNT.format(matches), COUNT.format(total), nounPlural) : t.count(COUNT.format(total), total === 1 ? noun : nounPlural)
|
|
140
142
|
})
|
|
141
143
|
});
|
|
142
144
|
}
|
package/dist/list/listView.d.ts
CHANGED
|
@@ -19,6 +19,10 @@ export interface ColumnDef {
|
|
|
19
19
|
* column there: for something short that compares best lined up, like a
|
|
20
20
|
* total. The first column never stacks; it is what the others stack under. */
|
|
21
21
|
stack?: boolean;
|
|
22
|
+
/** The `value` of the {@link OrderByOption} this column sorts by. Its header
|
|
23
|
+
* then sorts the list: it shows, and sets, the same order as Display
|
|
24
|
+
* options' Ordering. */
|
|
25
|
+
orderBy?: string;
|
|
22
26
|
}
|
|
23
27
|
/** Column responsive importance; `low` drops before `medium`. See {@link ColumnDef.priority}. */
|
|
24
28
|
type ColumnPriority = 'low' | 'medium';
|
|
@@ -65,6 +69,8 @@ export interface ListViewConfig<T> {
|
|
|
65
69
|
actions?: ActionDef[];
|
|
66
70
|
/** Explicit pinned-button count when not using actions+isPinned; sizes the actions column. */
|
|
67
71
|
actionCount?: number;
|
|
72
|
+
/** Whether the column-header row shows before the user changes Display
|
|
73
|
+
* options (default true). */
|
|
68
74
|
defaultShowColumnHeaders?: boolean;
|
|
69
75
|
/** Whether row action affordances show before the user changes Display options. */
|
|
70
76
|
defaultShowActions?: boolean;
|
|
@@ -111,6 +117,9 @@ export interface ListView<T> extends ListViewChrome {
|
|
|
111
117
|
setOrderBy: (value: string) => void;
|
|
112
118
|
orderDir: OrderDir;
|
|
113
119
|
toggleOrderDir: () => void;
|
|
120
|
+
/** Orders by `value` ascending, or flips the direction when the list
|
|
121
|
+
* already orders by it: a sortable column header's click. */
|
|
122
|
+
sortBy: (value: string) => void;
|
|
114
123
|
applyOrder: (rows: T[]) => T[];
|
|
115
124
|
facets: FilterFacet<T>[];
|
|
116
125
|
filters: Record<string, string[]>;
|
|
@@ -121,7 +130,7 @@ export interface ListView<T> extends ListViewChrome {
|
|
|
121
130
|
actions: ActionDef[];
|
|
122
131
|
isPinned: (key: string) => boolean;
|
|
123
132
|
togglePinned: (key: string) => void;
|
|
124
|
-
/** Whether the table renders its column-header row (default
|
|
133
|
+
/** Whether the table renders its column-header row (default on). */
|
|
125
134
|
showColumnHeaders: boolean;
|
|
126
135
|
toggleColumnHeaders: () => void;
|
|
127
136
|
/** Toggle whether rows expose action affordances. */
|