@entifix/react-controls 0.19.0 → 0.20.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 +8 -0
- package/dist/i18n/catalog/en.d.ts.map +1 -1
- package/dist/i18n/catalog/en.js +55 -9
- package/dist/i18n/catalog/en.js.map +1 -1
- package/dist/i18n/catalog/es.d.ts +64 -5
- package/dist/i18n/catalog/es.d.ts.map +1 -1
- package/dist/i18n/catalog/es.js +61 -9
- package/dist/i18n/catalog/es.js.map +1 -1
- package/dist/i18n/catalog/index.d.ts +102 -10
- package/dist/i18n/catalog/index.d.ts.map +1 -1
- package/dist/i18n/entity-labels.d.ts +14 -0
- package/dist/i18n/entity-labels.d.ts.map +1 -1
- package/dist/i18n/entity-labels.js +15 -0
- package/dist/i18n/entity-labels.js.map +1 -1
- package/dist/i18n/i18n-context.js +2 -2
- package/dist/i18n/i18n-context.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/primitives.d.ts +0 -1
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +0 -1
- package/dist/primitives.js.map +1 -1
- package/dist/theme/index.d.ts +1 -0
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +1 -0
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/theme-context.d.ts +15 -3
- package/dist/theme/theme-context.d.ts.map +1 -1
- package/dist/theme/theme-context.js +49 -23
- package/dist/theme/theme-context.js.map +1 -1
- package/dist/theme/theme-cookie.d.ts +9 -0
- package/dist/theme/theme-cookie.d.ts.map +1 -0
- package/dist/theme/theme-cookie.js +8 -0
- package/dist/theme/theme-cookie.js.map +1 -0
- package/dist/theme/theme-script.d.ts +8 -6
- package/dist/theme/theme-script.d.ts.map +1 -1
- package/dist/theme/theme-script.js +21 -12
- package/dist/theme/theme-script.js.map +1 -1
- package/dist/ui/actions/action-surfaces.d.ts +1 -1
- package/dist/ui/actions/action-surfaces.js +1 -1
- package/dist/ui/actions/action-surfaces.js.map +1 -1
- package/dist/ui/actions/error-actions.d.ts +32 -0
- package/dist/ui/actions/error-actions.d.ts.map +1 -0
- package/dist/ui/actions/error-actions.js +40 -0
- package/dist/ui/actions/error-actions.js.map +1 -0
- package/dist/ui/actions/index.d.ts +2 -0
- package/dist/ui/actions/index.d.ts.map +1 -1
- package/dist/ui/actions/index.js +2 -0
- package/dist/ui/actions/index.js.map +1 -1
- package/dist/ui/actions/shortcut.d.ts +13 -0
- package/dist/ui/actions/shortcut.d.ts.map +1 -0
- package/dist/ui/actions/shortcut.js +18 -0
- package/dist/ui/actions/shortcut.js.map +1 -0
- package/dist/ui/actions/use-verb-invoker.d.ts +50 -0
- package/dist/ui/actions/use-verb-invoker.d.ts.map +1 -0
- package/dist/ui/actions/use-verb-invoker.js +93 -0
- package/dist/ui/actions/use-verb-invoker.js.map +1 -0
- package/dist/ui/atoms/cell-value/cell-value.d.ts.map +1 -1
- package/dist/ui/atoms/cell-value/cell-value.js +28 -14
- package/dist/ui/atoms/cell-value/cell-value.js.map +1 -1
- package/dist/ui/atoms/field-control/field-control.d.ts +1 -0
- package/dist/ui/atoms/field-control/field-control.d.ts.map +1 -1
- package/dist/ui/atoms/field-control/field-control.js +2 -0
- package/dist/ui/atoms/field-control/field-control.js.map +1 -1
- package/dist/ui/atoms/number-input/quantity-input.d.ts +8 -1
- package/dist/ui/atoms/number-input/quantity-input.d.ts.map +1 -1
- package/dist/ui/atoms/number-input/quantity-input.js +2 -1
- package/dist/ui/atoms/number-input/quantity-input.js.map +1 -1
- package/dist/ui/atoms/table/table.d.ts +12 -3
- package/dist/ui/atoms/table/table.d.ts.map +1 -1
- package/dist/ui/atoms/table/table.js +59 -10
- package/dist/ui/atoms/table/table.js.map +1 -1
- package/dist/ui/atoms/text/text.d.ts +2 -2
- package/dist/ui/atoms/text/text.d.ts.map +1 -1
- package/dist/ui/atoms/text/text.js.map +1 -1
- package/dist/ui/molecules/action-bar/action-bar.d.ts +76 -0
- package/dist/ui/molecules/action-bar/action-bar.d.ts.map +1 -0
- package/dist/ui/molecules/action-bar/action-bar.js +218 -0
- package/dist/ui/molecules/action-bar/action-bar.js.map +1 -0
- package/dist/ui/molecules/action-bar/index.d.ts +2 -0
- package/dist/ui/molecules/action-bar/index.d.ts.map +1 -0
- package/dist/ui/molecules/action-bar/index.js +3 -0
- package/dist/ui/molecules/action-bar/index.js.map +1 -0
- package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.d.ts.map +1 -1
- package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.js +8 -10
- package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.js.map +1 -1
- package/dist/ui/molecules/bulk-result/bulk-result.d.ts +3 -3
- package/dist/ui/molecules/bulk-result/bulk-result.js +4 -4
- package/dist/ui/molecules/bulk-result/bulk-result.js.map +1 -1
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.d.ts +24 -9
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.d.ts.map +1 -1
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.js +36 -11
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.js.map +1 -1
- package/dist/ui/molecules/entity-record-card/entity-record-card.d.ts +33 -20
- package/dist/ui/molecules/entity-record-card/entity-record-card.d.ts.map +1 -1
- package/dist/ui/molecules/entity-record-card/entity-record-card.js +53 -20
- package/dist/ui/molecules/entity-record-card/entity-record-card.js.map +1 -1
- package/dist/ui/molecules/filter-builder/filter-builder.d.ts +8 -2
- package/dist/ui/molecules/filter-builder/filter-builder.d.ts.map +1 -1
- package/dist/ui/molecules/filter-builder/filter-builder.js +14 -5
- package/dist/ui/molecules/filter-builder/filter-builder.js.map +1 -1
- package/dist/ui/molecules/filter-chips/filter-chips.d.ts +16 -0
- package/dist/ui/molecules/filter-chips/filter-chips.d.ts.map +1 -0
- package/dist/ui/molecules/filter-chips/filter-chips.js +73 -0
- package/dist/ui/molecules/filter-chips/filter-chips.js.map +1 -0
- package/dist/ui/molecules/filter-chips/index.d.ts +2 -0
- package/dist/ui/molecules/filter-chips/index.d.ts.map +1 -0
- package/dist/ui/molecules/filter-chips/index.js +3 -0
- package/dist/ui/molecules/filter-chips/index.js.map +1 -0
- package/dist/ui/molecules/menu/menu.d.ts +11 -1
- package/dist/ui/molecules/menu/menu.d.ts.map +1 -1
- package/dist/ui/molecules/menu/menu.js +62 -2
- package/dist/ui/molecules/menu/menu.js.map +1 -1
- package/dist/ui/molecules/pagination/pagination.d.ts +5 -0
- package/dist/ui/molecules/pagination/pagination.d.ts.map +1 -1
- package/dist/ui/molecules/pagination/pagination.js +35 -18
- package/dist/ui/molecules/pagination/pagination.js.map +1 -1
- package/dist/ui/molecules/region-state/index.d.ts +2 -0
- package/dist/ui/molecules/region-state/index.d.ts.map +1 -0
- package/dist/ui/molecules/region-state/index.js +3 -0
- package/dist/ui/molecules/region-state/index.js.map +1 -0
- package/dist/ui/molecules/region-state/region-state.d.ts +42 -0
- package/dist/ui/molecules/region-state/region-state.d.ts.map +1 -0
- package/dist/ui/molecules/region-state/region-state.js +83 -0
- package/dist/ui/molecules/region-state/region-state.js.map +1 -0
- package/dist/ui/molecules/table-toolbar/table-toolbar.d.ts +3 -1
- package/dist/ui/molecules/table-toolbar/table-toolbar.d.ts.map +1 -1
- package/dist/ui/molecules/table-toolbar/table-toolbar.js +3 -2
- package/dist/ui/molecules/table-toolbar/table-toolbar.js.map +1 -1
- package/dist/ui/molecules/toast-region/toast-region.d.ts +63 -19
- package/dist/ui/molecules/toast-region/toast-region.d.ts.map +1 -1
- package/dist/ui/molecules/toast-region/toast-region.js +129 -42
- package/dist/ui/molecules/toast-region/toast-region.js.map +1 -1
- package/dist/ui/organisms/command-palette/command-palette.d.ts.map +1 -1
- package/dist/ui/organisms/command-palette/command-palette.js +19 -12
- package/dist/ui/organisms/command-palette/command-palette.js.map +1 -1
- package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.d.ts.map +1 -1
- package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js +0 -1
- package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.d.ts +1 -1
- package/dist/ui/organisms/entity-form/entity-form.d.ts.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.js +322 -214
- package/dist/ui/organisms/entity-form/entity-form.js.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.types.d.ts +8 -0
- package/dist/ui/organisms/entity-form/entity-form.types.d.ts.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.types.js.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.d.ts +1 -1
- package/dist/ui/organisms/entity-table/entity-table.d.ts.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.js +332 -197
- package/dist/ui/organisms/entity-table/entity-table.js.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.types.d.ts +19 -4
- package/dist/ui/organisms/entity-table/entity-table.types.d.ts.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.types.js.map +1 -1
- package/dist/ui/organisms/entity-table/header-sort.d.ts +18 -0
- package/dist/ui/organisms/entity-table/header-sort.d.ts.map +1 -0
- package/dist/ui/organisms/entity-table/header-sort.js +54 -0
- package/dist/ui/organisms/entity-table/header-sort.js.map +1 -0
- package/dist/ui/organisms/entity-table/pivot.d.ts +25 -0
- package/dist/ui/organisms/entity-table/pivot.d.ts.map +1 -0
- package/dist/ui/organisms/entity-table/pivot.js +106 -0
- package/dist/ui/organisms/entity-table/pivot.js.map +1 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.d.ts +13 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.d.ts.map +1 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.js +31 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.js.map +1 -0
- package/dist/ui/organisms/top-bar/live-indicator.d.ts +11 -0
- package/dist/ui/organisms/top-bar/live-indicator.d.ts.map +1 -0
- package/dist/ui/organisms/top-bar/live-indicator.js +46 -0
- package/dist/ui/organisms/top-bar/live-indicator.js.map +1 -0
- package/dist/ui/organisms/top-bar/top-bar.d.ts +11 -2
- package/dist/ui/organisms/top-bar/top-bar.d.ts.map +1 -1
- package/dist/ui/organisms/top-bar/top-bar.js +14 -5
- package/dist/ui/organisms/top-bar/top-bar.js.map +1 -1
- package/dist/ui/organisms/wizard/wizard.d.ts +1 -1
- package/dist/ui/organisms/wizard/wizard.d.ts.map +1 -1
- package/dist/ui/organisms/wizard/wizard.js +7 -1
- package/dist/ui/organisms/wizard/wizard.js.map +1 -1
- package/dist/ui/organisms/wizard/wizard.types.d.ts +8 -0
- package/dist/ui/organisms/wizard/wizard.types.d.ts.map +1 -1
- package/dist/ui/organisms/wizard/wizard.types.js.map +1 -1
- package/dist/ui/utils/live-updates.d.ts +24 -0
- package/dist/ui/utils/live-updates.d.ts.map +1 -0
- package/dist/ui/utils/live-updates.js +20 -0
- package/dist/ui/utils/live-updates.js.map +1 -0
- package/dist/ui/utils/use-focus-on-arrival.d.ts +14 -0
- package/dist/ui/utils/use-focus-on-arrival.d.ts.map +1 -0
- package/dist/ui/utils/use-focus-on-arrival.js +42 -0
- package/dist/ui/utils/use-focus-on-arrival.js.map +1 -0
- package/dist/ui/utils/use-hotkey.d.ts +44 -25
- package/dist/ui/utils/use-hotkey.d.ts.map +1 -1
- package/dist/ui/utils/use-hotkey.js +80 -48
- package/dist/ui/utils/use-hotkey.js.map +1 -1
- package/package.json +5 -5
- package/dist/ui/molecules/split-button/index.d.ts +0 -2
- package/dist/ui/molecules/split-button/index.d.ts.map +0 -1
- package/dist/ui/molecules/split-button/index.js +0 -3
- package/dist/ui/molecules/split-button/index.js.map +0 -1
- package/dist/ui/molecules/split-button/split-button.d.ts +0 -21
- package/dist/ui/molecules/split-button/split-button.d.ts.map +0 -1
- package/dist/ui/molecules/split-button/split-button.js +0 -35
- package/dist/ui/molecules/split-button/split-button.js.map +0 -1
|
@@ -1,48 +1,34 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { emptySelection, extractMetaEntity, hierarchyOf, isSelected, selectionSize, toggleSelected } from '@entifix/core';
|
|
4
|
-
import { Fragment, useMemo, useRef, useState } from 'react';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { emptySelection, extractMetaEntity, hierarchyOf, isSelected, queryPropertyFor, selectionSize, toggleSelected } from '@entifix/core';
|
|
4
|
+
import { Fragment, useId, useMemo, useRef, useState } from 'react';
|
|
5
|
+
import { useEntityNoun, useLocale, useT, useTranslateKey } from '../../../i18n/index.js';
|
|
6
|
+
import { renderAnchor, useCasesForSurface } from '../../actions/index.js';
|
|
7
|
+
import { useVerbInvoker } from '../../actions/use-verb-invoker.js';
|
|
8
|
+
import { Button, button } from '../../atoms/button/index.js';
|
|
8
9
|
import { CellValue } from '../../atoms/cell-value/index.js';
|
|
9
10
|
import { Checkbox } from '../../atoms/field/index.js';
|
|
10
11
|
import { Skeleton } from '../../atoms/skeleton/index.js';
|
|
11
12
|
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableMessageRow, TableRow } from '../../atoms/table/index.js';
|
|
12
13
|
import { linkClassName } from '../../atoms/text/index.js';
|
|
14
|
+
import { ActionBar, itemsForUseCases } from '../../molecules/action-bar/index.js';
|
|
13
15
|
import { BulkActionBar } from '../../molecules/bulk-action-bar/index.js';
|
|
14
16
|
import { BulkResult } from '../../molecules/bulk-result/index.js';
|
|
15
17
|
import { ColumnSettings } from '../../molecules/column-settings/index.js';
|
|
16
|
-
import { ConfirmDialog } from '../../molecules/confirm-dialog/index.js';
|
|
17
18
|
import { EntityRecordCard } from '../../molecules/entity-record-card/index.js';
|
|
18
19
|
import { FilterBuilder } from '../../molecules/filter-builder/index.js';
|
|
20
|
+
import { FilterChips } from '../../molecules/filter-chips/index.js';
|
|
19
21
|
import { LoadingBoundary } from '../../molecules/loading-boundary/index.js';
|
|
20
|
-
import { Menu } from '../../molecules/menu/index.js';
|
|
21
22
|
import { Pagination } from '../../molecules/pagination/index.js';
|
|
23
|
+
import { RegionState } from '../../molecules/region-state/index.js';
|
|
22
24
|
import { SortBuilder } from '../../molecules/sort-builder/index.js';
|
|
23
25
|
import { TableToolbar } from '../../molecules/table-toolbar/index.js';
|
|
24
26
|
import { readEntityTableSlots } from './entity-table-slots.js';
|
|
25
27
|
import { shownTreeRows, TreeCell, treeRows } from './entity-table-tree.js';
|
|
28
|
+
import { nextHeaderSorting, sortKeys } from './header-sort.js';
|
|
29
|
+
import { ACTIONS_WIDTH, pivotClasses, pivotWidth, SELECTION_WIDTH } from './pivot.js';
|
|
26
30
|
import { useEntityTableColumns } from './use-entity-table-columns.js';
|
|
27
|
-
|
|
28
|
-
* The grid and the card list are both rendered, and CSS picks one. A JS
|
|
29
|
-
* breakpoint hook would have to guess during SSR and correct after mount —
|
|
30
|
-
* a hydration mismatch on every page load. Classes are written out in full
|
|
31
|
-
* because Tailwind cannot see a class name that is concatenated at runtime.
|
|
32
|
-
*/ const PIVOT_CLASS = {
|
|
33
|
-
sm: {
|
|
34
|
-
grid: 'hidden sm:block',
|
|
35
|
-
cards: 'sm:hidden'
|
|
36
|
-
},
|
|
37
|
-
md: {
|
|
38
|
-
grid: 'hidden md:block',
|
|
39
|
-
cards: 'md:hidden'
|
|
40
|
-
},
|
|
41
|
-
lg: {
|
|
42
|
-
grid: 'hidden lg:block',
|
|
43
|
-
cards: 'lg:hidden'
|
|
44
|
-
}
|
|
45
|
-
};
|
|
31
|
+
import { useResultAnnouncement } from './use-result-announcement.js';
|
|
46
32
|
/**
|
|
47
33
|
* How many placeholder rows the built-in skeleton draws.
|
|
48
34
|
*
|
|
@@ -51,36 +37,18 @@ import { useEntityTableColumns } from './use-entity-table-columns.js';
|
|
|
51
37
|
* a fifty-row page would otherwise paint fifty shimmer rows to stand in for
|
|
52
38
|
* content that arrives below the fold anyway.
|
|
53
39
|
*/ const SKELETON_ROW_CAP = 5;
|
|
54
|
-
|
|
55
|
-
|
|
40
|
+
/** How many members a card shows as meta when none declares a `card` role. */ const UNDECLARED_META_CAP = 3;
|
|
41
|
+
export function EntityTable({ entityConstructor, isLoading, skeleton = true, error, items, totalItems, currentPage, pageSize, onPageChange, onPageSizeChange, hrefFor, newHref, renderLink = renderAnchor, onSelect, preferencesKey, showControls = true, pivotBreakpoint, filtering, sorting, onFilteringChange, onSortingChange, facets, selection, onSelectionChange, metadata, isMetadataLoading = false, onBulkUseCase, onUseCase, onRetry, bulkOutcomes, onBulkDismiss, onBulkRetry, isBulkRunning = false, children }) {
|
|
42
|
+
var _ref, _ref1;
|
|
56
43
|
const t = useT();
|
|
57
44
|
// A descriptor's label is a runtime catalog key — the typed gate cannot see
|
|
58
45
|
// it, which is why a host's catalog check is what catches a typo.
|
|
59
46
|
const translateKey = useTranslateKey();
|
|
60
|
-
const
|
|
47
|
+
const entityNoun = useEntityNoun();
|
|
61
48
|
const metaEntity = extractMetaEntity(entityConstructor);
|
|
62
49
|
const slots = readEntityTableSlots(children);
|
|
63
50
|
const [panel, setPanel] = useState('none');
|
|
64
|
-
/**
|
|
65
|
-
* A verb waiting to be confirmed, and what it will act on.
|
|
66
|
-
*
|
|
67
|
-
* ⚠️ **The table had no confirmation flow at all** until a change moved a
|
|
68
|
-
* destructive verb onto it. It read `confirm.tone` — only to pick a tone for
|
|
69
|
-
* a button or a menu item — and then fired on the first click. `unpublish` is
|
|
70
|
-
* declared `destructive`, so a verb reachable from a row menu without this
|
|
71
|
-
* would have been a one-click unpublish with a red label explaining what had
|
|
72
|
-
* already happened.
|
|
73
|
-
*
|
|
74
|
-
* The state holds the confirmation itself rather than the descriptor, so the
|
|
75
|
-
* dialog cannot open for a verb that never asked for one — the same shape
|
|
76
|
-
* `EntityForm` uses, and for the same reason.
|
|
77
|
-
*
|
|
78
|
-
* It carries the **target** too, which the form's does not need: a form has
|
|
79
|
-
* one record and a table has a row or a selection, and those run through two
|
|
80
|
-
* different handlers with two different payloads.
|
|
81
|
-
*/ const [pending, setPending] = useState(undefined);
|
|
82
51
|
const { columns, visibleColumns, hidden, setPersonalization } = useEntityTableColumns(entityConstructor, slots.columns, items[0], `entity-table:${(_ref = preferencesKey != null ? preferencesKey : metaEntity.key) != null ? _ref : metaEntity.name}`);
|
|
83
|
-
const pivot = PIVOT_CLASS[pivotBreakpoint];
|
|
84
52
|
// A picker's table is choosing *one* value; a multi-selection there would
|
|
85
53
|
// offer a set to a form member that holds a single reference, and the two
|
|
86
54
|
// controls would fight over the same row. This is a wiring mistake rather
|
|
@@ -116,30 +84,91 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
|
|
|
116
84
|
total: totalItems,
|
|
117
85
|
excluded: new Set()
|
|
118
86
|
};
|
|
119
|
-
|
|
87
|
+
// Opening a record is its title's link, so a row needs an actions column
|
|
88
|
+
// only to pick it or to run a verb on it.
|
|
89
|
+
const hasRowAction = onSelect !== undefined || hasRowMenu;
|
|
120
90
|
const columnCount = visibleColumns.length + (hasRowAction ? 1 : 0) + (selectable ? 1 : 0);
|
|
121
91
|
/**
|
|
92
|
+
* The grid and the cards are both rendered, and a container query on the
|
|
93
|
+
* table's own box picks one — at the width its visible columns need. A
|
|
94
|
+
* viewport breakpoint was wrong inside a split view, a drawer or a wizard
|
|
95
|
+
* step, and a JS measurement would guess during SSR and correct after mount.
|
|
96
|
+
*/ const pivot = pivotClasses(pivotWidth(visibleColumns, (selectable ? SELECTION_WIDTH : 0) + (hasRowAction ? ACTIONS_WIDTH : 0), pivotBreakpoint));
|
|
97
|
+
/**
|
|
122
98
|
* The first load has nothing to show and is held with a skeleton; a refetch
|
|
123
99
|
* already has rows, so it keeps them and only marks the region busy. Splitting
|
|
124
100
|
* the two is what stops every pagination click flashing grey.
|
|
125
101
|
*/ const isFirstLoad = isLoading && items.length === 0;
|
|
126
|
-
const isRefetching = isLoading && items.length > 0;
|
|
127
102
|
/** `true`/omitted → the built-in default; a node → that node; `false` → none. */ const customSkeleton = typeof skeleton === 'boolean' ? undefined : skeleton;
|
|
128
103
|
const showSkeleton = isFirstLoad && skeleton !== false;
|
|
129
104
|
const skeletonRows = Array.from({
|
|
130
105
|
length: Math.min(pageSize, SKELETON_ROW_CAP)
|
|
131
106
|
}, (_, index)=>index);
|
|
132
107
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*/ const
|
|
137
|
-
const
|
|
108
|
+
* A refetch keeps its rows at full contrast and marks them `aria-busy`:
|
|
109
|
+
* dimming them through opacity took the text under the contrast a reader
|
|
110
|
+
* needs, on every page change.
|
|
111
|
+
*/ const busy = isLoading || undefined;
|
|
112
|
+
/** The column a row reads *as*: the first non-identifier one it filled in. */ const titleColumn = (item)=>visibleColumns.find((column)=>{
|
|
113
|
+
if (column.type === 'id') return false;
|
|
114
|
+
const value = item[column.name];
|
|
115
|
+
return value != null && String(value) !== '';
|
|
116
|
+
});
|
|
117
|
+
/** The column that links to the record: one declared `card: 'title'`, else the row's title. */ const declaredTitle = visibleColumns.find((column)=>column.card === 'title');
|
|
118
|
+
const linkColumn = (item)=>declaredTitle != null ? declaredTitle : titleColumn(item);
|
|
119
|
+
/**
|
|
120
|
+
* What a record's card shows, by each member's declared `card` role or the
|
|
121
|
+
* default: an id is hidden, the first enum is the badge, and up to
|
|
122
|
+
* {@link UNDECLARED_META_CAP} more members are meta — a card is a summary,
|
|
123
|
+
* and the grid holds the rest.
|
|
124
|
+
*/ const firstEnum = visibleColumns.find((column)=>column.card === undefined && column.type === 'enum');
|
|
125
|
+
const roleOf = (column)=>{
|
|
126
|
+
var _column_card;
|
|
127
|
+
return (_column_card = column.card) != null ? _column_card : column.type === 'id' ? 'hidden' : column === firstEnum ? 'badge' : 'meta';
|
|
128
|
+
};
|
|
129
|
+
const cardParts = (item)=>{
|
|
130
|
+
const title = linkColumn(item);
|
|
131
|
+
const rest = visibleColumns.filter((column)=>column !== title);
|
|
132
|
+
let undeclared = 0;
|
|
133
|
+
return {
|
|
134
|
+
title,
|
|
135
|
+
subtitle: rest.find((column)=>roleOf(column) === 'subtitle'),
|
|
136
|
+
badges: rest.filter((column)=>roleOf(column) === 'badge'),
|
|
137
|
+
meta: rest.filter((column)=>{
|
|
138
|
+
if (roleOf(column) !== 'meta') return false;
|
|
139
|
+
if (column.card !== undefined) return true;
|
|
140
|
+
undeclared += 1;
|
|
141
|
+
return undeclared <= UNDECLARED_META_CAP;
|
|
142
|
+
})
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
const renderValue = (column, item)=>column.render ? column.render(item) : /*#__PURE__*/ _jsx(CellValue, {
|
|
138
146
|
value: item[column.name],
|
|
139
147
|
descriptor: column,
|
|
140
148
|
record: item
|
|
141
149
|
});
|
|
142
150
|
/**
|
|
151
|
+
* A cell, and the row's title cell is the record's link
|
|
152
|
+
* ([ADR 0026](../../../../../../../docs/adr/0026-actions-hierarchy-overflow-and-destructive-verbs.md)).
|
|
153
|
+
* A column of identical "Open" links named nothing, and a reader tabbing
|
|
154
|
+
* down it heard "Open" once per row; the title says which record it opens.
|
|
155
|
+
* A picker's rows are chosen, not opened, so they stay plain.
|
|
156
|
+
*/ const renderCell = (column, item)=>{
|
|
157
|
+
var _linkColumn;
|
|
158
|
+
const value = renderValue(column, item);
|
|
159
|
+
if (hrefFor === undefined || onSelect !== undefined) return value;
|
|
160
|
+
if (((_linkColumn = linkColumn(item)) == null ? void 0 : _linkColumn.name) !== column.name) return value;
|
|
161
|
+
return renderLink({
|
|
162
|
+
href: hrefFor(item.id),
|
|
163
|
+
className: linkClassName,
|
|
164
|
+
children: value,
|
|
165
|
+
intent: {
|
|
166
|
+
kind: 'open',
|
|
167
|
+
id: item.id
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
143
172
|
* The row a shift-click ranges *from* — the last box the user actually
|
|
144
173
|
* toggled. Held in a ref rather than state because it changes nothing on
|
|
145
174
|
* screen, and re-rendering the whole table on every click to remember an
|
|
@@ -220,11 +249,7 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
|
|
|
220
249
|
//
|
|
221
250
|
// The id remains the last resort, because a row with nothing rendered
|
|
222
251
|
// still has to announce itself.
|
|
223
|
-
const named =
|
|
224
|
-
if (column.type === 'id') return false;
|
|
225
|
-
const value = item[column.name];
|
|
226
|
-
return value != null && String(value) !== '';
|
|
227
|
-
});
|
|
252
|
+
const named = titleColumn(item);
|
|
228
253
|
return named ? String(item[named.name]) : String(item.id);
|
|
229
254
|
};
|
|
230
255
|
const selectionCell = (item, index, // Passed in rather than closed over: this is only ever called under
|
|
@@ -245,113 +270,196 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
|
|
|
245
270
|
if (target.kind === 'row') onUseCase == null ? void 0 : onUseCase(key, target.item);
|
|
246
271
|
else onBulkUseCase == null ? void 0 : onBulkUseCase(key, target.selection);
|
|
247
272
|
};
|
|
273
|
+
/**
|
|
274
|
+
* Every verb on the table goes through here — the row menu, the bulk bar and
|
|
275
|
+
* the toolbar — so none reaches a destructive verb around its confirmation,
|
|
276
|
+
* its typed check or its Undo.
|
|
277
|
+
*/ const verbs = useVerbInvoker({
|
|
278
|
+
run: runTarget,
|
|
279
|
+
busy: isBulkRunning,
|
|
280
|
+
served: metadata == null ? void 0 : metadata.useCases
|
|
281
|
+
});
|
|
248
282
|
const invoke = (useCase, target)=>{
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
target
|
|
283
|
+
if (target.kind === 'row') {
|
|
284
|
+
verbs.invoke({
|
|
285
|
+
descriptor: useCase,
|
|
286
|
+
target,
|
|
287
|
+
object: rowLabel(target.item),
|
|
288
|
+
count: 1
|
|
256
289
|
});
|
|
257
290
|
return;
|
|
258
291
|
}
|
|
259
|
-
|
|
292
|
+
const count = selectionSize(target.selection);
|
|
293
|
+
verbs.invoke({
|
|
294
|
+
descriptor: useCase,
|
|
295
|
+
target,
|
|
296
|
+
object: t('confirm.selection', {
|
|
297
|
+
count,
|
|
298
|
+
label: entityNoun(metaEntity),
|
|
299
|
+
plural: entityNoun(metaEntity, 'plural')
|
|
300
|
+
}),
|
|
301
|
+
count,
|
|
302
|
+
matching: target.selection.mode === 'matching'
|
|
303
|
+
});
|
|
260
304
|
};
|
|
261
|
-
const rowMenu = (item)=>hasRowMenu ? /*#__PURE__*/
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
return /*#__PURE__*/ _jsx(Menu.Item, {
|
|
271
|
-
tone: ((_useCase_confirm = useCase.confirm) == null ? void 0 : _useCase_confirm.tone) === 'destructive' ? 'destructive' : 'neutral',
|
|
272
|
-
onClick: ()=>invoke(useCase, {
|
|
273
|
-
kind: 'row',
|
|
274
|
-
item
|
|
275
|
-
}),
|
|
276
|
-
children: translateKey(useCase.labelKey)
|
|
277
|
-
}, useCase.key);
|
|
278
|
-
})
|
|
279
|
-
})
|
|
280
|
-
]
|
|
305
|
+
const rowMenu = (item)=>hasRowMenu ? /*#__PURE__*/ _jsx(ActionBar, {
|
|
306
|
+
surface: "row-menu",
|
|
307
|
+
menuLabel: t('actions.forRecord', {
|
|
308
|
+
record: rowLabel(item)
|
|
309
|
+
}),
|
|
310
|
+
items: itemsForUseCases(rowUseCases, translateKey, (useCase)=>invoke(useCase, {
|
|
311
|
+
kind: 'row',
|
|
312
|
+
item
|
|
313
|
+
}))
|
|
281
314
|
}) : undefined;
|
|
282
315
|
/**
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
* The row menu sits *beside* whichever of the two applies rather than
|
|
287
|
-
* replacing it — "open this record" and "run a verb on it" are both true at
|
|
288
|
-
* once, and folding the first into the menu would bury the action every row
|
|
289
|
-
* of a list exists for.
|
|
316
|
+
* A picker's Select, then the row's verbs. Opening the record is not here:
|
|
317
|
+
* it is the title's link.
|
|
290
318
|
*/ const recordAction = (item)=>{
|
|
291
|
-
const
|
|
319
|
+
const pick = onSelect ? /*#__PURE__*/ _jsx(Button, {
|
|
292
320
|
type: "button",
|
|
293
321
|
variant: "secondary",
|
|
294
322
|
size: "sm",
|
|
295
323
|
onClick: ()=>onSelect(item),
|
|
296
324
|
children: t('table.select')
|
|
297
|
-
}) : hrefFor ? renderLink({
|
|
298
|
-
href: hrefFor(item.id),
|
|
299
|
-
className: linkClassName,
|
|
300
|
-
children: t('table.open'),
|
|
301
|
-
intent: {
|
|
302
|
-
kind: 'open',
|
|
303
|
-
id: item.id
|
|
304
|
-
}
|
|
305
325
|
}) : undefined;
|
|
306
326
|
const menu = rowMenu(item);
|
|
307
|
-
if (!menu) return
|
|
327
|
+
if (!menu) return pick;
|
|
308
328
|
return /*#__PURE__*/ _jsxs("span", {
|
|
309
329
|
className: "flex items-center gap-2xs",
|
|
310
330
|
children: [
|
|
311
|
-
|
|
331
|
+
pick,
|
|
312
332
|
menu
|
|
313
333
|
]
|
|
314
334
|
});
|
|
315
335
|
};
|
|
316
336
|
/**
|
|
317
|
-
* "
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
|
|
337
|
+
* "New" is the list's primary, and only where something can be created
|
|
338
|
+
* here: the entity is not one only a flow writes (`creatable: false`), and
|
|
339
|
+
* the caller may write it. A list that offered "New" to a reader who could
|
|
340
|
+
* never save opened a form with no Save on it.
|
|
341
|
+
*/ const mayCreate = newHref !== undefined && metaEntity.creatable && (metadata === undefined || metadata.actions.includes('write'));
|
|
342
|
+
const toolbarItems = itemsForUseCases(toolbarUseCases, translateKey, (useCase)=>invoke(useCase, {
|
|
343
|
+
kind: 'selection',
|
|
344
|
+
selection: everythingMatching
|
|
345
|
+
}), isBulkRunning);
|
|
346
|
+
const declaresToolbarPrimary = toolbarItems.some((item)=>item.emphasis === 'primary');
|
|
347
|
+
const toolbarActions = [
|
|
348
|
+
...mayCreate ? [
|
|
349
|
+
{
|
|
350
|
+
key: 'new',
|
|
351
|
+
label: t('table.new'),
|
|
352
|
+
emphasis: declaresToolbarPrimary ? 'default' : 'primary',
|
|
353
|
+
href: newHref,
|
|
354
|
+
intent: {
|
|
355
|
+
kind: 'new'
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
] : [],
|
|
359
|
+
...toolbarItems
|
|
360
|
+
];
|
|
361
|
+
const locale = useLocale();
|
|
362
|
+
const panelId = useId();
|
|
363
|
+
const keys = sortKeys(sorting, columns);
|
|
364
|
+
const activeFilters = (_ref1 = filtering == null ? void 0 : filtering.values.length) != null ? _ref1 : 0;
|
|
365
|
+
const results = t('table.results', {
|
|
366
|
+
count: totalItems
|
|
367
|
+
});
|
|
368
|
+
/**
|
|
369
|
+
* What the status region says once a filter, a sort or a page has settled —
|
|
370
|
+
* debounced, and silent on the first load.
|
|
371
|
+
*/ const announcement = useResultAnnouncement(!isLoading, totalItems === 0 && activeFilters > 0 ? t('table.noResultsFiltered') : results, JSON.stringify([
|
|
372
|
+
filtering,
|
|
373
|
+
sorting,
|
|
374
|
+
currentPage,
|
|
375
|
+
pageSize
|
|
376
|
+
]));
|
|
377
|
+
/** The caption: what the table holds, how many, and in what order. */ const primaryKey = keys[0];
|
|
378
|
+
const primaryColumn = primaryKey === undefined ? undefined : columns.find((column)=>column.name === primaryKey.member);
|
|
379
|
+
const caption = primaryKey === undefined || primaryColumn === undefined ? t('table.caption', {
|
|
380
|
+
entity: entityNoun(metaEntity, 'plural'),
|
|
381
|
+
results
|
|
382
|
+
}) : t('table.captionSorted', {
|
|
383
|
+
entity: entityNoun(metaEntity, 'plural'),
|
|
384
|
+
results,
|
|
385
|
+
column: primaryColumn.label,
|
|
386
|
+
direction: t(primaryKey.type === 'asc' ? 'sort.ascending' : 'sort.descending')
|
|
387
|
+
});
|
|
388
|
+
/**
|
|
389
|
+
* A column's header: its name, and — for a sortable one — a button that
|
|
390
|
+
* cycles it ascending → descending → unsorted, with Shift adding it as the
|
|
391
|
+
* next key. Only the primary key carries `aria-sort`.
|
|
392
|
+
*/ const headerCell = (column)=>{
|
|
393
|
+
var _column_header;
|
|
394
|
+
var _keys_position;
|
|
395
|
+
const label = (_column_header = column.header) != null ? _column_header : column.label;
|
|
396
|
+
if (!column.sortable || onSortingChange === undefined) return /*#__PURE__*/ _jsx(TableHeaderCell, {
|
|
397
|
+
children: label
|
|
398
|
+
}, column.name);
|
|
399
|
+
const position = keys.findIndex((key)=>key.member === column.name);
|
|
400
|
+
const type = (_keys_position = keys[position]) == null ? void 0 : _keys_position.type;
|
|
401
|
+
return /*#__PURE__*/ _jsx(TableHeaderCell, {
|
|
402
|
+
"aria-sort": position === 0 ? type === 'asc' ? 'ascending' : 'descending' : undefined,
|
|
403
|
+
children: /*#__PURE__*/ _jsxs("button", {
|
|
404
|
+
type: "button",
|
|
405
|
+
className: "inline-flex min-h-(--target-min) items-center gap-3xs rounded-sm focus-ring hover:text-content",
|
|
406
|
+
onClick: (event)=>onSortingChange(nextHeaderSorting(keys, {
|
|
407
|
+
member: column.name,
|
|
408
|
+
property: queryPropertyFor(column, locale)
|
|
409
|
+
}, event.shiftKey)),
|
|
410
|
+
children: [
|
|
411
|
+
label,
|
|
412
|
+
/*#__PURE__*/ _jsx("span", {
|
|
413
|
+
"aria-hidden": "true",
|
|
414
|
+
children: type === 'asc' ? '▲' : type === 'desc' ? '▼' : '↕'
|
|
415
|
+
}),
|
|
416
|
+
keys.length > 1 && position >= 0 && /*#__PURE__*/ _jsx("span", {
|
|
417
|
+
"aria-hidden": "true",
|
|
418
|
+
className: "text-step-sm",
|
|
419
|
+
children: position + 1
|
|
420
|
+
})
|
|
421
|
+
]
|
|
422
|
+
})
|
|
423
|
+
}, column.name);
|
|
424
|
+
};
|
|
425
|
+
/** A panel toggle: its state said by `aria-expanded`, and its count shown. */ const panelToggle = (which, count)=>/*#__PURE__*/ _jsxs(Button, {
|
|
426
|
+
type: "button",
|
|
427
|
+
variant: panel === which ? 'primary' : 'secondary',
|
|
428
|
+
size: "sm",
|
|
429
|
+
"aria-expanded": panel === which,
|
|
430
|
+
"aria-controls": panelId,
|
|
431
|
+
onClick: ()=>setPanel((current)=>current === which ? 'none' : which),
|
|
432
|
+
children: [
|
|
433
|
+
t(which === 'filters' ? 'table.filters' : 'table.sorting'),
|
|
434
|
+
count > 0 && // Its name stays "Filters": the chips say which filters, and a count
|
|
435
|
+
// in the name would change it under the reader with every filter.
|
|
436
|
+
/*#__PURE__*/ _jsx("span", {
|
|
437
|
+
"aria-hidden": "true",
|
|
438
|
+
className: "ms-3xs rounded-full bg-surface px-3xs text-step-sm text-content",
|
|
439
|
+
children: count
|
|
440
|
+
})
|
|
441
|
+
]
|
|
442
|
+
});
|
|
321
443
|
return /*#__PURE__*/ _jsxs("div", {
|
|
322
|
-
className: "flex flex-col gap-s",
|
|
444
|
+
className: "@container/entity-table flex flex-col gap-s",
|
|
323
445
|
children: [
|
|
324
446
|
/*#__PURE__*/ _jsx("span", {
|
|
325
447
|
role: "status",
|
|
326
448
|
"aria-live": "polite",
|
|
327
449
|
className: "sr-only",
|
|
328
|
-
children: isFirstLoad ? t('table.loading') :
|
|
450
|
+
children: isFirstLoad ? t('table.loading') : announcement
|
|
329
451
|
}),
|
|
330
452
|
showControls && /*#__PURE__*/ _jsx(TableToolbar, {
|
|
331
453
|
start: /*#__PURE__*/ _jsxs(_Fragment, {
|
|
332
454
|
children: [
|
|
333
|
-
newHref && renderLink({
|
|
334
|
-
href: newHref,
|
|
335
|
-
className: linkClassName,
|
|
336
|
-
children: t('table.new'),
|
|
337
|
-
intent: {
|
|
338
|
-
kind: 'new'
|
|
339
|
-
}
|
|
340
|
-
}),
|
|
341
455
|
/*#__PURE__*/ _jsx(LoadingBoundary, {
|
|
342
456
|
isLoading: isMetadataLoading,
|
|
343
457
|
lines: 0,
|
|
344
458
|
children: /*#__PURE__*/ _jsx(_Fragment, {
|
|
345
|
-
children:
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
variant: ((_useCase_confirm = useCase.confirm) == null ? void 0 : _useCase_confirm.tone) === 'destructive' ? 'destructive' : 'secondary',
|
|
350
|
-
size: "sm",
|
|
351
|
-
disabled: isBulkRunning,
|
|
352
|
-
onClick: ()=>onBulkUseCase == null ? void 0 : onBulkUseCase(useCase.key, everythingMatching),
|
|
353
|
-
children: translateKey(useCase.labelKey)
|
|
354
|
-
}, useCase.key);
|
|
459
|
+
children: toolbarActions.length > 0 && /*#__PURE__*/ _jsx(ActionBar, {
|
|
460
|
+
surface: "table-toolbar",
|
|
461
|
+
items: toolbarActions,
|
|
462
|
+
renderLink: renderLink
|
|
355
463
|
})
|
|
356
464
|
})
|
|
357
465
|
}),
|
|
@@ -360,20 +468,8 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
|
|
|
360
468
|
}),
|
|
361
469
|
end: /*#__PURE__*/ _jsxs(_Fragment, {
|
|
362
470
|
children: [
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
variant: panel === 'filters' ? 'primary' : 'secondary',
|
|
366
|
-
size: "sm",
|
|
367
|
-
onClick: ()=>setPanel((current)=>current === 'filters' ? 'none' : 'filters'),
|
|
368
|
-
children: t('table.filters')
|
|
369
|
-
}),
|
|
370
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
371
|
-
type: "button",
|
|
372
|
-
variant: panel === 'sorting' ? 'primary' : 'secondary',
|
|
373
|
-
size: "sm",
|
|
374
|
-
onClick: ()=>setPanel((current)=>current === 'sorting' ? 'none' : 'sorting'),
|
|
375
|
-
children: t('table.sorting')
|
|
376
|
-
}),
|
|
471
|
+
panelToggle('filters', activeFilters),
|
|
472
|
+
panelToggle('sorting', keys.length),
|
|
377
473
|
/*#__PURE__*/ _jsx(ColumnSettings, {
|
|
378
474
|
columns: columns,
|
|
379
475
|
hidden: hidden,
|
|
@@ -381,16 +477,23 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
|
|
|
381
477
|
})
|
|
382
478
|
]
|
|
383
479
|
}),
|
|
480
|
+
panelId: panelId,
|
|
384
481
|
panel: panel === 'filters' ? /*#__PURE__*/ _jsx(FilterBuilder, {
|
|
385
482
|
descriptors: columns.filter((column)=>column.filterable),
|
|
483
|
+
facets: facets,
|
|
386
484
|
value: filtering,
|
|
387
485
|
onChange: (applied)=>onFilteringChange == null ? void 0 : onFilteringChange(applied)
|
|
388
|
-
}) : panel === 'sorting' ? /*#__PURE__*/ _jsx(SortBuilder, {
|
|
486
|
+
}, JSON.stringify(filtering != null ? filtering : null)) : panel === 'sorting' ? /*#__PURE__*/ _jsx(SortBuilder, {
|
|
389
487
|
descriptors: columns.filter((column)=>column.sortable),
|
|
390
488
|
value: sorting,
|
|
391
489
|
onChange: (applied)=>onSortingChange == null ? void 0 : onSortingChange(applied)
|
|
392
490
|
}) : undefined
|
|
393
491
|
}),
|
|
492
|
+
showControls && onFilteringChange !== undefined && /*#__PURE__*/ _jsx(FilterChips, {
|
|
493
|
+
descriptors: columns.filter((column)=>column.filterable),
|
|
494
|
+
value: filtering,
|
|
495
|
+
onChange: onFilteringChange
|
|
496
|
+
}),
|
|
394
497
|
selectionState && selectionSize(selectionState) > 0 && /*#__PURE__*/ _jsx(BulkActionBar, {
|
|
395
498
|
count: selectionSize(selectionState),
|
|
396
499
|
useCases: bulkUseCases,
|
|
@@ -405,19 +508,7 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
|
|
|
405
508
|
selection: selectionState
|
|
406
509
|
})
|
|
407
510
|
}),
|
|
408
|
-
|
|
409
|
-
open: true,
|
|
410
|
-
tone: pending.confirm.tone,
|
|
411
|
-
title: translateKey(pending.labelKey),
|
|
412
|
-
message: translateKey(pending.confirm.messageKey),
|
|
413
|
-
busy: isBulkRunning,
|
|
414
|
-
onCancel: ()=>setPending(undefined),
|
|
415
|
-
onConfirm: ()=>{
|
|
416
|
-
const { key, target } = pending;
|
|
417
|
-
setPending(undefined);
|
|
418
|
-
runTarget(key, target);
|
|
419
|
-
}
|
|
420
|
-
}),
|
|
511
|
+
verbs.dialog,
|
|
421
512
|
bulkOutcomes && bulkOutcomes.length > 0 && onBulkDismiss && /*#__PURE__*/ _jsx(BulkResult, {
|
|
422
513
|
outcomes: bulkOutcomes,
|
|
423
514
|
busy: isBulkRunning,
|
|
@@ -428,15 +519,37 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
|
|
|
428
519
|
onRetryFailed: onBulkRetry,
|
|
429
520
|
onDismiss: onBulkDismiss
|
|
430
521
|
}),
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
522
|
+
/*#__PURE__*/ _jsx(RegionState, {
|
|
523
|
+
plural: entityNoun(metaEntity, 'plural'),
|
|
524
|
+
isLoading: isLoading,
|
|
525
|
+
error: error,
|
|
526
|
+
onRetry: onRetry,
|
|
527
|
+
hasStaleData: items.length > 0,
|
|
528
|
+
isEmpty: items.length === 0,
|
|
529
|
+
isFiltered: activeFilters > 0,
|
|
530
|
+
onClearFilters: onFilteringChange === undefined ? undefined : ()=>onFilteringChange({
|
|
531
|
+
// Only offered under a filter, so there is one to keep the
|
|
532
|
+
// logic of.
|
|
533
|
+
operator: filtering.operator,
|
|
534
|
+
values: []
|
|
535
|
+
}),
|
|
536
|
+
emptyAction: mayCreate ? renderLink({
|
|
537
|
+
href: newHref,
|
|
538
|
+
className: button({
|
|
539
|
+
variant: 'primary'
|
|
540
|
+
}),
|
|
541
|
+
children: t('table.new'),
|
|
542
|
+
intent: {
|
|
543
|
+
kind: 'new'
|
|
544
|
+
}
|
|
545
|
+
}) : undefined
|
|
436
546
|
}),
|
|
437
547
|
/*#__PURE__*/ _jsx("div", {
|
|
438
|
-
className:
|
|
548
|
+
className: pivot.grid,
|
|
549
|
+
"aria-busy": busy,
|
|
439
550
|
children: /*#__PURE__*/ _jsxs(Table, {
|
|
551
|
+
caption: caption,
|
|
552
|
+
containerClassName: "max-h-(--table-max-block) scroll-pt-12",
|
|
440
553
|
children: [
|
|
441
554
|
/*#__PURE__*/ _jsx(TableHead, {
|
|
442
555
|
children: slots.header ? slots.header.render(visibleColumns) : /*#__PURE__*/ _jsxs("tr", {
|
|
@@ -450,12 +563,7 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
|
|
|
450
563
|
onChange: (event)=>toggleAllOnPage(event.currentTarget.checked, selectionState)
|
|
451
564
|
})
|
|
452
565
|
}),
|
|
453
|
-
visibleColumns.map(
|
|
454
|
-
var _column_header;
|
|
455
|
-
return /*#__PURE__*/ _jsx(TableHeaderCell, {
|
|
456
|
-
children: (_column_header = column.header) != null ? _column_header : column.label
|
|
457
|
-
}, column.name);
|
|
458
|
-
}),
|
|
566
|
+
visibleColumns.map(headerCell),
|
|
459
567
|
hasRowAction && /*#__PURE__*/ _jsx(TableHeaderCell, {
|
|
460
568
|
children: t('table.actions')
|
|
461
569
|
})
|
|
@@ -463,7 +571,6 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
|
|
|
463
571
|
})
|
|
464
572
|
}),
|
|
465
573
|
/*#__PURE__*/ _jsxs(TableBody, {
|
|
466
|
-
"aria-busy": isLoading || undefined,
|
|
467
574
|
children: [
|
|
468
575
|
showSkeleton && (customSkeleton ? /*#__PURE__*/ _jsx(TableMessageRow, {
|
|
469
576
|
colSpan: columnCount,
|
|
@@ -490,10 +597,6 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
|
|
|
490
597
|
})
|
|
491
598
|
]
|
|
492
599
|
}, row))),
|
|
493
|
-
!isLoading && items.length === 0 && /*#__PURE__*/ _jsx(TableMessageRow, {
|
|
494
|
-
colSpan: columnCount,
|
|
495
|
-
children: emptyMessage
|
|
496
|
-
}),
|
|
497
600
|
shown.map(({ item, depth, hasChildren }, index)=>{
|
|
498
601
|
var _item_id, _item_id1;
|
|
499
602
|
return slots.row ? // A Fragment carries the key without wrapping the custom row in
|
|
@@ -529,30 +632,62 @@ export function EntityTable({ entityConstructor, isLoading, skeleton = true, err
|
|
|
529
632
|
})
|
|
530
633
|
}),
|
|
531
634
|
/*#__PURE__*/ _jsxs("div", {
|
|
532
|
-
className:
|
|
533
|
-
"aria-busy":
|
|
635
|
+
className: pivot.cards,
|
|
636
|
+
"aria-busy": busy,
|
|
534
637
|
children: [
|
|
535
|
-
showSkeleton && (customSkeleton != null ? customSkeleton :
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
638
|
+
showSkeleton && (customSkeleton != null ? customSkeleton : /*#__PURE__*/ _jsx("ul", {
|
|
639
|
+
role: "list",
|
|
640
|
+
className: "m-0 p-0 flex list-none flex-col gap-2xs",
|
|
641
|
+
children: skeletonRows.map((row)=>/*#__PURE__*/ _jsx("li", {
|
|
642
|
+
children: /*#__PURE__*/ _jsx(EntityRecordCard, {
|
|
643
|
+
title: /*#__PURE__*/ _jsx(Skeleton, {
|
|
644
|
+
shape: "line",
|
|
645
|
+
className: "w-32"
|
|
646
|
+
}),
|
|
647
|
+
meta: visibleColumns.slice(1).map((column)=>({
|
|
648
|
+
key: column.name,
|
|
649
|
+
label: column.label,
|
|
650
|
+
value: /*#__PURE__*/ _jsx(Skeleton, {
|
|
651
|
+
shape: "line",
|
|
652
|
+
className: "w-24"
|
|
653
|
+
})
|
|
654
|
+
}))
|
|
540
655
|
})
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
656
|
+
}, row))
|
|
657
|
+
})),
|
|
658
|
+
shown.length > 0 && /*#__PURE__*/ _jsx("ul", {
|
|
659
|
+
role: "list",
|
|
660
|
+
className: "m-0 p-0 flex list-none flex-col gap-2xs",
|
|
661
|
+
children: shown.map(({ item, depth }, index)=>{
|
|
662
|
+
var _item_id;
|
|
663
|
+
const parts = cardParts(item);
|
|
664
|
+
return /*#__PURE__*/ _jsx("li", {
|
|
665
|
+
// A tree's card says how deep it sits, as its row does.
|
|
666
|
+
"aria-level": treeKeys === undefined ? undefined : depth + 1,
|
|
667
|
+
style: treeKeys === undefined ? undefined : {
|
|
668
|
+
marginInlineStart: `${depth * 1.5}rem`
|
|
669
|
+
},
|
|
670
|
+
children: /*#__PURE__*/ _jsx(EntityRecordCard, {
|
|
671
|
+
// The same renderers as the grid, so the two layouts agree.
|
|
672
|
+
title: parts.title === undefined ? rowLabel(item) : renderCell(parts.title, item),
|
|
673
|
+
subtitle: parts.subtitle === undefined ? undefined : renderCell(parts.subtitle, item),
|
|
674
|
+
badges: parts.badges.map((column)=>({
|
|
675
|
+
key: column.name,
|
|
676
|
+
value: renderCell(column, item)
|
|
677
|
+
})),
|
|
678
|
+
meta: parts.meta.map((column)=>{
|
|
679
|
+
var _column_header;
|
|
680
|
+
return {
|
|
681
|
+
key: column.name,
|
|
682
|
+
label: (_column_header = column.header) != null ? _column_header : column.label,
|
|
683
|
+
value: renderCell(column, item)
|
|
684
|
+
};
|
|
685
|
+
}),
|
|
686
|
+
leading: selectionState ? selectionCell(item, index, selectionState) : undefined,
|
|
687
|
+
actions: recordAction(item)
|
|
688
|
+
})
|
|
689
|
+
}, String((_item_id = item.id) != null ? _item_id : index));
|
|
690
|
+
})
|
|
556
691
|
})
|
|
557
692
|
]
|
|
558
693
|
}),
|