@parallelworks/ui 0.84.1 → 0.85.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 +1 -1
- package/dist/components/CopyButton.d.ts +7 -2
- package/dist/components/CopyButton.js +11 -52
- package/dist/components/PageHeaderAction.d.ts +12 -5
- package/dist/components/PageHeaderAction.js +10 -9
- package/dist/components/Pagination.d.ts +4 -2
- package/dist/components/Pagination.js +54 -17
- package/dist/components/Provider.d.ts +4 -0
- package/dist/components/Provider.js +5 -1
- package/dist/components/Table.d.ts +3 -0
- package/dist/components/Table.js +6 -3
- package/dist/components/Tabs.js +31 -2
- package/dist/components/Tag.d.ts +2 -1
- package/dist/components/Tag.js +5 -4
- package/dist/components/chart.d.ts +57 -10
- package/dist/components/chart.js +117 -22
- package/dist/components/scrollFade.d.ts +13 -0
- package/dist/components/scrollFade.js +51 -0
- package/dist/file-explorer/FileExplorer.js +8 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/list/ListPage.d.ts +27 -0
- package/dist/list/ListPage.js +172 -20
- package/dist/list/ListTable.d.ts +3 -6
- package/dist/list/ListTable.js +12 -25
- package/dist/list/ListViewControls.d.ts +1 -1
- package/dist/list/ListViewControls.js +2 -1
- package/dist/list/index.d.ts +2 -2
- package/dist/list/index.js +4 -4
- package/dist/list/listView.d.ts +19 -1
- package/dist/list/listView.js +11 -4
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/components/chart.js
CHANGED
|
@@ -1,36 +1,65 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
2
|
import { useLocale, useStrings } from "./Provider.js";
|
|
3
|
-
import { CATEGORY_CLASSES
|
|
4
|
-
import { useCallback, useMemo, useState } from "react";
|
|
3
|
+
import { CATEGORY_CLASSES } from "./category.js";
|
|
4
|
+
import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
//#region src/components/chart.tsx
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
/** How many series a chart colors: a series past the eighth folds into "Other" (`foldSeries`)
|
|
8
|
+
* rather than taking a hue made up for it. */
|
|
9
|
+
var SERIES_LIMIT = CATEGORY_CLASSES.length;
|
|
10
|
+
/** The theme's category slots in the order series take them. Each run from the first — three,
|
|
11
|
+
* four or all eight — keeps neighbors apart in hue and lightness, for color-blind readers too,
|
|
12
|
+
* in light and dark, where the theme's own order steps through neighboring hues. */
|
|
13
|
+
var SERIES_ORDER = [
|
|
14
|
+
5,
|
|
15
|
+
2,
|
|
16
|
+
8,
|
|
17
|
+
3,
|
|
18
|
+
6,
|
|
19
|
+
4,
|
|
20
|
+
7,
|
|
21
|
+
1
|
|
22
|
+
];
|
|
23
|
+
/** The key `foldSeries` gives the series that sums those past the limit. */
|
|
24
|
+
var OTHER_SERIES_KEY = "__other__";
|
|
25
|
+
/** The mark color of the "Other" series: a neutral gray, so it never reads as one more series. */
|
|
26
|
+
var OTHER_SERIES_COLOR = "color-mix(in oklch, var(--theme-muted-text-color) 75%, var(--theme-panel-bg))";
|
|
27
|
+
/** The color of a chart's nth series, 1–8: the theme's category hue, between the slot's soft
|
|
28
|
+
* fill and its text and twice as saturated, so a bar or a line stands out from the page in
|
|
29
|
+
* light and dark alike. Past the eighth it is the "Other" gray; a hue is never repeated. */
|
|
30
|
+
function seriesSlotColor(position) {
|
|
31
|
+
const n = SERIES_ORDER[position - 1];
|
|
32
|
+
if (n === void 0) return OTHER_SERIES_COLOR;
|
|
13
33
|
return `oklch(from color-mix(in oklch, var(--theme-category-${n}), var(--theme-category-${n}-text)) l calc(c * 2) h)`;
|
|
14
34
|
}
|
|
15
|
-
/**
|
|
16
|
-
*
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
/** Colors for a chart's series, each key its `seriesColor` unless another key took that slot
|
|
21
|
-
* first, when it moves to the next free one: up to eight series never share a color. */
|
|
35
|
+
/** Colors for a chart's series by their place in `keys`: the first takes the first color, the
|
|
36
|
+
* second the next, so the first few are always the most distinct. Pass every key the chart can
|
|
37
|
+
* show, in an order that doesn't depend on the data shown, such as by name or as configured:
|
|
38
|
+
* a filter that hides a series then leaves the others their colors. `OTHER_SERIES_KEY`, and any
|
|
39
|
+
* key past the eighth, is the "Other" gray; fold them first with `foldSeries`. */
|
|
22
40
|
function seriesColors(keys) {
|
|
23
|
-
const taken = /* @__PURE__ */ new Set();
|
|
24
41
|
const colors = {};
|
|
42
|
+
let position = 0;
|
|
25
43
|
for (const key of keys) {
|
|
26
44
|
if (key in colors) continue;
|
|
27
|
-
|
|
28
|
-
if (taken.size < SLOTS) while (taken.has(slot)) slot = slot % SLOTS + 1;
|
|
29
|
-
taken.add(slot);
|
|
30
|
-
colors[key] = seriesSlotColor(slot);
|
|
45
|
+
colors[key] = key === "__other__" ? OTHER_SERIES_COLOR : seriesSlotColor(++position);
|
|
31
46
|
}
|
|
32
47
|
return colors;
|
|
33
48
|
}
|
|
49
|
+
/** Splits a chart's series at the limit: up to eight show as they are, and more keep the first
|
|
50
|
+
* seven and fold the rest into one "Other" series, `OTHER_SERIES_KEY`, whose value at a point
|
|
51
|
+
* is the sum of `folded`. Name it with the `chart.other` string. */
|
|
52
|
+
function foldSeries(keys, limit = SERIES_LIMIT) {
|
|
53
|
+
const unique = [...new Set(keys)];
|
|
54
|
+
if (unique.length <= limit) return {
|
|
55
|
+
keys: unique,
|
|
56
|
+
folded: []
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
keys: [...unique.slice(0, limit - 1), OTHER_SERIES_KEY],
|
|
60
|
+
folded: unique.slice(limit - 1)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
34
63
|
/** A series' color as a mark, for a legend or a tooltip's row. Only seen: the series' name
|
|
35
64
|
* beside it says which it is. */
|
|
36
65
|
function SeriesSwatch({ color, shape = "square", className }) {
|
|
@@ -107,7 +136,7 @@ function ChartTooltipContent({ label, items, formatValue, total, highlighted, hi
|
|
|
107
136
|
const sum = rows.reduce((acc, item) => acc + item.value, 0);
|
|
108
137
|
const showTotal = total ?? rows.length > 1;
|
|
109
138
|
return /* @__PURE__ */ jsxs("div", {
|
|
110
|
-
className: cx("min-w-
|
|
139
|
+
className: cx("min-w-[var(--chart-tooltip-min,10rem)] rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) p-3 text-xs text-(--theme-app) shadow-(--theme-shadow-lg)", className),
|
|
111
140
|
style,
|
|
112
141
|
children: [
|
|
113
142
|
label != null && label !== "" && /* @__PURE__ */ jsx("div", {
|
|
@@ -141,5 +170,71 @@ function ChartTooltipContent({ label, items, formatValue, total, highlighted, hi
|
|
|
141
170
|
]
|
|
142
171
|
});
|
|
143
172
|
}
|
|
173
|
+
/** Where a chart's tooltip goes beside a crosshair at `x`, so it never covers the column under
|
|
174
|
+
* the pointer: `gap` to the `prefer` side, or the other when it doesn't fit between `x` and
|
|
175
|
+
* that edge, or held to the wider side when neither fits. `start` and `end` bound it, in the
|
|
176
|
+
* same coordinates as `x`, such as the chart's box or the viewport. A charting library's
|
|
177
|
+
* tooltip takes `left` as its position. */
|
|
178
|
+
function chartTooltipPlacement({ x, width, start, end, gap = 12, prefer = "right" }) {
|
|
179
|
+
const room = {
|
|
180
|
+
left: x - gap - start,
|
|
181
|
+
right: end - x - gap
|
|
182
|
+
};
|
|
183
|
+
let side = (prefer === "right" ? ["right", "left"] : ["left", "right"]).find((s) => width <= room[s]);
|
|
184
|
+
let maxWidth = null;
|
|
185
|
+
if (side === void 0) {
|
|
186
|
+
side = room.right >= room.left ? "right" : "left";
|
|
187
|
+
maxWidth = Math.max(0, room[side]);
|
|
188
|
+
}
|
|
189
|
+
const shown = maxWidth ?? width;
|
|
190
|
+
return {
|
|
191
|
+
left: side === "right" ? x + gap : x - gap - shown,
|
|
192
|
+
side,
|
|
193
|
+
maxWidth
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/** Keeps a tooltip clear of the viewport's edge by this much. */
|
|
197
|
+
var VIEWPORT_MARGIN = 8;
|
|
198
|
+
/** Holds a chart's tooltip beside its crosshair, inside a positioned box around the plot: `x`
|
|
199
|
+
* is the crosshair in that box, and the tooltip sits `top` from its top, to the crosshair's
|
|
200
|
+
* inline end, or its start where the box has no room. When neither side of the box has room,
|
|
201
|
+
* as on a phone, it may reach past the box to the viewport's edge, and is held narrower when
|
|
202
|
+
* even that is too small. It never covers the hovered column or the pointer on it. Nothing
|
|
203
|
+
* shows while `x` is null. */
|
|
204
|
+
function ChartTooltipBeside({ x, top = 0, gap = 12, className, children }) {
|
|
205
|
+
const ref = useRef(null);
|
|
206
|
+
useLayoutEffect(() => {
|
|
207
|
+
const el = ref.current;
|
|
208
|
+
if (!el || x === null) return;
|
|
209
|
+
el.style.maxWidth = "";
|
|
210
|
+
el.style.removeProperty("--chart-tooltip-min");
|
|
211
|
+
const width = el.offsetWidth;
|
|
212
|
+
const box = el.offsetParent;
|
|
213
|
+
const origin = box ? box.getBoundingClientRect().left + box.clientLeft : 0;
|
|
214
|
+
const view = document.documentElement.clientWidth || window.innerWidth;
|
|
215
|
+
const place = (start, end) => chartTooltipPlacement({
|
|
216
|
+
x,
|
|
217
|
+
width,
|
|
218
|
+
start,
|
|
219
|
+
end,
|
|
220
|
+
gap,
|
|
221
|
+
prefer: getComputedStyle(el).direction === "rtl" ? "left" : "right"
|
|
222
|
+
});
|
|
223
|
+
let placement = box ? place(0, box.clientWidth) : null;
|
|
224
|
+
if (placement === null || placement.maxWidth !== null) placement = place(VIEWPORT_MARGIN - origin, view - VIEWPORT_MARGIN - origin);
|
|
225
|
+
el.style.left = `${placement.left}px`;
|
|
226
|
+
if (placement.maxWidth !== null) {
|
|
227
|
+
el.style.maxWidth = `${placement.maxWidth}px`;
|
|
228
|
+
el.style.setProperty("--chart-tooltip-min", "0px");
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
if (x === null) return null;
|
|
232
|
+
return /* @__PURE__ */ jsx("div", {
|
|
233
|
+
ref,
|
|
234
|
+
className: cx("pointer-events-none absolute z-10 w-max", className),
|
|
235
|
+
style: { top },
|
|
236
|
+
children
|
|
237
|
+
});
|
|
238
|
+
}
|
|
144
239
|
//#endregion
|
|
145
|
-
export { ChartLegendList, ChartTooltipContent, SeriesSwatch,
|
|
240
|
+
export { ChartLegendList, ChartTooltipBeside, ChartTooltipContent, OTHER_SERIES_COLOR, OTHER_SERIES_KEY, SERIES_LIMIT, SeriesSwatch, chartTooltipPlacement, foldSeries, seriesColors, seriesOpacity, seriesSlotColor, useSeriesHighlight };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type CSSProperties } from 'react';
|
|
2
|
+
/** Which ends of a sideways scroller hide some of its content, kept up to date as it
|
|
3
|
+
* scrolls or resizes. */
|
|
4
|
+
export type HiddenEnds = {
|
|
5
|
+
start: boolean;
|
|
6
|
+
end: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function useHiddenEnds(active: boolean): {
|
|
9
|
+
ref: import("react").RefObject<HTMLElement | null>;
|
|
10
|
+
ends: HiddenEnds;
|
|
11
|
+
onScroll: () => void;
|
|
12
|
+
};
|
|
13
|
+
export declare function fadeMask({ start, end }: HiddenEnds): CSSProperties | undefined;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useEffectEvent, useLayoutEffect, useRef, useState } from "react";
|
|
2
|
+
//#region src/components/scrollFade.ts
|
|
3
|
+
var NO_ENDS = {
|
|
4
|
+
start: false,
|
|
5
|
+
end: false
|
|
6
|
+
};
|
|
7
|
+
function useHiddenEnds(active) {
|
|
8
|
+
const ref = useRef(null);
|
|
9
|
+
const [ends, setEnds] = useState(NO_ENDS);
|
|
10
|
+
const measureNow = () => {
|
|
11
|
+
const el = ref.current;
|
|
12
|
+
if (!el || !active) {
|
|
13
|
+
setEnds(NO_ENDS);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const scrolled = Math.abs(el.scrollLeft);
|
|
17
|
+
const start = scrolled > 1;
|
|
18
|
+
const end = scrolled + el.clientWidth < el.scrollWidth - 1;
|
|
19
|
+
setEnds((was) => was.start === start && was.end === end ? was : {
|
|
20
|
+
start,
|
|
21
|
+
end
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
const measure = useEffectEvent(measureNow);
|
|
25
|
+
useLayoutEffect(() => {
|
|
26
|
+
measure();
|
|
27
|
+
});
|
|
28
|
+
useLayoutEffect(() => {
|
|
29
|
+
const el = ref.current;
|
|
30
|
+
if (!el || !active || typeof ResizeObserver === "undefined") return;
|
|
31
|
+
const observer = new ResizeObserver(() => measure());
|
|
32
|
+
observer.observe(el);
|
|
33
|
+
return () => observer.disconnect();
|
|
34
|
+
}, [active]);
|
|
35
|
+
return {
|
|
36
|
+
ref,
|
|
37
|
+
ends,
|
|
38
|
+
onScroll: measureNow
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
var FADE = "1.25rem";
|
|
42
|
+
function fadeMask({ start, end }) {
|
|
43
|
+
if (!start && !end) return;
|
|
44
|
+
const image = `linear-gradient(to var(--fade-end, right), ${start ? `transparent, #000 ${FADE}` : "#000"}, ${end ? `#000 calc(100% - ${FADE}), transparent` : "#000"})`;
|
|
45
|
+
return {
|
|
46
|
+
maskImage: image,
|
|
47
|
+
WebkitMaskImage: image
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { fadeMask, useHiddenEnds };
|
|
@@ -551,6 +551,14 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
|
|
|
551
551
|
const triggerBrowserDownload = (url, filename) => {
|
|
552
552
|
const href = safeUrl(url);
|
|
553
553
|
if (!href) return;
|
|
554
|
+
if (new URL(href, window.location.href).origin !== window.location.origin) {
|
|
555
|
+
const frame = document.createElement("iframe");
|
|
556
|
+
frame.hidden = true;
|
|
557
|
+
frame.src = href;
|
|
558
|
+
document.body.appendChild(frame);
|
|
559
|
+
setTimeout(() => frame.remove(), 6e4);
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
554
562
|
const a = document.createElement("a");
|
|
555
563
|
a.href = href;
|
|
556
564
|
a.download = filename;
|
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export { ContextMenuProvider, type MenuCloseTrigger, type MenuOpener, type OpenM
|
|
|
15
15
|
export { CopyButton, type CopyButtonProps, CopyCodeBlock, type CopyCodeBlockProps, } from './components/CopyButton.js';
|
|
16
16
|
export { CreateModal, CreateModalSelect, CreateModalSwitch, } from './components/CreateModal.js';
|
|
17
17
|
export { categoryClasses, categoryOf } from './components/category.js';
|
|
18
|
-
export { type ChartLegendItem, ChartLegendList, ChartTooltipContent, type ChartTooltipItem, SeriesSwatch, type SeriesSwatchShape,
|
|
18
|
+
export { type ChartLegendItem, ChartLegendList, ChartTooltipBeside, ChartTooltipContent, type ChartTooltipItem, type ChartTooltipPlacement, chartTooltipPlacement, foldSeries, OTHER_SERIES_COLOR, OTHER_SERIES_KEY, SERIES_LIMIT, SeriesSwatch, type SeriesSwatchShape, seriesColors, seriesOpacity, seriesSlotColor, useSeriesHighlight, } from './components/chart.js';
|
|
19
19
|
export { Calendar, type CalendarProps, DatePicker, type DatePickerProps, } from './components/DatePicker.js';
|
|
20
20
|
export { DescriptionListGroup, DescriptionListItem, type DescriptionListItemProps, type DescriptionListProps, type DescriptionListSize, type DescriptionListVariant, default as DescriptionList, } from './components/DescriptionList.js';
|
|
21
21
|
export { collapsePanelClassName, Disclosure, DisclosurePanel, type DisclosureProps, } from './components/Disclosure.js';
|
package/dist/index.js
CHANGED
|
@@ -45,7 +45,7 @@ import { ConfirmModal, useConfirm } from "./components/ConfirmModal.js";
|
|
|
45
45
|
import { Disclosure, DisclosurePanel, collapsePanelClassName } from "./components/Disclosure.js";
|
|
46
46
|
import { Switch } from "./components/Switch.js";
|
|
47
47
|
import { CreateModal, CreateModalSelect, CreateModalSwitch } from "./components/CreateModal.js";
|
|
48
|
-
import { ChartLegendList, ChartTooltipContent, SeriesSwatch,
|
|
48
|
+
import { ChartLegendList, ChartTooltipBeside, ChartTooltipContent, OTHER_SERIES_COLOR, OTHER_SERIES_KEY, SERIES_LIMIT, SeriesSwatch, chartTooltipPlacement, foldSeries, seriesColors, seriesOpacity, seriesSlotColor, useSeriesHighlight } from "./components/chart.js";
|
|
49
49
|
import { Calendar, DatePicker } from "./components/DatePicker.js";
|
|
50
50
|
import DescriptionList, { DescriptionListGroup, DescriptionListItem } from "./components/DescriptionList.js";
|
|
51
51
|
import { Drawer } from "./components/Drawer.js";
|
|
@@ -84,4 +84,4 @@ import { ToggleGroup } from "./components/ToggleGroup.js";
|
|
|
84
84
|
import { useClosingValue } from "./components/useClosingValue.js";
|
|
85
85
|
import { useCssIsDark } from "./components/useCssIsDark.js";
|
|
86
86
|
import { useApplyTheme, useColorMode } from "./components/useTheme.js";
|
|
87
|
-
export { ActionMenu, AppLink, Autocomplete, Avatar, AvatarGroup, Breadcrumbs, Button, CODE_STYLES, Calendar, Callout, Card, CardHeader, ChartLegendList, ChartTooltipContent, Checkbox, CheckboxGroup, CodeBlock, ColorInput, Combobox, ConfirmModal, ContextMenuProvider, CopyButton, CopyCodeBlock, CountBadge, CreateModal, CreateModalSelect, CreateModalSwitch, DEFAULT_CONTRAST, DEFAULT_PRESET, DEFAULT_THEME, DatePicker, DescriptionList, DescriptionListGroup, DescriptionListItem, Disclosure, DisclosurePanel, Drawer, Elapsed, EmptyState, ErrorPage, ErrorText, ExternalLink, Field, FieldOption, FieldValue, FileButton, HoverCard, IconButton, InfoTip, Input, JND, Kbd, LetterBadge, ListboxGroup, ListboxOption, ListboxPanel, Loader, LoadingRegion, Markdown, MenuCheckboxItem, MenuEntries, MenuFilter, MenuGroupLabel, MenuItem, MenuLinkItem, MenuPopup, MenuRadioItem, MenuSeparator, MenuSubmenuTrigger, Meter, MethodButton, Modal, ModalDescription, ModalTitle, NumberInput, OneTimeCodeInput, Overview, PAGE_SIZES, PageHeader, PageHeaderAction, PageHeaderAddButton, PageHeaderBar, PageHeaderMenu, PageHeaderProvider, Pagination, Popover, PopoverClose, ProgressBar, Radio, RadioGroup, RefreshButton, RelativeTime, RequiredMark, RevealToggle, RunStatusIcon, SIDEBAR_TOKENS, SearchInput, Section, SegmentedControl, Select, SelectionCopy, SeriesSwatch, SettingModeOption, SettingRow, SettingsCard, SettingsHeading, Skeleton, Slider, StatusBadge, StatusDot, StickyBar, Switch, THEME_PRESETS, THEME_TOKENS, TabPanel, Table, Tabs, Tag, TagList, Textarea, ThemeEditor, ThemePreview, TitleInput, ToggleGroup, Tooltip, TooltipProvider, UIProvider, apcaContrast, applyTheme, ariaKeyShortcuts, avatarInitials, buttonClasses, categoryClasses, categoryOf, collapsePanelClassName, composite, contrastRatio, cx, deltaE, deriveTheme, errorPageKind, fieldBox, fitSeed, formatBytes, formatCount, formatDateTime, formatDuration, formatInfoTipContent, formatShortcut, formatTimeLeft, generateTheme, isApplePlatform, isDarkColor, isMenuDivider, isMenuGroup, isMenuSubmenu, isPlainClick, isTextEntryContext, levelTone, menuDivider, modalPanelClassName, modeOf, normalizeTags, parseColor, parseTheme, prefersWideGamut, resolveMode, runStatusTone, schemeFor, serializeTheme,
|
|
87
|
+
export { ActionMenu, AppLink, Autocomplete, Avatar, AvatarGroup, Breadcrumbs, Button, CODE_STYLES, Calendar, Callout, Card, CardHeader, ChartLegendList, ChartTooltipBeside, ChartTooltipContent, Checkbox, CheckboxGroup, CodeBlock, ColorInput, Combobox, ConfirmModal, ContextMenuProvider, CopyButton, CopyCodeBlock, CountBadge, CreateModal, CreateModalSelect, CreateModalSwitch, DEFAULT_CONTRAST, DEFAULT_PRESET, DEFAULT_THEME, DatePicker, DescriptionList, DescriptionListGroup, DescriptionListItem, Disclosure, DisclosurePanel, Drawer, Elapsed, EmptyState, ErrorPage, ErrorText, ExternalLink, Field, FieldOption, FieldValue, FileButton, HoverCard, IconButton, InfoTip, Input, JND, Kbd, LetterBadge, ListboxGroup, ListboxOption, ListboxPanel, Loader, LoadingRegion, Markdown, MenuCheckboxItem, MenuEntries, MenuFilter, MenuGroupLabel, MenuItem, MenuLinkItem, MenuPopup, MenuRadioItem, MenuSeparator, MenuSubmenuTrigger, Meter, MethodButton, Modal, ModalDescription, ModalTitle, NumberInput, OTHER_SERIES_COLOR, OTHER_SERIES_KEY, OneTimeCodeInput, Overview, PAGE_SIZES, PageHeader, PageHeaderAction, PageHeaderAddButton, PageHeaderBar, PageHeaderMenu, PageHeaderProvider, Pagination, Popover, PopoverClose, ProgressBar, Radio, RadioGroup, RefreshButton, RelativeTime, RequiredMark, RevealToggle, RunStatusIcon, SERIES_LIMIT, SIDEBAR_TOKENS, SearchInput, Section, SegmentedControl, Select, SelectionCopy, SeriesSwatch, SettingModeOption, SettingRow, SettingsCard, SettingsHeading, Skeleton, Slider, StatusBadge, StatusDot, StickyBar, Switch, THEME_PRESETS, THEME_TOKENS, TabPanel, Table, Tabs, Tag, TagList, Textarea, ThemeEditor, ThemePreview, TitleInput, ToggleGroup, Tooltip, TooltipProvider, UIProvider, apcaContrast, applyTheme, ariaKeyShortcuts, avatarInitials, buttonClasses, categoryClasses, categoryOf, chartTooltipPlacement, collapsePanelClassName, composite, contrastRatio, cx, deltaE, deriveTheme, errorPageKind, fieldBox, fitSeed, foldSeries, formatBytes, formatCount, formatDateTime, formatDuration, formatInfoTipContent, formatShortcut, formatTimeLeft, generateTheme, isApplePlatform, isDarkColor, isMenuDivider, isMenuGroup, isMenuSubmenu, isPlainClick, isTextEntryContext, levelTone, menuDivider, modalPanelClassName, modeOf, normalizeTags, parseColor, parseTheme, prefersWideGamut, resolveMode, runStatusTone, schemeFor, serializeTheme, seriesColors, seriesOpacity, seriesSlotColor, shortcutText, statusTextClass, tagClasses, themeStylesheet, toHex, toP3, toast, useApplyTheme, useAvatarColoring, useClock, useCloseMenu, useClosePopover, useClosingValue, useColorMode, useConfirm, useContextMenu, useCopy, useCssIsDark, useElapsed, useFieldControl, useFieldLabelledControl, useListboxNavigation, useLocale, useMenuOpenedBy, useNavigation, useOpenMenu, useOptionalWorkflowEngine, usePersistedState, useProblemText, useProvisionCorsRules, useRelativeTime, useRunFile, useSeriesHighlight, useShortcutFormat, useShortcutKey, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader };
|
package/dist/list/ListPage.d.ts
CHANGED
|
@@ -80,6 +80,33 @@ export declare function ListRow({ href, onActivate, items, goTo, openMenu, pinne
|
|
|
80
80
|
leading?: ReactNode;
|
|
81
81
|
children: ReactNode;
|
|
82
82
|
}): import("react").JSX.Element;
|
|
83
|
+
/**
|
|
84
|
+
* A group's header row in a list: its label, such as a status or a cluster,
|
|
85
|
+
* and, against the row's far end, what sums it up, such as "2/3 running".
|
|
86
|
+
*
|
|
87
|
+
* Inside a `ListPage` with a view, it has one cell per column, each hiding
|
|
88
|
+
* with its column as the list narrows, so a group never holds a hidden
|
|
89
|
+
* column's width open; its content lays out across the row's visible width
|
|
90
|
+
* from the first cell. Elsewhere it is one cell spanning `colSpan` columns.
|
|
91
|
+
*/
|
|
92
|
+
export declare function GroupRow({ label, detail, count, trailing, children, leading, colSpan, className, }: {
|
|
93
|
+
/** The group's name: text, or an icon, a name with its tooltip, badges. */
|
|
94
|
+
label?: ReactNode;
|
|
95
|
+
/** A secondary detail after the label, such as an ID, that gives way first: it shows only
|
|
96
|
+
* where the list is at least 36rem wide, and truncates before the label does. */
|
|
97
|
+
detail?: ReactNode;
|
|
98
|
+
/** How many rows the group holds, shown after the label. */
|
|
99
|
+
count?: number | undefined;
|
|
100
|
+
/** Set against the row's far end, such as "2/3 running". */
|
|
101
|
+
trailing?: ReactNode;
|
|
102
|
+
/** The whole header, laid out in a row, in place of `label`, `count` and `trailing`. */
|
|
103
|
+
children?: ReactNode;
|
|
104
|
+
/** Cells the list's rows have before its columns, such as a selection checkbox. */
|
|
105
|
+
leading?: number | undefined;
|
|
106
|
+
/** Outside a list view, the columns the row spans. */
|
|
107
|
+
colSpan?: number | undefined;
|
|
108
|
+
className?: string | undefined;
|
|
109
|
+
}): import("react").JSX.Element;
|
|
83
110
|
/** Name column min-width is by role, not position, so a leading checkbox
|
|
84
111
|
* doesn't shift it. A column with an `orderBy` the view offers sorts by it.
|
|
85
112
|
* While the view's column headers are off, the header row collapses: its
|
package/dist/list/ListPage.js
CHANGED
|
@@ -4,11 +4,11 @@ import { Tooltip } from "../components/Tooltip.js";
|
|
|
4
4
|
import { useNavigation } from "../components/Provider.js";
|
|
5
5
|
import { AppLink, isPlainClick } from "../components/AppLink.js";
|
|
6
6
|
import { isMenuDivider, isMenuGroup, isMenuSubmenu, useRunAction, warnIfInert } from "../components/MenuEntries.js";
|
|
7
|
-
import { CellPlacementContext, Table } from "../components/Table.js";
|
|
7
|
+
import { CellPlacementContext, STACKED_ITEM, Table } from "../components/Table.js";
|
|
8
8
|
import { ListFilterBar } from "./ListFilterBar.js";
|
|
9
9
|
import { ListActionsHeader, ListError, ListSkeleton, StretchRowLinkContext } from "./ListTable.js";
|
|
10
10
|
import { MoreButton, rowContextMenuProps, useRowMenuActive } from "./rowMenu.js";
|
|
11
|
-
import { Children, cloneElement, createContext, isValidElement, useContext, useMemo } from "react";
|
|
11
|
+
import { Children, cloneElement, createContext, isValidElement, useContext, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
12
12
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
13
13
|
//#region src/list/ListPage.tsx
|
|
14
14
|
/** Defaults mean rows outside a ListView fully show actions (no view = show everything). */
|
|
@@ -16,19 +16,22 @@ var RowActionsContext = createContext({
|
|
|
16
16
|
show: true,
|
|
17
17
|
always: false,
|
|
18
18
|
columnClasses: [],
|
|
19
|
-
columnStacks: []
|
|
19
|
+
columnStacks: [],
|
|
20
|
+
lastLocked: false
|
|
20
21
|
});
|
|
21
22
|
function useRowActions(view) {
|
|
22
23
|
return useMemo(() => ({
|
|
23
24
|
show: view?.showActions ?? true,
|
|
24
25
|
always: view?.alwaysShowActions ?? false,
|
|
25
26
|
columnClasses: view?.columnClasses ?? [],
|
|
26
|
-
columnStacks: view?.columnStacks ?? []
|
|
27
|
+
columnStacks: view?.columnStacks ?? [],
|
|
28
|
+
lastLocked: view?.lastColumnLocked ?? false
|
|
27
29
|
}), [
|
|
28
30
|
view?.showActions,
|
|
29
31
|
view?.alwaysShowActions,
|
|
30
32
|
view?.columnClasses,
|
|
31
|
-
view?.columnStacks
|
|
33
|
+
view?.columnStacks,
|
|
34
|
+
view?.lastColumnLocked
|
|
32
35
|
]);
|
|
33
36
|
}
|
|
34
37
|
function ListRowActionsProvider({ view, children }) {
|
|
@@ -86,10 +89,11 @@ function ListPage({ bleed = false, toolbar, filterBar, view, loading = false, er
|
|
|
86
89
|
});
|
|
87
90
|
}
|
|
88
91
|
var STACKED = { stacked: true };
|
|
92
|
+
var STACKED_LINE = "mt-1 flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1 empty:hidden @[36rem]:hidden";
|
|
89
93
|
var isCellElement = (child) => child.type === Table.Item || child.type === "td";
|
|
90
94
|
function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selected, selectionActive, onRowSelect, leading, className, children }) {
|
|
91
95
|
const { active: menuActive, openMenu: openRowMenu } = useRowMenuActive(openMenu);
|
|
92
|
-
const { show: showActions, always: alwaysShowActions, columnClasses, columnStacks } = useContext(RowActionsContext);
|
|
96
|
+
const { show: showActions, always: alwaysShowActions, columnClasses, columnStacks, lastLocked } = useContext(RowActionsContext);
|
|
93
97
|
const cells = Children.toArray(children);
|
|
94
98
|
const stacked = cells.flatMap((child, i) => {
|
|
95
99
|
if (i === 0 || !columnStacks[i] || !isValidElement(child)) return [];
|
|
@@ -99,14 +103,18 @@ function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selec
|
|
|
99
103
|
}
|
|
100
104
|
return [child];
|
|
101
105
|
});
|
|
102
|
-
const under = stacked.length > 0 ?
|
|
103
|
-
className:
|
|
104
|
-
"data-stacked": true,
|
|
105
|
-
children: child.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
const under = stacked.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
107
|
+
className: STACKED_LINE,
|
|
108
|
+
"data-stacked-line": true,
|
|
109
|
+
children: stacked.map((child, j) => isValidElement(child) && child.type === "td" ? /* @__PURE__ */ jsx("div", {
|
|
110
|
+
className: STACKED_ITEM,
|
|
111
|
+
"data-stacked": true,
|
|
112
|
+
children: child.props.children
|
|
113
|
+
}, j) : /* @__PURE__ */ jsx(CellPlacementContext, {
|
|
114
|
+
value: STACKED,
|
|
115
|
+
children: child
|
|
116
|
+
}, j))
|
|
117
|
+
}) : void 0;
|
|
110
118
|
const styledCells = cells.map((child, i) => {
|
|
111
119
|
const cls = cx(columnClasses[i], i > 0 && stacked.length > 0 && !columnStacks[i] && STAYS_BESIDE_STACK);
|
|
112
120
|
const after = i === 0 ? under : void 0;
|
|
@@ -126,7 +134,7 @@ function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selec
|
|
|
126
134
|
children: child
|
|
127
135
|
}, child.key);
|
|
128
136
|
});
|
|
129
|
-
const floating = !alwaysShowActions && !(pinnedActions && pinnedActions.length > 0);
|
|
137
|
+
const floating = !alwaysShowActions && !(pinnedActions && pinnedActions.length > 0) && !lastLocked;
|
|
130
138
|
const stretch = !!href && !selectionActive;
|
|
131
139
|
const handleRowClick = (e) => {
|
|
132
140
|
if (e.target.closest("a,button,input,label")) return;
|
|
@@ -151,9 +159,9 @@ function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selec
|
|
|
151
159
|
children: styledCells
|
|
152
160
|
}),
|
|
153
161
|
showActions && /* @__PURE__ */ jsx(Table.Item, {
|
|
154
|
-
className: cx("relative py-2.5", floating && "pointer-fine:w-0! pointer-fine:min-w-0! pointer-fine:pl-0! pointer-fine:pr-1!"),
|
|
162
|
+
className: cx("relative overflow-visible py-2.5", floating && "pointer-fine:w-0! pointer-fine:min-w-0! pointer-fine:pl-0! pointer-fine:pr-1!"),
|
|
155
163
|
children: /* @__PURE__ */ jsxs("div", {
|
|
156
|
-
className: cx("absolute inset-y-0 right-0 flex items-center gap-0.5 pr-4", floating && !menuActive && "pointer-fine:opacity-0 pointer-fine:group-hover:opacity-100 pointer-fine:focus-within:opacity-100", floating && "pointer-fine:bg-linear-to-l pointer-fine:from-(--theme-hover) pointer-fine:from-70% pointer-fine:to-transparent pointer-fine:pl-6"),
|
|
164
|
+
className: cx("absolute inset-y-0 right-0 flex items-center gap-0.5 pr-4", stacked.length > 0 && "@max-[36rem]:items-start @max-[36rem]:pt-2", floating && !menuActive && "pointer-fine:opacity-0 pointer-fine:group-hover:opacity-100 pointer-fine:focus-within:opacity-100", floating && "pointer-fine:bg-linear-to-l pointer-fine:from-(--theme-hover) pointer-fine:from-70% pointer-fine:to-transparent pointer-fine:pl-6"),
|
|
157
165
|
children: [pinnedActions && pinnedActions.length > 0 && /* @__PURE__ */ jsx("span", {
|
|
158
166
|
className: "hidden items-center gap-0.5 @[44rem]:flex",
|
|
159
167
|
children: pinnedActions.map((action) => /* @__PURE__ */ jsx(PinnedActionButton, {
|
|
@@ -171,6 +179,111 @@ function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selec
|
|
|
171
179
|
]
|
|
172
180
|
});
|
|
173
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* A group's header row in a list: its label, such as a status or a cluster,
|
|
184
|
+
* and, against the row's far end, what sums it up, such as "2/3 running".
|
|
185
|
+
*
|
|
186
|
+
* Inside a `ListPage` with a view, it has one cell per column, each hiding
|
|
187
|
+
* with its column as the list narrows, so a group never holds a hidden
|
|
188
|
+
* column's width open; its content lays out across the row's visible width
|
|
189
|
+
* from the first cell. Elsewhere it is one cell spanning `colSpan` columns.
|
|
190
|
+
*/
|
|
191
|
+
function GroupRow({ label, detail, count, trailing, children, leading = 0, colSpan, className }) {
|
|
192
|
+
const { show: showActions, columnClasses } = useContext(RowActionsContext);
|
|
193
|
+
const gutters = useRowGutters();
|
|
194
|
+
const content = children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
195
|
+
/* @__PURE__ */ jsx("span", {
|
|
196
|
+
className: "flex min-w-0 items-center gap-2 text-(--theme-app)",
|
|
197
|
+
children: label
|
|
198
|
+
}),
|
|
199
|
+
detail !== void 0 && detail !== null && detail !== false && /* @__PURE__ */ jsx("span", {
|
|
200
|
+
className: "ml-2 hidden min-w-0 shrink-[100] truncate text-(--theme-muted-text-color) @[36rem]:block",
|
|
201
|
+
"data-group-detail": true,
|
|
202
|
+
children: detail
|
|
203
|
+
}),
|
|
204
|
+
count !== void 0 && /* @__PURE__ */ jsxs("span", {
|
|
205
|
+
className: "shrink-0 text-(--theme-muted-text-color)",
|
|
206
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
207
|
+
className: "mx-1.5 opacity-50",
|
|
208
|
+
"aria-hidden": "true",
|
|
209
|
+
children: "·"
|
|
210
|
+
}), count]
|
|
211
|
+
}),
|
|
212
|
+
trailing !== void 0 && trailing !== null && trailing !== false && /* @__PURE__ */ jsx("span", {
|
|
213
|
+
className: "ml-auto flex shrink-0 items-center gap-2 pl-3 text-(--theme-muted-text-color) tabular-nums",
|
|
214
|
+
children: trailing
|
|
215
|
+
})
|
|
216
|
+
] });
|
|
217
|
+
const line = "flex h-8 min-w-0 items-center text-xs font-medium whitespace-nowrap";
|
|
218
|
+
const row = cx("bg-(--theme-muted-panel-bg)", className);
|
|
219
|
+
if (columnClasses.length === 0) return /* @__PURE__ */ jsx("tr", {
|
|
220
|
+
className: row,
|
|
221
|
+
children: /* @__PURE__ */ jsx("td", {
|
|
222
|
+
colSpan,
|
|
223
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
224
|
+
className: line,
|
|
225
|
+
children: content
|
|
226
|
+
})
|
|
227
|
+
})
|
|
228
|
+
});
|
|
229
|
+
const cells = leading + columnClasses.length + (showActions ? 1 : 0);
|
|
230
|
+
return /* @__PURE__ */ jsx("tr", {
|
|
231
|
+
className: row,
|
|
232
|
+
"data-group-row": true,
|
|
233
|
+
ref: gutters.ref,
|
|
234
|
+
style: gutters.style,
|
|
235
|
+
children: Array.from({ length: cells }, (_, i) => {
|
|
236
|
+
const column = i - leading;
|
|
237
|
+
const cls = column >= 0 && column < columnClasses.length ? columnClasses[column] : void 0;
|
|
238
|
+
return /* @__PURE__ */ jsx("td", {
|
|
239
|
+
className: cx("p-0", cls),
|
|
240
|
+
children: i === 0 && /* @__PURE__ */ jsx("div", {
|
|
241
|
+
className: "w-0",
|
|
242
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
243
|
+
className: line,
|
|
244
|
+
style: { width: "calc(100cqw - var(--group-start, 1rem) - var(--group-end, 1rem))" },
|
|
245
|
+
children: content
|
|
246
|
+
})
|
|
247
|
+
})
|
|
248
|
+
}, i);
|
|
249
|
+
})
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/** The padding at a row's ends, read from its first and last shown cells, as custom properties a
|
|
253
|
+
* group row's header subtracts from the list's width: so it lines up with the rows however the
|
|
254
|
+
* host pads its list. Until it has measured, 16px, as `listTableProps` pads. */
|
|
255
|
+
function useRowGutters() {
|
|
256
|
+
const ref = useRef(null);
|
|
257
|
+
const [gutters, setGutters] = useState(null);
|
|
258
|
+
useLayoutEffect(() => {
|
|
259
|
+
const row = ref.current;
|
|
260
|
+
if (!row || typeof getComputedStyle === "undefined") return;
|
|
261
|
+
const measure = () => {
|
|
262
|
+
const cells = Array.from(row.cells).filter((cell) => cell.getClientRects().length > 0);
|
|
263
|
+
const first = cells[0];
|
|
264
|
+
const last = cells.at(-1);
|
|
265
|
+
if (!first || !last) return;
|
|
266
|
+
const start = getComputedStyle(first).paddingInlineStart;
|
|
267
|
+
const end = getComputedStyle(last).paddingInlineEnd;
|
|
268
|
+
setGutters((was) => was?.start === start && was.end === end ? was : {
|
|
269
|
+
start,
|
|
270
|
+
end
|
|
271
|
+
});
|
|
272
|
+
};
|
|
273
|
+
measure();
|
|
274
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
275
|
+
const observer = new ResizeObserver(measure);
|
|
276
|
+
observer.observe(row);
|
|
277
|
+
return () => observer.disconnect();
|
|
278
|
+
}, []);
|
|
279
|
+
return {
|
|
280
|
+
ref,
|
|
281
|
+
style: gutters ? {
|
|
282
|
+
"--group-start": gutters.start,
|
|
283
|
+
"--group-end": gutters.end
|
|
284
|
+
} : void 0
|
|
285
|
+
};
|
|
286
|
+
}
|
|
174
287
|
function PinnedActionButton({ action, visible }) {
|
|
175
288
|
warnIfInert(action, "ListPage pinned action");
|
|
176
289
|
const runAction = useRunAction();
|
|
@@ -205,18 +318,57 @@ function columnSort(view, orderBy) {
|
|
|
205
318
|
if (view.orderBy !== orderBy) return "none";
|
|
206
319
|
return view.orderDir === "asc" ? "ascending" : "descending";
|
|
207
320
|
}
|
|
321
|
+
var SHARE_WIDTH = "w-(--share-narrow) @[36rem]:w-(--share-medium) @[52rem]:w-(--share-wide)";
|
|
322
|
+
function percent(width) {
|
|
323
|
+
const match = typeof width === "string" ? /^(\d+(?:\.\d+)?)%$/.exec(width.trim()) : null;
|
|
324
|
+
return match ? Number(match[1]) : void 0;
|
|
325
|
+
}
|
|
326
|
+
/** Each column's width at each tier, for a column whose width is a share of the list. The
|
|
327
|
+
* shares of the columns a tier drops go to those left, each in proportion to its own: the
|
|
328
|
+
* name's, the rest of the list, among them. */
|
|
329
|
+
function shareWidths(columns, stacks) {
|
|
330
|
+
const shares = columns.map((col) => percent(col.width));
|
|
331
|
+
const shows = (col, i, tier) => tier === "wide" || (tier === "medium" ? col.priority !== "low" : !col.priority && !stacks[i]);
|
|
332
|
+
const total = shares.reduce((sum, share) => sum + (share ?? 0), 0);
|
|
333
|
+
const scale = (tier) => {
|
|
334
|
+
const kept = columns.reduce((sum, col, i) => sum + (shows(col, i, tier) ? shares[i] ?? 0 : 0), 0);
|
|
335
|
+
const left = 100 - (total - kept);
|
|
336
|
+
return left > 0 ? 100 / left : 1;
|
|
337
|
+
};
|
|
338
|
+
const factors = {
|
|
339
|
+
wide: 1,
|
|
340
|
+
medium: scale("medium"),
|
|
341
|
+
narrow: scale("narrow")
|
|
342
|
+
};
|
|
343
|
+
return shares.map((share) => share === void 0 ? void 0 : {
|
|
344
|
+
wide: share,
|
|
345
|
+
medium: share * factors.medium,
|
|
346
|
+
narrow: share * factors.narrow
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
function headerStyle(col, tiers) {
|
|
350
|
+
const style = {};
|
|
351
|
+
if (col.alwaysVisible) style["minWidth"] = 200;
|
|
352
|
+
if (tiers) {
|
|
353
|
+
style["--share-wide"] = `${tiers.wide}%`;
|
|
354
|
+
style["--share-medium"] = `${tiers.medium}%`;
|
|
355
|
+
style["--share-narrow"] = `${tiers.narrow}%`;
|
|
356
|
+
} else if (col.width !== void 0) style["width"] = col.width;
|
|
357
|
+
return Object.keys(style).length > 0 ? style : void 0;
|
|
358
|
+
}
|
|
208
359
|
/** Name column min-width is by role, not position, so a leading checkbox
|
|
209
360
|
* doesn't shift it. A column with an `orderBy` the view offers sorts by it.
|
|
210
361
|
* While the view's column headers are off, the header row collapses: its
|
|
211
362
|
* cells still size the columns, but nobody sees or hears them, as with any
|
|
212
363
|
* other display option that is off. */
|
|
213
364
|
function ListColumns({ view }) {
|
|
365
|
+
const widths = shareWidths(view.visibleColumns, view.columnStacks);
|
|
214
366
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [view.visibleColumns.map((col, i) => {
|
|
215
367
|
const orderBy = view.orderBys.some((o) => o.value === col.orderBy) ? col.orderBy : void 0;
|
|
216
368
|
return /* @__PURE__ */ jsx(Table.Header, {
|
|
217
369
|
caps: false,
|
|
218
|
-
className: cx(col.headerClassName, view.columnClasses[i], !view.showColumnHeaders && "list-headers-off"),
|
|
219
|
-
style: col
|
|
370
|
+
className: cx(col.headerClassName, view.columnClasses[i], widths[i] && SHARE_WIDTH, !view.showColumnHeaders && "list-headers-off"),
|
|
371
|
+
style: headerStyle(col, widths[i]),
|
|
220
372
|
sort: orderBy === void 0 ? void 0 : columnSort(view, orderBy),
|
|
221
373
|
onSort: orderBy === void 0 ? void 0 : () => view.sortBy(orderBy),
|
|
222
374
|
children: col.label
|
|
@@ -229,4 +381,4 @@ function useListNavigate() {
|
|
|
229
381
|
return useNavigation().goTo;
|
|
230
382
|
}
|
|
231
383
|
//#endregion
|
|
232
|
-
export { ListColumns, ListPage, ListRow, ListRowActionsProvider, useListNavigate };
|
|
384
|
+
export { GroupRow, ListColumns, ListPage, ListRow, ListRowActionsProvider, useListNavigate };
|
package/dist/list/ListTable.d.ts
CHANGED
|
@@ -54,17 +54,13 @@ export declare function NameCell({ icon, iconTile, name, subtitle, href, badge,
|
|
|
54
54
|
}): import("react").JSX.Element;
|
|
55
55
|
/** A row's column text: muted 13px, or monospace for an ID, a path or a
|
|
56
56
|
* hash. The style sits on the text rather than the cell, so it carries over
|
|
57
|
-
* when a narrow list stacks the column under the name.
|
|
57
|
+
* when a narrow list stacks the column under the name. Text wider than its
|
|
58
|
+
* column is cut off with an ellipsis, and shows whole in a tooltip. */
|
|
58
59
|
export declare function ListCellText({ mono, className, children, }: {
|
|
59
60
|
mono?: boolean | undefined;
|
|
60
61
|
className?: string | undefined;
|
|
61
62
|
children: ReactNode;
|
|
62
63
|
}): import("react").JSX.Element;
|
|
63
|
-
export declare function GroupRow({ label, count, colSpan, }: {
|
|
64
|
-
label: string;
|
|
65
|
-
count: number;
|
|
66
|
-
colSpan: number;
|
|
67
|
-
}): import("react").JSX.Element;
|
|
68
64
|
/** Says a list couldn't load. It never shows the error's own text, which is
|
|
69
65
|
* the server's words, in its language and not written for the reader. */
|
|
70
66
|
export declare function ListError({ noun, message, }: {
|
|
@@ -117,6 +113,7 @@ export declare function ListActionsHeader({ view, actionCount, className, }: {
|
|
|
117
113
|
showActions: boolean;
|
|
118
114
|
actionsWidth: number;
|
|
119
115
|
alwaysShowActions?: boolean;
|
|
116
|
+
lastColumnLocked?: boolean | undefined;
|
|
120
117
|
};
|
|
121
118
|
actionCount?: number;
|
|
122
119
|
className?: string;
|