@panneau/lists 5.0.0-alpha.3 → 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.
- package/dist/ItemDetails.css +34 -0
- package/dist/ItemDetails.d.ts +16 -0
- package/dist/ItemDetails.d.ts.map +1 -0
- package/dist/ItemDetails.js +62 -0
- package/dist/ItemDetails.js.map +1 -0
- package/dist/ItemDetails.module.js +16 -0
- package/dist/ItemDetails.module.js.map +1 -0
- package/dist/ListView.d.ts +6 -1
- package/dist/ListView.d.ts.map +1 -1
- package/dist/ListView.js +17 -31
- package/dist/ListView.js.map +1 -1
- package/dist/filters/Filters.css +25 -11
- package/dist/filters/Filters.module.js +5 -1
- package/dist/filters/Filters.module.js.map +1 -1
- package/dist/filters/controls.d.ts.map +1 -1
- package/dist/filters/controls.js +57 -35
- package/dist/filters/controls.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/layouts/CardsLayout.css +5 -0
- package/dist/layouts/CardsLayout.d.ts +1 -1
- package/dist/layouts/CardsLayout.d.ts.map +1 -1
- package/dist/layouts/CardsLayout.js +39 -35
- package/dist/layouts/CardsLayout.js.map +1 -1
- package/dist/layouts/CardsLayout.module.js.map +1 -1
- package/dist/layouts/ItemTitle.d.ts +3 -1
- package/dist/layouts/ItemTitle.d.ts.map +1 -1
- package/dist/layouts/ItemTitle.js +7 -16
- package/dist/layouts/ItemTitle.js.map +1 -1
- package/dist/layouts/TableLayout.css +16 -0
- package/dist/layouts/TableLayout.d.ts +1 -1
- package/dist/layouts/TableLayout.d.ts.map +1 -1
- package/dist/layouts/TableLayout.js +38 -33
- package/dist/layouts/TableLayout.js.map +1 -1
- package/dist/layouts/TableLayout.module.js +3 -3
- package/dist/layouts/TableLayout.module.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/useRenderValue.d.ts +8 -0
- package/dist/useRenderValue.d.ts.map +1 -0
- package/dist/useRenderValue.js +64 -0
- package/dist/useRenderValue.js.map +1 -0
- 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":""}
|
package/dist/ListView.d.ts
CHANGED
|
@@ -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
|
package/dist/ListView.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListView.d.ts","sourceRoot":"","sources":["../src/ListView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,OAAO,CAAC;AAEzD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,KAAK,EAAU,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAO/D,OAAO,EACH,KAAK,WAAW,EAKnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
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 = (
|
|
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,
|
|
119
|
+
const runOnItem = (action_5, item_1) => run({
|
|
135
120
|
action: action_5,
|
|
136
121
|
scope: "item",
|
|
137
|
-
item:
|
|
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((
|
|
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 = (
|
|
159
|
-
const allowed = rowActions.filter((action_8) => isAllowedOn(action_8,
|
|
160
|
-
const menu = rowMenu.filter((action_9) => isAllowedOn(action_9,
|
|
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${
|
|
147
|
+
const running = pending?.endsWith(`\u0000${item_3.id}`) === true ? pending.split("\0")[0] : null;
|
|
163
148
|
return /* @__PURE__ */ jsx(RowActions, {
|
|
164
|
-
item:
|
|
165
|
-
itemLabel: getItemLabel(
|
|
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,
|
|
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((
|
|
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((
|
|
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: (
|
|
206
|
+
onSort: (column_1) => list.toggleSort(column_1.id),
|
|
221
207
|
label,
|
|
222
208
|
pageSelection: pageCheckbox
|
|
223
209
|
});
|
package/dist/ListView.js.map
CHANGED
|
@@ -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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"}
|
package/dist/filters/Filters.css
CHANGED
|
@@ -10,23 +10,33 @@
|
|
|
10
10
|
max-width: 100%;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
.
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
29
|
+
align-items: center;
|
|
23
30
|
gap: var(--panneau-space-2);
|
|
24
|
-
max-width: 100%;
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
.panneau-filters-range > :not(
|
|
28
|
-
width:
|
|
29
|
-
|
|
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:
|
|
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,+
|
|
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"}
|