@panneau/lists 5.0.0-alpha.4 → 5.0.0-alpha.5

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 (44) hide show
  1. package/dist/ItemDetails.css +34 -0
  2. package/dist/ItemDetails.d.ts +16 -0
  3. package/dist/ItemDetails.d.ts.map +1 -0
  4. package/dist/ItemDetails.js +62 -0
  5. package/dist/ItemDetails.js.map +1 -0
  6. package/dist/ItemDetails.module.js +16 -0
  7. package/dist/ItemDetails.module.js.map +1 -0
  8. package/dist/ListView.d.ts +6 -1
  9. package/dist/ListView.d.ts.map +1 -1
  10. package/dist/ListView.js +17 -31
  11. package/dist/ListView.js.map +1 -1
  12. package/dist/filters/Filters.css +25 -11
  13. package/dist/filters/Filters.module.js +5 -1
  14. package/dist/filters/Filters.module.js.map +1 -1
  15. package/dist/filters/controls.d.ts.map +1 -1
  16. package/dist/filters/controls.js +57 -35
  17. package/dist/filters/controls.js.map +1 -1
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +2 -1
  21. package/dist/layouts/CardsLayout.css +5 -0
  22. package/dist/layouts/CardsLayout.d.ts +1 -1
  23. package/dist/layouts/CardsLayout.d.ts.map +1 -1
  24. package/dist/layouts/CardsLayout.js +39 -35
  25. package/dist/layouts/CardsLayout.js.map +1 -1
  26. package/dist/layouts/CardsLayout.module.js.map +1 -1
  27. package/dist/layouts/ItemTitle.d.ts +3 -1
  28. package/dist/layouts/ItemTitle.d.ts.map +1 -1
  29. package/dist/layouts/ItemTitle.js +7 -16
  30. package/dist/layouts/ItemTitle.js.map +1 -1
  31. package/dist/layouts/TableLayout.css +16 -0
  32. package/dist/layouts/TableLayout.d.ts +1 -1
  33. package/dist/layouts/TableLayout.d.ts.map +1 -1
  34. package/dist/layouts/TableLayout.js +38 -33
  35. package/dist/layouts/TableLayout.js.map +1 -1
  36. package/dist/layouts/TableLayout.module.js +3 -3
  37. package/dist/layouts/TableLayout.module.js.map +1 -1
  38. package/dist/types.d.ts +2 -0
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/useRenderValue.d.ts +8 -0
  41. package/dist/useRenderValue.d.ts.map +1 -0
  42. package/dist/useRenderValue.js +64 -0
  43. package/dist/useRenderValue.js.map +1 -0
  44. package/package.json +7 -7
@@ -0,0 +1,34 @@
1
+ .panneau-item-details-details {
2
+ container: panneau-item-details / inline-size;
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: var(--panneau-space-3);
6
+ margin: 0;
7
+ }
8
+
9
+ .panneau-item-details-entry {
10
+ display: flex;
11
+ flex-direction: column;
12
+ gap: var(--panneau-space-1);
13
+ min-width: 0;
14
+ }
15
+
16
+ .panneau-item-details-label {
17
+ color: var(--panneau-color-text-muted);
18
+ font-size: var(--panneau-font-size-sm);
19
+ }
20
+
21
+ .panneau-item-details-value {
22
+ min-width: 0;
23
+ margin: 0;
24
+ overflow-wrap: anywhere;
25
+ }
26
+
27
+ /* Wide enough: the label and its value side by side. */
28
+ @container panneau-item-details (min-width: 30rem) {
29
+ .panneau-item-details-entry {
30
+ display: grid;
31
+ grid-template-columns: minmax(8rem, 30%) minmax(0, 1fr);
32
+ gap: var(--panneau-space-3);
33
+ }
34
+ }
@@ -0,0 +1,16 @@
1
+ import type { DisplayEntry, ListColumn, ListItem } from './types';
2
+ export interface ItemDetailsProps {
3
+ item: ListItem;
4
+ /** The values to show, with their label and display, in order. */
5
+ columns: readonly ListColumn[];
6
+ /** Displays by name, over the built-in ones and those of the plugins. */
7
+ displays?: Readonly<Record<string, DisplayEntry>>;
8
+ 'aria-label'?: string;
9
+ className?: string;
10
+ }
11
+ /**
12
+ * The values of one item, each with its label, shown with the displays of the lists: for the
13
+ * details of an item next to its list, or anywhere a read-only view of it is needed.
14
+ */
15
+ export declare function ItemDetails({ item, columns, displays, 'aria-label': ariaLabel, className, }: ItemDetailsProps): import("react").JSX.Element;
16
+ //# sourceMappingURL=ItemDetails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemDetails.d.ts","sourceRoot":"","sources":["../src/ItemDetails.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGlE,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,kEAAkE;IAClE,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,yEAAyE;IACzE,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EACxB,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,SAAS,GACZ,EAAE,gBAAgB,+BAYlB"}
@@ -0,0 +1,62 @@
1
+ import { cx } from "./cx.js";
2
+ import ItemDetails_module_default from "./ItemDetails.module.js";
3
+ import { useRenderValue } from "./useRenderValue.js";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { c } from "react/compiler-runtime";
6
+ //#region src/ItemDetails.tsx
7
+ /**
8
+ * The values of one item, each with its label, shown with the displays of the lists: for the
9
+ * details of an item next to its list, or anywhere a read-only view of it is needed.
10
+ */
11
+ function ItemDetails(t0) {
12
+ const $ = c(13);
13
+ const { item, columns, displays, "aria-label": ariaLabel, className } = t0;
14
+ const renderValue = useRenderValue(displays);
15
+ let t1;
16
+ if ($[0] !== className) {
17
+ t1 = cx(ItemDetails_module_default.details, className);
18
+ $[0] = className;
19
+ $[1] = t1;
20
+ } else t1 = $[1];
21
+ let t2;
22
+ if ($[2] !== columns || $[3] !== item || $[4] !== renderValue) {
23
+ let t3;
24
+ if ($[6] !== item || $[7] !== renderValue) {
25
+ t3 = (column) => /* @__PURE__ */ jsxs("div", {
26
+ className: ItemDetails_module_default.entry,
27
+ children: [/* @__PURE__ */ jsx("dt", {
28
+ className: ItemDetails_module_default.label,
29
+ children: column.label ?? column.id
30
+ }), /* @__PURE__ */ jsx("dd", {
31
+ className: ItemDetails_module_default.value,
32
+ children: renderValue(item, column)
33
+ })]
34
+ }, column.id);
35
+ $[6] = item;
36
+ $[7] = renderValue;
37
+ $[8] = t3;
38
+ } else t3 = $[8];
39
+ t2 = columns.map(t3);
40
+ $[2] = columns;
41
+ $[3] = item;
42
+ $[4] = renderValue;
43
+ $[5] = t2;
44
+ } else t2 = $[5];
45
+ let t3;
46
+ if ($[9] !== ariaLabel || $[10] !== t1 || $[11] !== t2) {
47
+ t3 = /* @__PURE__ */ jsx("dl", {
48
+ "aria-label": ariaLabel,
49
+ className: t1,
50
+ children: t2
51
+ });
52
+ $[9] = ariaLabel;
53
+ $[10] = t1;
54
+ $[11] = t2;
55
+ $[12] = t3;
56
+ } else t3 = $[12];
57
+ return t3;
58
+ }
59
+ //#endregion
60
+ export { ItemDetails };
61
+
62
+ //# sourceMappingURL=ItemDetails.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemDetails.js","names":["ariaLabel","_c","styles"],"sources":["../src/ItemDetails.tsx"],"sourcesContent":["import styles from './ItemDetails.module.css';\nimport { cx } from './cx';\nimport type { DisplayEntry, ListColumn, ListItem } from './types';\nimport { useRenderValue } from './useRenderValue';\n\nexport interface ItemDetailsProps {\n item: ListItem;\n /** The values to show, with their label and display, in order. */\n columns: readonly ListColumn[];\n /** Displays by name, over the built-in ones and those of the plugins. */\n displays?: Readonly<Record<string, DisplayEntry>>;\n 'aria-label'?: string;\n className?: string;\n}\n\n/**\n * The values of one item, each with its label, shown with the displays of the lists: for the\n * details of an item next to its list, or anywhere a read-only view of it is needed.\n */\nexport function ItemDetails({\n item,\n columns,\n displays,\n 'aria-label': ariaLabel,\n className,\n}: ItemDetailsProps) {\n const renderValue = useRenderValue(displays);\n return (\n <dl aria-label={ariaLabel} className={cx(styles.details, className)}>\n {columns.map((column) => (\n <div key={column.id} className={styles.entry}>\n <dt className={styles.label}>{column.label ?? column.id}</dt>\n <dd className={styles.value}>{renderValue(item, column)}</dd>\n </div>\n ))}\n </dl>\n );\n}\n"],"mappings":";;;;;;;;;;AAmBA,SAAO,YAAA,IAAA;CAAA,MAAA,IAAAC,EAAA,EAAA;CAAqB,MAAA,EAAA,MAAA,SAAA,UAAA,cAAA,WAAA,cAAA;CAOxB,MAAA,cAAoB,eAAe,QAAQ;CAAE,IAAA;CAAA,IAAA,EAAA,OAAA,WAAA;EAEH,KAAA,GAAGC,2BAAM,SAAU,SAAS;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,WAAA,EAAA,OAAA,QAAA,EAAA,OAAA,aAAA;EAAA,IAAA;EAAA,IAAA,EAAA,OAAA,QAAA,EAAA,OAAA,aAAA;GAClD,MAAA,WACT,qBAAA,OAAA;IAAgC,WAAAA,2BAAM;IAAtC,UAAA,CACI,oBAAA,MAAA;KAAe,WAAAA,2BAAM;KAAS,UAAA,OAAM,SAAU,OAAM;IAAS,CAAA,GAC7D,oBAAA,MAAA;KAAe,WAAAA,2BAAM;KAAS,UAAA,YAAY,MAAM,MAAM;IAAO,CAAA,CAC3D;GAHI,GAAA,OAAM,EAGV;GACT,EAAA,KAAA;GAAA,EAAA,KAAA;GAAA,EAAA,KAAA;EAAA,OAAA,KAAA,EAAA;EALA,KAAA,QAAO,IAAK,EAKZ;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,aAAA,EAAA,QAAA,MAAA,EAAA,QAAA,IAAA;EANN,KAAA,oBAAA,MAAA;GAAgBF,cAAA;GAAsB,WAAA;GACjC,UAAA;EAMA,CAAA;EAAA,EAAA,KAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OAPL;AAOK"}
@@ -0,0 +1,16 @@
1
+ import "./ItemDetails.css";
2
+ //#region src/ItemDetails.module.css
3
+ var details = "panneau-item-details-details";
4
+ var entry = "panneau-item-details-entry";
5
+ var label = "panneau-item-details-label";
6
+ var value = "panneau-item-details-value";
7
+ var ItemDetails_module_default = {
8
+ details,
9
+ entry,
10
+ label,
11
+ value
12
+ };
13
+ //#endregion
14
+ export { ItemDetails_module_default as default, details, entry, label, value };
15
+
16
+ //# sourceMappingURL=ItemDetails.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemDetails.module.js","names":[],"sources":["../src/ItemDetails.module.css"],"sourcesContent":[".details {\n container: panneau-item-details / inline-size;\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-3);\n margin: 0;\n}\n\n.entry {\n display: flex;\n flex-direction: column;\n gap: var(--panneau-space-1);\n min-width: 0;\n}\n\n.label {\n color: var(--panneau-color-text-muted);\n font-size: var(--panneau-font-size-sm);\n}\n\n.value {\n min-width: 0;\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n/* Wide enough: the label and its value side by side. */\n@container panneau-item-details (min-width: 30rem) {\n .entry {\n display: grid;\n grid-template-columns: minmax(8rem, 30%) minmax(0, 1fr);\n gap: var(--panneau-space-3);\n }\n}\n"],"mappings":""}
@@ -59,6 +59,11 @@ export interface ListViewProps {
59
59
  getItemLabel?: (item: ListItem) => string;
60
60
  /** A link to an item, on its title. */
61
61
  getItemHref?: (item: ListItem) => string | null;
62
+ /**
63
+ * The item shown next to the list, such as in a panel of its details: its row is marked, and
64
+ * the link of its title is the current page.
65
+ */
66
+ currentItemId?: string | null;
62
67
  /** Displays by name, over the built-in ones and those of the plugins. */
63
68
  displays?: Readonly<Record<string, DisplayEntry>>;
64
69
  /** Layouts by id, over the built-in ones and those of the plugins. */
@@ -78,5 +83,5 @@ export interface ListViewProps {
78
83
  * cards), with sorting, search, filters and their chips, pagination, selection and actions. It
79
84
  * fetches nothing: the caller gives the items of the list's query and their total.
80
85
  */
81
- export declare function ListView({ list, items, columns, total, isLoading, error, onRetry, filters, fields, search, layouts: layoutsProp, layout: controlledLayout, onLayoutChange, perPageOptions, selectable: selectableProp, actions: actionsProp, onAction, previewAction, actionIcons, itemTitle, getItemLabel: getItemLabelProp, getItemHref, displays, layoutComponents, filterControls, toolbar, emptyMessage, 'aria-label': ariaLabel, className, }: ListViewProps): import("react").JSX.Element;
86
+ export declare function ListView({ list, items, columns, total, isLoading, error, onRetry, filters, fields, search, layouts: layoutsProp, layout: controlledLayout, onLayoutChange, perPageOptions, selectable: selectableProp, actions: actionsProp, onAction, previewAction, actionIcons, itemTitle, getItemLabel: getItemLabelProp, getItemHref, currentItemId, displays, layoutComponents, filterControls, toolbar, emptyMessage, 'aria-label': ariaLabel, className, }: ListViewProps): import("react").JSX.Element;
82
87
  //# sourceMappingURL=ListView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ListView.d.ts","sourceRoot":"","sources":["../src/ListView.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ListView.d.ts","sourceRoot":"","sources":["../src/ListView.tsx"],"names":[],"mappings":"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"}
package/dist/ListView.js CHANGED
@@ -2,9 +2,9 @@ import { getActionHref, groupListActions, hasScope, isAllowedOn } from "./action
2
2
  import { messages } from "./messages.js";
3
3
  import { ConfirmDialog, needsConfirmation } from "./actions/ConfirmDialog.js";
4
4
  import { getColumnValue, toText } from "./values.js";
5
- import { builtInDisplays } from "./displays/displays.js";
6
5
  import { cx } from "./cx.js";
7
6
  import { builtInLayouts } from "./layouts/builtIn.js";
7
+ import { useRenderValue } from "./useRenderValue.js";
8
8
  import ListView_module_default from "./ListView.module.js";
9
9
  import { ActionButton } from "./actions/ActionButton.js";
10
10
  import { RowActions } from "./actions/RowActions.js";
@@ -28,7 +28,7 @@ function keyOf(action, item) {
28
28
  * cards), with sorting, search, filters and their chips, pagination, selection and actions. It
29
29
  * fetches nothing: the caller gives the items of the list's query and their total.
30
30
  */
31
- function ListView({ list, items, columns, total, isLoading = false, error = null, onRetry, filters = [], fields = [], search = false, layouts: layoutsProp = ["table"], layout: controlledLayout, onLayoutChange, perPageOptions, selectable: selectableProp, actions: actionsProp, onAction, previewAction, actionIcons, itemTitle, getItemLabel: getItemLabelProp, getItemHref, displays, layoutComponents, filterControls, toolbar, emptyMessage, "aria-label": ariaLabel, className }) {
31
+ function ListView({ list, items, columns, total, isLoading = false, error = null, onRetry, filters = [], fields = [], search = false, layouts: layoutsProp = ["table"], layout: controlledLayout, onLayoutChange, perPageOptions, selectable: selectableProp, actions: actionsProp, onAction, previewAction, actionIcons, itemTitle, getItemLabel: getItemLabelProp, getItemHref, currentItemId = null, displays, layoutComponents, filterControls, toolbar, emptyMessage, "aria-label": ariaLabel, className }) {
32
32
  const intl = usePanneauIntl();
33
33
  const toasts = useToast();
34
34
  const plugins = usePlugins();
@@ -45,11 +45,6 @@ function ListView({ list, items, columns, total, isLoading = false, error = null
45
45
  const sort = query.sort ?? [];
46
46
  const filterValues = query.filter ?? {};
47
47
  const hasQuery = Object.keys(filterValues).length > 0 || (query.q ?? "") !== "";
48
- const allDisplays = {
49
- ...builtInDisplays,
50
- ...Object.fromEntries(plugins.displays),
51
- ...displays
52
- };
53
48
  const allLayouts = {
54
49
  ...builtInLayouts,
55
50
  ...Object.fromEntries(plugins.listLayouts),
@@ -75,17 +70,7 @@ function ListView({ list, items, columns, total, isLoading = false, error = null
75
70
  const title = titleColumn !== void 0 ? toText(getColumnValue(item_0, titleColumn, intl.locale), intl.locale) : itemTitle !== void 0 ? toText(item_0[itemTitle], intl.locale) : "";
76
71
  return title !== "" ? title : item_0.id;
77
72
  };
78
- const renderValue = (item_1, column_0) => {
79
- if (column_0.render !== void 0) return column_0.render(item_1);
80
- const Display = (column_0.display !== void 0 && column_0.display !== null ? allDisplays[column_0.display] : void 0) ?? builtInDisplays.text;
81
- if (Display === void 0) return null;
82
- return /* @__PURE__ */ jsx(Display, {
83
- value: getColumnValue(item_1, column_0, intl.locale),
84
- item: item_1,
85
- column: column_0,
86
- field: column_0.field ?? null
87
- });
88
- };
73
+ const renderValue = useRenderValue(displays);
89
74
  const closeConfirmation = () => {
90
75
  confirmation.current += 1;
91
76
  setConfirming(null);
@@ -131,10 +116,10 @@ function ListView({ list, items, columns, total, isLoading = false, error = null
131
116
  if (needsConfirmation(event_0)) setConfirming(event_0);
132
117
  else execute(event_0);
133
118
  };
134
- const runOnItem = (action_5, item_2) => run({
119
+ const runOnItem = (action_5, item_1) => run({
135
120
  action: action_5,
136
121
  scope: "item",
137
- item: item_2,
122
+ item: item_1,
138
123
  count: 1,
139
124
  skipped: []
140
125
  });
@@ -146,7 +131,7 @@ function ListView({ list, items, columns, total, isLoading = false, error = null
146
131
  scope: "selection",
147
132
  selection: selected,
148
133
  count: selectedCount,
149
- skipped: selectedItems.filter((item_3) => !isAllowedOn(action_6, item_3))
134
+ skipped: selectedItems.filter((item_2) => !isAllowedOn(action_6, item_2))
150
135
  });
151
136
  };
152
137
  const runOnResource = (action_7) => run({
@@ -155,18 +140,18 @@ function ListView({ list, items, columns, total, isLoading = false, error = null
155
140
  count,
156
141
  skipped: []
157
142
  });
158
- const renderActions = (item_4) => {
159
- const allowed = rowActions.filter((action_8) => isAllowedOn(action_8, item_4));
160
- const menu = rowMenu.filter((action_9) => isAllowedOn(action_9, item_4));
143
+ const renderActions = (item_3) => {
144
+ const allowed = rowActions.filter((action_8) => isAllowedOn(action_8, item_3));
145
+ const menu = rowMenu.filter((action_9) => isAllowedOn(action_9, item_3));
161
146
  if (allowed.length === 0 && menu.length === 0) return null;
162
- const running = pending?.endsWith(`\u0000${item_4.id}`) === true ? pending.split("\0")[0] : null;
147
+ const running = pending?.endsWith(`\u0000${item_3.id}`) === true ? pending.split("\0")[0] : null;
163
148
  return /* @__PURE__ */ jsx(RowActions, {
164
- item: item_4,
165
- itemLabel: getItemLabel(item_4),
149
+ item: item_3,
150
+ itemLabel: getItemLabel(item_3),
166
151
  actions: allowed,
167
152
  menu,
168
153
  pending: running ?? null,
169
- onRun: (action_10) => runOnItem(action_10, item_4),
154
+ onRun: (action_10) => runOnItem(action_10, item_3),
170
155
  icons: actionIcons
171
156
  });
172
157
  };
@@ -176,12 +161,12 @@ function ListView({ list, items, columns, total, isLoading = false, error = null
176
161
  isIndeterminate: pageSelection === "some",
177
162
  isDisabled: pageItems.length === 0,
178
163
  onChange: () => {
179
- const ids = pageItems.map((item_5) => item_5.id);
164
+ const ids = pageItems.map((item_4) => item_4.id);
180
165
  if (pageSelection === "all") list.deselect(ids);
181
166
  else list.select(ids);
182
167
  }
183
168
  });
184
- const sortable = columns.some((column_1) => column_1.sortable === true);
169
+ const sortable = columns.some((column_0) => column_0.sortable === true);
185
170
  const showToolbar = search || filters.length > 0 || sortable || layouts.length > 1 || resourceActions.length > 0 || toolbar !== void 0;
186
171
  const body = (() => {
187
172
  if (error !== null) return /* @__PURE__ */ jsx(Alert, {
@@ -212,12 +197,13 @@ function ListView({ list, items, columns, total, isLoading = false, error = null
212
197
  renderValue,
213
198
  getItemLabel,
214
199
  getItemHref,
200
+ isCurrent: (item_5) => item_5.id === currentItemId,
215
201
  selectable,
216
202
  isSelected: (item_6) => isItemSelected(selection, item_6.id),
217
203
  onToggle: (item_7) => list.toggle(item_7.id),
218
204
  renderActions,
219
205
  sort,
220
- onSort: (column_2) => list.toggleSort(column_2.id),
206
+ onSort: (column_1) => list.toggleSort(column_1.id),
221
207
  label,
222
208
  pageSelection: pageCheckbox
223
209
  });
@@ -1 +1 @@
1
- {"version":3,"file":"ListView.js","names":["action","item","column","event","selection","id","next","skipped","styles"],"sources":["../src/ListView.tsx"],"sourcesContent":["import { type ReactNode, useRef, useState } from 'react';\n\nimport type { List } from '@panneau/core';\nimport { usePlugins } from '@panneau/core';\nimport type { Action, Field, Filter } from '@panneau/protocol';\nimport { Alert, Button, Checkbox, Spinner, usePanneauIntl, useToast } from '@panneau/ui';\n\nimport styles from './ListView.module.css';\nimport { ActionButton } from './actions/ActionButton';\nimport { ConfirmDialog, type ConfirmPreview, needsConfirmation } from './actions/ConfirmDialog';\nimport { RowActions } from './actions/RowActions';\nimport {\n type ListActions,\n getActionHref,\n groupListActions,\n hasScope,\n isAllowedOn,\n} from './actions/actions';\nimport type { ActionIcons } from './actions/icons';\nimport { cx } from './cx';\nimport { builtInDisplays } from './displays/displays';\nimport { FilterChips, FilterControls, useFilterLabels } from './filters/Filters';\nimport { builtInLayouts } from './layouts/builtIn';\nimport { messages } from './messages';\nimport { countSelected, getPageSelection, isItemSelected } from './selection';\nimport { LayoutSwitch } from './toolbar/LayoutSwitch';\nimport { Pagination } from './toolbar/Pagination';\nimport { SearchField } from './toolbar/SearchField';\nimport { SortSelect } from './toolbar/SortSelect';\nimport type {\n DisplayEntry,\n FilterEntry,\n ListActionEvent,\n ListActionHandler,\n ListActionPreviewer,\n ListColumn,\n ListItem,\n ListLayoutEntry,\n} from './types';\nimport { useListState } from './useListState';\nimport { getColumnValue, toText } from './values';\n\nexport interface ListViewProps {\n /** The list state of `@panneau/core` (`useList()`): query and selection. */\n list: List;\n /** The items of the current page. `undefined` while they load for the first time. */\n items: readonly ListItem[] | undefined;\n columns: readonly ListColumn[];\n /**\n * How many items match the query, on every page (`meta.total`). With it, the list shows\n * pagination and offers to select every matching item. Without it, `items` is the whole list.\n */\n total?: number | undefined;\n /** Shows that items are loading. Items already shown stay, dimmed. */\n isLoading?: boolean;\n /** An error while loading: an alert with a retry replaces the items. */\n error?: Error | null;\n onRetry?: () => void;\n /** Filter controls, with chips for the active filters. */\n filters?: readonly Filter[];\n /** Fields of the items, for the labels and options of filters that are not columns. */\n fields?: readonly Field[];\n /** Shows a search field (`q`). */\n search?: boolean;\n /** Layouts to choose from, the first one being the default. Defaults to `['table']`. */\n layouts?: readonly string[];\n /** The layout, controlled. */\n layout?: string;\n onLayoutChange?: (layout: string) => void;\n /** Page sizes to choose from. */\n perPageOptions?: readonly number[];\n /** Shows checkboxes. Defaults to whether there are selection actions. */\n selectable?: boolean;\n /**\n * Actions: a list (placed by their `placement`, or by scope), or grouped by placement as\n * `resolveList()` does. Those the user can't run (`abilities.run`) are hidden.\n */\n actions?: ListActions;\n /** Runs an action, after its confirmation. */\n onAction?: ListActionHandler;\n /**\n * Asks the backend how many items of a query selection (\"Select all N items\") an action will\n * skip, before the confirmation: the list only knows the abilities of the current page. Only\n * for actions with `dryRun`. `useActionPreview()` of `@panneau/actions` is one.\n */\n previewAction?: ListActionPreviewer;\n /**\n * Icons of actions by action id (`{ archive: Archive }`), for actions written in code. They\n * win over the Lucide icon an action names (`\"icon\": \"archive\"`).\n */\n actionIcons?: ActionIcons;\n /** The field that titles items, for their label (`itemTitle` of the resource). */\n itemTitle?: string;\n /** The label of an item, for checkboxes and actions. Defaults to its title, then its id. */\n getItemLabel?: (item: ListItem) => string;\n /** A link to an item, on its title. */\n getItemHref?: (item: ListItem) => string | null;\n /** Displays by name, over the built-in ones and those of the plugins. */\n displays?: Readonly<Record<string, DisplayEntry>>;\n /** Layouts by id, over the built-in ones and those of the plugins. */\n layoutComponents?: Readonly<Record<string, ListLayoutEntry>>;\n /** Filter controls by filter type, over the built-in ones. */\n filterControls?: Readonly<Record<string, FilterEntry>>;\n /** Content at the end of the toolbar, such as a button to create an item. */\n toolbar?: ReactNode;\n /** Shown when the list has no items, without filters or search. */\n emptyMessage?: ReactNode;\n /** Accessible name of the list. Defaults to \"Items\". */\n 'aria-label'?: string;\n className?: string;\n}\n\nfunction keyOf(action: Action, item?: ListItem): string {\n return item !== undefined ? `${action.id}\\u0000${item.id}` : action.id;\n}\n\n/**\n * Renders the list state of `@panneau/core`: the items of the current page in a layout (table or\n * cards), with sorting, search, filters and their chips, pagination, selection and actions. It\n * fetches nothing: the caller gives the items of the list's query and their total.\n */\nexport function ListView({\n list,\n items,\n columns,\n total,\n isLoading = false,\n error = null,\n onRetry,\n filters = [],\n fields = [],\n search = false,\n layouts: layoutsProp = ['table'],\n layout: controlledLayout,\n onLayoutChange,\n perPageOptions,\n selectable: selectableProp,\n actions: actionsProp,\n onAction,\n previewAction,\n actionIcons,\n itemTitle,\n getItemLabel: getItemLabelProp,\n getItemHref,\n displays,\n layoutComponents,\n filterControls,\n toolbar,\n emptyMessage,\n 'aria-label': ariaLabel,\n className,\n}: ListViewProps) {\n const intl = usePanneauIntl();\n const toasts = useToast();\n const plugins = usePlugins();\n const { query, selection } = useListState(list);\n const filterLabels = useFilterLabels();\n const [uncontrolledLayout, setLayout] = useState<string | null>(null);\n const [confirming, setConfirming] = useState<ListActionEvent | null>(null);\n const [preview, setPreview] = useState<ConfirmPreview | null>(null);\n // The confirmation a dry run belongs to: a later one, or a cancel, discards its answer.\n const confirmation = useRef(0);\n const [pending, setPending] = useState<string | null>(null);\n\n const label = ariaLabel ?? intl.formatMessage(messages.list);\n const pageItems = items ?? [];\n const count = total ?? pageItems.length;\n const sort = query.sort ?? [];\n const filterValues = query.filter ?? {};\n const hasQuery = Object.keys(filterValues).length > 0 || (query.q ?? '') !== '';\n\n const allDisplays: Record<string, DisplayEntry> = {\n ...builtInDisplays,\n ...(Object.fromEntries(plugins.displays) as Record<string, DisplayEntry>),\n ...displays,\n };\n const allLayouts: Record<string, ListLayoutEntry> = {\n ...builtInLayouts,\n ...(Object.fromEntries(plugins.listLayouts) as Record<string, ListLayoutEntry>),\n ...layoutComponents,\n };\n // Layouts without a component (a plugin's that isn't installed) are left out.\n const available = layoutsProp.filter((id) => allLayouts[id] !== undefined);\n const layouts = available.length > 0 ? available : ['table'];\n const layout = controlledLayout ?? uncontrolledLayout ?? layouts[0] ?? 'table';\n const Layout = allLayouts[layout] ?? builtInLayouts.table;\n\n const grouped = groupListActions(actionsProp);\n const rowActions = grouped.row.filter((action) => hasScope(action, 'item'));\n const rowMenu = grouped.menu.filter((action) => hasScope(action, 'item'));\n // Actions placed in the menu also apply to selections, from the toolbar (once each).\n const toolbarActions = [...grouped.toolbar, ...grouped.menu].filter(\n (action, index, all) =>\n (hasScope(action, 'selection') || hasScope(action, 'resource')) &&\n all.findIndex((candidate) => candidate.id === action.id) === index,\n );\n const selectionActions = toolbarActions.filter((action) => hasScope(action, 'selection'));\n const resourceActions = toolbarActions.filter((action) => hasScope(action, 'resource'));\n const selectable = selectableProp ?? selectionActions.length > 0;\n\n const selectedCount = selectable ? countSelected(selection, count) : 0;\n const selectedItems = pageItems.filter((item) => isItemSelected(selection, item.id));\n const pageSelection = getPageSelection(selection, pageItems);\n\n const getItemLabel = (item: ListItem): string => {\n if (getItemLabelProp !== undefined) {\n return getItemLabelProp(item);\n }\n const titleColumn =\n columns.find((column) => column.id === itemTitle) ??\n (itemTitle === undefined ? columns[0] : undefined);\n const title =\n titleColumn !== undefined\n ? toText(getColumnValue(item, titleColumn, intl.locale), intl.locale)\n : itemTitle !== undefined\n ? toText(item[itemTitle], intl.locale)\n : '';\n return title !== '' ? title : item.id;\n };\n\n const renderValue = (item: ListItem, column: ListColumn): ReactNode => {\n if (column.render !== undefined) {\n return column.render(item);\n }\n const Display =\n (column.display !== undefined && column.display !== null\n ? allDisplays[column.display]\n : undefined) ?? builtInDisplays.text;\n if (Display === undefined) {\n return null;\n }\n return (\n <Display\n value={getColumnValue(item, column, intl.locale)}\n item={item}\n column={column}\n field={column.field ?? null}\n />\n );\n };\n\n const closeConfirmation = () => {\n confirmation.current += 1;\n setConfirming(null);\n setPreview(null);\n };\n\n const execute = async (event: ListActionEvent) => {\n closeConfirmation();\n setPending(keyOf(event.action, event.item));\n try {\n const outcome = await onAction?.(event);\n // `false`: the action didn't run (its parameters were cancelled).\n if (event.scope === 'selection' && outcome !== false) {\n list.clearSelection();\n }\n } catch (caught) {\n toasts.show({\n title: intl.formatMessage(messages.actionFailed, { action: event.action.label }),\n ...(caught instanceof Error && caught.message !== ''\n ? { description: caught.message }\n : {}),\n tone: 'danger',\n });\n } finally {\n setPending(null);\n }\n };\n\n const run = (event: ListActionEvent) => {\n const { action, selection } = event;\n if (\n previewAction !== undefined &&\n action.dryRun === true &&\n selection !== undefined &&\n 'query' in selection\n ) {\n // Every item matching a query: only the backend knows how many it would skip.\n const current = ++confirmation.current;\n const asks = action.confirm !== undefined && action.confirm !== false;\n setConfirming(event);\n setPreview({ status: 'loading' });\n previewAction(event).then(\n (result) => {\n if (confirmation.current !== current) {\n return;\n }\n const skipped = result?.skipped ?? event.skipped.length;\n if (skipped === 0 && !asks) {\n void execute(event);\n } else {\n setPreview(result !== null ? { status: 'done', ...result } : null);\n }\n },\n () => {\n // Without an answer, the list confirms with what it knows.\n if (confirmation.current !== current) {\n return;\n }\n if (needsConfirmation(event)) {\n setPreview(null);\n } else {\n void execute(event);\n }\n },\n );\n return;\n }\n if (needsConfirmation(event)) {\n setConfirming(event);\n } else {\n void execute(event);\n }\n };\n\n const runOnItem = (action: Action, item: ListItem) =>\n run({ action, scope: 'item', item, count: 1, skipped: [] });\n\n const runOnSelection = (action: Action) => {\n const selected = list.getSelection();\n if (selected === null) {\n return;\n }\n run({\n action,\n scope: 'selection',\n selection: selected,\n count: selectedCount,\n skipped: selectedItems.filter((item) => !isAllowedOn(action, item)),\n });\n };\n\n const runOnResource = (action: Action) =>\n run({ action, scope: 'resource', count: count, skipped: [] });\n\n const renderActions = (item: ListItem): ReactNode => {\n const allowed = rowActions.filter((action) => isAllowedOn(action, item));\n const menu = rowMenu.filter((action) => isAllowedOn(action, item));\n if (allowed.length === 0 && menu.length === 0) {\n return null;\n }\n const running =\n pending?.endsWith(`\\u0000${item.id}`) === true ? pending.split('\\u0000')[0] : null;\n return (\n <RowActions\n item={item}\n itemLabel={getItemLabel(item)}\n actions={allowed}\n menu={menu}\n pending={running ?? null}\n onRun={(action) => runOnItem(action, item)}\n icons={actionIcons}\n />\n );\n };\n\n const pageCheckbox = (\n <Checkbox\n aria-label={intl.formatMessage(messages.selectPage)}\n isSelected={pageSelection === 'all'}\n isIndeterminate={pageSelection === 'some'}\n isDisabled={pageItems.length === 0}\n onChange={() => {\n const ids = pageItems.map((item) => item.id);\n if (pageSelection === 'all') {\n list.deselect(ids);\n } else {\n list.select(ids);\n }\n }}\n />\n );\n\n const sortable = columns.some((column) => column.sortable === true);\n const showToolbar =\n search ||\n filters.length > 0 ||\n sortable ||\n layouts.length > 1 ||\n resourceActions.length > 0 ||\n toolbar !== undefined;\n\n const body = (() => {\n if (error !== null) {\n return (\n <Alert\n tone=\"danger\"\n title={intl.formatMessage(messages.loadFailed)}\n actions={\n onRetry !== undefined ? (\n <Button size=\"sm\" onPress={onRetry}>\n {intl.formatMessage(messages.retry)}\n </Button>\n ) : undefined\n }\n >\n {error.message}\n </Alert>\n );\n }\n if (items === undefined) {\n return (\n <div className={styles.state}>\n <Spinner showLabel />\n </div>\n );\n }\n if (pageItems.length === 0) {\n return (\n <div className={styles.state}>\n <p>\n {hasQuery\n ? intl.formatMessage(messages.noResults)\n : (emptyMessage ?? intl.formatMessage(messages.empty))}\n </p>\n {hasQuery ? (\n <Button size=\"sm\" onPress={() => clearFilters()}>\n {intl.formatMessage(messages.clearFilters)}\n </Button>\n ) : null}\n </div>\n );\n }\n return (\n <Layout\n items={pageItems}\n columns={columns}\n renderValue={renderValue}\n getItemLabel={getItemLabel}\n getItemHref={getItemHref}\n selectable={selectable}\n isSelected={(item) => isItemSelected(selection, item.id)}\n onToggle={(item) => list.toggle(item.id)}\n renderActions={renderActions}\n sort={sort}\n onSort={(column) => list.toggleSort(column.id)}\n label={label}\n pageSelection={pageCheckbox}\n />\n );\n })();\n\n function clearFilters() {\n Object.keys(filterValues).forEach((id) => list.setFilter(id, undefined));\n if ((query.q ?? '') !== '') {\n list.setSearch('');\n }\n }\n\n return (\n <div className={cx(styles.list, className)}>\n {showToolbar ? (\n <div className={styles.toolbar}>\n <div className={styles.toolbarStart}>\n {search ? (\n <SearchField\n value={query.q ?? ''}\n onChange={(q) => list.setSearch(q)}\n />\n ) : null}\n {filters.length > 0 ? (\n <FilterControls\n filters={filters}\n values={filterValues}\n onChange={(id, value) => list.setFilter(id, value)}\n onLabel={filterLabels.remember}\n controls={filterControls}\n columns={columns}\n fields={fields}\n labels={filterLabels.labels}\n />\n ) : null}\n </div>\n <div className={styles.toolbarEnd}>\n {sortable ? (\n <div className={layout === 'table' ? styles.tableSort : undefined}>\n <SortSelect\n columns={columns}\n sort={sort}\n onChange={(next) => list.setSort(next)}\n />\n </div>\n ) : null}\n {layouts.length > 1 ? (\n <LayoutSwitch\n layouts={layouts}\n value={layout}\n onChange={(next) => {\n setLayout(next);\n onLayoutChange?.(next);\n }}\n />\n ) : null}\n {resourceActions\n .filter(\n (action) => selectedCount === 0 || !hasScope(action, 'selection'),\n )\n .map((action) => (\n <ActionButton\n key={action.id}\n action={action}\n icons={actionIcons}\n size=\"md\"\n href={getActionHref(action)}\n isPending={pending === keyOf(action)}\n onPress={() => runOnResource(action)}\n />\n ))}\n {toolbar}\n </div>\n </div>\n ) : null}\n <FilterChips\n filters={filters}\n values={filterValues}\n q={query.q}\n onRemove={(id) => list.setFilter(id, undefined)}\n onClearSearch={() => list.setSearch('')}\n onClear={clearFilters}\n columns={columns}\n fields={fields}\n labels={filterLabels.labels}\n />\n {selectedCount > 0 ? (\n <div className={styles.selection}>\n <span className={styles.selectionCount} role=\"status\">\n {selection.mode === 'all'\n ? intl.formatMessage(messages.allMatchingSelected, {\n total: selectedCount,\n })\n : intl.formatMessage(messages.selectedCount, { count: selectedCount })}\n </span>\n {selection.mode === 'ids' &&\n pageSelection === 'all' &&\n count > pageItems.length ? (\n <Button size=\"sm\" variant=\"ghost\" onPress={() => list.selectAllMatching()}>\n {intl.formatMessage(messages.selectAllMatching, { total: count })}\n </Button>\n ) : null}\n <Button size=\"sm\" variant=\"ghost\" onPress={() => list.clearSelection()}>\n {intl.formatMessage(messages.clearSelection)}\n </Button>\n {selectionActions.length > 0 ? (\n <div className={styles.selectionActions}>\n {selectionActions.map((action) => {\n const skipped = selectedItems.filter(\n (item) => !isAllowedOn(action, item),\n ).length;\n return (\n <ActionButton\n key={action.id}\n action={action}\n icons={actionIcons}\n size=\"md\"\n href={null}\n isPending={pending === keyOf(action)}\n isDisabled={\n (pending !== null && pending !== keyOf(action)) ||\n skipped >= selectedCount\n }\n onPress={() => runOnSelection(action)}\n />\n );\n })}\n </div>\n ) : null}\n </div>\n ) : null}\n <div className={styles.body} aria-busy={isLoading && items !== undefined}>\n {body}\n </div>\n {total !== undefined && error === null && total > 0 ? (\n <Pagination\n page={query.page ?? 1}\n perPage={query.perPage ?? pageItems.length}\n total={total}\n onPageChange={(page) => list.setPage(page)}\n perPageOptions={perPageOptions}\n onPerPageChange={(perPage) => list.setPerPage(perPage)}\n />\n ) : null}\n <ConfirmDialog\n event={confirming}\n preview={preview}\n onConfirm={(event) => void execute(event)}\n onCancel={closeConfirmation}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ListView.js","names":["action","item","event","selection","column","id","next","skipped","styles"],"sources":["../src/ListView.tsx"],"sourcesContent":["import { type ReactNode, useRef, useState } from 'react';\n\nimport type { List } from '@panneau/core';\nimport { usePlugins } from '@panneau/core';\nimport type { Action, Field, Filter } from '@panneau/protocol';\nimport { Alert, Button, Checkbox, Spinner, usePanneauIntl, useToast } from '@panneau/ui';\n\nimport styles from './ListView.module.css';\nimport { ActionButton } from './actions/ActionButton';\nimport { ConfirmDialog, type ConfirmPreview, needsConfirmation } from './actions/ConfirmDialog';\nimport { RowActions } from './actions/RowActions';\nimport {\n type ListActions,\n getActionHref,\n groupListActions,\n hasScope,\n isAllowedOn,\n} from './actions/actions';\nimport type { ActionIcons } from './actions/icons';\nimport { cx } from './cx';\nimport { FilterChips, FilterControls, useFilterLabels } from './filters/Filters';\nimport { builtInLayouts } from './layouts/builtIn';\nimport { messages } from './messages';\nimport { countSelected, getPageSelection, isItemSelected } from './selection';\nimport { LayoutSwitch } from './toolbar/LayoutSwitch';\nimport { Pagination } from './toolbar/Pagination';\nimport { SearchField } from './toolbar/SearchField';\nimport { SortSelect } from './toolbar/SortSelect';\nimport type {\n DisplayEntry,\n FilterEntry,\n ListActionEvent,\n ListActionHandler,\n ListActionPreviewer,\n ListColumn,\n ListItem,\n ListLayoutEntry,\n} from './types';\nimport { useListState } from './useListState';\nimport { useRenderValue } from './useRenderValue';\nimport { getColumnValue, toText } from './values';\n\nexport interface ListViewProps {\n /** The list state of `@panneau/core` (`useList()`): query and selection. */\n list: List;\n /** The items of the current page. `undefined` while they load for the first time. */\n items: readonly ListItem[] | undefined;\n columns: readonly ListColumn[];\n /**\n * How many items match the query, on every page (`meta.total`). With it, the list shows\n * pagination and offers to select every matching item. Without it, `items` is the whole list.\n */\n total?: number | undefined;\n /** Shows that items are loading. Items already shown stay, dimmed. */\n isLoading?: boolean;\n /** An error while loading: an alert with a retry replaces the items. */\n error?: Error | null;\n onRetry?: () => void;\n /** Filter controls, with chips for the active filters. */\n filters?: readonly Filter[];\n /** Fields of the items, for the labels and options of filters that are not columns. */\n fields?: readonly Field[];\n /** Shows a search field (`q`). */\n search?: boolean;\n /** Layouts to choose from, the first one being the default. Defaults to `['table']`. */\n layouts?: readonly string[];\n /** The layout, controlled. */\n layout?: string;\n onLayoutChange?: (layout: string) => void;\n /** Page sizes to choose from. */\n perPageOptions?: readonly number[];\n /** Shows checkboxes. Defaults to whether there are selection actions. */\n selectable?: boolean;\n /**\n * Actions: a list (placed by their `placement`, or by scope), or grouped by placement as\n * `resolveList()` does. Those the user can't run (`abilities.run`) are hidden.\n */\n actions?: ListActions;\n /** Runs an action, after its confirmation. */\n onAction?: ListActionHandler;\n /**\n * Asks the backend how many items of a query selection (\"Select all N items\") an action will\n * skip, before the confirmation: the list only knows the abilities of the current page. Only\n * for actions with `dryRun`. `useActionPreview()` of `@panneau/actions` is one.\n */\n previewAction?: ListActionPreviewer;\n /**\n * Icons of actions by action id (`{ archive: Archive }`), for actions written in code. They\n * win over the Lucide icon an action names (`\"icon\": \"archive\"`).\n */\n actionIcons?: ActionIcons;\n /** The field that titles items, for their label (`itemTitle` of the resource). */\n itemTitle?: string;\n /** The label of an item, for checkboxes and actions. Defaults to its title, then its id. */\n getItemLabel?: (item: ListItem) => string;\n /** A link to an item, on its title. */\n getItemHref?: (item: ListItem) => string | null;\n /**\n * The item shown next to the list, such as in a panel of its details: its row is marked, and\n * the link of its title is the current page.\n */\n currentItemId?: string | null;\n /** Displays by name, over the built-in ones and those of the plugins. */\n displays?: Readonly<Record<string, DisplayEntry>>;\n /** Layouts by id, over the built-in ones and those of the plugins. */\n layoutComponents?: Readonly<Record<string, ListLayoutEntry>>;\n /** Filter controls by filter type, over the built-in ones. */\n filterControls?: Readonly<Record<string, FilterEntry>>;\n /** Content at the end of the toolbar, such as a button to create an item. */\n toolbar?: ReactNode;\n /** Shown when the list has no items, without filters or search. */\n emptyMessage?: ReactNode;\n /** Accessible name of the list. Defaults to \"Items\". */\n 'aria-label'?: string;\n className?: string;\n}\n\nfunction keyOf(action: Action, item?: ListItem): string {\n return item !== undefined ? `${action.id}\\u0000${item.id}` : action.id;\n}\n\n/**\n * Renders the list state of `@panneau/core`: the items of the current page in a layout (table or\n * cards), with sorting, search, filters and their chips, pagination, selection and actions. It\n * fetches nothing: the caller gives the items of the list's query and their total.\n */\nexport function ListView({\n list,\n items,\n columns,\n total,\n isLoading = false,\n error = null,\n onRetry,\n filters = [],\n fields = [],\n search = false,\n layouts: layoutsProp = ['table'],\n layout: controlledLayout,\n onLayoutChange,\n perPageOptions,\n selectable: selectableProp,\n actions: actionsProp,\n onAction,\n previewAction,\n actionIcons,\n itemTitle,\n getItemLabel: getItemLabelProp,\n getItemHref,\n currentItemId = null,\n displays,\n layoutComponents,\n filterControls,\n toolbar,\n emptyMessage,\n 'aria-label': ariaLabel,\n className,\n}: ListViewProps) {\n const intl = usePanneauIntl();\n const toasts = useToast();\n const plugins = usePlugins();\n const { query, selection } = useListState(list);\n const filterLabels = useFilterLabels();\n const [uncontrolledLayout, setLayout] = useState<string | null>(null);\n const [confirming, setConfirming] = useState<ListActionEvent | null>(null);\n const [preview, setPreview] = useState<ConfirmPreview | null>(null);\n // The confirmation a dry run belongs to: a later one, or a cancel, discards its answer.\n const confirmation = useRef(0);\n const [pending, setPending] = useState<string | null>(null);\n\n const label = ariaLabel ?? intl.formatMessage(messages.list);\n const pageItems = items ?? [];\n const count = total ?? pageItems.length;\n const sort = query.sort ?? [];\n const filterValues = query.filter ?? {};\n const hasQuery = Object.keys(filterValues).length > 0 || (query.q ?? '') !== '';\n\n const allLayouts: Record<string, ListLayoutEntry> = {\n ...builtInLayouts,\n ...(Object.fromEntries(plugins.listLayouts) as Record<string, ListLayoutEntry>),\n ...layoutComponents,\n };\n // Layouts without a component (a plugin's that isn't installed) are left out.\n const available = layoutsProp.filter((id) => allLayouts[id] !== undefined);\n const layouts = available.length > 0 ? available : ['table'];\n const layout = controlledLayout ?? uncontrolledLayout ?? layouts[0] ?? 'table';\n const Layout = allLayouts[layout] ?? builtInLayouts.table;\n\n const grouped = groupListActions(actionsProp);\n const rowActions = grouped.row.filter((action) => hasScope(action, 'item'));\n const rowMenu = grouped.menu.filter((action) => hasScope(action, 'item'));\n // Actions placed in the menu also apply to selections, from the toolbar (once each).\n const toolbarActions = [...grouped.toolbar, ...grouped.menu].filter(\n (action, index, all) =>\n (hasScope(action, 'selection') || hasScope(action, 'resource')) &&\n all.findIndex((candidate) => candidate.id === action.id) === index,\n );\n const selectionActions = toolbarActions.filter((action) => hasScope(action, 'selection'));\n const resourceActions = toolbarActions.filter((action) => hasScope(action, 'resource'));\n const selectable = selectableProp ?? selectionActions.length > 0;\n\n const selectedCount = selectable ? countSelected(selection, count) : 0;\n const selectedItems = pageItems.filter((item) => isItemSelected(selection, item.id));\n const pageSelection = getPageSelection(selection, pageItems);\n\n const getItemLabel = (item: ListItem): string => {\n if (getItemLabelProp !== undefined) {\n return getItemLabelProp(item);\n }\n const titleColumn =\n columns.find((column) => column.id === itemTitle) ??\n (itemTitle === undefined ? columns[0] : undefined);\n const title =\n titleColumn !== undefined\n ? toText(getColumnValue(item, titleColumn, intl.locale), intl.locale)\n : itemTitle !== undefined\n ? toText(item[itemTitle], intl.locale)\n : '';\n return title !== '' ? title : item.id;\n };\n\n const renderValue = useRenderValue(displays);\n\n const closeConfirmation = () => {\n confirmation.current += 1;\n setConfirming(null);\n setPreview(null);\n };\n\n const execute = async (event: ListActionEvent) => {\n closeConfirmation();\n setPending(keyOf(event.action, event.item));\n try {\n const outcome = await onAction?.(event);\n // `false`: the action didn't run (its parameters were cancelled).\n if (event.scope === 'selection' && outcome !== false) {\n list.clearSelection();\n }\n } catch (caught) {\n toasts.show({\n title: intl.formatMessage(messages.actionFailed, { action: event.action.label }),\n ...(caught instanceof Error && caught.message !== ''\n ? { description: caught.message }\n : {}),\n tone: 'danger',\n });\n } finally {\n setPending(null);\n }\n };\n\n const run = (event: ListActionEvent) => {\n const { action, selection } = event;\n if (\n previewAction !== undefined &&\n action.dryRun === true &&\n selection !== undefined &&\n 'query' in selection\n ) {\n // Every item matching a query: only the backend knows how many it would skip.\n const current = ++confirmation.current;\n const asks = action.confirm !== undefined && action.confirm !== false;\n setConfirming(event);\n setPreview({ status: 'loading' });\n previewAction(event).then(\n (result) => {\n if (confirmation.current !== current) {\n return;\n }\n const skipped = result?.skipped ?? event.skipped.length;\n if (skipped === 0 && !asks) {\n void execute(event);\n } else {\n setPreview(result !== null ? { status: 'done', ...result } : null);\n }\n },\n () => {\n // Without an answer, the list confirms with what it knows.\n if (confirmation.current !== current) {\n return;\n }\n if (needsConfirmation(event)) {\n setPreview(null);\n } else {\n void execute(event);\n }\n },\n );\n return;\n }\n if (needsConfirmation(event)) {\n setConfirming(event);\n } else {\n void execute(event);\n }\n };\n\n const runOnItem = (action: Action, item: ListItem) =>\n run({ action, scope: 'item', item, count: 1, skipped: [] });\n\n const runOnSelection = (action: Action) => {\n const selected = list.getSelection();\n if (selected === null) {\n return;\n }\n run({\n action,\n scope: 'selection',\n selection: selected,\n count: selectedCount,\n skipped: selectedItems.filter((item) => !isAllowedOn(action, item)),\n });\n };\n\n const runOnResource = (action: Action) =>\n run({ action, scope: 'resource', count: count, skipped: [] });\n\n const renderActions = (item: ListItem): ReactNode => {\n const allowed = rowActions.filter((action) => isAllowedOn(action, item));\n const menu = rowMenu.filter((action) => isAllowedOn(action, item));\n if (allowed.length === 0 && menu.length === 0) {\n return null;\n }\n const running =\n pending?.endsWith(`\\u0000${item.id}`) === true ? pending.split('\\u0000')[0] : null;\n return (\n <RowActions\n item={item}\n itemLabel={getItemLabel(item)}\n actions={allowed}\n menu={menu}\n pending={running ?? null}\n onRun={(action) => runOnItem(action, item)}\n icons={actionIcons}\n />\n );\n };\n\n const pageCheckbox = (\n <Checkbox\n aria-label={intl.formatMessage(messages.selectPage)}\n isSelected={pageSelection === 'all'}\n isIndeterminate={pageSelection === 'some'}\n isDisabled={pageItems.length === 0}\n onChange={() => {\n const ids = pageItems.map((item) => item.id);\n if (pageSelection === 'all') {\n list.deselect(ids);\n } else {\n list.select(ids);\n }\n }}\n />\n );\n\n const sortable = columns.some((column) => column.sortable === true);\n const showToolbar =\n search ||\n filters.length > 0 ||\n sortable ||\n layouts.length > 1 ||\n resourceActions.length > 0 ||\n toolbar !== undefined;\n\n const body = (() => {\n if (error !== null) {\n return (\n <Alert\n tone=\"danger\"\n title={intl.formatMessage(messages.loadFailed)}\n actions={\n onRetry !== undefined ? (\n <Button size=\"sm\" onPress={onRetry}>\n {intl.formatMessage(messages.retry)}\n </Button>\n ) : undefined\n }\n >\n {error.message}\n </Alert>\n );\n }\n if (items === undefined) {\n return (\n <div className={styles.state}>\n <Spinner showLabel />\n </div>\n );\n }\n if (pageItems.length === 0) {\n return (\n <div className={styles.state}>\n <p>\n {hasQuery\n ? intl.formatMessage(messages.noResults)\n : (emptyMessage ?? intl.formatMessage(messages.empty))}\n </p>\n {hasQuery ? (\n <Button size=\"sm\" onPress={() => clearFilters()}>\n {intl.formatMessage(messages.clearFilters)}\n </Button>\n ) : null}\n </div>\n );\n }\n return (\n <Layout\n items={pageItems}\n columns={columns}\n renderValue={renderValue}\n getItemLabel={getItemLabel}\n getItemHref={getItemHref}\n isCurrent={(item) => item.id === currentItemId}\n selectable={selectable}\n isSelected={(item) => isItemSelected(selection, item.id)}\n onToggle={(item) => list.toggle(item.id)}\n renderActions={renderActions}\n sort={sort}\n onSort={(column) => list.toggleSort(column.id)}\n label={label}\n pageSelection={pageCheckbox}\n />\n );\n })();\n\n function clearFilters() {\n Object.keys(filterValues).forEach((id) => list.setFilter(id, undefined));\n if ((query.q ?? '') !== '') {\n list.setSearch('');\n }\n }\n\n return (\n <div className={cx(styles.list, className)}>\n {showToolbar ? (\n <div className={styles.toolbar}>\n <div className={styles.toolbarStart}>\n {search ? (\n <SearchField\n value={query.q ?? ''}\n onChange={(q) => list.setSearch(q)}\n />\n ) : null}\n {filters.length > 0 ? (\n <FilterControls\n filters={filters}\n values={filterValues}\n onChange={(id, value) => list.setFilter(id, value)}\n onLabel={filterLabels.remember}\n controls={filterControls}\n columns={columns}\n fields={fields}\n labels={filterLabels.labels}\n />\n ) : null}\n </div>\n <div className={styles.toolbarEnd}>\n {sortable ? (\n <div className={layout === 'table' ? styles.tableSort : undefined}>\n <SortSelect\n columns={columns}\n sort={sort}\n onChange={(next) => list.setSort(next)}\n />\n </div>\n ) : null}\n {layouts.length > 1 ? (\n <LayoutSwitch\n layouts={layouts}\n value={layout}\n onChange={(next) => {\n setLayout(next);\n onLayoutChange?.(next);\n }}\n />\n ) : null}\n {resourceActions\n .filter(\n (action) => selectedCount === 0 || !hasScope(action, 'selection'),\n )\n .map((action) => (\n <ActionButton\n key={action.id}\n action={action}\n icons={actionIcons}\n size=\"md\"\n href={getActionHref(action)}\n isPending={pending === keyOf(action)}\n onPress={() => runOnResource(action)}\n />\n ))}\n {toolbar}\n </div>\n </div>\n ) : null}\n <FilterChips\n filters={filters}\n values={filterValues}\n q={query.q}\n onRemove={(id) => list.setFilter(id, undefined)}\n onClearSearch={() => list.setSearch('')}\n onClear={clearFilters}\n columns={columns}\n fields={fields}\n labels={filterLabels.labels}\n />\n {selectedCount > 0 ? (\n <div className={styles.selection}>\n <span className={styles.selectionCount} role=\"status\">\n {selection.mode === 'all'\n ? intl.formatMessage(messages.allMatchingSelected, {\n total: selectedCount,\n })\n : intl.formatMessage(messages.selectedCount, { count: selectedCount })}\n </span>\n {selection.mode === 'ids' &&\n pageSelection === 'all' &&\n count > pageItems.length ? (\n <Button size=\"sm\" variant=\"ghost\" onPress={() => list.selectAllMatching()}>\n {intl.formatMessage(messages.selectAllMatching, { total: count })}\n </Button>\n ) : null}\n <Button size=\"sm\" variant=\"ghost\" onPress={() => list.clearSelection()}>\n {intl.formatMessage(messages.clearSelection)}\n </Button>\n {selectionActions.length > 0 ? (\n <div className={styles.selectionActions}>\n {selectionActions.map((action) => {\n const skipped = selectedItems.filter(\n (item) => !isAllowedOn(action, item),\n ).length;\n return (\n <ActionButton\n key={action.id}\n action={action}\n icons={actionIcons}\n size=\"md\"\n href={null}\n isPending={pending === keyOf(action)}\n isDisabled={\n (pending !== null && pending !== keyOf(action)) ||\n skipped >= selectedCount\n }\n onPress={() => runOnSelection(action)}\n />\n );\n })}\n </div>\n ) : null}\n </div>\n ) : null}\n <div className={styles.body} aria-busy={isLoading && items !== undefined}>\n {body}\n </div>\n {total !== undefined && error === null && total > 0 ? (\n <Pagination\n page={query.page ?? 1}\n perPage={query.perPage ?? pageItems.length}\n total={total}\n onPageChange={(page) => list.setPage(page)}\n perPageOptions={perPageOptions}\n onPerPageChange={(perPage) => list.setPerPage(perPage)}\n />\n ) : null}\n <ConfirmDialog\n event={confirming}\n preview={preview}\n onConfirm={(event) => void execute(event)}\n onCancel={closeConfirmation}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -10,23 +10,33 @@
10
10
  max-width: 100%;
11
11
  }
12
12
 
13
- .panneau-filters-toggle {
14
- align-self: center;
15
- min-height: var(--panneau-control-height);
13
+ /* On the line of the controls, below the labels of the other filters. The switch's own wrapper
14
+ * is a column: two classes outweigh it. */
15
+ .panneau-filters .panneau-filters-toggle {
16
16
  display: flex;
17
- align-items: center;
17
+ flex-direction: column;
18
+ justify-content: center;
19
+ align-self: flex-end;
20
+ min-height: var(--panneau-control-height);
18
21
  }
19
22
 
20
23
  .panneau-filters-range {
24
+ max-width: 100%;
25
+ }
26
+
27
+ .panneau-filters-range-inputs {
21
28
  display: flex;
22
- flex-wrap: wrap;
29
+ align-items: center;
23
30
  gap: var(--panneau-space-2);
24
- max-width: 100%;
25
31
  }
26
32
 
27
- .panneau-filters-range > :not(legend) {
28
- width: 11rem;
29
- max-width: 100%;
33
+ .panneau-filters-range-inputs > :not(.panneau-filters-range-dash) {
34
+ width: 10.5rem;
35
+ min-width: 0;
36
+ }
37
+
38
+ .panneau-filters-range-dash {
39
+ color: var(--panneau-color-text-muted);
30
40
  }
31
41
 
32
42
  .panneau-filters-chips {
@@ -64,8 +74,12 @@
64
74
  @container panneau-list (max-width: 40rem) {
65
75
  .panneau-filters,
66
76
  .panneau-filters-control,
67
- .panneau-filters-range,
68
- .panneau-filters-range > :not(legend) {
77
+ .panneau-filters-range {
69
78
  width: 100%;
70
79
  }
80
+
81
+ .panneau-filters-range-inputs > :not(.panneau-filters-range-dash) {
82
+ flex: 1 1 0;
83
+ width: auto;
84
+ }
71
85
  }
@@ -4,6 +4,8 @@ var filters = "panneau-filters";
4
4
  var control = "panneau-filters-control";
5
5
  var toggle = "panneau-filters-toggle";
6
6
  var range = "panneau-filters-range";
7
+ var rangeInputs = "panneau-filters-range-inputs";
8
+ var rangeDash = "panneau-filters-range-dash";
7
9
  var chips = "panneau-filters-chips";
8
10
  var chip = "panneau-filters-chip";
9
11
  var chipText = "panneau-filters-chip-text";
@@ -13,12 +15,14 @@ var Filters_module_default = {
13
15
  control,
14
16
  toggle,
15
17
  range,
18
+ rangeInputs,
19
+ rangeDash,
16
20
  chips,
17
21
  chip,
18
22
  chipText,
19
23
  chipLabel
20
24
  };
21
25
  //#endregion
22
- export { chip, chipLabel, chipText, chips, control, Filters_module_default as default, filters, range, toggle };
26
+ export { chip, chipLabel, chipText, chips, control, Filters_module_default as default, filters, range, rangeDash, rangeInputs, toggle };
23
27
 
24
28
  //# sourceMappingURL=Filters.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Filters.module.js","names":[],"sources":["../../src/filters/Filters.module.css"],"sourcesContent":[".filters {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-end;\n gap: var(--panneau-space-3);\n}\n\n.control {\n width: 12rem;\n max-width: 100%;\n}\n\n.toggle {\n align-self: center;\n min-height: var(--panneau-control-height);\n display: flex;\n align-items: center;\n}\n\n.range {\n display: flex;\n flex-wrap: wrap;\n gap: var(--panneau-space-2);\n max-width: 100%;\n}\n\n.range > :not(legend) {\n width: 11rem;\n max-width: 100%;\n}\n\n.chips {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--panneau-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n gap: var(--panneau-space-1);\n max-width: 100%;\n padding-inline-start: var(--panneau-space-3);\n font-size: var(--panneau-font-size-sm);\n background-color: var(--panneau-color-surface-sunken);\n border: var(--panneau-border-width) solid var(--panneau-color-border);\n border-radius: var(--panneau-radius-full);\n}\n\n.chipText {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chipLabel {\n color: var(--panneau-color-text-muted);\n}\n\n@container panneau-list (max-width: 40rem) {\n .filters,\n .control,\n .range,\n .range > :not(legend) {\n width: 100%;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"Filters.module.js","names":[],"sources":["../../src/filters/Filters.module.css"],"sourcesContent":[".filters {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-end;\n gap: var(--panneau-space-3);\n}\n\n.control {\n width: 12rem;\n max-width: 100%;\n}\n\n/* On the line of the controls, below the labels of the other filters. The switch's own wrapper\n * is a column: two classes outweigh it. */\n.filters .toggle {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-self: flex-end;\n min-height: var(--panneau-control-height);\n}\n\n.range {\n max-width: 100%;\n}\n\n.rangeInputs {\n display: flex;\n align-items: center;\n gap: var(--panneau-space-2);\n}\n\n.rangeInputs > :not(.rangeDash) {\n width: 10.5rem;\n min-width: 0;\n}\n\n.rangeDash {\n color: var(--panneau-color-text-muted);\n}\n\n.chips {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--panneau-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n gap: var(--panneau-space-1);\n max-width: 100%;\n padding-inline-start: var(--panneau-space-3);\n font-size: var(--panneau-font-size-sm);\n background-color: var(--panneau-color-surface-sunken);\n border: var(--panneau-border-width) solid var(--panneau-color-border);\n border-radius: var(--panneau-radius-full);\n}\n\n.chipText {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chipLabel {\n color: var(--panneau-color-text-muted);\n}\n\n@container panneau-list (max-width: 40rem) {\n .filters,\n .control,\n .range {\n width: 100%;\n }\n\n .rangeInputs > :not(.rangeDash) {\n flex: 1 1 0;\n width: auto;\n }\n}\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"controls.d.ts","sourceRoot":"","sources":["../../src/filters/controls.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAchE,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAmBxE;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAgC3F;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAU1E;AAED,4BAA4B;AAC5B,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BASxE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BA4B7E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC3B,MAAM,EACN,KAAK,EACL,KAAK,EACL,QAAQ,EACR,OAAO,EACP,aAAa,GAChB,EAAE,kBAAkB,+BA8CpB;AAED,oFAAoF;AACpF,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAOhE,CAAC"}
1
+ {"version":3,"file":"controls.d.ts","sourceRoot":"","sources":["../../src/filters/controls.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAchE,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAmBxE;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAgC3F;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAU1E;AAED,4BAA4B;AAC5B,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BASxE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAmC7E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC3B,MAAM,EACN,KAAK,EACL,KAAK,EACL,QAAQ,EACR,OAAO,EACP,aAAa,GAChB,EAAE,kBAAkB,+BA8CpB;AAED,oFAAoF;AACpF,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAOhE,CAAC"}