@panneau/lists 5.0.0-alpha.2 → 5.0.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/README.md +17 -15
  2. package/dist/ItemDetails.css +50 -0
  3. package/dist/ItemDetails.d.ts +27 -0
  4. package/dist/ItemDetails.d.ts.map +1 -0
  5. package/dist/ItemDetails.js +134 -0
  6. package/dist/ItemDetails.js.map +1 -0
  7. package/dist/ItemDetails.module.js +20 -0
  8. package/dist/ItemDetails.module.js.map +1 -0
  9. package/dist/List.d.ts +3 -3
  10. package/dist/List.d.ts.map +1 -1
  11. package/dist/List.js +31 -10
  12. package/dist/List.js.map +1 -1
  13. package/dist/ListSkeleton.d.ts +19 -0
  14. package/dist/ListSkeleton.d.ts.map +1 -0
  15. package/dist/ListSkeleton.js +115 -0
  16. package/dist/ListSkeleton.js.map +1 -0
  17. package/dist/ListView.d.ts +73 -8
  18. package/dist/ListView.d.ts.map +1 -1
  19. package/dist/ListView.js +616 -218
  20. package/dist/ListView.js.map +1 -1
  21. package/dist/actions/ActionButton.d.ts +8 -2
  22. package/dist/actions/ActionButton.d.ts.map +1 -1
  23. package/dist/actions/ActionButton.js +98 -26
  24. package/dist/actions/ActionButton.js.map +1 -1
  25. package/dist/actions/Actions.css +16 -38
  26. package/dist/actions/Actions.module.js +6 -6
  27. package/dist/actions/Actions.module.js.map +1 -1
  28. package/dist/actions/ConfirmDialog.d.ts +20 -4
  29. package/dist/actions/ConfirmDialog.d.ts.map +1 -1
  30. package/dist/actions/ConfirmDialog.js +110 -92
  31. package/dist/actions/ConfirmDialog.js.map +1 -1
  32. package/dist/actions/RowActions.d.ts +25 -9
  33. package/dist/actions/RowActions.d.ts.map +1 -1
  34. package/dist/actions/RowActions.js +151 -80
  35. package/dist/actions/RowActions.js.map +1 -1
  36. package/dist/actions/actions.d.ts +5 -4
  37. package/dist/actions/actions.d.ts.map +1 -1
  38. package/dist/actions/actions.js +7 -14
  39. package/dist/actions/actions.js.map +1 -1
  40. package/dist/actions/fit.d.ts +25 -0
  41. package/dist/actions/fit.d.ts.map +1 -0
  42. package/dist/actions/fit.js +197 -0
  43. package/dist/actions/fit.js.map +1 -0
  44. package/dist/actions/icons.d.ts +5 -0
  45. package/dist/actions/icons.d.ts.map +1 -1
  46. package/dist/actions/icons.js +15 -1
  47. package/dist/actions/icons.js.map +1 -1
  48. package/dist/columns.d.ts +10 -0
  49. package/dist/columns.d.ts.map +1 -0
  50. package/dist/columns.js +25 -0
  51. package/dist/columns.js.map +1 -0
  52. package/dist/cx.js.map +1 -1
  53. package/dist/displays/Displays.css +48 -0
  54. package/dist/displays/Displays.module.js +18 -2
  55. package/dist/displays/Displays.module.js.map +1 -1
  56. package/dist/displays/displays.d.ts +62 -6
  57. package/dist/displays/displays.d.ts.map +1 -1
  58. package/dist/displays/displays.js +1151 -89
  59. package/dist/displays/displays.js.map +1 -1
  60. package/dist/filters/Filters.css +25 -11
  61. package/dist/filters/Filters.d.ts +1 -1
  62. package/dist/filters/Filters.js.map +1 -1
  63. package/dist/filters/Filters.module.js +5 -1
  64. package/dist/filters/Filters.module.js.map +1 -1
  65. package/dist/filters/controls.d.ts +1 -1
  66. package/dist/filters/controls.d.ts.map +1 -1
  67. package/dist/filters/controls.js +57 -35
  68. package/dist/filters/controls.js.map +1 -1
  69. package/dist/filters/format.d.ts +1 -1
  70. package/dist/filters/format.js.map +1 -1
  71. package/dist/images.d.ts +7 -0
  72. package/dist/images.d.ts.map +1 -0
  73. package/dist/images.js +39 -0
  74. package/dist/images.js.map +1 -0
  75. package/dist/index.d.ts +22 -18
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +7 -3
  78. package/dist/inline/Inline.css +58 -0
  79. package/dist/inline/Inline.module.js +20 -0
  80. package/dist/inline/Inline.module.js.map +1 -0
  81. package/dist/inline/InlineCell.d.ts +29 -0
  82. package/dist/inline/InlineCell.d.ts.map +1 -0
  83. package/dist/inline/InlineCell.js +490 -0
  84. package/dist/inline/InlineCell.js.map +1 -0
  85. package/dist/inline/editable.d.ts +12 -0
  86. package/dist/inline/editable.d.ts.map +1 -0
  87. package/dist/inline/editable.js +29 -0
  88. package/dist/inline/editable.js.map +1 -0
  89. package/dist/layouts/CalendarLayout.css +153 -0
  90. package/dist/layouts/CalendarLayout.d.ts +9 -0
  91. package/dist/layouts/CalendarLayout.d.ts.map +1 -0
  92. package/dist/layouts/CalendarLayout.js +303 -0
  93. package/dist/layouts/CalendarLayout.js.map +1 -0
  94. package/dist/layouts/CalendarLayout.module.js +28 -0
  95. package/dist/layouts/CalendarLayout.module.js.map +1 -0
  96. package/dist/layouts/CardsLayout.css +5 -0
  97. package/dist/layouts/CardsLayout.d.ts +2 -2
  98. package/dist/layouts/CardsLayout.d.ts.map +1 -1
  99. package/dist/layouts/CardsLayout.js +92 -91
  100. package/dist/layouts/CardsLayout.js.map +1 -1
  101. package/dist/layouts/CardsLayout.module.js.map +1 -1
  102. package/dist/layouts/GalleryLayout.css +87 -0
  103. package/dist/layouts/GalleryLayout.d.ts +8 -0
  104. package/dist/layouts/GalleryLayout.d.ts.map +1 -0
  105. package/dist/layouts/GalleryLayout.js +152 -0
  106. package/dist/layouts/GalleryLayout.js.map +1 -0
  107. package/dist/layouts/GalleryLayout.module.js +26 -0
  108. package/dist/layouts/GalleryLayout.module.js.map +1 -0
  109. package/dist/layouts/ItemTitle.d.ts +3 -1
  110. package/dist/layouts/ItemTitle.d.ts.map +1 -1
  111. package/dist/layouts/ItemTitle.js +12 -8
  112. package/dist/layouts/ItemTitle.js.map +1 -1
  113. package/dist/layouts/TableLayout.css +56 -0
  114. package/dist/layouts/TableLayout.d.ts +5 -4
  115. package/dist/layouts/TableLayout.d.ts.map +1 -1
  116. package/dist/layouts/TableLayout.js +171 -101
  117. package/dist/layouts/TableLayout.js.map +1 -1
  118. package/dist/layouts/TableLayout.module.js +8 -4
  119. package/dist/layouts/TableLayout.module.js.map +1 -1
  120. package/dist/layouts/builtIn.d.ts +2 -2
  121. package/dist/layouts/builtIn.d.ts.map +1 -1
  122. package/dist/layouts/builtIn.js +6 -2
  123. package/dist/layouts/builtIn.js.map +1 -1
  124. package/dist/layouts/calendarDays.d.ts +14 -0
  125. package/dist/layouts/calendarDays.d.ts.map +1 -0
  126. package/dist/layouts/calendarDays.js +44 -0
  127. package/dist/layouts/calendarDays.js.map +1 -0
  128. package/dist/plugin.d.ts +1 -1
  129. package/dist/plugin.js.map +1 -1
  130. package/dist/query.d.ts +4 -3
  131. package/dist/query.d.ts.map +1 -1
  132. package/dist/query.js +15 -4
  133. package/dist/query.js.map +1 -1
  134. package/dist/selection.d.ts +1 -1
  135. package/dist/selection.js.map +1 -1
  136. package/dist/toolbar/ColumnMenu.d.ts +17 -0
  137. package/dist/toolbar/ColumnMenu.d.ts.map +1 -0
  138. package/dist/toolbar/ColumnMenu.js +193 -0
  139. package/dist/toolbar/ColumnMenu.js.map +1 -0
  140. package/dist/toolbar/LayoutSwitch.d.ts.map +1 -1
  141. package/dist/toolbar/LayoutSwitch.js +73 -55
  142. package/dist/toolbar/LayoutSwitch.js.map +1 -1
  143. package/dist/toolbar/Pagination.d.ts +33 -0
  144. package/dist/toolbar/Pagination.d.ts.map +1 -1
  145. package/dist/toolbar/Pagination.js +282 -42
  146. package/dist/toolbar/Pagination.js.map +1 -1
  147. package/dist/toolbar/SearchField.js.map +1 -1
  148. package/dist/toolbar/SortSelect.d.ts +1 -1
  149. package/dist/toolbar/SortSelect.js.map +1 -1
  150. package/dist/toolbar/Toolbar.css +36 -0
  151. package/dist/toolbar/Toolbar.module.js +12 -2
  152. package/dist/toolbar/Toolbar.module.js.map +1 -1
  153. package/dist/types.d.ts +69 -1
  154. package/dist/types.d.ts.map +1 -1
  155. package/dist/useDraft.js.map +1 -1
  156. package/dist/useListState.js.map +1 -1
  157. package/dist/useRenderValue.d.ts +10 -0
  158. package/dist/useRenderValue.d.ts.map +1 -0
  159. package/dist/useRenderValue.js +84 -0
  160. package/dist/useRenderValue.js.map +1 -0
  161. package/dist/values.d.ts +4 -1
  162. package/dist/values.d.ts.map +1 -1
  163. package/dist/values.js +6 -2
  164. package/dist/values.js.map +1 -1
  165. package/package.json +9 -9
package/README.md CHANGED
@@ -77,21 +77,23 @@ const { data, isFetching, error } = useResourceList('pages', query); // @panneau
77
77
 
78
78
  ## What a list does
79
79
 
80
- | Feature | How |
81
- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
82
- | Columns | `item[id]` shown with a display: the column's `display`, else text. Localized values in the UI's locale. `render` for a cell of its own |
83
- | Displays | `text`, `textarea`, `slug`, `richtext`, `number`, `boolean`, `date`, `datetime`, `time`, `select`, `relation`, `url`, `email`, `color`, `media` |
84
- | Layouts | `table` and `cards` (`layouts`, the first is the default). On narrow lists, table rows stack and show the label of each value |
85
- | Sorting | Sortable column headers (`aria-sort`), and a select for cards and phones |
86
- | Filters | `text`, `select`, `toggle`, `date`, `date-range` (sent as bounds: `filter[id][from]`, `filter[id][to]`), `relation`, with chips for the active filters and the search |
87
- | Pagination | With `total`: the range, previous and next pages, and the page size (`perPageOptions`) |
88
- | Selection | Checkboxes, the page, then "select all N items", which selects every item matching the query, with exceptions |
89
- | Actions | `row` (buttons), `menu` (the row's menu), `toolbar` (selection and resource actions), with `confirm`, hidden by abilities ([0011](../../docs/decisions/0011-permissions.md)) |
90
- | States | A spinner, an error with a retry, an empty message, and "no results" with a button that clears the filters |
91
-
92
- An action shows the Lucide icon it names (`"icon": "send"`, through `getNamedIcon()` of `@panneau/ui`), or the icon of a built-in action (`edit`, `delete`…). Actions written in code can get icon components by id instead, which win over names: `actionIcons={{ archive: Archive }}`.
93
-
94
- Lists confirm an action when it has `confirm` (its title and message are ICU messages with `{count}`), or when some selected items don't allow it, then call `onAction` with the action, its scope, the item or the `Selection` of the protocol, the count and the skipped items. A promise shows the action as pending; when it rejects, a toast says that it failed. After a selection action, the selection is cleared.
80
+ | Feature | How |
81
+ | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
82
+ | Columns | `item[id]` shown with a display: the column's `display`, else text. Localized values in the UI's locale. `render` for a cell of its own |
83
+ | Displays | `text`, `textarea`, `slug`, `richtext`, `number`, `boolean`, `date`, `datetime`, `time`, `select`, `relation`, `url`, `email`, `color`, `media` |
84
+ | Columns | A "Columns" menu shows, hides and orders them: `hidden` columns are shown when the user picks them, and `hideable: false` ones always are. In the view of the list state |
85
+ | Layouts | `table`, `cards`, `gallery` (on `itemImage`) and `calendar` (with `calendar`), the first of `layouts` being the default, in the view of the list state. With `itemImage`, the table starts each title with a thumbnail ([0061](../../docs/decisions/0061-item-images-in-lists.md)). On narrow lists, table rows stack and show the label of each value, and the calendar lists its days with items ([0044](../../docs/decisions/0044-gallery-and-calendar.md)) |
86
+ | Sorting | Sortable column headers (`aria-sort`), and a select for cards and phones |
87
+ | Filters | `text`, `select`, `toggle`, `date`, `date-range` (sent as bounds: `filter[id][from]`, `filter[id][to]`), `relation`, with chips for the active filters and the search |
88
+ | Pagination | With `total`: the range, previous and next pages, and the page size (`perPageOptions`) |
89
+ | Selection | Checkboxes, the page, then "select all N items", which selects every item matching the query, with exceptions |
90
+ | Actions | `row` (buttons), `menu` (the row's menu), `toolbar` (selection and resource actions), with `confirm`, hidden by abilities ([0011](../../docs/decisions/0011-permissions.md)) |
91
+ | Editing | Columns of `inlineEdit` edit their field in place in the table (`text`, `number`, `select`, `boolean`, `date`), on items that can be updated: `onInlineEdit` saves the one field ([0043](../../docs/decisions/0043-inline-editing.md)) |
92
+ | States | Skeleton rows of the columns while `items` is `undefined`, an error with a retry, an empty message, and "no results" with a button that clears the filters |
93
+
94
+ An action shows the icon it names (`"icon": "send"`, through `getNamedIcon()` of `@panneau/ui`, which needs an `iconLoader` on `PanneauRoot`, such as `lucideIconLoader` of `@panneau/ui/named-icons`), or the icon of a built-in action (`edit`, `delete`…). Actions written in code can get icon components by id instead, which win over names: `actionIcons={{ archive: Archive }}`.
95
+
96
+ Lists confirm an action when it has `confirm` (its title and message are ICU messages with `{count}`), or when some selected items don't allow it. An `undoable` action runs without a confirmation, unless it sets one, up to `UNDO_LIMIT` items (100), counted from the selection or the dry run: its toast offers "Undo" instead (`asksConfirmation()` of `@panneau/core`, [decision 0063](../../docs/decisions/0063-undo-instead-of-a-confirmation.md)). A value changed in place says so in a toast whose "Undo" saves the previous value the same way, with the version the save got. For every item matching a query, they only know the current page: with `previewAction` (`useActionPreview()` of `@panneau/actions`), an action that declares `dryRun` asks the backend first, and the confirmation gives its count of skipped items. Then they call `onAction` with the action, its scope, the item or the `Selection` of the protocol, the count and the skipped items. A promise shows the action as pending; when it rejects, a toast says that it failed. After a selection action, the selection is cleared.
95
97
 
96
98
  A `relation` filter keeps ids in the query (`filter[author]=7`). Its chip and picker show the labels of the items it picked, and those of ids from the URL once the relation source's `resolve()` gives them.
97
99
 
@@ -0,0 +1,50 @@
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
+ /* A group: its label over its values, which are indented. */
28
+ .panneau-item-details-group > .panneau-item-details-label {
29
+ color: var(--panneau-color-text);
30
+ font-weight: var(--panneau-font-weight-medium);
31
+ }
32
+
33
+ .panneau-item-details-nested {
34
+ padding-inline-start: var(--panneau-space-3);
35
+ border-inline-start: var(--panneau-border-width) solid var(--panneau-color-border);
36
+ }
37
+
38
+ /* Wide enough: the label and its value side by side. */
39
+ @container panneau-item-details (min-width: 30rem) {
40
+ .panneau-item-details-entry {
41
+ display: grid;
42
+ grid-template-columns: minmax(8rem, 30%) minmax(0, 1fr);
43
+ gap: var(--panneau-space-3);
44
+ }
45
+
46
+ .panneau-item-details-group {
47
+ display: flex;
48
+ gap: var(--panneau-space-2);
49
+ }
50
+ }
@@ -0,0 +1,27 @@
1
+ import type { DisplayEntry, ListColumn, ListItem } from './types.js';
2
+ /** A value of the details, or a group of values under its label. */
3
+ export interface ItemDetailsColumn extends ListColumn {
4
+ /**
5
+ * The values of a group (a `group` field): read in the value of the column, an object, and
6
+ * listed under its label.
7
+ */
8
+ columns?: readonly ItemDetailsColumn[];
9
+ }
10
+ export interface ItemDetailsProps {
11
+ /** The item. `undefined` while it loads: the labels, with a skeleton of each value. */
12
+ item: ListItem | undefined;
13
+ /** The values to show, with their label and display, in order. */
14
+ columns: readonly ItemDetailsColumn[];
15
+ /** Displays by name, over the built-in ones and those of the plugins. */
16
+ displays?: Readonly<Record<string, DisplayEntry>>;
17
+ 'aria-label'?: string;
18
+ className?: string;
19
+ }
20
+ /**
21
+ * The values of one item, each with its label, shown with the displays of the lists: for the
22
+ * details of an item next to its list, or anywhere a read-only view of it is needed. A column with
23
+ * `columns` is a group, whose values are listed under its label. While the item loads, it draws
24
+ * the labels with a skeleton of each value (decision 0034).
25
+ */
26
+ export declare function ItemDetails({ item, columns, displays, 'aria-label': ariaLabel, className, }: ItemDetailsProps): import("react").JSX.Element;
27
+ //# sourceMappingURL=ItemDetails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemDetails.d.ts","sourceRoot":"","sources":["../src/ItemDetails.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAOlE,oEAAoE;AACpE,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACjD;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,gBAAgB;IAC7B,uFAAuF;IACvF,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,kEAAkE;IAClE,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACtC,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;AAMD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EACxB,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,SAAS,GACZ,EAAE,gBAAgB,+BA0DlB"}
@@ -0,0 +1,134 @@
1
+ import { messages } from "./messages.js";
2
+ import { getColumnValue } from "./values.js";
3
+ import { cx } from "./cx.js";
4
+ import ItemDetails_module_default from "./ItemDetails.module.js";
5
+ import { useRenderValue } from "./useRenderValue.js";
6
+ import { c } from "react/compiler-runtime";
7
+ import { LoadingRegion, Skeleton, usePanneauIntl } from "@panneau/ui";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/ItemDetails.tsx
10
+ /** Widths of the values of a skeleton, varied so they read as text. */
11
+ var WIDTHS = [
12
+ "70%",
13
+ "40%",
14
+ "55%",
15
+ "30%",
16
+ "65%"
17
+ ];
18
+ function isRecord(value) {
19
+ return value !== null && typeof value === "object" && !Array.isArray(value);
20
+ }
21
+ /**
22
+ * The values of one item, each with its label, shown with the displays of the lists: for the
23
+ * details of an item next to its list, or anywhere a read-only view of it is needed. A column with
24
+ * `columns` is a group, whose values are listed under its label. While the item loads, it draws
25
+ * the labels with a skeleton of each value (decision 0034).
26
+ */
27
+ function ItemDetails(t0) {
28
+ const $ = c(22);
29
+ const { item, columns, displays, "aria-label": ariaLabel, className } = t0;
30
+ const intl = usePanneauIntl();
31
+ const renderValue = useRenderValue(displays);
32
+ let t1;
33
+ let t2;
34
+ let t3;
35
+ if ($[0] !== ariaLabel || $[1] !== className || $[2] !== columns || $[3] !== intl || $[4] !== item || $[5] !== renderValue) {
36
+ const renderEntries = (entryItem, entryColumns) => entryColumns.map((column, index) => {
37
+ const label = /* @__PURE__ */ jsx("dt", {
38
+ className: ItemDetails_module_default.label,
39
+ children: column.label ?? column.id
40
+ });
41
+ if (column.columns !== void 0) {
42
+ const value = entryItem !== void 0 ? getColumnValue(entryItem, column, intl.locale) : void 0;
43
+ const groupItem = entryItem !== void 0 ? {
44
+ ...isRecord(value) ? value : {},
45
+ id: entryItem.id
46
+ } : void 0;
47
+ return /* @__PURE__ */ jsxs("div", {
48
+ className: cx(ItemDetails_module_default.entry, ItemDetails_module_default.group),
49
+ children: [label, /* @__PURE__ */ jsx("dd", {
50
+ className: ItemDetails_module_default.value,
51
+ children: /* @__PURE__ */ jsx("dl", {
52
+ className: cx(ItemDetails_module_default.details, ItemDetails_module_default.nested),
53
+ children: renderEntries(groupItem, column.columns)
54
+ })
55
+ })]
56
+ }, column.id);
57
+ }
58
+ return /* @__PURE__ */ jsxs("div", {
59
+ className: ItemDetails_module_default.entry,
60
+ children: [label, /* @__PURE__ */ jsx("dd", {
61
+ className: ItemDetails_module_default.value,
62
+ children: entryItem !== void 0 ? renderValue(entryItem, column) : /* @__PURE__ */ jsx(Skeleton, { width: WIDTHS[index % WIDTHS.length] })
63
+ })]
64
+ }, column.id);
65
+ });
66
+ t1 = ariaLabel;
67
+ if ($[9] !== className) {
68
+ t2 = cx(ItemDetails_module_default.details, className);
69
+ $[9] = className;
70
+ $[10] = t2;
71
+ } else t2 = $[10];
72
+ t3 = renderEntries(item, columns);
73
+ $[0] = ariaLabel;
74
+ $[1] = className;
75
+ $[2] = columns;
76
+ $[3] = intl;
77
+ $[4] = item;
78
+ $[5] = renderValue;
79
+ $[6] = t1;
80
+ $[7] = t2;
81
+ $[8] = t3;
82
+ } else {
83
+ t1 = $[6];
84
+ t2 = $[7];
85
+ t3 = $[8];
86
+ }
87
+ let t4;
88
+ if ($[11] !== t1 || $[12] !== t2 || $[13] !== t3) {
89
+ t4 = /* @__PURE__ */ jsx("dl", {
90
+ "aria-label": t1,
91
+ className: t2,
92
+ children: t3
93
+ });
94
+ $[11] = t1;
95
+ $[12] = t2;
96
+ $[13] = t3;
97
+ $[14] = t4;
98
+ } else t4 = $[14];
99
+ const details = t4;
100
+ if (item === void 0) {
101
+ let t5;
102
+ if ($[15] !== intl) {
103
+ t5 = intl.formatMessage(messages.loadingItem);
104
+ $[15] = intl;
105
+ $[16] = t5;
106
+ } else t5 = $[16];
107
+ let t6;
108
+ if ($[17] !== details) {
109
+ t6 = /* @__PURE__ */ jsx("div", {
110
+ inert: true,
111
+ "aria-hidden": "true",
112
+ children: details
113
+ });
114
+ $[17] = details;
115
+ $[18] = t6;
116
+ } else t6 = $[18];
117
+ let t7;
118
+ if ($[19] !== t5 || $[20] !== t6) {
119
+ t7 = /* @__PURE__ */ jsx(LoadingRegion, {
120
+ label: t5,
121
+ children: t6
122
+ });
123
+ $[19] = t5;
124
+ $[20] = t6;
125
+ $[21] = t7;
126
+ } else t7 = $[21];
127
+ return t7;
128
+ }
129
+ return details;
130
+ }
131
+ //#endregion
132
+ export { ItemDetails };
133
+
134
+ //# sourceMappingURL=ItemDetails.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ItemDetails.js","names":["LoadingRegion","Skeleton","usePanneauIntl","styles","cx","messages","DisplayEntry","ListColumn","ListItem","useRenderValue","getColumnValue","WIDTHS","ItemDetailsColumn","columns","ItemDetailsProps","item","displays","Readonly","Record","className","isRecord","value","Array","isArray","ItemDetails","t0","$","_c","ariaLabel","intl","renderValue","t1","t2","t3","renderEntries","entryItem","entryColumns","map","column","index","label","id","undefined","locale","groupItem","entry","group","details","nested","length","t4","t5","formatMessage","loadingItem","t6","t7","_c","styles"],"sources":["../src/ItemDetails.tsx"],"sourcesContent":["import { LoadingRegion, Skeleton, usePanneauIntl } from '@panneau/ui';\n\nimport styles from './ItemDetails.module.css';\nimport { cx } from './cx';\nimport { messages } from './messages';\nimport type { DisplayEntry, ListColumn, ListItem } from './types';\nimport { useRenderValue } from './useRenderValue';\nimport { getColumnValue } from './values';\n\n/** Widths of the values of a skeleton, varied so they read as text. */\nconst WIDTHS = ['70%', '40%', '55%', '30%', '65%'];\n\n/** A value of the details, or a group of values under its label. */\nexport interface ItemDetailsColumn extends ListColumn {\n /**\n * The values of a group (a `group` field): read in the value of the column, an object, and\n * listed under its label.\n */\n columns?: readonly ItemDetailsColumn[];\n}\n\nexport interface ItemDetailsProps {\n /** The item. `undefined` while it loads: the labels, with a skeleton of each value. */\n item: ListItem | undefined;\n /** The values to show, with their label and display, in order. */\n columns: readonly ItemDetailsColumn[];\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\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\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. A column with\n * `columns` is a group, whose values are listed under its label. While the item loads, it draws\n * the labels with a skeleton of each value (decision 0034).\n */\nexport function ItemDetails({\n item,\n columns,\n displays,\n 'aria-label': ariaLabel,\n className,\n}: ItemDetailsProps) {\n const intl = usePanneauIntl();\n const renderValue = useRenderValue(displays);\n const renderEntries = (\n entryItem: ListItem | undefined,\n entryColumns: readonly ItemDetailsColumn[],\n ) =>\n entryColumns.map((column, index) => {\n const label = <dt className={styles.label}>{column.label ?? column.id}</dt>;\n if (column.columns !== undefined) {\n // The values of a group are those of an item made of the value of the column.\n const value =\n entryItem !== undefined\n ? getColumnValue(entryItem, column, intl.locale)\n : undefined;\n const groupItem =\n entryItem !== undefined\n ? { ...(isRecord(value) ? value : {}), id: entryItem.id }\n : undefined;\n return (\n <div key={column.id} className={cx(styles.entry, styles.group)}>\n {label}\n <dd className={styles.value}>\n <dl className={cx(styles.details, styles.nested)}>\n {renderEntries(groupItem, column.columns)}\n </dl>\n </dd>\n </div>\n );\n }\n return (\n <div key={column.id} className={styles.entry}>\n {label}\n <dd className={styles.value}>\n {entryItem !== undefined ? (\n renderValue(entryItem, column)\n ) : (\n <Skeleton width={WIDTHS[index % WIDTHS.length]} />\n )}\n </dd>\n </div>\n );\n });\n const details = (\n <dl aria-label={ariaLabel} className={cx(styles.details, className)}>\n {renderEntries(item, columns)}\n </dl>\n );\n if (item === undefined) {\n return (\n <LoadingRegion label={intl.formatMessage(messages.loadingItem)}>\n <div inert aria-hidden=\"true\">\n {details}\n </div>\n </LoadingRegion>\n );\n }\n return details;\n}\n"],"mappings":"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"}
@@ -0,0 +1,20 @@
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 group = "panneau-item-details-group";
8
+ var nested = "panneau-item-details-nested";
9
+ var ItemDetails_module_default = {
10
+ details,
11
+ entry,
12
+ label,
13
+ value,
14
+ group,
15
+ nested
16
+ };
17
+ //#endregion
18
+ export { ItemDetails_module_default as default, details, entry, group, label, nested, value };
19
+
20
+ //# 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/* A group: its label over its values, which are indented. */\n.group > .label {\n color: var(--panneau-color-text);\n font-weight: var(--panneau-font-weight-medium);\n}\n\n.nested {\n padding-inline-start: var(--panneau-space-3);\n border-inline-start: var(--panneau-border-width) solid var(--panneau-color-border);\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 .group {\n display: flex;\n gap: var(--panneau-space-2);\n }\n}\n"],"mappings":""}
package/dist/List.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type ListOptions } from '@panneau/core';
2
- import { type ListViewProps } from './ListView';
3
- import type { ListItem } from './types';
2
+ import { type ListViewProps } from './ListView.js';
3
+ import type { ListItem } from './types.js';
4
4
  export interface ListProps extends Omit<ListViewProps, 'list' | 'total' | 'items'> {
5
5
  /** Every item: the list searches, filters, sorts and paginates them in memory. */
6
6
  items: readonly ListItem[] | undefined;
@@ -20,7 +20,7 @@ export interface ListProps extends Omit<ListViewProps, 'list' | 'total' | 'items
20
20
  * For items fetched page by page, create the state with `useList()`, fetch its `query`, and render
21
21
  * `ListView`.
22
22
  *
23
- * The page size and the default sort are read once.
23
+ * The page size, the default sort, the first layout and the calendar are read once.
24
24
  */
25
25
  export declare function List({ items, perPage, defaultSort, router, ...props }: ListProps): import("react").JSX.Element;
26
26
  //# sourceMappingURL=List.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"List.d.ts","sourceRoot":"","sources":["../src/List.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAW,MAAM,eAAe,CAAC;AAG1D,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IAC9E,kFAAkF;IAClF,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,CAAC;IACvC,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,EAAE,KAAK,EAAE,OAAY,EAAE,WAAgB,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EAAE,SAAS,+BAW1F"}
1
+ {"version":3,"file":"List.d.ts","sourceRoot":"","sources":["../src/List.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,WAAW,EAAW,MAAM,eAAe,CAAC;AAGrF,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IAC9E,kFAAkF;IAClF,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,CAAC;IACvC,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,EAAE,KAAK,EAAE,OAAY,EAAE,WAAgB,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EAAE,SAAS,+BAkB1F"}
package/dist/List.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ListView } from "./ListView.js";
2
2
  import { applyListQuery } from "./query.js";
3
- import { useList } from "@panneau/core";
3
+ import { DEFAULT_CALENDAR_PER_PAGE, useList } from "@panneau/core";
4
+ import { c } from "react/compiler-runtime";
4
5
  import { usePanneauIntl } from "@panneau/ui";
5
6
  import { jsx } from "react/jsx-runtime";
6
7
  //#region src/List.tsx
@@ -10,14 +11,23 @@ import { jsx } from "react/jsx-runtime";
10
11
  * For items fetched page by page, create the state with `useList()`, fetch its `query`, and render
11
12
  * `ListView`.
12
13
  *
13
- * The page size and the default sort are read once.
14
+ * The page size, the default sort, the first layout and the calendar are read once.
14
15
  */
15
- function List({ items, perPage = 20, defaultSort = [], router, ...props }) {
16
+ function List(t0) {
17
+ const $ = c(5);
18
+ const { items, perPage: t1, defaultSort: t2, router, ...props } = t0;
19
+ const perPage = t1 === void 0 ? 20 : t1;
20
+ const defaultSort = t2 === void 0 ? [] : t2;
16
21
  const intl = usePanneauIntl();
17
22
  const { query, list } = useList({
18
23
  defaults: {
19
24
  perPage,
20
- sort: defaultSort
25
+ sort: defaultSort,
26
+ ...props.layouts?.[0] !== void 0 ? { layout: props.layouts[0] } : {},
27
+ ...props.calendar !== null && props.calendar !== void 0 ? { calendar: {
28
+ ...props.calendar,
29
+ perPage: DEFAULT_CALENDAR_PER_PAGE
30
+ } } : {}
21
31
  },
22
32
  ...router !== void 0 ? { router } : {}
23
33
  });
@@ -25,12 +35,23 @@ function List({ items, perPage = 20, defaultSort = [], router, ...props }) {
25
35
  columns: props.columns,
26
36
  locale: intl.locale
27
37
  }) : void 0;
28
- return /* @__PURE__ */ jsx(ListView, {
29
- ...props,
30
- list,
31
- items: result?.items,
32
- total: result?.total
33
- });
38
+ const t3 = result?.items;
39
+ const t4 = result?.total;
40
+ let t5;
41
+ if ($[0] !== list || $[1] !== props || $[2] !== t3 || $[3] !== t4) {
42
+ t5 = /* @__PURE__ */ jsx(ListView, {
43
+ ...props,
44
+ list,
45
+ items: t3,
46
+ total: t4
47
+ });
48
+ $[0] = list;
49
+ $[1] = props;
50
+ $[2] = t3;
51
+ $[3] = t4;
52
+ $[4] = t5;
53
+ } else t5 = $[4];
54
+ return t5;
34
55
  }
35
56
  //#endregion
36
57
  export { List };
package/dist/List.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"List.js","names":[],"sources":["../src/List.tsx"],"sourcesContent":["import { type ListOptions, useList } from '@panneau/core';\nimport { usePanneauIntl } from '@panneau/ui';\n\nimport { ListView, type ListViewProps } from './ListView';\nimport { applyListQuery } from './query';\nimport type { ListItem } from './types';\n\nexport interface ListProps extends Omit<ListViewProps, 'list' | 'total' | 'items'> {\n /** Every item: the list searches, filters, sorts and paginates them in memory. */\n items: readonly ListItem[] | undefined;\n /** Items per page. Defaults to 20. */\n perPage?: number;\n /** Default sort, as `sort` query values (`['-published_at']`). */\n defaultSort?: string[];\n /**\n * Keeps the query in a router (`createHistoryRouter()`). Defaults to the router of the closest\n * `PanneauProvider`; `null` keeps it in memory.\n */\n router?: ListOptions['router'];\n}\n\n/**\n * A list of items held in memory, from columns and items, with or without a definition. It\n * creates its state with `useList()` of `@panneau/core`, and applies the query to `items` itself.\n * For items fetched page by page, create the state with `useList()`, fetch its `query`, and render\n * `ListView`.\n *\n * The page size and the default sort are read once.\n */\nexport function List({ items, perPage = 20, defaultSort = [], router, ...props }: ListProps) {\n const intl = usePanneauIntl();\n const { query, list } = useList({\n defaults: { perPage, sort: defaultSort },\n ...(router !== undefined ? { router } : {}),\n });\n const result =\n items !== undefined\n ? applyListQuery(items, query, { columns: props.columns, locale: intl.locale })\n : undefined;\n return <ListView {...props} list={list} items={result?.items} total={result?.total} />;\n}\n"],"mappings":";;;;;;;;;;;;;;AA6BA,SAAgB,KAAK,EAAE,OAAO,UAAU,IAAI,cAAc,CAAA,GAAI,QAAQ,GAAG,SAAoB;CACzF,MAAM,OAAO,eAAe;CAC5B,MAAM,EAAE,OAAO,SAAS,QAAQ;EAC5B,UAAU;GAAE;GAAS,MAAM;EAAY;EACvC,GAAI,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI,CAAC;CAC7C,CAAC;CACD,MAAM,SACF,UAAU,KAAA,IACJ,eAAe,OAAO,OAAO;EAAE,SAAS,MAAM;EAAS,QAAQ,KAAK;CAAO,CAAC,IAC5E,KAAA;CACV,OAAO,oBAAC,UAAD;EAAU,GAAI;EAAa;EAAM,OAAO,QAAQ;EAAO,OAAO,QAAQ;CAAM,CAAA;AACvF"}
1
+ {"version":3,"file":"List.js","names":["DEFAULT_CALENDAR_PER_PAGE","ListOptions","useList","usePanneauIntl","ListView","ListViewProps","applyListQuery","ListItem","ListProps","Omit","items","perPage","defaultSort","router","List","t0","$","_c","t1","t2","props","undefined","intl","query","list","defaults","sort","layouts","layout","calendar","result","columns","locale","t3","t4","total","t5","_c"],"sources":["../src/List.tsx"],"sourcesContent":["import { DEFAULT_CALENDAR_PER_PAGE, type ListOptions, useList } from '@panneau/core';\nimport { usePanneauIntl } from '@panneau/ui';\n\nimport { ListView, type ListViewProps } from './ListView';\nimport { applyListQuery } from './query';\nimport type { ListItem } from './types';\n\nexport interface ListProps extends Omit<ListViewProps, 'list' | 'total' | 'items'> {\n /** Every item: the list searches, filters, sorts and paginates them in memory. */\n items: readonly ListItem[] | undefined;\n /** Items per page. Defaults to 20. */\n perPage?: number;\n /** Default sort, as `sort` query values (`['-published_at']`). */\n defaultSort?: string[];\n /**\n * Keeps the query in a router (`createHistoryRouter()`). Defaults to the router of the closest\n * `PanneauProvider`; `null` keeps it in memory.\n */\n router?: ListOptions['router'];\n}\n\n/**\n * A list of items held in memory, from columns and items, with or without a definition. It\n * creates its state with `useList()` of `@panneau/core`, and applies the query to `items` itself.\n * For items fetched page by page, create the state with `useList()`, fetch its `query`, and render\n * `ListView`.\n *\n * The page size, the default sort, the first layout and the calendar are read once.\n */\nexport function List({ items, perPage = 20, defaultSort = [], router, ...props }: ListProps) {\n const intl = usePanneauIntl();\n const { query, list } = useList({\n defaults: {\n perPage,\n sort: defaultSort,\n ...(props.layouts?.[0] !== undefined ? { layout: props.layouts[0] } : {}),\n ...(props.calendar !== null && props.calendar !== undefined\n ? { calendar: { ...props.calendar, perPage: DEFAULT_CALENDAR_PER_PAGE } }\n : {}),\n },\n ...(router !== undefined ? { router } : {}),\n });\n const result =\n items !== undefined\n ? applyListQuery(items, query, { columns: props.columns, locale: intl.locale })\n : undefined;\n return <ListView {...props} list={list} items={result?.items} total={result?.total} />;\n}\n"],"mappings":";;;;;;;;;;;;;;;AA6BA,SAAOc,KAAAC,IAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAc,MAAA,EAAAP,OAAAC,SAAAO,IAAAN,aAAAO,IAAAN,QAAA,GAAAO,UAAAL;CAAS,MAAAJ,UAAAO,OAAAG,KAAAA,IAAA,KAAAH;CAAc,MAAAN,cAAAO,OAAAE,KAAAA,IAAA,CAAA,IAAAF;CACxC,MAAAG,OAAanB,eAAe;CAC5B,MAAA,EAAAoB,OAAAC,SAAwBtB,QAAQ;EAAAuB,UAClB;GAAAd;GAAAe,MAEAd;GAAW,GACbQ,MAAKO,UAAa,OAAKN,KAAAA,IAAvB,EAAAO,QAA6CR,MAAKO,QAAQ,GAAS,IAAnE,CAAmE;GAAC,GACpEP,MAAKS,aAAc,QAAQT,MAAKS,aAAcR,KAAAA,IAA9C,EAAAQ,UACc;IAAA,GAAKT,MAAKS;IAASlB,SAAWX;GAA0B,EACnE,IAFH,CAEG;EACX;EAAC,GACGa,WAAWQ,KAAAA,IAAX,EAAAR,OAAqC,IAArC,CAAqC;CAC7C,CAAC;CACD,MAAAiB,SACIpB,UAAUW,KAAAA,IACJf,eAAeI,OAAOa,OAAO;EAAAQ,SAAWX,MAAKW;EAAQC,QAAUV,KAAIU;CAAQ,CACnE,IAFdX,KAAAA;CAG2C,MAAAY,KAAAH,QAAMpB;CAAgB,MAAAwB,KAAAJ,QAAMK;CAAO,IAAAC;CAAA,IAAApB,EAAA,OAAAQ,QAAAR,EAAA,OAAAI,SAAAJ,EAAA,OAAAiB,MAAAjB,EAAA,OAAAkB,IAAA;EAA3EE,KAAA,oBAAC,UAAD;GAAS,GAAKhB;GAAaI;GAAa,OAAAS;GAAsB,OAAAC;EAAa,CAAA;EAAIlB,EAAA,KAAAQ;EAAAR,EAAA,KAAAI;EAAAJ,EAAA,KAAAiB;EAAAjB,EAAA,KAAAkB;EAAAlB,EAAA,KAAAoB;CAAA,OAAAA,KAAApB,EAAA;CAAA,OAA/EoB;AAA+E"}
@@ -0,0 +1,19 @@
1
+ import type { ListColumn, ListLayoutEntry } from './types.js';
2
+ export interface ListSkeletonProps {
3
+ Layout: ListLayoutEntry;
4
+ columns: readonly ListColumn[];
5
+ /** The page size: as many rows, up to what fits. */
6
+ perPage: number | undefined;
7
+ sort: readonly string[];
8
+ label: string;
9
+ /** Whether items have an image: the table draws the placeholder of their thumbnails. */
10
+ withImages?: boolean;
11
+ }
12
+ /**
13
+ * The first page of a list that loads (decision 0034): the list's own layout, with its columns
14
+ * and a skeleton for each value, as many rows as the page size, up to what fits. The layout is
15
+ * inert and hidden: its headers can't be used before the items are there, and the status message
16
+ * of the region says that the list loads.
17
+ */
18
+ export declare function ListSkeleton({ Layout, columns, perPage, sort, label, withImages, }: ListSkeletonProps): import("react").JSX.Element;
19
+ //# sourceMappingURL=ListSkeleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListSkeleton.d.ts","sourceRoot":"","sources":["../src/ListSkeleton.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAY,eAAe,EAAE,MAAM,SAAS,CAAC;AAUrE,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,oDAAoD;IACpD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EACzB,MAAM,EACN,OAAO,EACP,OAAO,EACP,IAAI,EACJ,KAAK,EACL,UAAkB,GACrB,EAAE,iBAAiB,+BAiCnB"}
@@ -0,0 +1,115 @@
1
+ import { messages } from "./messages.js";
2
+ import { c } from "react/compiler-runtime";
3
+ import { LoadingRegion, Skeleton, usePanneauIntl } from "@panneau/ui";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/ListSkeleton.tsx
6
+ /** The most rows a skeleton draws: about what fits in a window. */
7
+ var MAX_ROWS = 10;
8
+ /** Widths of the values, varied so the rows read as text. */
9
+ var WIDTHS = [
10
+ "72%",
11
+ "48%",
12
+ "64%",
13
+ "40%",
14
+ "56%",
15
+ "80%"
16
+ ];
17
+ var none = () => null;
18
+ var nothing = () => void 0;
19
+ /**
20
+ * The first page of a list that loads (decision 0034): the list's own layout, with its columns
21
+ * and a skeleton for each value, as many rows as the page size, up to what fits. The layout is
22
+ * inert and hidden: its headers can't be used before the items are there, and the status message
23
+ * of the region says that the list loads.
24
+ */
25
+ function ListSkeleton(t0) {
26
+ const $ = c(18);
27
+ const { Layout, columns, perPage, sort, label, withImages: t1 } = t0;
28
+ const withImages = t1 === void 0 ? false : t1;
29
+ const intl = usePanneauIntl();
30
+ const rows = Math.max(1, Math.min(perPage ?? MAX_ROWS, MAX_ROWS));
31
+ let t2;
32
+ if ($[0] !== rows) {
33
+ t2 = Array.from({ length: rows }, _temp);
34
+ $[0] = rows;
35
+ $[1] = t2;
36
+ } else t2 = $[1];
37
+ const items = t2;
38
+ let t3;
39
+ if ($[2] !== columns || $[3] !== items) {
40
+ t3 = (item, column) => {
41
+ const offset = items.indexOf(item) + columns.indexOf(column);
42
+ return /* @__PURE__ */ jsx(Skeleton, { width: WIDTHS[offset % WIDTHS.length] });
43
+ };
44
+ $[2] = columns;
45
+ $[3] = items;
46
+ $[4] = t3;
47
+ } else t3 = $[4];
48
+ const renderValue = t3;
49
+ let t4;
50
+ if ($[5] !== intl) {
51
+ t4 = intl.formatMessage(messages.loading);
52
+ $[5] = intl;
53
+ $[6] = t4;
54
+ } else t4 = $[6];
55
+ const t5 = withImages ? none : void 0;
56
+ let t6;
57
+ if ($[7] !== Layout || $[8] !== columns || $[9] !== items || $[10] !== label || $[11] !== renderValue || $[12] !== sort || $[13] !== t5) {
58
+ t6 = /* @__PURE__ */ jsx("div", {
59
+ inert: true,
60
+ "aria-hidden": "true",
61
+ children: /* @__PURE__ */ jsx(Layout, {
62
+ items,
63
+ columns,
64
+ renderValue,
65
+ getItemLabel: _temp2,
66
+ getItemHref: none,
67
+ getItemImage: t5,
68
+ isCurrent: _temp3,
69
+ selectable: false,
70
+ isSelected: _temp4,
71
+ onToggle: nothing,
72
+ renderActions: none,
73
+ sort,
74
+ onSort: nothing,
75
+ label,
76
+ pageSelection: null
77
+ })
78
+ });
79
+ $[7] = Layout;
80
+ $[8] = columns;
81
+ $[9] = items;
82
+ $[10] = label;
83
+ $[11] = renderValue;
84
+ $[12] = sort;
85
+ $[13] = t5;
86
+ $[14] = t6;
87
+ } else t6 = $[14];
88
+ let t7;
89
+ if ($[15] !== t4 || $[16] !== t6) {
90
+ t7 = /* @__PURE__ */ jsx(LoadingRegion, {
91
+ label: t4,
92
+ children: t6
93
+ });
94
+ $[15] = t4;
95
+ $[16] = t6;
96
+ $[17] = t7;
97
+ } else t7 = $[17];
98
+ return t7;
99
+ }
100
+ function _temp4() {
101
+ return false;
102
+ }
103
+ function _temp3() {
104
+ return false;
105
+ }
106
+ function _temp2(item_0) {
107
+ return item_0.id;
108
+ }
109
+ function _temp(_, index) {
110
+ return { id: `skeleton-${String(index)}` };
111
+ }
112
+ //#endregion
113
+ export { ListSkeleton };
114
+
115
+ //# sourceMappingURL=ListSkeleton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListSkeleton.js","names":["ReactNode","LoadingRegion","Skeleton","usePanneauIntl","messages","ListColumn","ListItem","ListLayoutEntry","MAX_ROWS","WIDTHS","none","nothing","undefined","ListSkeletonProps","Layout","columns","perPage","sort","label","withImages","ListSkeleton","t0","$","_c","t1","intl","rows","Math","max","min","t2","Array","from","length","_temp","items","t3","item","column","offset","indexOf","renderValue","t4","formatMessage","loading","t5","t6","_temp2","_temp3","_temp4","t7","item_0","id","_","index","String","_c"],"sources":["../src/ListSkeleton.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { LoadingRegion, Skeleton, usePanneauIntl } from '@panneau/ui';\n\nimport { messages } from './messages';\nimport type { ListColumn, ListItem, ListLayoutEntry } from './types';\n\n/** The most rows a skeleton draws: about what fits in a window. */\nconst MAX_ROWS = 10;\n/** Widths of the values, varied so the rows read as text. */\nconst WIDTHS = ['72%', '48%', '64%', '40%', '56%', '80%'];\n\nconst none = () => null;\nconst nothing = () => undefined;\n\nexport interface ListSkeletonProps {\n Layout: ListLayoutEntry;\n columns: readonly ListColumn[];\n /** The page size: as many rows, up to what fits. */\n perPage: number | undefined;\n sort: readonly string[];\n label: string;\n /** Whether items have an image: the table draws the placeholder of their thumbnails. */\n withImages?: boolean;\n}\n\n/**\n * The first page of a list that loads (decision 0034): the list's own layout, with its columns\n * and a skeleton for each value, as many rows as the page size, up to what fits. The layout is\n * inert and hidden: its headers can't be used before the items are there, and the status message\n * of the region says that the list loads.\n */\nexport function ListSkeleton({\n Layout,\n columns,\n perPage,\n sort,\n label,\n withImages = false,\n}: ListSkeletonProps) {\n const intl = usePanneauIntl();\n const rows = Math.max(1, Math.min(perPage ?? MAX_ROWS, MAX_ROWS));\n const items: ListItem[] = Array.from({ length: rows }, (_, index) => ({\n id: `skeleton-${String(index)}`,\n }));\n const renderValue = (item: ListItem, column: ListColumn): ReactNode => {\n const offset = items.indexOf(item) + columns.indexOf(column);\n return <Skeleton width={WIDTHS[offset % WIDTHS.length]} />;\n };\n return (\n <LoadingRegion label={intl.formatMessage(messages.loading)}>\n <div inert aria-hidden=\"true\">\n <Layout\n items={items}\n columns={columns}\n renderValue={renderValue}\n getItemLabel={(item) => item.id}\n getItemHref={none}\n getItemImage={withImages ? none : undefined}\n isCurrent={() => false}\n selectable={false}\n isSelected={() => false}\n onToggle={nothing}\n renderActions={none}\n sort={sort}\n onSort={nothing}\n label={label}\n pageSelection={null}\n />\n </div>\n </LoadingRegion>\n );\n}\n"],"mappings":";;;;;;AAQA,IAAMQ,WAAW;;AAEjB,IAAMC,SAAS;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAK;AAExD,IAAMC,aAAa;AACnB,IAAMC,gBAAgBC,KAAAA;;;;;;;AAmBtB,SAAOQ,aAAAC,IAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAAsB,MAAA,EAAAT,QAAAC,SAAAC,SAAAC,MAAAC,OAAAC,YAAAK,OAAAH;CAMzB,MAAAF,aAAAK,OAAAZ,KAAAA,IAAA,QAAAY;CAEA,MAAAC,OAAatB,eAAe;CAC5B,MAAAuB,OAAaC,KAAIC,IAAK,GAAGD,KAAIE,IAAKb,WAAAR,UAAqBA,QAAQ,CAAC;CAAE,IAAAsB;CAAA,IAAAR,EAAA,OAAAI,MAAA;EACxCI,KAAAC,MAAKC,KAAM,EAAAC,QAAUP,KAAK,GAAGQ,KAErD;EAACZ,EAAA,KAAAI;EAAAJ,EAAA,KAAAQ;CAAA,OAAAA,KAAAR,EAAA;CAFH,MAAAa,QAA0BL;CAEtB,IAAAM;CAAA,IAAAd,EAAA,OAAAP,WAAAO,EAAA,OAAAa,OAAA;EACgBC,MAAAC,MAAAC,WAAA;GAChB,MAAAC,SAAeJ,MAAKK,QAASH,IAAI,IAAItB,QAAOyB,QAASF,MAAM;GAAE,OACtD,oBAAC,UAAD,EAAiB,OAAA7B,OAAO8B,SAAS9B,OAAMwB,QAAQ,CAAA;EAAI;EAC7DX,EAAA,KAAAP;EAAAO,EAAA,KAAAa;EAAAb,EAAA,KAAAc;CAAA,OAAAA,KAAAd,EAAA;CAHD,MAAAmB,cAAoBL;CAGlB,IAAAM;CAAA,IAAApB,EAAA,OAAAG,MAAA;EAEwBiB,KAAAjB,KAAIkB,cAAevC,SAAQwC,OAAQ;EAACtB,EAAA,KAAAG;EAAAH,EAAA,KAAAoB;CAAA,OAAAA,KAAApB,EAAA;CAQhC,MAAAuB,KAAA1B,aAAAT,OAAAE,KAAAA;CAA6B,IAAAkC;CAAA,IAAAxB,EAAA,OAAAR,UAAAQ,EAAA,OAAAP,WAAAO,EAAA,OAAAa,SAAAb,EAAA,QAAAJ,SAAAI,EAAA,QAAAmB,eAAAnB,EAAA,QAAAL,QAAAK,EAAA,QAAAuB,IAAA;EAPnDC,KAAA,oBAAA,OAAA;GAAK,OAAA;GAAkB,eAAA;GACnB,UAAA,oBAAC,QAAD;IACWX;IACEpB;IACI0B;IACC,cAAAM;IACDrC,aAAAA;IACC,cAAAmC;IACH,WAAAG;IACC,YAAA;IACA,YAAAC;IACFtC,UAAAA;IACKD,eAAAA;IACTO;IACEN,QAAAA;IACDO;IACQ,eAAA;GAAI,CAAA;EAErB,CAAA;EAAAI,EAAA,KAAAR;EAAAQ,EAAA,KAAAP;EAAAO,EAAA,KAAAa;EAAAb,EAAA,MAAAJ;EAAAI,EAAA,MAAAmB;EAAAnB,EAAA,MAAAL;EAAAK,EAAA,MAAAuB;EAAAvB,EAAA,MAAAwB;CAAA,OAAAA,KAAAxB,EAAA;CAAA,IAAA4B;CAAA,IAAA5B,EAAA,QAAAoB,MAAApB,EAAA,QAAAwB,IAAA;EAnBVI,KAAA,oBAAC,eAAD;GAAsB,OAAAR;GAClBI,UAAAA;EADU,CAAA;EAoBExB,EAAA,MAAAoB;EAAApB,EAAA,MAAAwB;EAAAxB,EAAA,MAAA4B;CAAA,OAAAA,KAAA5B,EAAA;CAAA,OApBhB4B;AAoBgB;AAtCjB,SAAAD,SAAA;CAAA,OA6B+B;AAAK;AA7BpC,SAAAD,SAAA;CAAA,OA2B8B;AAAK;AA3BnC,SAAAD,OAAAI,QAAA;CAAA,OAwBqCd,OAAIe;AAAG;AAxB5C,SAAAlB,MAAAmB,GAAAC,OAAA;CAAA,OAUmE,EAAAF,IAC9D,YAAYG,OAAOD,KAAK,IAChC;AAAC"}