@panneau/lists 5.0.0-alpha.0 → 5.0.0-alpha.10

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 (120) hide show
  1. package/README.md +7 -3
  2. package/dist/ItemDetails.css +34 -0
  3. package/dist/ItemDetails.d.ts +18 -0
  4. package/dist/ItemDetails.d.ts.map +1 -0
  5. package/dist/ItemDetails.js +104 -0
  6. package/dist/ItemDetails.js.map +1 -0
  7. package/dist/ItemDetails.module.js +16 -0
  8. package/dist/ItemDetails.module.js.map +1 -0
  9. package/dist/List.d.ts +2 -2
  10. package/dist/List.js +54 -12
  11. package/dist/List.js.map +1 -1
  12. package/dist/ListSkeleton.d.ts +17 -0
  13. package/dist/ListSkeleton.d.ts.map +1 -0
  14. package/dist/ListSkeleton.js +111 -0
  15. package/dist/ListSkeleton.js.map +1 -0
  16. package/dist/ListView.css +16 -16
  17. package/dist/ListView.d.ts +40 -5
  18. package/dist/ListView.d.ts.map +1 -1
  19. package/dist/ListView.js +547 -211
  20. package/dist/ListView.js.map +1 -1
  21. package/dist/ListView.module.js +10 -10
  22. package/dist/actions/ActionButton.d.ts +4 -1
  23. package/dist/actions/ActionButton.d.ts.map +1 -1
  24. package/dist/actions/ActionButton.js +91 -23
  25. package/dist/actions/ActionButton.js.map +1 -1
  26. package/dist/actions/Actions.css +9 -9
  27. package/dist/actions/Actions.module.js +6 -6
  28. package/dist/actions/ConfirmDialog.d.ts +15 -3
  29. package/dist/actions/ConfirmDialog.d.ts.map +1 -1
  30. package/dist/actions/ConfirmDialog.js +103 -89
  31. package/dist/actions/ConfirmDialog.js.map +1 -1
  32. package/dist/actions/RowActions.d.ts +8 -6
  33. package/dist/actions/RowActions.d.ts.map +1 -1
  34. package/dist/actions/RowActions.js +40 -30
  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/icons.d.ts +8 -3
  41. package/dist/actions/icons.d.ts.map +1 -1
  42. package/dist/actions/icons.js +11 -7
  43. package/dist/actions/icons.js.map +1 -1
  44. package/dist/cx.js.map +1 -1
  45. package/dist/displays/Displays.css +25 -13
  46. package/dist/displays/Displays.module.js +18 -14
  47. package/dist/displays/Displays.module.js.map +1 -1
  48. package/dist/displays/displays.d.ts +18 -3
  49. package/dist/displays/displays.d.ts.map +1 -1
  50. package/dist/displays/displays.js +355 -12
  51. package/dist/displays/displays.js.map +1 -1
  52. package/dist/filters/Filters.css +34 -20
  53. package/dist/filters/Filters.d.ts +1 -1
  54. package/dist/filters/Filters.js.map +1 -1
  55. package/dist/filters/Filters.module.js +13 -9
  56. package/dist/filters/Filters.module.js.map +1 -1
  57. package/dist/filters/controls.d.ts +3 -3
  58. package/dist/filters/controls.d.ts.map +1 -1
  59. package/dist/filters/controls.js +171 -123
  60. package/dist/filters/controls.js.map +1 -1
  61. package/dist/filters/format.d.ts +1 -1
  62. package/dist/filters/format.d.ts.map +1 -1
  63. package/dist/filters/format.js +4 -1
  64. package/dist/filters/format.js.map +1 -1
  65. package/dist/index.d.ts +19 -17
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +5 -3
  68. package/dist/layouts/CardsLayout.css +22 -11
  69. package/dist/layouts/CardsLayout.d.ts +2 -2
  70. package/dist/layouts/CardsLayout.d.ts.map +1 -1
  71. package/dist/layouts/CardsLayout.js +39 -35
  72. package/dist/layouts/CardsLayout.js.map +1 -1
  73. package/dist/layouts/CardsLayout.module.js +8 -8
  74. package/dist/layouts/CardsLayout.module.js.map +1 -1
  75. package/dist/layouts/ItemTitle.d.ts +4 -2
  76. package/dist/layouts/ItemTitle.d.ts.map +1 -1
  77. package/dist/layouts/ItemTitle.js +12 -8
  78. package/dist/layouts/ItemTitle.js.map +1 -1
  79. package/dist/layouts/TableLayout.css +51 -35
  80. package/dist/layouts/TableLayout.d.ts +2 -2
  81. package/dist/layouts/TableLayout.d.ts.map +1 -1
  82. package/dist/layouts/TableLayout.js +38 -33
  83. package/dist/layouts/TableLayout.js.map +1 -1
  84. package/dist/layouts/TableLayout.module.js +14 -14
  85. package/dist/layouts/TableLayout.module.js.map +1 -1
  86. package/dist/layouts/builtIn.d.ts +1 -1
  87. package/dist/layouts/builtIn.js.map +1 -1
  88. package/dist/layouts/link.css +3 -3
  89. package/dist/layouts/link.module.js +1 -1
  90. package/dist/plugin.d.ts +1 -1
  91. package/dist/plugin.js.map +1 -1
  92. package/dist/query.d.ts +3 -3
  93. package/dist/query.d.ts.map +1 -1
  94. package/dist/query.js +7 -2
  95. package/dist/query.js.map +1 -1
  96. package/dist/selection.d.ts +1 -1
  97. package/dist/selection.js.map +1 -1
  98. package/dist/toolbar/LayoutSwitch.js.map +1 -1
  99. package/dist/toolbar/Pagination.d.ts +33 -0
  100. package/dist/toolbar/Pagination.d.ts.map +1 -1
  101. package/dist/toolbar/Pagination.js +282 -42
  102. package/dist/toolbar/Pagination.js.map +1 -1
  103. package/dist/toolbar/SearchField.js.map +1 -1
  104. package/dist/toolbar/SortSelect.d.ts +1 -1
  105. package/dist/toolbar/SortSelect.js.map +1 -1
  106. package/dist/toolbar/Toolbar.css +12 -12
  107. package/dist/toolbar/Toolbar.module.js +7 -7
  108. package/dist/types.d.ts +18 -2
  109. package/dist/types.d.ts.map +1 -1
  110. package/dist/useDraft.js.map +1 -1
  111. package/dist/useListState.js.map +1 -1
  112. package/dist/useRenderValue.d.ts +8 -0
  113. package/dist/useRenderValue.d.ts.map +1 -0
  114. package/dist/useRenderValue.js +64 -0
  115. package/dist/useRenderValue.js.map +1 -0
  116. package/dist/values.d.ts +3 -1
  117. package/dist/values.d.ts.map +1 -1
  118. package/dist/values.js +6 -2
  119. package/dist/values.js.map +1 -1
  120. package/package.json +9 -9
@@ -22,8 +22,8 @@ function alignClass(column) {
22
22
  * block that shows the label of each value.
23
23
  */
24
24
  function TableLayout(t0) {
25
- const $ = c(52);
26
- const { items, columns, renderValue, getItemLabel, getItemHref, selectable, isSelected, onToggle, renderActions, sort, onSort, label, pageSelection } = t0;
25
+ const $ = c(54);
26
+ const { items, columns, renderValue, getItemLabel, getItemHref, isCurrent, selectable, isSelected, onToggle, renderActions, sort, onSort, label, pageSelection } = t0;
27
27
  const intl = usePanneauIntl();
28
28
  let actions;
29
29
  let t1;
@@ -116,14 +116,16 @@ function TableLayout(t0) {
116
116
  $[22] = t5;
117
117
  } else t5 = $[22];
118
118
  let t6;
119
- if ($[23] !== actions || $[24] !== columns || $[25] !== getItemHref || $[26] !== getItemLabel || $[27] !== hasActions || $[28] !== intl || $[29] !== isSelected || $[30] !== items || $[31] !== onToggle || $[32] !== renderValue || $[33] !== selectable) {
119
+ if ($[23] !== actions || $[24] !== columns || $[25] !== getItemHref || $[26] !== getItemLabel || $[27] !== hasActions || $[28] !== intl || $[29] !== isCurrent || $[30] !== isSelected || $[31] !== items || $[32] !== onToggle || $[33] !== renderValue || $[34] !== selectable) {
120
120
  let t7;
121
- if ($[35] !== actions || $[36] !== columns || $[37] !== getItemHref || $[38] !== getItemLabel || $[39] !== hasActions || $[40] !== intl || $[41] !== isSelected || $[42] !== onToggle || $[43] !== renderValue || $[44] !== selectable) {
121
+ if ($[36] !== actions || $[37] !== columns || $[38] !== getItemHref || $[39] !== getItemLabel || $[40] !== hasActions || $[41] !== intl || $[42] !== isCurrent || $[43] !== isSelected || $[44] !== onToggle || $[45] !== renderValue || $[46] !== selectable) {
122
122
  t7 = (item_0, row) => {
123
123
  const selected = selectable && isSelected(item_0);
124
124
  const href = getItemHref?.(item_0) ?? null;
125
+ const current = isCurrent?.(item_0) ?? false;
125
126
  return /* @__PURE__ */ jsxs("tr", {
126
127
  "data-selected": selected || void 0,
128
+ "data-current": current || void 0,
127
129
  children: [
128
130
  selectable ? /* @__PURE__ */ jsx("td", {
129
131
  className: TableLayout_module_default.check,
@@ -140,6 +142,7 @@ function TableLayout(t0) {
140
142
  children: column_0.label ?? column_0.id
141
143
  }), /* @__PURE__ */ jsx("span", { children: index === 0 ? /* @__PURE__ */ jsx(ItemTitle, {
142
144
  href,
145
+ current,
143
146
  children: renderValue(item_0, column_0)
144
147
  }) : renderValue(item_0, column_0) })]
145
148
  }, column_0.id)),
@@ -150,18 +153,19 @@ function TableLayout(t0) {
150
153
  ]
151
154
  }, item_0.id);
152
155
  };
153
- $[35] = actions;
154
- $[36] = columns;
155
- $[37] = getItemHref;
156
- $[38] = getItemLabel;
157
- $[39] = hasActions;
158
- $[40] = intl;
159
- $[41] = isSelected;
160
- $[42] = onToggle;
161
- $[43] = renderValue;
162
- $[44] = selectable;
163
- $[45] = t7;
164
- } else t7 = $[45];
156
+ $[36] = actions;
157
+ $[37] = columns;
158
+ $[38] = getItemHref;
159
+ $[39] = getItemLabel;
160
+ $[40] = hasActions;
161
+ $[41] = intl;
162
+ $[42] = isCurrent;
163
+ $[43] = isSelected;
164
+ $[44] = onToggle;
165
+ $[45] = renderValue;
166
+ $[46] = selectable;
167
+ $[47] = t7;
168
+ } else t7 = $[47];
165
169
  t6 = items.map(t7);
166
170
  $[23] = actions;
167
171
  $[24] = columns;
@@ -169,21 +173,22 @@ function TableLayout(t0) {
169
173
  $[26] = getItemLabel;
170
174
  $[27] = hasActions;
171
175
  $[28] = intl;
172
- $[29] = isSelected;
173
- $[30] = items;
174
- $[31] = onToggle;
175
- $[32] = renderValue;
176
- $[33] = selectable;
177
- $[34] = t6;
178
- } else t6 = $[34];
176
+ $[29] = isCurrent;
177
+ $[30] = isSelected;
178
+ $[31] = items;
179
+ $[32] = onToggle;
180
+ $[33] = renderValue;
181
+ $[34] = selectable;
182
+ $[35] = t6;
183
+ } else t6 = $[35];
179
184
  let t7;
180
- if ($[46] !== t6) {
185
+ if ($[48] !== t6) {
181
186
  t7 = /* @__PURE__ */ jsx("tbody", { children: t6 });
182
- $[46] = t6;
183
- $[47] = t7;
184
- } else t7 = $[47];
187
+ $[48] = t6;
188
+ $[49] = t7;
189
+ } else t7 = $[49];
185
190
  let t8;
186
- if ($[48] !== label || $[49] !== t5 || $[50] !== t7) {
191
+ if ($[50] !== label || $[51] !== t5 || $[52] !== t7) {
187
192
  t8 = /* @__PURE__ */ jsx("div", {
188
193
  className: TableLayout_module_default.scroller,
189
194
  children: /* @__PURE__ */ jsxs("table", {
@@ -192,11 +197,11 @@ function TableLayout(t0) {
192
197
  children: [t5, t7]
193
198
  })
194
199
  });
195
- $[48] = label;
196
- $[49] = t5;
197
- $[50] = t7;
198
- $[51] = t8;
199
- } else t8 = $[51];
200
+ $[50] = label;
201
+ $[51] = t5;
202
+ $[52] = t7;
203
+ $[53] = t8;
204
+ } else t8 = $[53];
200
205
  return t8;
201
206
  }
202
207
  function _temp(node) {
@@ -1 +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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"}
1
+ {"version":3,"file":"TableLayout.js","names":["ArrowDown","ArrowUp","ArrowUpDown","Checkbox","Icon","usePanneauIntl","cx","messages","ListColumn","ListLayoutProps","ItemTitle","styles","getSortDirection","sort","column","first","id","alignClass","align","center","end","undefined","TableLayout","t0","$","_c","items","columns","renderValue","getItemLabel","getItemHref","isCurrent","selectable","isSelected","onToggle","renderActions","onSort","label","pageSelection","intl","actions","t1","t2","item","map","some","_temp","hasActions","check","t3","t4","direction","width","sortable","sorted","sortIcon","actionsCell","visuallyHidden","formatMessage","t5","t6","t7","item_0","row","selected","href","current","selectItem","column_0","index","title","cellLabel","t8","scroller","table","node","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 isCurrent,\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 const current = isCurrent?.(item) ?? false;\n return (\n <tr\n key={item.id}\n data-selected={selected || undefined}\n data-current={current || undefined}\n >\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} current={current}>\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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"}
@@ -1,20 +1,21 @@
1
1
  import "./TableLayout.css";
2
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";
3
+ var scroller = "panneau-table-layout-scroller";
4
+ var table = "panneau-table-layout-table";
5
+ var title = "panneau-table-layout-title";
6
+ var center = "panneau-table-layout-center";
7
+ var end = "panneau-table-layout-end";
8
+ var check = "panneau-table-layout-check";
9
+ var actionsCell = "panneau-table-layout-actions-cell";
10
+ var sort = "panneau-table-layout-sort";
11
+ var sortIcon = "panneau-table-layout-sort-icon";
12
+ var sorted = "panneau-table-layout-sorted";
13
+ var cellLabel = "panneau-table-layout-cell-label";
14
+ var visuallyHidden = "panneau-table-layout-visually-hidden";
15
15
  var TableLayout_module_default = {
16
16
  scroller,
17
17
  table,
18
+ title,
18
19
  center,
19
20
  end,
20
21
  check,
@@ -23,8 +24,7 @@ var TableLayout_module_default = {
23
24
  sortIcon,
24
25
  sorted,
25
26
  cellLabel,
26
- visuallyHidden,
27
- title
27
+ visuallyHidden
28
28
  };
29
29
  //#endregion
30
30
  export { actionsCell, cellLabel, center, check, TableLayout_module_default as default, end, scroller, sort, sortIcon, sorted, table, title, visuallyHidden };
@@ -1 +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":""}
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-row-padding-y) 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/* The title stays readable in a narrow list, such as next to an item's details: the table\n * scrolls instead. */\n.table td.title {\n min-width: 12rem;\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/* The item shown next to the list: a bar on its first cell. */\n.table tbody tr[data-current] td:first-child {\n box-shadow: inset 3px 0 0 var(--panneau-color-accent);\n}\n\n.table tbody tr[data-current] {\n background-color: var(--panneau-color-hover);\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 min-width: 0;\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":""}
@@ -1,4 +1,4 @@
1
- import type { ListLayoutEntry } from '../types';
1
+ import type { ListLayoutEntry } from '../types.js';
2
2
  /** The built-in list layouts, by id. `gallery` and `calendar` come later. */
3
3
  export declare const builtInLayouts: Readonly<Record<string, ListLayoutEntry>> & {
4
4
  table: ListLayoutEntry;
@@ -1 +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"}
1
+ {"version":3,"file":"builtIn.js","names":["ListLayoutEntry","CardsLayout","TableLayout","builtInLayouts","Readonly","Record","table","cards"],"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,IAAaG,iBAET;CACAG,OAAOJ;CACPK,OAAON;AACX"}
@@ -1,4 +1,4 @@
1
- .panneau-link-1crRKJ {
1
+ .panneau-link {
2
2
  color: inherit;
3
3
  font-weight: var(--panneau-font-weight-medium);
4
4
  text-decoration: none;
@@ -6,11 +6,11 @@
6
6
  cursor: pointer;
7
7
  }
8
8
 
9
- .panneau-link-1crRKJ:hover {
9
+ .panneau-link:hover {
10
10
  text-decoration: underline;
11
11
  }
12
12
 
13
- .panneau-link-1crRKJ[data-focus-visible] {
13
+ .panneau-link[data-focus-visible] {
14
14
  outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
15
15
  outline-offset: 2px;
16
16
  }
@@ -1,6 +1,6 @@
1
1
  import "./link.css";
2
2
  //#region src/layouts/link.module.css
3
- var link = "panneau-link-1crRKJ";
3
+ var link = "panneau-link";
4
4
  var link_module_default = { link };
5
5
  //#endregion
6
6
  export { link_module_default as default, link };
package/dist/plugin.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { DisplayEntry, ListLayoutEntry } from './types';
1
+ import type { DisplayEntry, ListLayoutEntry } from './types.js';
2
2
  /**
3
3
  * The built-in displays and layouts as a `@panneau/core` plugin, with the French messages of every
4
4
  * Panneau package (from `@panneau/intl`). Lists use the built-in displays and layouts without it:
@@ -1 +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"}
1
+ {"version":3,"file":"plugin.js","names":["fr","builtInDisplays","builtInLayouts","DisplayEntry","ListLayoutEntry","listsPlugin","id","displays","Readonly","Record","listLayouts","locales"],"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,IAAaK,cAKT;CACAC,IAAI;CACJC,UAAUN;CACVS,aAAaR;CACbS,SAAS,EAAEX,GAAG;AAClB"}
package/dist/query.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ListQuery } from '@panneau/protocol';
2
- import type { ListColumn, ListItem } from './types';
2
+ import type { ListColumn, ListItem } from './types.js';
3
3
  export interface LocalQueryOptions {
4
4
  /** The columns: values of localized fields are compared in `locale`. */
5
5
  columns?: readonly ListColumn[];
@@ -14,8 +14,8 @@ export interface LocalQueryResult<T extends ListItem> {
14
14
  }
15
15
  /**
16
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), search in every text value, sort, then the page. For a product
18
- * that has every item at hand.
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
19
  */
20
20
  export declare function applyListQuery<T extends ListItem>(items: readonly T[], query: ListQuery, options?: LocalQueryOptions): LocalQueryResult<T>;
21
21
  //# sourceMappingURL=query.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,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,CAuDrB"}
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 CHANGED
@@ -1,4 +1,5 @@
1
1
  import { getColumnValue, toText } from "./values.js";
2
+ import { isFilterRange, matchesFilterRange } from "@panneau/protocol/runtime";
2
3
  //#region src/query.ts
3
4
  function valueOf(item, key, options) {
4
5
  const column = options.columns?.find((candidate) => candidate.id === key);
@@ -6,13 +7,17 @@ function valueOf(item, key, options) {
6
7
  }
7
8
  /**
8
9
  * Applies a list query to items in memory, as a backend would: filters (the value, or one of the
9
- * values, matches as a string), search in every text value, sort, then the page. For a product
10
- * that has every item at hand.
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.
11
12
  */
12
13
  function applyListQuery(items, query, options = {}) {
13
14
  const locale = options.locale ?? "en";
14
15
  let result = [...items];
15
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
+ }
16
21
  const accepted = (Array.isArray(expected) ? expected : [expected]).map(String);
17
22
  result = result.filter((item) => {
18
23
  const value = valueOf(item, key, options);
package/dist/query.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"query.js","names":[],"sources":["../src/query.ts"],"sourcesContent":["import type { ListQuery } from '@panneau/protocol';\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), search in every text value, sort, then the page. For a product\n * 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 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":";;AAmBA,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,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"}
1
+ {"version":3,"file":"query.js","names":["ListQuery","isFilterRange","matchesFilterRange","ListColumn","ListItem","getColumnValue","toText","LocalQueryOptions","columns","locale","LocalQueryResult","items","T","total","valueOf","item","key","options","column","find","candidate","id","undefined","applyListQuery","query","result","Object","entries","filter","forEach","expected","accepted","Array","isArray","map","String","value","values","some","includes","q","trim","toLocaleLowerCase","sort","length","collator","Intl","Collator","numeric","sensitivity","a","b","part","descending","startsWith","slice","left","right","order","compareText","perPage","page","compare"],"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":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { ListSelection } from '@panneau/core';
2
- import type { ListItem } from './types';
2
+ import type { ListItem } from './types.js';
3
3
  /** Whether an item is selected. */
4
4
  export declare function isItemSelected(selection: ListSelection, id: string): boolean;
5
5
  /** How many items are selected, given the total of the list (or the count of items without it). */
@@ -1 +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"}
1
+ {"version":3,"file":"selection.js","names":["ListSelection","ListItem","isItemSelected","selection","id","mode","except","includes","ids","countSelected","total","Math","max","length","getPageSelection","items","selected","filter","item"],"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,SAAgBE,eAAeC,WAA0BC,IAAqB;CAC1E,OAAOD,UAAUE,SAAS,QAAQ,CAACF,UAAUG,OAAOC,SAASH,EAAE,IAAID,UAAUK,IAAID,SAASH,EAAE;AAChG;;AAGA,SAAgBK,cAAcN,WAA0BO,OAAuB;CAC3E,OAAOP,UAAUE,SAAS,QACpBM,KAAKC,IAAI,GAAGF,QAAQP,UAAUG,OAAOO,MAAM,IAC3CV,UAAUK,IAAIK;AACxB;;AAGA,SAAgBC,iBACZX,WACAY,OACuB;CACvB,MAAMC,WAAWD,MAAME,QAAQC,SAAShB,eAAeC,WAAWe,KAAKd,EAAE,CAAC,CAAC,CAACS;CAC5E,IAAIG,aAAa,KAAKD,MAAMF,WAAW,GACnC,OAAO;CAEX,OAAOG,aAAaD,MAAMF,SAAS,QAAQ;AAC/C"}
@@ -1 +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"}
1
+ {"version":3,"file":"LayoutSwitch.js","names":["LayoutGrid","LucideIcon","Rows3","Square","ToggleButton","ToggleButtonGroup","Icon","Tooltip","usePanneauIntl","messages","styles","ICONS","Record","table","cards","LayoutSwitchProps","layouts","value","onChange","layout","LayoutSwitch","t0","$","_c","intl","t1","formatMessage","layoutTable","t2","layoutCards","t3","labels","t4","t5","t6","keys","next","undefined","String","t7","t8","label","layoutButton","map","_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,IAAMW,QAAoC;CAAEE,OAAOX;CAAOY,OAAOd;AAAW;;AAS5E,SAAOoB,aAAAC,IAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAAsB,MAAA,EAAAP,SAAAC,OAAAC,aAAAG;CACzB,MAAAG,OAAahB,eAAe;CAAE,IAAAiB;CAAA,IAAAH,EAAA,OAAAE,MAAA;EAEnBC,KAAAD,KAAIE,cAAejB,SAAQkB,WAAY;EAACL,EAAA,KAAAE;EAAAF,EAAA,KAAAG;CAAA,OAAAA,KAAAH,EAAA;CAAA,IAAAM;CAAA,IAAAN,EAAA,OAAAE,MAAA;EACxCI,KAAAJ,KAAIE,cAAejB,SAAQoB,WAAY;EAACP,EAAA,KAAAE;EAAAF,EAAA,KAAAM;CAAA,OAAAA,KAAAN,EAAA;CAAA,IAAAQ;CAAA,IAAAR,EAAA,OAAAG,MAAAH,EAAA,OAAAM,IAAA;EAFZE,KAAA;GAAAjB,OAC5BY;GAAwCX,OACxCc;EACX;EAACN,EAAA,KAAAG;EAAAH,EAAA,KAAAM;EAAAN,EAAA,KAAAQ;CAAA,OAAAA,KAAAR,EAAA;CAHD,MAAAS,SAAuCD;CAGrC,IAAAE;CAAA,IAAAV,EAAA,OAAAE,MAAA;EAGkBQ,KAAAR,KAAIE,cAAejB,SAAQU,MAAO;EAACG,EAAA,KAAAE;EAAAF,EAAA,KAAAU;CAAA,OAAAA,KAAAV,EAAA;CAAA,IAAAW;CAAA,IAAAX,EAAA,OAAAL,OAAA;EAGjCgB,KAAA,CAAChB,KAAK;EAACK,EAAA,KAAAL;EAAAK,EAAA,MAAAW;CAAA,OAAAA,KAAAX,EAAA;CAAA,IAAAY;CAAA,IAAAZ,EAAA,QAAAJ,UAAA;EACFgB,MAAAC,SAAA;GACf,MAAA,CAAAC,QAAe,CAAA,GAAID,IAAI;GACvB,IAAIC,SAASC,KAAAA,GACTnB,SAASoB,OAAOF,IAAI,CAAC;EACxB;EACJd,EAAA,MAAAJ;EAAAI,EAAA,MAAAY;CAAA,OAAAA,KAAAZ,EAAA;CAAA,IAAAiB;CAAA,IAAAjB,EAAA,QAAAS,UAAAT,EAAA,QAAAN,SAAA;EAAA,IAAAwB;EAAA,IAAAlB,EAAA,QAAAS,QAAA;GAGYS,MAAArB,WAAA;IACT,MAAAsB,QAAcV,OAAOZ,WAAPA;IAAyB,OAEnC,oBAAC,SAAD;KAA+BsB,SAAAA;KAC3B,UAAA,oBAAC,cAAD;MACQtB,IAAAA;MACQsB,cAAAA;MACD,WAAA/B,uBAAMgC;MAEjB,UAAA,oBAAC,MAAD,EAAY,MAAA/B,MAAMQ,WAANhB,OAAuB,CAAA;KAL1B,CAAA;IADT,GAAMgB,MAAN;GAQE;GAEjBG,EAAA,MAAAS;GAAAT,EAAA,MAAAkB;EAAA,OAAAA,KAAAlB,EAAA;EAbAiB,KAAAvB,QAAO2B,IAAKH,EAaZ;EAAClB,EAAA,MAAAS;EAAAT,EAAA,MAAAN;EAAAM,EAAA,MAAAiB;CAAA,OAAAA,KAAAjB,EAAA;CAAA,IAAAkB;CAAA,IAAAlB,EAAA,QAAAU,MAAAV,EAAA,QAAAW,MAAAX,EAAA,QAAAY,MAAAZ,EAAA,QAAAiB,IAAA;EA1BNC,KAAA,oBAAC,mBAAD;GACgB,cAAAR;GACE,eAAA;GACd,wBAAA;GACc,cAAAC;GACK,mBAAAC;GAMR,WAAAxB,uBAAMM;GAEhBuB,UAAAA;EAba,CAAA;EA2BEjB,EAAA,MAAAU;EAAAV,EAAA,MAAAW;EAAAX,EAAA,MAAAY;EAAAZ,EAAA,MAAAiB;EAAAjB,EAAA,MAAAkB;CAAA,OAAAA,KAAAlB,EAAA;CAAA,OA3BpBkB;AA2BoB"}
@@ -1,3 +1,4 @@
1
+ import type { ListResponse } from '@panneau/protocol';
1
2
  export interface PaginationProps {
2
3
  page: number;
3
4
  perPage: number;
@@ -10,4 +11,36 @@ export interface PaginationProps {
10
11
  }
11
12
  /** The range of items shown, the page, and buttons to the previous and next pages. */
12
13
  export declare function Pagination({ page, perPage, total, onPageChange, perPageOptions, onPerPageChange, }: PaginationProps): import("react").JSX.Element;
14
+ export interface CursorPaginationProps {
15
+ perPage: number;
16
+ /** Whether there is a page before: the list isn't on its first page. */
17
+ hasPrevious: boolean;
18
+ /** Whether there is a page after: the page has a `nextCursor`. */
19
+ hasNext: boolean;
20
+ onPrevious: () => void;
21
+ onNext: () => void;
22
+ /** Page sizes to choose from. Without them, the page size can't be changed. */
23
+ perPageOptions?: readonly number[] | undefined;
24
+ onPerPageChange?: (perPage: number) => void;
25
+ }
26
+ /**
27
+ * Buttons to the previous and next pages of a list paged with cursors, which has no page numbers
28
+ * and no total (decision 0039).
29
+ */
30
+ export declare function CursorPagination({ perPage, hasPrevious, hasNext, onPrevious, onNext, perPageOptions, onPerPageChange, }: CursorPaginationProps): import("react").JSX.Element;
31
+ /**
32
+ * The props of a `ListView` that page it, from the `meta` of a page of the list: `total` for
33
+ * numbered pages, `cursors` for a list paged with cursors.
34
+ *
35
+ * ```tsx
36
+ * <ListView {...getPagingProps(data?.meta)} items={data?.data} … />
37
+ * ```
38
+ */
39
+ export declare function getPagingProps(meta: ListResponse['meta'] | undefined): {
40
+ total?: number;
41
+ cursors?: {
42
+ next: string | null;
43
+ previous?: string | null;
44
+ };
45
+ };
13
46
  //# sourceMappingURL=Pagination.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../src/toolbar/Pagination.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAOtD,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;AAED,MAAM,WAAW,qBAAqB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,WAAW,EAAE,OAAO,CAAC;IACrB,kEAAkE;IAClE,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,+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;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAC7B,OAAO,EACP,WAAW,EACX,OAAO,EACP,UAAU,EACV,MAAM,EACN,cAAmB,EACnB,eAAe,GAClB,EAAE,qBAAqB,+BAmCvB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,GAAG,SAAS,GAAG;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CAC/D,CAaA"}