@parallelworks/ui 0.84.2 → 0.86.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 (39) hide show
  1. package/README.md +1 -1
  2. package/dist/ai/components/ChatMessage.js +6 -0
  3. package/dist/ai/core/ChatProvider.js +16 -5
  4. package/dist/components/CopyButton.d.ts +7 -2
  5. package/dist/components/CopyButton.js +11 -52
  6. package/dist/components/PageHeaderAction.d.ts +12 -5
  7. package/dist/components/PageHeaderAction.js +10 -9
  8. package/dist/components/Pagination.d.ts +4 -2
  9. package/dist/components/Pagination.js +54 -17
  10. package/dist/components/Provider.d.ts +4 -0
  11. package/dist/components/Provider.js +5 -1
  12. package/dist/components/RunStatusIcon.js +14 -17
  13. package/dist/components/StatusBadge.d.ts +10 -1
  14. package/dist/components/StatusBadge.js +27 -15
  15. package/dist/components/StatusIcons.d.ts +2 -0
  16. package/dist/components/StatusIcons.js +5 -3
  17. package/dist/components/Tabs.js +31 -2
  18. package/dist/components/Tag.d.ts +2 -1
  19. package/dist/components/Tag.js +5 -4
  20. package/dist/components/chart.d.ts +57 -10
  21. package/dist/components/chart.js +117 -22
  22. package/dist/components/scrollFade.d.ts +13 -0
  23. package/dist/components/scrollFade.js +51 -0
  24. package/dist/file-explorer/FileExplorer.js +8 -0
  25. package/dist/icons.d.ts +14 -1
  26. package/dist/icons.js +104 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +2 -2
  29. package/dist/list/ListPage.d.ts +4 -1
  30. package/dist/list/ListPage.js +96 -14
  31. package/dist/list/ListTable.d.ts +1 -0
  32. package/dist/list/ListTable.js +1 -1
  33. package/dist/list/ListViewControls.d.ts +1 -1
  34. package/dist/list/ListViewControls.js +2 -1
  35. package/dist/list/index.js +2 -2
  36. package/dist/list/listView.d.ts +15 -3
  37. package/dist/list/listView.js +11 -4
  38. package/dist/styles.css +1 -1
  39. package/package.json +1 -1
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, seriesColor, seriesColors, seriesOpacity, seriesSlotColor, useSeriesHighlight } from "./components/chart.js";
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, seriesColor, 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 };
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 };
@@ -89,9 +89,12 @@ export declare function ListRow({ href, onActivate, items, goTo, openMenu, pinne
89
89
  * column's width open; its content lays out across the row's visible width
90
90
  * from the first cell. Elsewhere it is one cell spanning `colSpan` columns.
91
91
  */
92
- export declare function GroupRow({ label, count, trailing, children, leading, colSpan, className, }: {
92
+ export declare function GroupRow({ label, detail, count, trailing, children, leading, colSpan, className, }: {
93
93
  /** The group's name: text, or an icon, a name with its tooltip, badges. */
94
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;
95
98
  /** How many rows the group holds, shown after the label. */
96
99
  count?: number | undefined;
97
100
  /** Set against the row's far end, such as "2/3 running". */
@@ -8,7 +8,7 @@ import { CellPlacementContext, STACKED_ITEM, Table } from "../components/Table.j
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 }) {
@@ -90,7 +93,7 @@ var STACKED_LINE = "mt-1 flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1 emp
90
93
  var isCellElement = (child) => child.type === Table.Item || child.type === "td";
91
94
  function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selected, selectionActive, onRowSelect, leading, className, children }) {
92
95
  const { active: menuActive, openMenu: openRowMenu } = useRowMenuActive(openMenu);
93
- const { show: showActions, always: alwaysShowActions, columnClasses, columnStacks } = useContext(RowActionsContext);
96
+ const { show: showActions, always: alwaysShowActions, columnClasses, columnStacks, lastLocked } = useContext(RowActionsContext);
94
97
  const cells = Children.toArray(children);
95
98
  const stacked = cells.flatMap((child, i) => {
96
99
  if (i === 0 || !columnStacks[i] || !isValidElement(child)) return [];
@@ -131,7 +134,7 @@ function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selec
131
134
  children: child
132
135
  }, child.key);
133
136
  });
134
- const floating = !alwaysShowActions && !(pinnedActions && pinnedActions.length > 0);
137
+ const floating = !alwaysShowActions && !(pinnedActions && pinnedActions.length > 0) && !lastLocked;
135
138
  const stretch = !!href && !selectionActive;
136
139
  const handleRowClick = (e) => {
137
140
  if (e.target.closest("a,button,input,label")) return;
@@ -158,7 +161,7 @@ function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selec
158
161
  showActions && /* @__PURE__ */ jsx(Table.Item, {
159
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!"),
160
163
  children: /* @__PURE__ */ jsxs("div", {
161
- 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"),
162
165
  children: [pinnedActions && pinnedActions.length > 0 && /* @__PURE__ */ jsx("span", {
163
166
  className: "hidden items-center gap-0.5 @[44rem]:flex",
164
167
  children: pinnedActions.map((action) => /* @__PURE__ */ jsx(PinnedActionButton, {
@@ -185,13 +188,19 @@ function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selec
185
188
  * column's width open; its content lays out across the row's visible width
186
189
  * from the first cell. Elsewhere it is one cell spanning `colSpan` columns.
187
190
  */
188
- function GroupRow({ label, count, trailing, children, leading = 0, colSpan, className }) {
191
+ function GroupRow({ label, detail, count, trailing, children, leading = 0, colSpan, className }) {
189
192
  const { show: showActions, columnClasses } = useContext(RowActionsContext);
193
+ const gutters = useRowGutters();
190
194
  const content = children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
191
195
  /* @__PURE__ */ jsx("span", {
192
196
  className: "flex min-w-0 items-center gap-2 text-(--theme-app)",
193
197
  children: label
194
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
+ }),
195
204
  count !== void 0 && /* @__PURE__ */ jsxs("span", {
196
205
  className: "shrink-0 text-(--theme-muted-text-color)",
197
206
  children: [/* @__PURE__ */ jsx("span", {
@@ -221,6 +230,8 @@ function GroupRow({ label, count, trailing, children, leading = 0, colSpan, clas
221
230
  return /* @__PURE__ */ jsx("tr", {
222
231
  className: row,
223
232
  "data-group-row": true,
233
+ ref: gutters.ref,
234
+ style: gutters.style,
224
235
  children: Array.from({ length: cells }, (_, i) => {
225
236
  const column = i - leading;
226
237
  const cls = column >= 0 && column < columnClasses.length ? columnClasses[column] : void 0;
@@ -230,7 +241,7 @@ function GroupRow({ label, count, trailing, children, leading = 0, colSpan, clas
230
241
  className: "w-0",
231
242
  children: /* @__PURE__ */ jsx("div", {
232
243
  className: line,
233
- style: { width: "calc(100cqw - 2rem)" },
244
+ style: { width: "calc(100cqw - var(--group-start, 1rem) - var(--group-end, 1rem))" },
234
245
  children: content
235
246
  })
236
247
  })
@@ -238,6 +249,41 @@ function GroupRow({ label, count, trailing, children, leading = 0, colSpan, clas
238
249
  })
239
250
  });
240
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
+ }
241
287
  function PinnedActionButton({ action, visible }) {
242
288
  warnIfInert(action, "ListPage pinned action");
243
289
  const runAction = useRunAction();
@@ -272,21 +318,57 @@ function columnSort(view, orderBy) {
272
318
  if (view.orderBy !== orderBy) return "none";
273
319
  return view.orderDir === "asc" ? "ascending" : "descending";
274
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
+ }
275
359
  /** Name column min-width is by role, not position, so a leading checkbox
276
360
  * doesn't shift it. A column with an `orderBy` the view offers sorts by it.
277
361
  * While the view's column headers are off, the header row collapses: its
278
362
  * cells still size the columns, but nobody sees or hears them, as with any
279
363
  * other display option that is off. */
280
364
  function ListColumns({ view }) {
365
+ const widths = shareWidths(view.visibleColumns, view.columnStacks);
281
366
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [view.visibleColumns.map((col, i) => {
282
367
  const orderBy = view.orderBys.some((o) => o.value === col.orderBy) ? col.orderBy : void 0;
283
368
  return /* @__PURE__ */ jsx(Table.Header, {
284
369
  caps: false,
285
- className: cx(col.headerClassName, view.columnClasses[i], !view.showColumnHeaders && "list-headers-off"),
286
- style: col.alwaysVisible || col.width !== void 0 ? {
287
- ...col.alwaysVisible && { minWidth: 200 },
288
- ...col.width !== void 0 && { width: col.width }
289
- } : void 0,
370
+ className: cx(col.headerClassName, view.columnClasses[i], widths[i] && SHARE_WIDTH, !view.showColumnHeaders && "list-headers-off"),
371
+ style: headerStyle(col, widths[i]),
290
372
  sort: orderBy === void 0 ? void 0 : columnSort(view, orderBy),
291
373
  onSort: orderBy === void 0 ? void 0 : () => view.sortBy(orderBy),
292
374
  children: col.label
@@ -113,6 +113,7 @@ export declare function ListActionsHeader({ view, actionCount, className, }: {
113
113
  showActions: boolean;
114
114
  actionsWidth: number;
115
115
  alwaysShowActions?: boolean;
116
+ lastColumnLocked?: boolean | undefined;
116
117
  };
117
118
  actionCount?: number;
118
119
  className?: string;
@@ -215,7 +215,7 @@ function ListActionsHeader({ view, actionCount = 0, className }) {
215
215
  const { common } = useStrings();
216
216
  if (view && !view.showActions) return null;
217
217
  const width = view ? view.actionsWidth : actionsColumnWidth(actionCount);
218
- const floating = !!view && !view.alwaysShowActions && view.actionsWidth === actionsColumnWidth(0);
218
+ const floating = !!view && !view.alwaysShowActions && !view.lastColumnLocked && view.actionsWidth === actionsColumnWidth(0);
219
219
  return /* @__PURE__ */ jsx(Table.Header, {
220
220
  caps: false,
221
221
  style: {
@@ -1,4 +1,4 @@
1
- import type { ListView } from './listView.js';
1
+ import { type ListView } from './listView.js';
2
2
  import type { ListFilters } from './useListFilters.js';
3
3
  export declare function ListDisplayMenu<T>({ view, label }: {
4
4
  view: ListView<T>;
@@ -10,6 +10,7 @@ import { InfoTip } from "../components/InfoTip.js";
10
10
  import { Switch } from "../components/Switch.js";
11
11
  import { Select } from "../components/Select.js";
12
12
  import { AddFilterMenu } from "./ListFilterBar.js";
13
+ import { isLocked } from "./listView.js";
13
14
  import { Menu } from "@base-ui/react/menu";
14
15
  import { useState } from "react";
15
16
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -20,7 +21,7 @@ var pillClassName = "whitespace-nowrap rounded-full border border-(--theme-borde
20
21
  var SECTION_LABEL = "mb-2 text-[11px] font-medium uppercase tracking-wide text-(--theme-muted-text-color)";
21
22
  function ListDisplayMenu({ view, label }) {
22
23
  const { common, list: t } = useStrings();
23
- const toggleable = view.columns.filter((c) => !c.alwaysVisible);
24
+ const toggleable = view.columns.filter((c) => !isLocked(c));
24
25
  const hasGrouping = view.groupBys.length > 0;
25
26
  const orderDirLabel = view.orderDir === "asc" ? t.ascending : t.descending;
26
27
  return /* @__PURE__ */ jsxs(Popover, {
@@ -4,10 +4,10 @@ import { AddFilterMenu, FilterChip, ListFilterBar } from "./ListFilterBar.js";
4
4
  import { ListActionsHeader, ListCellText, ListError, ListSelectAllHeader, ListSkeleton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, actionsColumnWidth, listTableFixedProps, listTableProps } from "./ListTable.js";
5
5
  import { MoreButton, assembleRowMenu, rowContextMenuProps, useCopySubmenu, useRowMenuActive } from "./rowMenu.js";
6
6
  import { GroupRow, ListColumns, ListPage, ListRow, ListRowActionsProvider, useListNavigate } from "./ListPage.js";
7
+ import { useListFilters } from "./useListFilters.js";
8
+ import { DEFAULT_ORDER, FAVORITE_ORDER, useListView } from "./listView.js";
7
9
  import { ListDisplayMenu, ListFilterMenu } from "./ListViewControls.js";
8
10
  import { ListCount, ListSearchControl, useListSearch } from "./listSearch.js";
9
11
  import { ListToolbar } from "./ListToolbar.js";
10
- import { useListFilters } from "./useListFilters.js";
11
- import { DEFAULT_ORDER, FAVORITE_ORDER, useListView } from "./listView.js";
12
12
  import { HoverCardRow, UserHoverCard } from "./UserHoverCard.js";
13
13
  export { ActionToolbar, AddFilterMenu, DATE_PRESETS, DEFAULT_ORDER, FAVORITE_ORDER, FilterChip, GroupRow, HoverCardRow, ListActionsHeader, ListCellText, ListColumns, ListCount, ListDisplayMenu, ListError, ListFilterBar, ListFilterMenu, ListPage, ListRow, ListRowActionsProvider, ListSearchControl, ListSelectAllHeader, ListSkeleton, ListToolbar, MoreButton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, ToolbarButton, UserHoverCard, actionsColumnWidth, applyFilterList, assembleRowMenu, dateFilterRange, decodeFilters, encodeFilters, filterParamKeys, listTableFixedProps, listTableProps, matchFilter, rowContextMenuProps, sameFilters, useCopySubmenu, useListFilters, useListNavigate, useListSearch, useListView, useRowMenuActive, withFilterParams };
@@ -7,8 +7,13 @@ export interface ColumnDef {
7
7
  key: string;
8
8
  label: string;
9
9
  headerClassName?: string;
10
- /** Pinned on — never offered in the column picker (e.g. the Name column). */
10
+ /** Pinned on — never offered in the column picker — and the list's name
11
+ * column, which keeps a minimum width so it can't be crushed. */
11
12
  alwaysVisible?: boolean;
13
+ /** Always shown and never offered in the column picker, at its own width:
14
+ * for a column such as a delete button's, which `alwaysVisible` would widen
15
+ * to a name's minimum. */
16
+ locked?: boolean;
12
17
  /** Hidden until the user turns it on in the Display menu. */
13
18
  defaultHidden?: boolean;
14
19
  /** NOT a table column (no header) — appears in picker and isVisible, but excluded from visibleColumns. */
@@ -28,8 +33,9 @@ export interface ColumnDef {
28
33
  /** The column's width, such as `'12%'` or `128`, set on its header. In a
29
34
  * fixed-layout list (`listTableFixedProps`), where every column without one
30
35
  * takes an equal share, give the other columns a width each and leave the
31
- * name without one, so it takes what they leave. A percentage is of the
32
- * list's width, and a hidden column's no longer counts. */
36
+ * name without one, so it takes what they leave. A percentage is a share of
37
+ * the list: when narrower widths drop columns, the shares they held go to
38
+ * the columns left, each in proportion to its own, the name's among them. */
33
39
  width?: string | number;
34
40
  /** `end` sets the header and the cells against the column's far edge, for
35
41
  * figures, sizes and times that compare best lined up on their last digit. */
@@ -37,6 +43,8 @@ export interface ColumnDef {
37
43
  }
38
44
  /** Column responsive importance; `low` drops before `medium`. See {@link ColumnDef.priority}. */
39
45
  type ColumnPriority = 'low' | 'medium';
46
+ /** Whether a column is always shown and kept out of the column picker. */
47
+ export declare function isLocked(col: ColumnDef): boolean;
40
48
  interface GroupByOption {
41
49
  value: string;
42
50
  label: string;
@@ -119,6 +127,10 @@ export interface ListViewChrome {
119
127
  /** Per visible column, whether it stacks under the first on a narrow
120
128
  * container ({@link ColumnDef.stack}); `ListRow` reads entry `i`. */
121
129
  columnStacks: boolean[];
130
+ /** Whether the last column is a locked one, such as a delete button's: the
131
+ * row's `⋯` then keeps a lane of its own after it rather than floating over
132
+ * it on hover. */
133
+ lastColumnLocked?: boolean | undefined;
122
134
  /** The list's filters, which `ListPage` shows as a row of chips under its toolbar. */
123
135
  filterState?: ListFilters | undefined;
124
136
  }
@@ -11,6 +11,10 @@ var PRIORITY_SHOW_CLASS = {
11
11
  function stacks(col, i) {
12
12
  return i > 0 && !col.priority && col.stack !== false;
13
13
  }
14
+ /** Whether a column is always shown and kept out of the column picker. */
15
+ function isLocked(col) {
16
+ return Boolean(col.alwaysVisible || col.locked);
17
+ }
14
18
  function columnResponsiveClass(col, i) {
15
19
  if (stacks(col, i)) return PRIORITY_SHOW_CLASS.medium;
16
20
  return col.priority ? PRIORITY_SHOW_CLASS[col.priority] : "";
@@ -55,7 +59,7 @@ function useListView({ storageKey, sharedFiltersKey, columns, groupBys = [], def
55
59
  ]);
56
60
  const defaultGroupByValue = defaultGroupBy ?? groupBys[0]?.value ?? "";
57
61
  const defaultOrderByValue = isFavorite ? DEFAULT_ORDER : defaultOrderBy ?? orderBys[0]?.value ?? "";
58
- const defaultHiddenKeys = useMemo(() => columns.filter((c) => c.defaultHidden && !c.alwaysVisible).map((c) => c.key), [columns]);
62
+ const defaultHiddenKeys = useMemo(() => columns.filter((c) => c.defaultHidden && !isLocked(c)).map((c) => c.key), [columns]);
59
63
  const defaultPinnedKeys = useMemo(() => actions.filter((a) => a.defaultPinned).map((a) => a.key), [actions]);
60
64
  const [hiddenKeys, setHiddenKeys] = usePersistedState(`${storageKey}:hiddenColumns`, defaultHiddenKeys);
61
65
  const [pinnedKeys, setPinnedKeys] = usePersistedState(`${storageKey}:pinnedActions`, defaultPinnedKeys);
@@ -84,11 +88,13 @@ function useListView({ storageKey, sharedFiltersKey, columns, groupBys = [], def
84
88
  const actionsWidth = effectiveShowActions ? actionsColumnWidth(pinnedCount) : 0;
85
89
  const isVisible = useCallback((key) => {
86
90
  const col = columns.find((c) => c.key === key);
87
- return Boolean(col?.alwaysVisible) || !hiddenKeys.includes(key);
91
+ return col !== void 0 && isLocked(col) || !hiddenKeys.includes(key);
88
92
  }, [columns, hiddenKeys]);
89
- const visibleColumns = useMemo(() => columns.filter((c) => !c.inline && (c.alwaysVisible || !hiddenKeys.includes(c.key))), [columns, hiddenKeys]);
93
+ const visibleColumns = useMemo(() => columns.filter((c) => !c.inline && (isLocked(c) || !hiddenKeys.includes(c.key))), [columns, hiddenKeys]);
90
94
  const columnClasses = useMemo(() => visibleColumns.map(columnClass), [visibleColumns]);
91
95
  const columnStacks = useMemo(() => visibleColumns.map(stacks), [visibleColumns]);
96
+ const last = visibleColumns.at(-1);
97
+ const lastColumnLocked = visibleColumns.length > 1 && last !== void 0 && !last.alwaysVisible && isLocked(last);
92
98
  const toggleColumn = useCallback((key) => setHiddenKeys((prev) => prev.includes(key) ? prev.filter((k) => k !== key) : [...prev, key]), [setHiddenKeys]);
93
99
  const { add, update, remove } = filterState;
94
100
  const setFacetValues = useCallback((key, values) => {
@@ -183,6 +189,7 @@ function useListView({ storageKey, sharedFiltersKey, columns, groupBys = [], def
183
189
  visibleColumns,
184
190
  columnClasses,
185
191
  columnStacks,
192
+ lastColumnLocked,
186
193
  isVisible,
187
194
  pinnedCount,
188
195
  actionsWidth,
@@ -230,4 +237,4 @@ function facetField(facet) {
230
237
  };
231
238
  }
232
239
  //#endregion
233
- export { DEFAULT_ORDER, FAVORITE_ORDER, useListView };
240
+ export { DEFAULT_ORDER, FAVORITE_ORDER, isLocked, useListView };