@panneau/lists 4.1.1 → 5.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -0
- package/dist/List.d.ts +26 -0
- package/dist/List.d.ts.map +1 -0
- package/dist/List.js +38 -0
- package/dist/List.js.map +1 -0
- package/dist/ListView.css +101 -0
- package/dist/ListView.d.ts +76 -0
- package/dist/ListView.d.ts.map +1 -0
- package/dist/ListView.js +325 -0
- package/dist/ListView.js.map +1 -0
- package/dist/ListView.module.js +28 -0
- package/dist/ListView.module.js.map +1 -0
- package/dist/actions/ActionButton.d.ts +18 -0
- package/dist/actions/ActionButton.d.ts.map +1 -0
- package/dist/actions/ActionButton.js +34 -0
- package/dist/actions/ActionButton.js.map +1 -0
- package/dist/actions/Actions.css +58 -0
- package/dist/actions/Actions.module.js +20 -0
- package/dist/actions/Actions.module.js.map +1 -0
- package/dist/actions/ConfirmDialog.d.ts +15 -0
- package/dist/actions/ConfirmDialog.d.ts.map +1 -0
- package/dist/actions/ConfirmDialog.js +157 -0
- package/dist/actions/ConfirmDialog.js.map +1 -0
- package/dist/actions/RowActions.d.ts +20 -0
- package/dist/actions/RowActions.d.ts.map +1 -0
- package/dist/actions/RowActions.js +99 -0
- package/dist/actions/RowActions.js.map +1 -0
- package/dist/actions/actions.d.ts +23 -0
- package/dist/actions/actions.d.ts.map +1 -0
- package/dist/actions/actions.js +56 -0
- package/dist/actions/actions.js.map +1 -0
- package/dist/actions/icons.d.ts +10 -0
- package/dist/actions/icons.d.ts.map +1 -0
- package/dist/actions/icons.js +27 -0
- package/dist/actions/icons.js.map +1 -0
- package/dist/cx.d.ts +3 -0
- package/dist/cx.d.ts.map +1 -0
- package/dist/cx.js +9 -0
- package/dist/cx.js.map +1 -0
- package/dist/displays/Displays.css +71 -0
- package/dist/displays/Displays.module.js +30 -0
- package/dist/displays/Displays.module.js.map +1 -0
- package/dist/displays/displays.d.ts +36 -0
- package/dist/displays/displays.d.ts.map +1 -0
- package/dist/displays/displays.js +570 -0
- package/dist/displays/displays.js.map +1 -0
- package/dist/filters/Filters.css +71 -0
- package/dist/filters/Filters.d.ts +38 -0
- package/dist/filters/Filters.d.ts.map +1 -0
- package/dist/filters/Filters.js +240 -0
- package/dist/filters/Filters.js.map +1 -0
- package/dist/filters/Filters.module.js +24 -0
- package/dist/filters/Filters.module.js.map +1 -0
- package/dist/filters/controls.d.ts +23 -0
- package/dist/filters/controls.d.ts.map +1 -0
- package/dist/filters/controls.js +431 -0
- package/dist/filters/controls.js.map +1 -0
- package/dist/filters/format.d.ts +16 -0
- package/dist/filters/format.d.ts.map +1 -0
- package/dist/filters/format.js +46 -0
- package/dist/filters/format.js.map +1 -0
- package/dist/index.d.ts +19 -10
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -66
- package/dist/layouts/CardsLayout.css +72 -0
- package/dist/layouts/CardsLayout.d.ts +4 -0
- package/dist/layouts/CardsLayout.d.ts.map +1 -0
- package/dist/layouts/CardsLayout.js +111 -0
- package/dist/layouts/CardsLayout.js.map +1 -0
- package/dist/layouts/CardsLayout.module.js +24 -0
- package/dist/layouts/CardsLayout.module.js.map +1 -0
- package/dist/layouts/ItemTitle.d.ts +10 -0
- package/dist/layouts/ItemTitle.d.ts.map +1 -0
- package/dist/layouts/ItemTitle.js +30 -0
- package/dist/layouts/ItemTitle.js.map +1 -0
- package/dist/layouts/TableLayout.css +177 -0
- package/dist/layouts/TableLayout.d.ts +9 -0
- package/dist/layouts/TableLayout.d.ts.map +1 -0
- package/dist/layouts/TableLayout.js +208 -0
- package/dist/layouts/TableLayout.js.map +1 -0
- package/dist/layouts/TableLayout.module.js +32 -0
- package/dist/layouts/TableLayout.module.js.map +1 -0
- package/dist/layouts/builtIn.d.ts +6 -0
- package/dist/layouts/builtIn.d.ts.map +1 -0
- package/dist/layouts/builtIn.js +12 -0
- package/dist/layouts/builtIn.js.map +1 -0
- package/dist/layouts/link.css +16 -0
- package/dist/layouts/link.module.js +8 -0
- package/dist/layouts/link.module.js.map +1 -0
- package/dist/messages.d.ts +2 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +1 -0
- package/dist/plugin.d.ts +13 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +19 -0
- package/dist/plugin.js.map +1 -0
- package/dist/query.d.ts +21 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +70 -0
- package/dist/query.js.map +1 -0
- package/dist/selection.d.ts +9 -0
- package/dist/selection.d.ts.map +1 -0
- package/dist/selection.js +19 -0
- package/dist/selection.js.map +1 -0
- package/dist/toolbar/LayoutSwitch.d.ts +8 -0
- package/dist/toolbar/LayoutSwitch.d.ts.map +1 -0
- package/dist/toolbar/LayoutSwitch.js +108 -0
- package/dist/toolbar/LayoutSwitch.js.map +1 -0
- package/dist/toolbar/Pagination.d.ts +13 -0
- package/dist/toolbar/Pagination.d.ts.map +1 -0
- package/dist/toolbar/Pagination.js +62 -0
- package/dist/toolbar/Pagination.js.map +1 -0
- package/dist/toolbar/SearchField.d.ts +9 -0
- package/dist/toolbar/SearchField.d.ts.map +1 -0
- package/dist/toolbar/SearchField.js +64 -0
- package/dist/toolbar/SearchField.js.map +1 -0
- package/dist/toolbar/SortSelect.d.ts +9 -0
- package/dist/toolbar/SortSelect.d.ts.map +1 -0
- package/dist/toolbar/SortSelect.js +90 -0
- package/dist/toolbar/SortSelect.js.map +1 -0
- package/dist/toolbar/Toolbar.css +72 -0
- package/dist/toolbar/Toolbar.module.js +22 -0
- package/dist/toolbar/Toolbar.module.js.map +1 -0
- package/dist/types.d.ts +106 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/useDraft.d.ts +11 -0
- package/dist/useDraft.d.ts.map +1 -0
- package/dist/useDraft.js +77 -0
- package/dist/useDraft.js.map +1 -0
- package/dist/useListState.d.ts +4 -0
- package/dist/useListState.d.ts.map +1 -0
- package/dist/useListState.js +10 -0
- package/dist/useListState.js.map +1 -0
- package/dist/values.d.ts +21 -0
- package/dist/values.d.ts.map +1 -0
- package/dist/values.js +52 -0
- package/dist/values.js.map +1 -0
- package/package.json +27 -57
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TableLayout.js","names":["pageSelection","item","selected","column","href","label","styles","_c"],"sources":["../../src/layouts/TableLayout.tsx"],"sourcesContent":["import { ArrowDown, ArrowUp, ArrowUpDown } from 'lucide-react';\n\nimport { Checkbox, Icon, usePanneauIntl } from '@panneau/ui';\n\nimport { cx } from '../cx';\nimport { messages } from '../messages';\nimport type { ListColumn, ListLayoutProps } from '../types';\nimport { ItemTitle } from './ItemTitle';\nimport styles from './TableLayout.module.css';\n\n/** The sort direction of a column, from the first `sort` value. */\nexport function getSortDirection(\n sort: readonly string[],\n column: ListColumn,\n): 'ascending' | 'descending' | null {\n const first = sort[0];\n if (first === column.id) {\n return 'ascending';\n }\n return first === `-${column.id}` ? 'descending' : null;\n}\n\nfunction alignClass(column: ListColumn): string | undefined {\n if (column.align === 'center') {\n return styles.center;\n }\n return column.align === 'end' ? styles.end : undefined;\n}\n\n/**\n * Items as a table, with sortable column headers. On narrow lists (phones), each row turns into a\n * block that shows the label of each value.\n */\nexport function TableLayout({\n items,\n columns,\n renderValue,\n getItemLabel,\n getItemHref,\n selectable,\n isSelected,\n onToggle,\n renderActions,\n sort,\n onSort,\n label,\n pageSelection,\n}: ListLayoutProps) {\n const intl = usePanneauIntl();\n const actions = items.map((item) => renderActions(item));\n const hasActions = actions.some((node) => node !== null);\n return (\n <div className={styles.scroller}>\n <table className={styles.table} aria-label={label}>\n <thead>\n <tr>\n {selectable ? <th className={styles.check}>{pageSelection}</th> : null}\n {columns.map((column) => {\n const direction = getSortDirection(sort, column);\n return (\n <th\n key={column.id}\n scope=\"col\"\n className={alignClass(column)}\n style={\n column.width !== undefined\n ? { width: column.width }\n : undefined\n }\n aria-sort={\n column.sortable === true ? (direction ?? 'none') : undefined\n }\n >\n {column.sortable === true ? (\n <button\n type=\"button\"\n className={cx(\n styles.sort,\n direction !== null && styles.sorted,\n )}\n onClick={() => onSort(column)}\n >\n {column.label ?? column.id}\n <span className={styles.sortIcon}>\n <Icon\n icon={\n direction === 'ascending'\n ? ArrowUp\n : direction === 'descending'\n ? ArrowDown\n : ArrowUpDown\n }\n size=\"sm\"\n />\n </span>\n </button>\n ) : (\n (column.label ?? column.id)\n )}\n </th>\n );\n })}\n {hasActions ? (\n <th className={styles.actionsCell}>\n <span className={styles.visuallyHidden}>\n {intl.formatMessage(messages.actions)}\n </span>\n </th>\n ) : null}\n </tr>\n </thead>\n <tbody>\n {items.map((item, row) => {\n const selected = selectable && isSelected(item);\n const href = getItemHref?.(item) ?? null;\n return (\n <tr key={item.id} data-selected={selected || undefined}>\n {selectable ? (\n <td className={styles.check}>\n <Checkbox\n aria-label={intl.formatMessage(messages.selectItem, {\n item: getItemLabel(item),\n })}\n isSelected={selected}\n onChange={() => onToggle(item)}\n />\n </td>\n ) : null}\n {columns.map((column, index) => (\n <td\n key={column.id}\n className={cx(\n alignClass(column),\n index === 0 && styles.title,\n )}\n >\n <span className={styles.cellLabel}>\n {column.label ?? column.id}\n </span>\n <span>\n {index === 0 ? (\n <ItemTitle href={href}>\n {renderValue(item, column)}\n </ItemTitle>\n ) : (\n renderValue(item, column)\n )}\n </span>\n </td>\n ))}\n {hasActions ? (\n <td className={styles.actionsCell}>{actions[row]}</td>\n ) : null}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import "./TableLayout.css";
|
|
2
|
+
//#region src/layouts/TableLayout.module.css
|
|
3
|
+
var scroller = "panneau-scroller-dntHlH";
|
|
4
|
+
var table = "panneau-table-adJh-G";
|
|
5
|
+
var center = "panneau-center-Fx-12L";
|
|
6
|
+
var end = "panneau-end-Jr3hRc";
|
|
7
|
+
var check = "panneau-check-E5-IqZ";
|
|
8
|
+
var actionsCell = "panneau-actionsCell-dzoCuU";
|
|
9
|
+
var sort = "panneau-sort-t4x1tD";
|
|
10
|
+
var sortIcon = "panneau-sortIcon-5pp-ve";
|
|
11
|
+
var sorted = "panneau-sorted-a6Fwul";
|
|
12
|
+
var cellLabel = "panneau-cellLabel-tiliX5";
|
|
13
|
+
var visuallyHidden = "panneau-visuallyHidden--8qvnp";
|
|
14
|
+
var title = "panneau-title-KEAnyJ";
|
|
15
|
+
var TableLayout_module_default = {
|
|
16
|
+
scroller,
|
|
17
|
+
table,
|
|
18
|
+
center,
|
|
19
|
+
end,
|
|
20
|
+
check,
|
|
21
|
+
actionsCell,
|
|
22
|
+
sort,
|
|
23
|
+
sortIcon,
|
|
24
|
+
sorted,
|
|
25
|
+
cellLabel,
|
|
26
|
+
visuallyHidden,
|
|
27
|
+
title
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { actionsCell, cellLabel, center, check, TableLayout_module_default as default, end, scroller, sort, sortIcon, sorted, table, title, visuallyHidden };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=TableLayout.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TableLayout.module.js","names":[],"sources":["../../src/layouts/TableLayout.module.css"],"sourcesContent":[".scroller {\n overflow-x: auto;\n border: var(--panneau-border-width) solid var(--panneau-color-border);\n border-radius: var(--panneau-radius-lg);\n background-color: var(--panneau-color-surface);\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--panneau-font-size-md);\n}\n\n.table th,\n.table td {\n padding: var(--panneau-space-2) var(--panneau-space-3);\n text-align: start;\n vertical-align: middle;\n border-bottom: var(--panneau-border-width) solid var(--panneau-color-border);\n}\n\n.table th {\n font-size: var(--panneau-font-size-sm);\n font-weight: var(--panneau-font-weight-medium);\n color: var(--panneau-color-text-muted);\n white-space: nowrap;\n background-color: var(--panneau-color-surface-sunken);\n}\n\n.table tbody tr:last-child td {\n border-bottom: 0;\n}\n\n.table tbody tr[data-selected] {\n background-color: var(--panneau-color-accent-subtle);\n}\n\n.center {\n text-align: center !important;\n}\n\n.end {\n text-align: end !important;\n}\n\n.check {\n width: 1px;\n}\n\n.actionsCell {\n width: 1px;\n text-align: end !important;\n white-space: nowrap;\n}\n\n.sort {\n display: inline-flex;\n align-items: center;\n gap: var(--panneau-space-1);\n margin: calc(-1 * var(--panneau-space-1)) calc(-1 * var(--panneau-space-2));\n padding: var(--panneau-space-1) var(--panneau-space-2);\n font: inherit;\n color: inherit;\n background: none;\n border: 0;\n border-radius: var(--panneau-radius-sm);\n cursor: pointer;\n}\n\n.sort:hover {\n color: var(--panneau-color-text);\n background-color: var(--panneau-color-hover);\n}\n\n.sort:focus-visible {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 1px;\n}\n\n.sortIcon {\n opacity: 0.5;\n}\n\n.sorted .sortIcon {\n opacity: 1;\n}\n\n.cellLabel {\n display: none;\n}\n\n.visuallyHidden {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n/* Narrow lists (phones): each row is a block, with the label of each value next to it. */\n@container panneau-list (max-width: 40rem) {\n .scroller {\n overflow: visible;\n background: none;\n border: 0;\n }\n\n /* The labels of the cells replace the headers, and the list's sort select their buttons. */\n .table thead {\n display: none;\n }\n\n .table,\n .table tbody,\n .table tr,\n .table td {\n display: block;\n }\n\n .table tbody {\n display: grid;\n gap: var(--panneau-space-2);\n }\n\n .table tr {\n position: relative;\n padding: var(--panneau-space-2) 0;\n background-color: var(--panneau-color-surface);\n border: var(--panneau-border-width) solid var(--panneau-color-border);\n border-radius: var(--panneau-radius-lg);\n }\n\n .table td {\n display: grid;\n grid-template-columns: minmax(5rem, 35%) 1fr;\n gap: var(--panneau-space-2);\n padding: var(--panneau-space-1) var(--panneau-space-3);\n text-align: start !important;\n border: 0;\n }\n\n .table td.check,\n .table td.actionsCell {\n display: flex;\n width: auto;\n }\n\n .table td.check {\n position: absolute;\n top: var(--panneau-space-2);\n inset-inline-end: var(--panneau-space-2);\n padding: 0;\n }\n\n .table td.actionsCell {\n justify-content: flex-start;\n flex-wrap: wrap;\n padding-top: var(--panneau-space-2);\n }\n\n .table td.title {\n display: block;\n padding-inline-end: var(--panneau-space-10);\n font-weight: var(--panneau-font-weight-medium);\n }\n\n .table td.title .cellLabel {\n display: none;\n }\n\n .cellLabel {\n display: block;\n font-size: var(--panneau-font-size-sm);\n color: var(--panneau-color-text-muted);\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ListLayoutEntry } from '../types';
|
|
2
|
+
/** The built-in list layouts, by id. `gallery` and `calendar` come later. */
|
|
3
|
+
export declare const builtInLayouts: Readonly<Record<string, ListLayoutEntry>> & {
|
|
4
|
+
table: ListLayoutEntry;
|
|
5
|
+
};
|
|
6
|
+
//# sourceMappingURL=builtIn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builtIn.d.ts","sourceRoot":"","sources":["../../src/layouts/builtIn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAIhD,6EAA6E;AAC7E,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,GAAG;IACrE,KAAK,EAAE,eAAe,CAAC;CAI1B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CardsLayout } from "./CardsLayout.js";
|
|
2
|
+
import { TableLayout } from "./TableLayout.js";
|
|
3
|
+
//#region src/layouts/builtIn.ts
|
|
4
|
+
/** The built-in list layouts, by id. `gallery` and `calendar` come later. */
|
|
5
|
+
var builtInLayouts = {
|
|
6
|
+
table: TableLayout,
|
|
7
|
+
cards: CardsLayout
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { builtInLayouts };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=builtIn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builtIn.js","names":[],"sources":["../../src/layouts/builtIn.ts"],"sourcesContent":["import type { ListLayoutEntry } from '../types';\nimport { CardsLayout } from './CardsLayout';\nimport { TableLayout } from './TableLayout';\n\n/** The built-in list layouts, by id. `gallery` and `calendar` come later. */\nexport const builtInLayouts: Readonly<Record<string, ListLayoutEntry>> & {\n table: ListLayoutEntry;\n} = {\n table: TableLayout,\n cards: CardsLayout,\n};\n"],"mappings":";;;;AAKA,IAAa,iBAET;CACA,OAAO;CACP,OAAO;AACX"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
.panneau-link-1crRKJ {
|
|
2
|
+
color: inherit;
|
|
3
|
+
font-weight: var(--panneau-font-weight-medium);
|
|
4
|
+
text-decoration: none;
|
|
5
|
+
border-radius: var(--panneau-radius-sm);
|
|
6
|
+
cursor: pointer;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.panneau-link-1crRKJ:hover {
|
|
10
|
+
text-decoration: underline;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.panneau-link-1crRKJ[data-focus-visible] {
|
|
14
|
+
outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
|
|
15
|
+
outline-offset: 2px;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.module.js","names":[],"sources":["../../src/layouts/link.module.css"],"sourcesContent":[".link {\n color: inherit;\n font-weight: var(--panneau-font-weight-medium);\n text-decoration: none;\n border-radius: var(--panneau-radius-sm);\n cursor: pointer;\n}\n\n.link:hover {\n text-decoration: underline;\n}\n\n.link[data-focus-visible] {\n outline: var(--panneau-focus-width) solid var(--panneau-color-focus);\n outline-offset: 2px;\n}\n"],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { listsMessages as messages } from "@panneau/intl";
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DisplayEntry, ListLayoutEntry } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* The built-in displays and layouts as a `@panneau/core` plugin, with the French messages of every
|
|
4
|
+
* Panneau package (from `@panneau/intl`). Lists use the built-in displays and layouts without it:
|
|
5
|
+
* pass it for the messages, before the plugins that replace a display.
|
|
6
|
+
*/
|
|
7
|
+
export declare const listsPlugin: {
|
|
8
|
+
id: string;
|
|
9
|
+
displays: Readonly<Record<string, DisplayEntry>>;
|
|
10
|
+
listLayouts: Readonly<Record<string, ListLayoutEntry>>;
|
|
11
|
+
locales: Readonly<Record<string, Record<string, string>>>;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE7D;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACjD,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;IACvD,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CAM7D,CAAC"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { builtInDisplays } from "./displays/displays.js";
|
|
2
|
+
import { builtInLayouts } from "./layouts/builtIn.js";
|
|
3
|
+
import { fr } from "@panneau/intl";
|
|
4
|
+
//#region src/plugin.ts
|
|
5
|
+
/**
|
|
6
|
+
* The built-in displays and layouts as a `@panneau/core` plugin, with the French messages of every
|
|
7
|
+
* Panneau package (from `@panneau/intl`). Lists use the built-in displays and layouts without it:
|
|
8
|
+
* pass it for the messages, before the plugins that replace a display.
|
|
9
|
+
*/
|
|
10
|
+
var listsPlugin = {
|
|
11
|
+
id: "panneau-lists",
|
|
12
|
+
displays: builtInDisplays,
|
|
13
|
+
listLayouts: builtInLayouts,
|
|
14
|
+
locales: { fr }
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { listsPlugin };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../src/plugin.ts"],"sourcesContent":["import { fr } from '@panneau/intl';\n\nimport { builtInDisplays } from './displays/displays';\nimport { builtInLayouts } from './layouts/builtIn';\nimport type { DisplayEntry, ListLayoutEntry } from './types';\n\n/**\n * The built-in displays and layouts as a `@panneau/core` plugin, with the French messages of every\n * Panneau package (from `@panneau/intl`). Lists use the built-in displays and layouts without it:\n * pass it for the messages, before the plugins that replace a display.\n */\nexport const listsPlugin: {\n id: string;\n displays: Readonly<Record<string, DisplayEntry>>;\n listLayouts: Readonly<Record<string, ListLayoutEntry>>;\n locales: Readonly<Record<string, Record<string, string>>>;\n} = {\n id: 'panneau-lists',\n displays: builtInDisplays,\n listLayouts: builtInLayouts,\n locales: { fr },\n};\n"],"mappings":";;;;;;;;;AAWA,IAAa,cAKT;CACA,IAAI;CACJ,UAAU;CACV,aAAa;CACb,SAAS,EAAE,GAAG;AAClB"}
|
package/dist/query.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ListQuery } from '@panneau/protocol';
|
|
2
|
+
import type { ListColumn, ListItem } from './types';
|
|
3
|
+
export interface LocalQueryOptions {
|
|
4
|
+
/** The columns: values of localized fields are compared in `locale`. */
|
|
5
|
+
columns?: readonly ListColumn[];
|
|
6
|
+
/** Locale of localized values and of the text comparison. Defaults to `en`. */
|
|
7
|
+
locale?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface LocalQueryResult<T extends ListItem> {
|
|
10
|
+
/** The items of the page. */
|
|
11
|
+
items: T[];
|
|
12
|
+
/** How many items match the filters and the search, on every page. */
|
|
13
|
+
total: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Applies a list query to items in memory, as a backend would: filters (the value, or one of the
|
|
17
|
+
* values, matches as a string; a range matches the values within its bounds), search in every text
|
|
18
|
+
* value, sort, then the page. For a product that has every item at hand.
|
|
19
|
+
*/
|
|
20
|
+
export declare function applyListQuery<T extends ListItem>(items: readonly T[], query: ListQuery, options?: LocalQueryOptions): LocalQueryResult<T>;
|
|
21
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGnD,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGpD,MAAM,WAAW,iBAAiB;IAC9B,wEAAwE;IACxE,OAAO,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAChC,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,QAAQ;IAChD,6BAA6B;IAC7B,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;CACjB;AAOD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,QAAQ,EAC7C,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,iBAAsB,GAChC,gBAAgB,CAAC,CAAC,CAAC,CA6DrB"}
|
package/dist/query.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { getColumnValue, toText } from "./values.js";
|
|
2
|
+
import { isFilterRange, matchesFilterRange } from "@panneau/protocol/runtime";
|
|
3
|
+
//#region src/query.ts
|
|
4
|
+
function valueOf(item, key, options) {
|
|
5
|
+
const column = options.columns?.find((candidate) => candidate.id === key);
|
|
6
|
+
return column !== void 0 ? getColumnValue(item, column, options.locale ?? "en") : item[key];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Applies a list query to items in memory, as a backend would: filters (the value, or one of the
|
|
10
|
+
* values, matches as a string; a range matches the values within its bounds), search in every text
|
|
11
|
+
* value, sort, then the page. For a product that has every item at hand.
|
|
12
|
+
*/
|
|
13
|
+
function applyListQuery(items, query, options = {}) {
|
|
14
|
+
const locale = options.locale ?? "en";
|
|
15
|
+
let result = [...items];
|
|
16
|
+
Object.entries(query.filter ?? {}).forEach(([key, expected]) => {
|
|
17
|
+
if (isFilterRange(expected)) {
|
|
18
|
+
result = result.filter((item) => matchesFilterRange(valueOf(item, key, options), expected));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const accepted = (Array.isArray(expected) ? expected : [expected]).map(String);
|
|
22
|
+
result = result.filter((item) => {
|
|
23
|
+
const value = valueOf(item, key, options);
|
|
24
|
+
return (Array.isArray(value) ? value : [value]).some((candidate) => {
|
|
25
|
+
const id = candidate !== null && typeof candidate === "object" && "id" in candidate ? candidate.id : candidate;
|
|
26
|
+
return accepted.includes(String(id));
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
const q = query.q?.trim().toLocaleLowerCase(locale) ?? "";
|
|
31
|
+
if (q !== "") result = result.filter((item) => Object.entries(item).filter(([key]) => key !== "id" && key !== "abilities" && key !== "version").some(([key]) => toText(valueOf(item, key, options), locale).toLocaleLowerCase(locale).includes(q)));
|
|
32
|
+
const sort = query.sort ?? [];
|
|
33
|
+
if (sort.length > 0) {
|
|
34
|
+
const collator = new Intl.Collator(locale, {
|
|
35
|
+
numeric: true,
|
|
36
|
+
sensitivity: "base"
|
|
37
|
+
});
|
|
38
|
+
result.sort((a, b) => {
|
|
39
|
+
for (const part of sort) {
|
|
40
|
+
const descending = part.startsWith("-");
|
|
41
|
+
const key = descending ? part.slice(1) : part;
|
|
42
|
+
const left = valueOf(a, key, options);
|
|
43
|
+
const right = valueOf(b, key, options);
|
|
44
|
+
const order = typeof left === "number" && typeof right === "number" ? left - right : compareText(toText(left, locale), toText(right, locale), collator);
|
|
45
|
+
if (order !== 0) return descending ? -order : order;
|
|
46
|
+
}
|
|
47
|
+
return 0;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const total = result.length;
|
|
51
|
+
if (query.perPage !== void 0) {
|
|
52
|
+
const page = query.page ?? 1;
|
|
53
|
+
result = result.slice((page - 1) * query.perPage, page * query.perPage);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
items: result,
|
|
57
|
+
total
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Compares texts, empty ones last. */
|
|
61
|
+
function compareText(left, right, collator) {
|
|
62
|
+
if (left === right) return 0;
|
|
63
|
+
if (left === "") return 1;
|
|
64
|
+
if (right === "") return -1;
|
|
65
|
+
return collator.compare(left, right);
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { applyListQuery };
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","names":[],"sources":["../src/query.ts"],"sourcesContent":["import type { ListQuery } from '@panneau/protocol';\nimport { isFilterRange, matchesFilterRange } from '@panneau/protocol/runtime';\n\nimport type { ListColumn, ListItem } from './types';\nimport { getColumnValue, toText } from './values';\n\nexport interface LocalQueryOptions {\n /** The columns: values of localized fields are compared in `locale`. */\n columns?: readonly ListColumn[];\n /** Locale of localized values and of the text comparison. Defaults to `en`. */\n locale?: string;\n}\n\nexport interface LocalQueryResult<T extends ListItem> {\n /** The items of the page. */\n items: T[];\n /** How many items match the filters and the search, on every page. */\n total: number;\n}\n\nfunction valueOf(item: ListItem, key: string, options: LocalQueryOptions): unknown {\n const column = options.columns?.find((candidate) => candidate.id === key);\n return column !== undefined ? getColumnValue(item, column, options.locale ?? 'en') : item[key];\n}\n\n/**\n * Applies a list query to items in memory, as a backend would: filters (the value, or one of the\n * values, matches as a string; a range matches the values within its bounds), search in every text\n * value, sort, then the page. For a product that has every item at hand.\n */\nexport function applyListQuery<T extends ListItem>(\n items: readonly T[],\n query: ListQuery,\n options: LocalQueryOptions = {},\n): LocalQueryResult<T> {\n const locale = options.locale ?? 'en';\n let result = [...items];\n Object.entries(query.filter ?? {}).forEach(([key, expected]) => {\n if (isFilterRange(expected)) {\n result = result.filter((item) =>\n matchesFilterRange(valueOf(item, key, options), expected),\n );\n return;\n }\n const accepted = (Array.isArray(expected) ? expected : [expected]).map(String);\n result = result.filter((item) => {\n const value = valueOf(item, key, options);\n const values: unknown[] = Array.isArray(value) ? value : [value];\n return values.some((candidate) => {\n const id =\n candidate !== null && typeof candidate === 'object' && 'id' in candidate\n ? candidate.id\n : candidate;\n return accepted.includes(String(id));\n });\n });\n });\n const q = query.q?.trim().toLocaleLowerCase(locale) ?? '';\n if (q !== '') {\n result = result.filter((item) =>\n Object.entries(item)\n .filter(([key]) => key !== 'id' && key !== 'abilities' && key !== 'version')\n .some(([key]) =>\n toText(valueOf(item, key, options), locale)\n .toLocaleLowerCase(locale)\n .includes(q),\n ),\n );\n }\n const sort = query.sort ?? [];\n if (sort.length > 0) {\n const collator = new Intl.Collator(locale, { numeric: true, sensitivity: 'base' });\n result.sort((a, b) => {\n for (const part of sort) {\n const descending = part.startsWith('-');\n const key = descending ? part.slice(1) : part;\n const left = valueOf(a, key, options);\n const right = valueOf(b, key, options);\n const order =\n typeof left === 'number' && typeof right === 'number'\n ? left - right\n : compareText(toText(left, locale), toText(right, locale), collator);\n if (order !== 0) {\n return descending ? -order : order;\n }\n }\n return 0;\n });\n }\n const total = result.length;\n if (query.perPage !== undefined) {\n const page = query.page ?? 1;\n result = result.slice((page - 1) * query.perPage, page * query.perPage);\n }\n return { items: result, total };\n}\n\n/** Compares texts, empty ones last. */\nfunction compareText(left: string, right: string, collator: Intl.Collator): number {\n if (left === right) {\n return 0;\n }\n if (left === '') {\n return 1;\n }\n if (right === '') {\n return -1;\n }\n return collator.compare(left, right);\n}\n"],"mappings":";;;AAoBA,SAAS,QAAQ,MAAgB,KAAa,SAAqC;CAC/E,MAAM,SAAS,QAAQ,SAAS,MAAM,cAAc,UAAU,OAAO,GAAG;CACxE,OAAO,WAAW,KAAA,IAAY,eAAe,MAAM,QAAQ,QAAQ,UAAU,IAAI,IAAI,KAAK;AAC9F;;;;;;AAOA,SAAgB,eACZ,OACA,OACA,UAA6B,CAAC,GACX;CACnB,MAAM,SAAS,QAAQ,UAAU;CACjC,IAAI,SAAS,CAAC,GAAG,KAAK;CACtB,OAAO,QAAQ,MAAM,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,cAAc;EAC5D,IAAI,cAAc,QAAQ,GAAG;GACzB,SAAS,OAAO,QAAQ,SACpB,mBAAmB,QAAQ,MAAM,KAAK,OAAO,GAAG,QAAQ,CAC5D;GACA;EACJ;EACA,MAAM,YAAY,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ,EAAA,CAAG,IAAI,MAAM;EAC7E,SAAS,OAAO,QAAQ,SAAS;GAC7B,MAAM,QAAQ,QAAQ,MAAM,KAAK,OAAO;GAExC,QAD0B,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK,EAAA,CACjD,MAAM,cAAc;IAC9B,MAAM,KACF,cAAc,QAAQ,OAAO,cAAc,YAAY,QAAQ,YACzD,UAAU,KACV;IACV,OAAO,SAAS,SAAS,OAAO,EAAE,CAAC;GACvC,CAAC;EACL,CAAC;CACL,CAAC;CACD,MAAM,IAAI,MAAM,GAAG,KAAK,CAAC,CAAC,kBAAkB,MAAM,KAAK;CACvD,IAAI,MAAM,IACN,SAAS,OAAO,QAAQ,SACpB,OAAO,QAAQ,IAAI,CAAC,CACf,QAAQ,CAAC,SAAS,QAAQ,QAAQ,QAAQ,eAAe,QAAQ,SAAS,CAAC,CAC3E,MAAM,CAAC,SACJ,OAAO,QAAQ,MAAM,KAAK,OAAO,GAAG,MAAM,CAAC,CACtC,kBAAkB,MAAM,CAAC,CACzB,SAAS,CAAC,CACnB,CACR;CAEJ,MAAM,OAAO,MAAM,QAAQ,CAAA;CAC3B,IAAI,KAAK,SAAS,GAAG;EACjB,MAAM,WAAW,IAAI,KAAK,SAAS,QAAQ;GAAE,SAAS;GAAM,aAAa;EAAO,CAAC;EACjF,OAAO,MAAM,GAAG,MAAM;GAClB,KAAK,MAAM,QAAQ,MAAM;IACrB,MAAM,aAAa,KAAK,WAAW,GAAG;IACtC,MAAM,MAAM,aAAa,KAAK,MAAM,CAAC,IAAI;IACzC,MAAM,OAAO,QAAQ,GAAG,KAAK,OAAO;IACpC,MAAM,QAAQ,QAAQ,GAAG,KAAK,OAAO;IACrC,MAAM,QACF,OAAO,SAAS,YAAY,OAAO,UAAU,WACvC,OAAO,QACP,YAAY,OAAO,MAAM,MAAM,GAAG,OAAO,OAAO,MAAM,GAAG,QAAQ;IAC3E,IAAI,UAAU,GACV,OAAO,aAAa,CAAC,QAAQ;GAErC;GACA,OAAO;EACX,CAAC;CACL;CACA,MAAM,QAAQ,OAAO;CACrB,IAAI,MAAM,YAAY,KAAA,GAAW;EAC7B,MAAM,OAAO,MAAM,QAAQ;EAC3B,SAAS,OAAO,OAAO,OAAO,KAAK,MAAM,SAAS,OAAO,MAAM,OAAO;CAC1E;CACA,OAAO;EAAE,OAAO;EAAQ;CAAM;AAClC;;AAGA,SAAS,YAAY,MAAc,OAAe,UAAiC;CAC/E,IAAI,SAAS,OACT,OAAO;CAEX,IAAI,SAAS,IACT,OAAO;CAEX,IAAI,UAAU,IACV,OAAO;CAEX,OAAO,SAAS,QAAQ,MAAM,KAAK;AACvC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ListSelection } from '@panneau/core';
|
|
2
|
+
import type { ListItem } from './types';
|
|
3
|
+
/** Whether an item is selected. */
|
|
4
|
+
export declare function isItemSelected(selection: ListSelection, id: string): boolean;
|
|
5
|
+
/** How many items are selected, given the total of the list (or the count of items without it). */
|
|
6
|
+
export declare function countSelected(selection: ListSelection, total: number): number;
|
|
7
|
+
/** Whether every, some or none of the items of a page are selected. */
|
|
8
|
+
export declare function getPageSelection(selection: ListSelection, items: readonly ListItem[]): 'all' | 'some' | 'none';
|
|
9
|
+
//# sourceMappingURL=selection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../src/selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAMxC,mCAAmC;AACnC,wBAAgB,cAAc,CAAC,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5E;AAED,mGAAmG;AACnG,wBAAgB,aAAa,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAC5B,SAAS,EAAE,aAAa,EACxB,KAAK,EAAE,SAAS,QAAQ,EAAE,GAC3B,KAAK,GAAG,MAAM,GAAG,MAAM,CAMzB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/selection.ts
|
|
2
|
+
/** Whether an item is selected. */
|
|
3
|
+
function isItemSelected(selection, id) {
|
|
4
|
+
return selection.mode === "all" ? !selection.except.includes(id) : selection.ids.includes(id);
|
|
5
|
+
}
|
|
6
|
+
/** How many items are selected, given the total of the list (or the count of items without it). */
|
|
7
|
+
function countSelected(selection, total) {
|
|
8
|
+
return selection.mode === "all" ? Math.max(0, total - selection.except.length) : selection.ids.length;
|
|
9
|
+
}
|
|
10
|
+
/** Whether every, some or none of the items of a page are selected. */
|
|
11
|
+
function getPageSelection(selection, items) {
|
|
12
|
+
const selected = items.filter((item) => isItemSelected(selection, item.id)).length;
|
|
13
|
+
if (selected === 0 || items.length === 0) return "none";
|
|
14
|
+
return selected === items.length ? "all" : "some";
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { countSelected, getPageSelection, isItemSelected };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.js","names":[],"sources":["../src/selection.ts"],"sourcesContent":["import type { ListSelection } from '@panneau/core';\n\nimport type { ListItem } from './types';\n\n// The selection is read from the subscribed state, not through the methods of the list\n// (`list.isSelected()`): under the React Compiler, a component that calls a method of an object\n// that doesn't change would keep its first result.\n\n/** Whether an item is selected. */\nexport function isItemSelected(selection: ListSelection, id: string): boolean {\n return selection.mode === 'all' ? !selection.except.includes(id) : selection.ids.includes(id);\n}\n\n/** How many items are selected, given the total of the list (or the count of items without it). */\nexport function countSelected(selection: ListSelection, total: number): number {\n return selection.mode === 'all'\n ? Math.max(0, total - selection.except.length)\n : selection.ids.length;\n}\n\n/** Whether every, some or none of the items of a page are selected. */\nexport function getPageSelection(\n selection: ListSelection,\n items: readonly ListItem[],\n): 'all' | 'some' | 'none' {\n const selected = items.filter((item) => isItemSelected(selection, item.id)).length;\n if (selected === 0 || items.length === 0) {\n return 'none';\n }\n return selected === items.length ? 'all' : 'some';\n}\n"],"mappings":";;AASA,SAAgB,eAAe,WAA0B,IAAqB;CAC1E,OAAO,UAAU,SAAS,QAAQ,CAAC,UAAU,OAAO,SAAS,EAAE,IAAI,UAAU,IAAI,SAAS,EAAE;AAChG;;AAGA,SAAgB,cAAc,WAA0B,OAAuB;CAC3E,OAAO,UAAU,SAAS,QACpB,KAAK,IAAI,GAAG,QAAQ,UAAU,OAAO,MAAM,IAC3C,UAAU,IAAI;AACxB;;AAGA,SAAgB,iBACZ,WACA,OACuB;CACvB,MAAM,WAAW,MAAM,QAAQ,SAAS,eAAe,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC;CAC5E,IAAI,aAAa,KAAK,MAAM,WAAW,GACnC,OAAO;CAEX,OAAO,aAAa,MAAM,SAAS,QAAQ;AAC/C"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface LayoutSwitchProps {
|
|
2
|
+
layouts: readonly string[];
|
|
3
|
+
value: string;
|
|
4
|
+
onChange: (layout: string) => void;
|
|
5
|
+
}
|
|
6
|
+
/** Buttons to show the items as a table, as cards, or in a plugin's layout. */
|
|
7
|
+
export declare function LayoutSwitch({ layouts, value, onChange }: LayoutSwitchProps): import("react").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=LayoutSwitch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LayoutSwitch.d.ts","sourceRoot":"","sources":["../../src/toolbar/LayoutSwitch.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,iBAAiB,+BAoC3E"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { messages } from "../messages.js";
|
|
2
|
+
import Toolbar_module_default from "./Toolbar.module.js";
|
|
3
|
+
import { c } from "react/compiler-runtime";
|
|
4
|
+
import { Icon, Tooltip, usePanneauIntl } from "@panneau/ui";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { LayoutGrid, Rows3, Square } from "lucide-react";
|
|
7
|
+
import { ToggleButton, ToggleButtonGroup } from "react-aria-components";
|
|
8
|
+
//#region src/toolbar/LayoutSwitch.tsx
|
|
9
|
+
var ICONS = {
|
|
10
|
+
table: Rows3,
|
|
11
|
+
cards: LayoutGrid
|
|
12
|
+
};
|
|
13
|
+
/** Buttons to show the items as a table, as cards, or in a plugin's layout. */
|
|
14
|
+
function LayoutSwitch(t0) {
|
|
15
|
+
const $ = c(23);
|
|
16
|
+
const { layouts, value, onChange } = t0;
|
|
17
|
+
const intl = usePanneauIntl();
|
|
18
|
+
let t1;
|
|
19
|
+
if ($[0] !== intl) {
|
|
20
|
+
t1 = intl.formatMessage(messages.layoutTable);
|
|
21
|
+
$[0] = intl;
|
|
22
|
+
$[1] = t1;
|
|
23
|
+
} else t1 = $[1];
|
|
24
|
+
let t2;
|
|
25
|
+
if ($[2] !== intl) {
|
|
26
|
+
t2 = intl.formatMessage(messages.layoutCards);
|
|
27
|
+
$[2] = intl;
|
|
28
|
+
$[3] = t2;
|
|
29
|
+
} else t2 = $[3];
|
|
30
|
+
let t3;
|
|
31
|
+
if ($[4] !== t1 || $[5] !== t2) {
|
|
32
|
+
t3 = {
|
|
33
|
+
table: t1,
|
|
34
|
+
cards: t2
|
|
35
|
+
};
|
|
36
|
+
$[4] = t1;
|
|
37
|
+
$[5] = t2;
|
|
38
|
+
$[6] = t3;
|
|
39
|
+
} else t3 = $[6];
|
|
40
|
+
const labels = t3;
|
|
41
|
+
let t4;
|
|
42
|
+
if ($[7] !== intl) {
|
|
43
|
+
t4 = intl.formatMessage(messages.layout);
|
|
44
|
+
$[7] = intl;
|
|
45
|
+
$[8] = t4;
|
|
46
|
+
} else t4 = $[8];
|
|
47
|
+
let t5;
|
|
48
|
+
if ($[9] !== value) {
|
|
49
|
+
t5 = [value];
|
|
50
|
+
$[9] = value;
|
|
51
|
+
$[10] = t5;
|
|
52
|
+
} else t5 = $[10];
|
|
53
|
+
let t6;
|
|
54
|
+
if ($[11] !== onChange) {
|
|
55
|
+
t6 = (keys) => {
|
|
56
|
+
const [next] = [...keys];
|
|
57
|
+
if (next !== void 0) onChange(String(next));
|
|
58
|
+
};
|
|
59
|
+
$[11] = onChange;
|
|
60
|
+
$[12] = t6;
|
|
61
|
+
} else t6 = $[12];
|
|
62
|
+
let t7;
|
|
63
|
+
if ($[13] !== labels || $[14] !== layouts) {
|
|
64
|
+
let t8;
|
|
65
|
+
if ($[16] !== labels) {
|
|
66
|
+
t8 = (layout) => {
|
|
67
|
+
const label = labels[layout] ?? layout;
|
|
68
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
69
|
+
content: label,
|
|
70
|
+
children: /* @__PURE__ */ jsx(ToggleButton, {
|
|
71
|
+
id: layout,
|
|
72
|
+
"aria-label": label,
|
|
73
|
+
className: Toolbar_module_default.layoutButton,
|
|
74
|
+
children: /* @__PURE__ */ jsx(Icon, { icon: ICONS[layout] ?? Square })
|
|
75
|
+
})
|
|
76
|
+
}, layout);
|
|
77
|
+
};
|
|
78
|
+
$[16] = labels;
|
|
79
|
+
$[17] = t8;
|
|
80
|
+
} else t8 = $[17];
|
|
81
|
+
t7 = layouts.map(t8);
|
|
82
|
+
$[13] = labels;
|
|
83
|
+
$[14] = layouts;
|
|
84
|
+
$[15] = t7;
|
|
85
|
+
} else t7 = $[15];
|
|
86
|
+
let t8;
|
|
87
|
+
if ($[18] !== t4 || $[19] !== t5 || $[20] !== t6 || $[21] !== t7) {
|
|
88
|
+
t8 = /* @__PURE__ */ jsx(ToggleButtonGroup, {
|
|
89
|
+
"aria-label": t4,
|
|
90
|
+
selectionMode: "single",
|
|
91
|
+
disallowEmptySelection: true,
|
|
92
|
+
selectedKeys: t5,
|
|
93
|
+
onSelectionChange: t6,
|
|
94
|
+
className: Toolbar_module_default.layouts,
|
|
95
|
+
children: t7
|
|
96
|
+
});
|
|
97
|
+
$[18] = t4;
|
|
98
|
+
$[19] = t5;
|
|
99
|
+
$[20] = t6;
|
|
100
|
+
$[21] = t7;
|
|
101
|
+
$[22] = t8;
|
|
102
|
+
} else t8 = $[22];
|
|
103
|
+
return t8;
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
export { LayoutSwitch };
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=LayoutSwitch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LayoutSwitch.js","names":["layout","label","_c","styles"],"sources":["../../src/toolbar/LayoutSwitch.tsx"],"sourcesContent":["import { LayoutGrid, type LucideIcon, Rows3, Square } from 'lucide-react';\nimport { ToggleButton, ToggleButtonGroup } from 'react-aria-components';\n\nimport { Icon, Tooltip, usePanneauIntl } from '@panneau/ui';\n\nimport { messages } from '../messages';\nimport styles from './Toolbar.module.css';\n\nconst ICONS: Record<string, LucideIcon> = { table: Rows3, cards: LayoutGrid };\n\nexport interface LayoutSwitchProps {\n layouts: readonly string[];\n value: string;\n onChange: (layout: string) => void;\n}\n\n/** Buttons to show the items as a table, as cards, or in a plugin's layout. */\nexport function LayoutSwitch({ layouts, value, onChange }: LayoutSwitchProps) {\n const intl = usePanneauIntl();\n const labels: Record<string, string> = {\n table: intl.formatMessage(messages.layoutTable),\n cards: intl.formatMessage(messages.layoutCards),\n };\n return (\n <ToggleButtonGroup\n aria-label={intl.formatMessage(messages.layout)}\n selectionMode=\"single\"\n disallowEmptySelection\n selectedKeys={[value]}\n onSelectionChange={(keys) => {\n const [next] = [...keys];\n if (next !== undefined) {\n onChange(String(next));\n }\n }}\n className={styles.layouts}\n >\n {layouts.map((layout) => {\n const label = labels[layout] ?? layout;\n return (\n <Tooltip key={layout} content={label}>\n <ToggleButton\n id={layout}\n aria-label={label}\n className={styles.layoutButton}\n >\n <Icon icon={ICONS[layout] ?? Square} />\n </ToggleButton>\n </Tooltip>\n );\n })}\n </ToggleButtonGroup>\n );\n}\n"],"mappings":";;;;;;;;AAQA,IAAM,QAAoC;CAAE,OAAO;CAAO,OAAO;AAAW;;AAS5E,SAAO,aAAA,IAAA;CAAA,MAAA,IAAAE,EAAA,EAAA;CAAsB,MAAA,EAAA,SAAA,OAAA,aAAA;CACzB,MAAA,OAAa,eAAe;CAAE,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA;EAEnB,KAAA,KAAI,cAAe,SAAQ,WAAY;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA;EACxC,KAAA,KAAI,cAAe,SAAQ,WAAY;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA,EAAA,OAAA,IAAA;EAFZ,KAAA;GAAA,OAC5B;GAAwC,OACxC;EACX;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAHD,MAAA,SAAuC;CAGrC,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA;EAGkB,KAAA,KAAI,cAAe,SAAQ,MAAO;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,OAAA;EAGjC,KAAA,CAAC,KAAK;EAAC,EAAA,KAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,QAAA,UAAA;EACF,MAAA,SAAA;GACf,MAAA,CAAA,QAAe,CAAA,GAAI,IAAI;GACvB,IAAI,SAAS,KAAA,GACT,SAAS,OAAO,IAAI,CAAC;EACxB;EACJ,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,QAAA,UAAA,EAAA,QAAA,SAAA;EAAA,IAAA;EAAA,IAAA,EAAA,QAAA,QAAA;GAGY,MAAA,WAAA;IACT,MAAA,QAAc,OAAO,WAAP;IAAyB,OAEnC,oBAAC,SAAD;KAA+BD,SAAA;KAC3B,UAAA,oBAAC,cAAD;MACQD,IAAA;MACQC,cAAA;MACD,WAAAE,uBAAM;MAEjB,UAAA,oBAAC,MAAD,EAAY,MAAA,MAAM,WAAN,OAAuB,CAAA;KAL1B,CAAA;IADT,GAAM,MAAN;GAQE;GAEjB,EAAA,MAAA;GAAA,EAAA,MAAA;EAAA,OAAA,KAAA,EAAA;EAbA,KAAA,QAAO,IAAK,EAaZ;EAAC,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,QAAA,MAAA,EAAA,QAAA,MAAA,EAAA,QAAA,MAAA,EAAA,QAAA,IAAA;EA1BN,KAAA,oBAAC,mBAAD;GACgB,cAAA;GACE,eAAA;GACd,wBAAA;GACc,cAAA;GACK,mBAAA;GAMR,WAAAA,uBAAM;GAEhB,UAAA;EAba,CAAA;EA2BE,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OA3BpB;AA2BoB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface PaginationProps {
|
|
2
|
+
page: number;
|
|
3
|
+
perPage: number;
|
|
4
|
+
/** How many items match the query, on every page. */
|
|
5
|
+
total: number;
|
|
6
|
+
onPageChange: (page: number) => void;
|
|
7
|
+
/** Page sizes to choose from. Without them, the page size can't be changed. */
|
|
8
|
+
perPageOptions?: readonly number[] | undefined;
|
|
9
|
+
onPerPageChange?: (perPage: number) => void;
|
|
10
|
+
}
|
|
11
|
+
/** The range of items shown, the page, and buttons to the previous and next pages. */
|
|
12
|
+
export declare function Pagination({ page, perPage, total, onPageChange, perPageOptions, onPerPageChange, }: PaginationProps): import("react").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=Pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../src/toolbar/Pagination.tsx"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,+EAA+E;IAC/E,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC/C,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAED,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,EACvB,IAAI,EACJ,OAAO,EACP,KAAK,EACL,YAAY,EACZ,cAAmB,EACnB,eAAe,GAClB,EAAE,eAAe,+BAyCjB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { messages } from "../messages.js";
|
|
2
|
+
import Toolbar_module_default from "./Toolbar.module.js";
|
|
3
|
+
import { IconButton, Select, usePanneauIntl } from "@panneau/ui";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
6
|
+
//#region src/toolbar/Pagination.tsx
|
|
7
|
+
/** The range of items shown, the page, and buttons to the previous and next pages. */
|
|
8
|
+
function Pagination({ page, perPage, total, onPageChange, perPageOptions = [], onPerPageChange }) {
|
|
9
|
+
const intl = usePanneauIntl();
|
|
10
|
+
const lastPage = Math.max(1, Math.ceil(total / perPage));
|
|
11
|
+
const start = total === 0 ? 0 : (page - 1) * perPage + 1;
|
|
12
|
+
const end = Math.min(total, page * perPage);
|
|
13
|
+
const sizes = [.../* @__PURE__ */ new Set([...perPageOptions, perPage])].sort((a, b) => a - b);
|
|
14
|
+
return /* @__PURE__ */ jsxs("nav", {
|
|
15
|
+
"aria-label": intl.formatMessage(messages.pagination),
|
|
16
|
+
className: Toolbar_module_default.pagination,
|
|
17
|
+
children: [/* @__PURE__ */ jsx("span", { children: intl.formatMessage(messages.range, {
|
|
18
|
+
start,
|
|
19
|
+
end,
|
|
20
|
+
total
|
|
21
|
+
}) }), /* @__PURE__ */ jsxs("div", {
|
|
22
|
+
className: Toolbar_module_default.pages,
|
|
23
|
+
children: [
|
|
24
|
+
perPageOptions.length > 0 && onPerPageChange !== void 0 ? /* @__PURE__ */ jsx(Select, {
|
|
25
|
+
"aria-label": intl.formatMessage(messages.perPage),
|
|
26
|
+
options: sizes.map((size) => ({
|
|
27
|
+
value: size,
|
|
28
|
+
label: String(size)
|
|
29
|
+
})),
|
|
30
|
+
value: perPage,
|
|
31
|
+
onChange: (value) => {
|
|
32
|
+
if (typeof value === "number") onPerPageChange(value);
|
|
33
|
+
},
|
|
34
|
+
className: Toolbar_module_default.perPage
|
|
35
|
+
}) : null,
|
|
36
|
+
/* @__PURE__ */ jsx(IconButton, {
|
|
37
|
+
icon: ChevronLeft,
|
|
38
|
+
label: intl.formatMessage(messages.previousPage),
|
|
39
|
+
isDisabled: page <= 1,
|
|
40
|
+
onPress: () => onPageChange(page - 1)
|
|
41
|
+
}),
|
|
42
|
+
/* @__PURE__ */ jsx("span", {
|
|
43
|
+
"aria-current": "page",
|
|
44
|
+
children: intl.formatMessage(messages.pageOf, {
|
|
45
|
+
page,
|
|
46
|
+
lastPage
|
|
47
|
+
})
|
|
48
|
+
}),
|
|
49
|
+
/* @__PURE__ */ jsx(IconButton, {
|
|
50
|
+
icon: ChevronRight,
|
|
51
|
+
label: intl.formatMessage(messages.nextPage),
|
|
52
|
+
isDisabled: page >= lastPage,
|
|
53
|
+
onPress: () => onPageChange(page + 1)
|
|
54
|
+
})
|
|
55
|
+
]
|
|
56
|
+
})]
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
export { Pagination };
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=Pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pagination.js","names":["styles"],"sources":["../../src/toolbar/Pagination.tsx"],"sourcesContent":["import { ChevronLeft, ChevronRight } from 'lucide-react';\n\nimport { IconButton, Select, usePanneauIntl } from '@panneau/ui';\n\nimport { messages } from '../messages';\nimport styles from './Toolbar.module.css';\n\nexport interface PaginationProps {\n page: number;\n perPage: number;\n /** How many items match the query, on every page. */\n total: number;\n onPageChange: (page: number) => void;\n /** Page sizes to choose from. Without them, the page size can't be changed. */\n perPageOptions?: readonly number[] | undefined;\n onPerPageChange?: (perPage: number) => void;\n}\n\n/** The range of items shown, the page, and buttons to the previous and next pages. */\nexport function Pagination({\n page,\n perPage,\n total,\n onPageChange,\n perPageOptions = [],\n onPerPageChange,\n}: PaginationProps) {\n const intl = usePanneauIntl();\n const lastPage = Math.max(1, Math.ceil(total / perPage));\n const start = total === 0 ? 0 : (page - 1) * perPage + 1;\n const end = Math.min(total, page * perPage);\n const sizes = [...new Set([...perPageOptions, perPage])].sort((a, b) => a - b);\n return (\n <nav aria-label={intl.formatMessage(messages.pagination)} className={styles.pagination}>\n <span>{intl.formatMessage(messages.range, { start, end, total })}</span>\n <div className={styles.pages}>\n {perPageOptions.length > 0 && onPerPageChange !== undefined ? (\n <Select\n aria-label={intl.formatMessage(messages.perPage)}\n options={sizes.map((size) => ({ value: size, label: String(size) }))}\n value={perPage}\n onChange={(value) => {\n if (typeof value === 'number') {\n onPerPageChange(value);\n }\n }}\n className={styles.perPage}\n />\n ) : null}\n <IconButton\n icon={ChevronLeft}\n label={intl.formatMessage(messages.previousPage)}\n isDisabled={page <= 1}\n onPress={() => onPageChange(page - 1)}\n />\n <span aria-current=\"page\">\n {intl.formatMessage(messages.pageOf, { page, lastPage })}\n </span>\n <IconButton\n icon={ChevronRight}\n label={intl.formatMessage(messages.nextPage)}\n isDisabled={page >= lastPage}\n onPress={() => onPageChange(page + 1)}\n />\n </div>\n </nav>\n );\n}\n"],"mappings":";;;;;;;AAmBA,SAAgB,WAAW,EACvB,MACA,SACA,OACA,cACA,iBAAiB,CAAA,GACjB,mBACgB;CAChB,MAAM,OAAO,eAAe;CAC5B,MAAM,WAAW,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,OAAO,CAAC;CACvD,MAAM,QAAQ,UAAU,IAAI,KAAK,OAAO,KAAK,UAAU;CACvD,MAAM,MAAM,KAAK,IAAI,OAAO,OAAO,OAAO;CAC1C,MAAM,QAAQ,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,gBAAgB,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAC7E,OACI,qBAAC,OAAD;EAAK,cAAY,KAAK,cAAc,SAAS,UAAU;EAAG,WAAWA,uBAAO;EAA5E,UAAA,CACI,oBAAC,QAAD,EAAA,UAAO,KAAK,cAAc,SAAS,OAAO;GAAE;GAAO;GAAK;EAAM,CAAC,EAAQ,CAAA,GACvE,qBAAC,OAAD;GAAK,WAAWA,uBAAO;GAAvB,UAAA;IACK,eAAe,SAAS,KAAK,oBAAoB,KAAA,IAC9C,oBAAC,QAAD;KACI,cAAY,KAAK,cAAc,SAAS,OAAO;KAC/C,SAAS,MAAM,KAAK,UAAU;MAAE,OAAO;MAAM,OAAO,OAAO,IAAI;KAAE,EAAE;KACnE,OAAO;KACP,WAAW,UAAU;MACjB,IAAI,OAAO,UAAU,UACjB,gBAAgB,KAAK;KAE7B;KACA,WAAWA,uBAAO;IAAQ,CAAA,IAE9B;IACJ,oBAAC,YAAD;KACI,MAAM;KACN,OAAO,KAAK,cAAc,SAAS,YAAY;KAC/C,YAAY,QAAQ;KACpB,eAAe,aAAa,OAAO,CAAC;IAAE,CAAA;IAE1C,oBAAC,QAAD;KAAM,gBAAa;KACd,UAAA,KAAK,cAAc,SAAS,QAAQ;MAAE;MAAM;KAAS,CAAC;IACrD,CAAA;IACN,oBAAC,YAAD;KACI,MAAM;KACN,OAAO,KAAK,cAAc,SAAS,QAAQ;KAC3C,YAAY,QAAQ;KACpB,eAAe,aAAa,OAAO,CAAC;IAAE,CAAA;GAEzC;EACJ,CAAA,CAAA;;AAEb"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface SearchFieldProps {
|
|
2
|
+
/** The search of the query. */
|
|
3
|
+
value: string;
|
|
4
|
+
/** Called once the user stops typing, or presses Enter. */
|
|
5
|
+
onChange: (q: string) => void;
|
|
6
|
+
}
|
|
7
|
+
/** The search of a list (`q`). */
|
|
8
|
+
export declare function SearchField({ value, onChange }: SearchFieldProps): import("react").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=SearchField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchField.d.ts","sourceRoot":"","sources":["../../src/toolbar/SearchField.tsx"],"names":[],"mappings":"AAQA,MAAM,WAAW,gBAAgB;IAC7B,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,kCAAkC;AAClC,wBAAgB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,gBAAgB,+BAmBhE"}
|