@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
@@ -1,7 +1,8 @@
1
1
  import { messages } from "../messages.js";
2
2
  import Actions_module_default from "./Actions.module.js";
3
3
  import { c } from "react/compiler-runtime";
4
- import { Button, Dialog, usePanneauIntl } from "@panneau/ui";
4
+ import { getActionLabel } from "@panneau/intl";
5
+ import { Button, Dialog, Spinner, usePanneauIntl } from "@panneau/ui";
5
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
7
  //#region src/actions/ConfirmDialog.tsx
7
8
  /** Formats an ICU message of the definition (`{count, plural, …}`) in the locale. */
@@ -19,16 +20,20 @@ function needsConfirmation(event) {
19
20
  }
20
21
  /**
21
22
  * Asks before running an action (decision 0017): the action's `confirm` title and message (an ICU
22
- * message with `{count}`), or default ones, and how many selected items will be skipped.
23
+ * message with `{count}`), or default ones, and how many selected items will be skipped: those of
24
+ * the current page that don't allow it, or the backend's count for every item matching a query.
23
25
  */
24
26
  function ConfirmDialog(t0) {
25
27
  const $ = c(40);
26
- const { event, onConfirm, onCancel } = t0;
28
+ const { event, preview: t1, onConfirm, onCancel } = t0;
29
+ const preview = t1 === void 0 ? null : t1;
27
30
  const intl = usePanneauIntl();
28
31
  if (event === null) return null;
29
- const { action, count, skipped } = event;
32
+ const { action, count } = event;
33
+ const loading = preview?.status === "loading";
34
+ const skipped = preview?.status === "done" ? preview.skipped : event.skipped.length;
30
35
  let T0;
31
- let t1;
36
+ let t10;
32
37
  let t2;
33
38
  let t3;
34
39
  let t4;
@@ -37,119 +42,128 @@ function ConfirmDialog(t0) {
37
42
  let t7;
38
43
  let t8;
39
44
  let t9;
40
- if ($[0] !== action.confirm || $[1] !== action.destructive || $[2] !== action.label || $[3] !== count || $[4] !== event || $[5] !== intl || $[6] !== onCancel || $[7] !== onConfirm) {
45
+ if ($[0] !== action || $[1] !== count || $[2] !== event || $[3] !== intl || $[4] !== loading || $[5] !== onCancel || $[6] !== onConfirm) {
41
46
  const confirm = typeof action.confirm === "object" ? action.confirm : {};
47
+ const label = getActionLabel(action, intl);
42
48
  const values = {
43
49
  count,
44
- action: action.label
50
+ action: label
45
51
  };
46
52
  T0 = Dialog;
47
- t3 = true;
48
- if ($[18] !== onCancel) {
49
- t4 = (open) => {
53
+ t4 = true;
54
+ if ($[17] !== onCancel) {
55
+ t5 = (open) => {
50
56
  if (!open) onCancel();
51
57
  };
52
- $[18] = onCancel;
53
- $[19] = t4;
54
- } else t4 = $[19];
55
- t5 = "alertdialog";
56
- t6 = false;
57
- t7 = "sm";
58
- t8 = confirm.title !== void 0 ? formatDefinitionMessage(intl, confirm.title, values) : intl.formatMessage(messages.confirmTitle, { action: action.label });
59
- let t10;
60
- if ($[20] !== event || $[21] !== onConfirm) {
61
- t10 = () => onConfirm(event);
62
- $[20] = event;
63
- $[21] = onConfirm;
64
- $[22] = t10;
65
- } else t10 = $[22];
66
- t9 = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Button, {
58
+ $[17] = onCancel;
59
+ $[18] = t5;
60
+ } else t5 = $[18];
61
+ t6 = "alertdialog";
62
+ t7 = false;
63
+ t8 = "sm";
64
+ t9 = confirm.title !== void 0 ? formatDefinitionMessage(intl, confirm.title, values) : intl.formatMessage(messages.confirmTitle, { action: label });
65
+ let t11;
66
+ if ($[19] !== event || $[20] !== onConfirm) {
67
+ t11 = () => onConfirm(event);
68
+ $[19] = event;
69
+ $[20] = onConfirm;
70
+ $[21] = t11;
71
+ } else t11 = $[21];
72
+ t10 = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Button, {
67
73
  variant: "ghost",
68
74
  onPress: onCancel,
69
75
  children: confirm.cancelLabel ?? intl.formatMessage(messages.cancel)
70
76
  }), /* @__PURE__ */ jsx(Button, {
71
77
  variant: action.destructive === true ? "danger" : "primary",
72
78
  autoFocus: true,
73
- onPress: t10,
74
- children: confirm.confirmLabel ?? action.label
79
+ isDisabled: loading,
80
+ onPress: t11,
81
+ children: confirm.confirmLabel ?? label
75
82
  })] });
76
- t1 = Actions_module_default.message;
77
- t2 = confirm.message !== void 0 ? formatDefinitionMessage(intl, confirm.message, values) : intl.formatMessage(messages.confirmMessage, values);
78
- $[0] = action.confirm;
79
- $[1] = action.destructive;
80
- $[2] = action.label;
81
- $[3] = count;
82
- $[4] = event;
83
- $[5] = intl;
84
- $[6] = onCancel;
85
- $[7] = onConfirm;
86
- $[8] = T0;
87
- $[9] = t1;
88
- $[10] = t2;
89
- $[11] = t3;
90
- $[12] = t4;
91
- $[13] = t5;
92
- $[14] = t6;
93
- $[15] = t7;
94
- $[16] = t8;
95
- $[17] = t9;
83
+ t2 = Actions_module_default.message;
84
+ t3 = confirm.message !== void 0 ? formatDefinitionMessage(intl, confirm.message, values) : intl.formatMessage(messages.confirmMessage, values);
85
+ $[0] = action;
86
+ $[1] = count;
87
+ $[2] = event;
88
+ $[3] = intl;
89
+ $[4] = loading;
90
+ $[5] = onCancel;
91
+ $[6] = onConfirm;
92
+ $[7] = T0;
93
+ $[8] = t10;
94
+ $[9] = t2;
95
+ $[10] = t3;
96
+ $[11] = t4;
97
+ $[12] = t5;
98
+ $[13] = t6;
99
+ $[14] = t7;
100
+ $[15] = t8;
101
+ $[16] = t9;
96
102
  } else {
97
- T0 = $[8];
98
- t1 = $[9];
99
- t2 = $[10];
100
- t3 = $[11];
101
- t4 = $[12];
102
- t5 = $[13];
103
- t6 = $[14];
104
- t7 = $[15];
105
- t8 = $[16];
106
- t9 = $[17];
103
+ T0 = $[7];
104
+ t10 = $[8];
105
+ t2 = $[9];
106
+ t3 = $[10];
107
+ t4 = $[11];
108
+ t5 = $[12];
109
+ t6 = $[13];
110
+ t7 = $[14];
111
+ t8 = $[15];
112
+ t9 = $[16];
107
113
  }
108
- let t10;
109
- if ($[23] !== t1 || $[24] !== t2) {
110
- t10 = /* @__PURE__ */ jsx("p", {
111
- className: t1,
112
- children: t2
113
- });
114
- $[23] = t1;
115
- $[24] = t2;
116
- $[25] = t10;
117
- } else t10 = $[25];
118
114
  let t11;
119
- if ($[26] !== intl || $[27] !== skipped.length) {
120
- t11 = skipped.length > 0 ? /* @__PURE__ */ jsx("p", {
115
+ if ($[22] !== t2 || $[23] !== t3) {
116
+ t11 = /* @__PURE__ */ jsx("p", {
117
+ className: t2,
118
+ children: t3
119
+ });
120
+ $[22] = t2;
121
+ $[23] = t3;
122
+ $[24] = t11;
123
+ } else t11 = $[24];
124
+ let t12;
125
+ if ($[25] !== intl || $[26] !== loading || $[27] !== skipped) {
126
+ t12 = loading ? /* @__PURE__ */ jsx("div", {
127
+ className: Actions_module_default.skipped,
128
+ children: /* @__PURE__ */ jsx(Spinner, {
129
+ size: "sm",
130
+ label: intl.formatMessage(messages.confirmChecking),
131
+ showLabel: true
132
+ })
133
+ }) : skipped > 0 ? /* @__PURE__ */ jsx("p", {
121
134
  className: Actions_module_default.skipped,
122
- children: intl.formatMessage(messages.confirmSkipped, { count: skipped.length })
135
+ children: intl.formatMessage(messages.confirmSkipped, { count: skipped })
123
136
  }) : null;
124
- $[26] = intl;
125
- $[27] = skipped.length;
126
- $[28] = t11;
127
- } else t11 = $[28];
128
- let t12;
129
- if ($[29] !== T0 || $[30] !== t10 || $[31] !== t11 || $[32] !== t3 || $[33] !== t4 || $[34] !== t5 || $[35] !== t6 || $[36] !== t7 || $[37] !== t8 || $[38] !== t9) {
130
- t12 = /* @__PURE__ */ jsxs(T0, {
131
- isOpen: t3,
132
- onOpenChange: t4,
133
- role: t5,
134
- isDismissable: t6,
135
- size: t7,
136
- title: t8,
137
- footer: t9,
138
- children: [t10, t11]
137
+ $[25] = intl;
138
+ $[26] = loading;
139
+ $[27] = skipped;
140
+ $[28] = t12;
141
+ } else t12 = $[28];
142
+ let t13;
143
+ if ($[29] !== T0 || $[30] !== t10 || $[31] !== t11 || $[32] !== t12 || $[33] !== t4 || $[34] !== t5 || $[35] !== t6 || $[36] !== t7 || $[37] !== t8 || $[38] !== t9) {
144
+ t13 = /* @__PURE__ */ jsxs(T0, {
145
+ isOpen: t4,
146
+ onOpenChange: t5,
147
+ role: t6,
148
+ isDismissable: t7,
149
+ size: t8,
150
+ title: t9,
151
+ footer: t10,
152
+ children: [t11, t12]
139
153
  });
140
154
  $[29] = T0;
141
155
  $[30] = t10;
142
156
  $[31] = t11;
143
- $[32] = t3;
157
+ $[32] = t12;
144
158
  $[33] = t4;
145
159
  $[34] = t5;
146
160
  $[35] = t6;
147
161
  $[36] = t7;
148
162
  $[37] = t8;
149
163
  $[38] = t9;
150
- $[39] = t12;
151
- } else t12 = $[39];
152
- return t12;
164
+ $[39] = t13;
165
+ } else t13 = $[39];
166
+ return t13;
153
167
  }
154
168
  //#endregion
155
169
  export { ConfirmDialog, needsConfirmation };
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmDialog.js","names":["onCancel","_c","_Fragment","styles"],"sources":["../../src/actions/ConfirmDialog.tsx"],"sourcesContent":["import type { IntlShape } from 'react-intl';\n\nimport { Button, Dialog, usePanneauIntl } from '@panneau/ui';\n\nimport { messages } from '../messages';\nimport type { ListActionEvent } from '../types';\nimport styles from './Actions.module.css';\n\n/** Formats an ICU message of the definition (`{count, plural, …}`) in the locale. */\nfunction formatDefinitionMessage(\n intl: IntlShape,\n message: string,\n values: Record<string, unknown>,\n) {\n try {\n return String(\n intl.formatters\n .getMessageFormat(message, intl.locale)\n .format(values as Record<string, string | number>),\n );\n } catch {\n return message;\n }\n}\n\n/** Whether an action needs a confirmation: it asks for one, or some selected items are skipped. */\nexport function needsConfirmation(event: ListActionEvent): boolean {\n const { confirm } = event.action;\n return (confirm !== undefined && confirm !== false) || event.skipped.length > 0;\n}\n\nexport interface ConfirmDialogProps {\n /** The action to confirm, or `null` when the dialog is closed. */\n event: ListActionEvent | null;\n onConfirm: (event: ListActionEvent) => void;\n onCancel: () => void;\n}\n\n/**\n * Asks before running an action (decision 0017): the action's `confirm` title and message (an ICU\n * message with `{count}`), or default ones, and how many selected items will be skipped.\n */\nexport function ConfirmDialog({ event, onConfirm, onCancel }: ConfirmDialogProps) {\n const intl = usePanneauIntl();\n if (event === null) {\n return null;\n }\n const { action, count, skipped } = event;\n const confirm = typeof action.confirm === 'object' ? action.confirm : {};\n const values = { count, action: action.label };\n return (\n <Dialog\n isOpen\n onOpenChange={(open) => {\n if (!open) {\n onCancel();\n }\n }}\n role=\"alertdialog\"\n isDismissable={false}\n size=\"sm\"\n title={\n confirm.title !== undefined\n ? formatDefinitionMessage(intl, confirm.title, values)\n : intl.formatMessage(messages.confirmTitle, { action: action.label })\n }\n footer={\n <>\n <Button variant=\"ghost\" onPress={onCancel}>\n {confirm.cancelLabel ?? intl.formatMessage(messages.cancel)}\n </Button>\n <Button\n variant={action.destructive === true ? 'danger' : 'primary'}\n autoFocus\n onPress={() => onConfirm(event)}\n >\n {confirm.confirmLabel ?? action.label}\n </Button>\n </>\n }\n >\n <p className={styles.message}>\n {confirm.message !== undefined\n ? formatDefinitionMessage(intl, confirm.message, values)\n : intl.formatMessage(messages.confirmMessage, values)}\n </p>\n {skipped.length > 0 ? (\n <p className={styles.skipped}>\n {intl.formatMessage(messages.confirmSkipped, { count: skipped.length })}\n </p>\n ) : null}\n </Dialog>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ConfirmDialog.js","names":["IntlShape","getActionLabel","Button","Dialog","Spinner","usePanneauIntl","messages","ListActionEvent","ListActionPreview","styles","formatDefinitionMessage","intl","message","values","Record","String","formatters","getMessageFormat","locale","format","needsConfirmation","event","confirm","action","undefined","skipped","length","ConfirmPreview","status","ConfirmDialogProps","preview","onConfirm","onCancel","ConfirmDialog","t0","$","_c","t1","count","loading","T0","t10","t2","t3","t4","t5","t6","t7","t8","t9","label","open","title","formatMessage","confirmTitle","t11","cancelLabel","cancel","destructive","confirmLabel","confirmMessage","t12","confirmChecking","confirmSkipped","t13","_c","_Fragment","styles"],"sources":["../../src/actions/ConfirmDialog.tsx"],"sourcesContent":["import type { IntlShape } from 'react-intl';\n\nimport { getActionLabel } from '@panneau/intl';\nimport { Button, Dialog, Spinner, usePanneauIntl } from '@panneau/ui';\n\nimport { messages } from '../messages';\nimport type { ListActionEvent, ListActionPreview } from '../types';\nimport styles from './Actions.module.css';\n\n/** Formats an ICU message of the definition (`{count, plural, …}`) in the locale. */\nfunction formatDefinitionMessage(\n intl: IntlShape,\n message: string,\n values: Record<string, unknown>,\n) {\n try {\n return String(\n intl.formatters\n .getMessageFormat(message, intl.locale)\n .format(values as Record<string, string | number>),\n );\n } catch {\n return message;\n }\n}\n\n/** Whether an action needs a confirmation: it asks for one, or some selected items are skipped. */\nexport function needsConfirmation(event: ListActionEvent): boolean {\n const { confirm } = event.action;\n return (confirm !== undefined && confirm !== false) || event.skipped.length > 0;\n}\n\n/** The dry run of a query selection: in progress, or done with the backend's count. */\nexport type ConfirmPreview = { status: 'loading' } | ({ status: 'done' } & ListActionPreview);\n\nexport interface ConfirmDialogProps {\n /** The action to confirm, or `null` when the dialog is closed. */\n event: ListActionEvent | null;\n /**\n * What the backend told about a query selection. Its count of skipped items replaces the\n * count of the current page; while it loads, the dialog says so and can't be confirmed.\n */\n preview?: ConfirmPreview | null;\n onConfirm: (event: ListActionEvent) => void;\n onCancel: () => void;\n}\n\n/**\n * Asks before running an action (decision 0017): the action's `confirm` title and message (an ICU\n * message with `{count}`), or default ones, and how many selected items will be skipped: those of\n * the current page that don't allow it, or the backend's count for every item matching a query.\n */\nexport function ConfirmDialog({ event, preview = null, onConfirm, onCancel }: ConfirmDialogProps) {\n const intl = usePanneauIntl();\n if (event === null) {\n return null;\n }\n const { action, count } = event;\n const loading = preview?.status === 'loading';\n const skipped = preview?.status === 'done' ? preview.skipped : event.skipped.length;\n const confirm = typeof action.confirm === 'object' ? action.confirm : {};\n const label = getActionLabel(action, intl);\n const values = { count, action: label };\n return (\n <Dialog\n isOpen\n onOpenChange={(open) => {\n if (!open) {\n onCancel();\n }\n }}\n role=\"alertdialog\"\n isDismissable={false}\n size=\"sm\"\n title={\n confirm.title !== undefined\n ? formatDefinitionMessage(intl, confirm.title, values)\n : intl.formatMessage(messages.confirmTitle, { action: label })\n }\n footer={\n <>\n <Button variant=\"ghost\" onPress={onCancel}>\n {confirm.cancelLabel ?? intl.formatMessage(messages.cancel)}\n </Button>\n <Button\n variant={action.destructive === true ? 'danger' : 'primary'}\n autoFocus\n isDisabled={loading}\n onPress={() => onConfirm(event)}\n >\n {confirm.confirmLabel ?? label}\n </Button>\n </>\n }\n >\n <p className={styles.message}>\n {confirm.message !== undefined\n ? formatDefinitionMessage(intl, confirm.message, values)\n : intl.formatMessage(messages.confirmMessage, values)}\n </p>\n {loading ? (\n <div className={styles.skipped}>\n <Spinner\n size=\"sm\"\n label={intl.formatMessage(messages.confirmChecking)}\n showLabel\n />\n </div>\n ) : skipped > 0 ? (\n <p className={styles.skipped}>\n {intl.formatMessage(messages.confirmSkipped, { count: skipped })}\n </p>\n ) : null}\n </Dialog>\n );\n}\n"],"mappings":"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"}
@@ -1,17 +1,19 @@
1
+ import type { ItemAction } from '@panneau/core';
1
2
  import type { Action } from '@panneau/protocol';
2
- import type { ListItem } from '../types';
3
+ import { type ActionIcons } from './icons.js';
3
4
  export interface RowActionsProps {
4
- item: ListItem;
5
5
  /** The label of the item, for the accessible names of its actions. */
6
6
  itemLabel: string;
7
- /** Actions shown as buttons. */
8
- actions: readonly Action[];
7
+ /** Actions shown as buttons, with their links (`getItemActions()` of `@panneau/core`). */
8
+ actions: readonly ItemAction[];
9
9
  /** Actions in the overflow menu. */
10
- menu: readonly Action[];
10
+ menu: readonly ItemAction[];
11
11
  /** Id of the action that is running on this item, if any. */
12
12
  pending: string | null;
13
13
  onRun: (action: Action) => void;
14
+ /** Icons of actions by id, over the icon the action names. */
15
+ icons?: ActionIcons | undefined;
14
16
  }
15
17
  /** The actions of a row: buttons, then an overflow menu. */
16
- export declare function RowActions({ item, itemLabel, actions, menu, pending, onRun }: RowActionsProps): import("react").JSX.Element;
18
+ export declare function RowActions({ itemLabel, actions, menu, pending, onRun, icons }: RowActionsProps): import("react").JSX.Element;
17
19
  //# sourceMappingURL=RowActions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RowActions.d.ts","sourceRoot":"","sources":["../../src/actions/RowActions.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAIhD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAMzC,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,oCAAoC;IACpC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,6DAA6D;IAC7D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,eAAe,+BAuD7F"}
1
+ {"version":3,"file":"RowActions.d.ts","sourceRoot":"","sources":["../../src/actions/RowActions.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAMhD,OAAO,EAAE,KAAK,WAAW,EAAiB,MAAM,SAAS,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC5B,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,oCAAoC;IACpC,IAAI,EAAE,SAAS,UAAU,EAAE,CAAC;IAC5B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CACnC;AAED,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,eAAe,+BAyD9F"}
@@ -1,9 +1,9 @@
1
- import { getActionHref } from "./actions.js";
2
1
  import { messages } from "../messages.js";
3
2
  import Actions_module_default from "./Actions.module.js";
4
3
  import { getActionIcon } from "./icons.js";
5
4
  import { ActionButton } from "./ActionButton.js";
6
5
  import { c } from "react/compiler-runtime";
6
+ import { getActionLabel } from "@panneau/intl";
7
7
  import { IconButton, Menu, MenuItem, MenuTrigger, usePanneauIntl } from "@panneau/ui";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Ellipsis } from "lucide-react";
@@ -11,25 +11,29 @@ import { Ellipsis } from "lucide-react";
11
11
  /** The actions of a row: buttons, then an overflow menu. */
12
12
  function RowActions(t0) {
13
13
  const $ = c(23);
14
- const { item, itemLabel, actions, menu, pending, onRun } = t0;
14
+ const { itemLabel, actions, menu, pending, onRun, icons } = t0;
15
15
  const intl = usePanneauIntl();
16
16
  let t1;
17
- if ($[0] !== actions || $[1] !== intl || $[2] !== item || $[3] !== itemLabel || $[4] !== onRun || $[5] !== pending) {
17
+ if ($[0] !== actions || $[1] !== icons || $[2] !== intl || $[3] !== itemLabel || $[4] !== onRun || $[5] !== pending) {
18
18
  let t2;
19
- if ($[7] !== intl || $[8] !== item || $[9] !== itemLabel || $[10] !== onRun || $[11] !== pending) {
20
- t2 = (action) => /* @__PURE__ */ jsx(ActionButton, {
21
- action,
22
- href: getActionHref(action, item),
23
- isPending: pending === action.id,
24
- isDisabled: pending !== null && pending !== action.id,
25
- "aria-label": intl.formatMessage(messages.actionOnItem, {
26
- action: action.label,
27
- item: itemLabel
28
- }),
29
- onPress: () => onRun(action)
30
- }, action.id);
31
- $[7] = intl;
32
- $[8] = item;
19
+ if ($[7] !== icons || $[8] !== intl || $[9] !== itemLabel || $[10] !== onRun || $[11] !== pending) {
20
+ t2 = (t3) => {
21
+ const { action, href } = t3;
22
+ return /* @__PURE__ */ jsx(ActionButton, {
23
+ action,
24
+ icons,
25
+ href,
26
+ isPending: pending === action.id,
27
+ isDisabled: pending !== null && pending !== action.id,
28
+ "aria-label": intl.formatMessage(messages.actionOnItem, {
29
+ action: getActionLabel(action, intl),
30
+ item: itemLabel
31
+ }),
32
+ onPress: () => onRun(action)
33
+ }, action.id);
34
+ };
35
+ $[7] = icons;
36
+ $[8] = intl;
33
37
  $[9] = itemLabel;
34
38
  $[10] = onRun;
35
39
  $[11] = pending;
@@ -37,40 +41,46 @@ function RowActions(t0) {
37
41
  } else t2 = $[12];
38
42
  t1 = actions.map(t2);
39
43
  $[0] = actions;
40
- $[1] = intl;
41
- $[2] = item;
44
+ $[1] = icons;
45
+ $[2] = intl;
42
46
  $[3] = itemLabel;
43
47
  $[4] = onRun;
44
48
  $[5] = pending;
45
49
  $[6] = t1;
46
50
  } else t1 = $[6];
47
51
  let t2;
48
- if ($[13] !== intl || $[14] !== item || $[15] !== itemLabel || $[16] !== menu || $[17] !== onRun || $[18] !== pending) {
52
+ if ($[13] !== icons || $[14] !== intl || $[15] !== itemLabel || $[16] !== menu || $[17] !== onRun || $[18] !== pending) {
49
53
  t2 = menu.length > 0 ? /* @__PURE__ */ jsxs(MenuTrigger, { children: [/* @__PURE__ */ jsx(IconButton, {
50
54
  icon: Ellipsis,
51
55
  size: "sm",
52
56
  label: intl.formatMessage(messages.itemActions, { item: itemLabel }),
53
- isPending: pending !== null && menu.some((action_0) => action_0.id === pending)
57
+ isPending: pending !== null && menu.some((t3) => {
58
+ const { action: action_0 } = t3;
59
+ return action_0.id === pending;
60
+ })
54
61
  }), /* @__PURE__ */ jsx(Menu, {
55
62
  placement: "bottom end",
56
63
  onAction: (key) => {
57
- const action_1 = menu.find((candidate) => candidate.id === key);
58
- if (action_1 !== void 0 && getActionHref(action_1, item) === null) onRun(action_1);
64
+ const entry = menu.find((t4) => {
65
+ const { action: action_1 } = t4;
66
+ return action_1.id === key;
67
+ });
68
+ if (entry !== void 0 && entry.href === null) onRun(entry.action);
59
69
  },
60
- children: menu.map((action_2) => {
61
- const href = getActionHref(action_2, item);
62
- const icon = getActionIcon(action_2);
70
+ children: menu.map((t5) => {
71
+ const { action: action_2, href: href_0 } = t5;
72
+ const icon = getActionIcon(action_2, icons);
63
73
  return /* @__PURE__ */ jsx(MenuItem, {
64
74
  id: action_2.id,
65
75
  isDanger: action_2.destructive === true,
66
76
  ...icon !== void 0 ? { icon } : {},
67
- ...href !== null ? { href } : {},
68
- children: action_2.label
77
+ ...href_0 !== null ? { href: href_0 } : {},
78
+ children: getActionLabel(action_2, intl)
69
79
  }, action_2.id);
70
80
  })
71
81
  })] }) : null;
72
- $[13] = intl;
73
- $[14] = item;
82
+ $[13] = icons;
83
+ $[14] = intl;
74
84
  $[15] = itemLabel;
75
85
  $[16] = menu;
76
86
  $[17] = onRun;
@@ -1 +1 @@
1
- {"version":3,"file":"RowActions.js","names":["action","Ellipsis","_c","styles"],"sources":["../../src/actions/RowActions.tsx"],"sourcesContent":["import { Ellipsis } from 'lucide-react';\n\nimport type { Action } from '@panneau/protocol';\nimport { IconButton, Menu, MenuItem, MenuTrigger, usePanneauIntl } from '@panneau/ui';\n\nimport { messages } from '../messages';\nimport type { ListItem } from '../types';\nimport { ActionButton } from './ActionButton';\nimport styles from './Actions.module.css';\nimport { getActionHref } from './actions';\nimport { getActionIcon } from './icons';\n\nexport interface RowActionsProps {\n item: ListItem;\n /** The label of the item, for the accessible names of its actions. */\n itemLabel: string;\n /** Actions shown as buttons. */\n actions: readonly Action[];\n /** Actions in the overflow menu. */\n menu: readonly Action[];\n /** Id of the action that is running on this item, if any. */\n pending: string | null;\n onRun: (action: Action) => void;\n}\n\n/** The actions of a row: buttons, then an overflow menu. */\nexport function RowActions({ item, itemLabel, actions, menu, pending, onRun }: RowActionsProps) {\n const intl = usePanneauIntl();\n return (\n <div className={styles.row}>\n {actions.map((action) => (\n <ActionButton\n key={action.id}\n action={action}\n href={getActionHref(action, item)}\n isPending={pending === action.id}\n isDisabled={pending !== null && pending !== action.id}\n aria-label={intl.formatMessage(messages.actionOnItem, {\n action: action.label,\n item: itemLabel,\n })}\n onPress={() => onRun(action)}\n />\n ))}\n {menu.length > 0 ? (\n <MenuTrigger>\n <IconButton\n icon={Ellipsis}\n size=\"sm\"\n label={intl.formatMessage(messages.itemActions, { item: itemLabel })}\n isPending={pending !== null && menu.some((action) => action.id === pending)}\n />\n <Menu\n placement=\"bottom end\"\n onAction={(key) => {\n const action = menu.find((candidate) => candidate.id === key);\n if (action !== undefined && getActionHref(action, item) === null) {\n onRun(action);\n }\n }}\n >\n {menu.map((action) => {\n const href = getActionHref(action, item);\n const icon = getActionIcon(action);\n return (\n <MenuItem\n key={action.id}\n id={action.id}\n isDanger={action.destructive === true}\n {...(icon !== undefined ? { icon } : {})}\n {...(href !== null ? { href } : {})}\n >\n {action.label}\n </MenuItem>\n );\n })}\n </Menu>\n </MenuTrigger>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;AA0BA,SAAO,WAAA,IAAA;CAAA,MAAA,IAAAE,EAAA,EAAA;CAAoB,MAAA,EAAA,MAAA,WAAA,SAAA,MAAA,SAAA,UAAA;CACvB,MAAA,OAAa,eAAe;CAAE,IAAA;CAAA,IAAA,EAAA,OAAA,WAAA,EAAA,OAAA,QAAA,EAAA,OAAA,QAAA,EAAA,OAAA,aAAA,EAAA,OAAA,SAAA,EAAA,OAAA,SAAA;EAAA,IAAA;EAAA,IAAA,EAAA,OAAA,QAAA,EAAA,OAAA,QAAA,EAAA,OAAA,aAAA,EAAA,QAAA,SAAA,EAAA,QAAA,SAAA;GAGT,MAAA,WACT,oBAAC,cAAD;IAEY;IACF,MAAA,cAAc,QAAQ,IAAI;IACrB,WAAA,YAAY,OAAM;IACjB,YAAA,YAAY,QAAQ,YAAY,OAAM;IACtC,cAAA,KAAI,cAAe,SAAQ,cAAe;KAAA,QAC1C,OAAM;KAAM,MACd;IACV,CAAC;IACQ,eAAM,MAAM,MAAM;GAAC,GATvB,OAAM,EASiB;GAEnC,EAAA,KAAA;GAAA,EAAA,KAAA;GAAA,EAAA,KAAA;GAAA,EAAA,MAAA;GAAA,EAAA,MAAA;GAAA,EAAA,MAAA;EAAA,OAAA,KAAA,EAAA;EAbA,KAAA,QAAO,IAAK,EAaZ;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,QAAA,QAAA,EAAA,QAAA,QAAA,EAAA,QAAA,aAAA,EAAA,QAAA,QAAA,EAAA,QAAA,SAAA,EAAA,QAAA,SAAA;EACD,KAAA,KAAI,SAAU,IACX,qBAAC,aAAD,EAAA,UAAA,CACI,oBAAC,YAAD;GACUD,MAAA;GACD,MAAA;GACE,OAAA,KAAI,cAAe,SAAQ,aAAc,EAAA,MAAQ,UAAU,CAAC;GACxD,WAAA,YAAY,QAAQ,KAAI,MAAM,aAAYD,SAAM,OAAQ,OAAO;EAAC,CAAA,GAE/E,oBAAC,MAAD;GACc,WAAA;GACA,WAAA,QAAA;IACN,MAAA,WAAe,KAAI,MAAM,cAAe,UAAS,OAAQ,GAAG;IAC5D,IAAIA,aAAW,KAAA,KAAa,cAAcA,UAAQ,IAAI,MAAM,MACxD,MAAMA,QAAM;GACf;GAGJ,UAAA,KAAI,KAAK,aAAA;IACN,MAAA,OAAa,cAAcA,UAAQ,IAAI;IACvC,MAAA,OAAa,cAAcA,QAAM;IAAE,OAE/B,oBAAC,UAAD;KAEQ,IAAAA,SAAM;KACA,UAAAA,SAAM,gBAAiB;KAAI,GAChC,SAAS,KAAA,IAAT,EAAA,KAAiC,IAAjC,CAAiC;KAAC,GAClC,SAAS,OAAT,EAAA,KAA4B,IAA5B,CAA4B;KAEhCA,UAAAA,SAAM;IAPF,GACAA,SAAM,EADN;GAQE,CAElB;EAvBA,CAAA,CAPG,EAAA,CAAA,IADf;EAkCO,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,QAAA,MAAA,EAAA,QAAA,IAAA;EAjDZ,KAAA,qBAAA,OAAA;GAAgB,WAAAG,uBAAM;GAAtB,UAAA,CACK,IAcA,EAmCC;;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OAlDN;AAkDM"}
1
+ {"version":3,"file":"RowActions.js","names":["Ellipsis","ItemAction","getActionLabel","Action","IconButton","Menu","MenuItem","MenuTrigger","usePanneauIntl","messages","ActionButton","styles","ActionIcons","getActionIcon","RowActionsProps","itemLabel","actions","menu","pending","onRun","action","icons","RowActions","t0","$","_c","intl","t1","t2","t3","href","id","formatMessage","actionOnItem","item","map","length","itemActions","some","action_0","key","entry","find","t4","action_1","undefined","t5","action_2","href_0","icon","destructive","row","_c","styles"],"sources":["../../src/actions/RowActions.tsx"],"sourcesContent":["import { Ellipsis } from 'lucide-react';\n\nimport type { ItemAction } from '@panneau/core';\nimport { getActionLabel } from '@panneau/intl';\nimport type { Action } from '@panneau/protocol';\nimport { IconButton, Menu, MenuItem, MenuTrigger, usePanneauIntl } from '@panneau/ui';\n\nimport { messages } from '../messages';\nimport { ActionButton } from './ActionButton';\nimport styles from './Actions.module.css';\nimport { type ActionIcons, getActionIcon } from './icons';\n\nexport interface RowActionsProps {\n /** The label of the item, for the accessible names of its actions. */\n itemLabel: string;\n /** Actions shown as buttons, with their links (`getItemActions()` of `@panneau/core`). */\n actions: readonly ItemAction[];\n /** Actions in the overflow menu. */\n menu: readonly ItemAction[];\n /** Id of the action that is running on this item, if any. */\n pending: string | null;\n onRun: (action: Action) => void;\n /** Icons of actions by id, over the icon the action names. */\n icons?: ActionIcons | undefined;\n}\n\n/** The actions of a row: buttons, then an overflow menu. */\nexport function RowActions({ itemLabel, actions, menu, pending, onRun, icons }: RowActionsProps) {\n const intl = usePanneauIntl();\n return (\n <div className={styles.row}>\n {actions.map(({ action, href }) => (\n <ActionButton\n key={action.id}\n action={action}\n icons={icons}\n href={href}\n isPending={pending === action.id}\n isDisabled={pending !== null && pending !== action.id}\n aria-label={intl.formatMessage(messages.actionOnItem, {\n action: getActionLabel(action, intl),\n item: itemLabel,\n })}\n onPress={() => onRun(action)}\n />\n ))}\n {menu.length > 0 ? (\n <MenuTrigger>\n <IconButton\n icon={Ellipsis}\n size=\"sm\"\n label={intl.formatMessage(messages.itemActions, { item: itemLabel })}\n isPending={\n pending !== null && menu.some(({ action }) => action.id === pending)\n }\n />\n <Menu\n placement=\"bottom end\"\n onAction={(key) => {\n const entry = menu.find(({ action }) => action.id === key);\n if (entry !== undefined && entry.href === null) {\n onRun(entry.action);\n }\n }}\n >\n {menu.map(({ action, href }) => {\n const icon = getActionIcon(action, icons);\n return (\n <MenuItem\n key={action.id}\n id={action.id}\n isDanger={action.destructive === true}\n {...(icon !== undefined ? { icon } : {})}\n {...(href !== null ? { href } : {})}\n >\n {getActionLabel(action, intl)}\n </MenuItem>\n );\n })}\n </Menu>\n </MenuTrigger>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { Action, ActionPlacement } from '@panneau/protocol';
2
- import type { ListItem } from '../types';
2
+ import type { ListItem } from '../types.js';
3
3
  /** Actions of a list: a list (grouped by their placements), or already grouped by placement. */
4
4
  export type ListActions = readonly Action[] | Partial<Record<ActionPlacement, readonly Action[]>>;
5
5
  /**
@@ -8,9 +8,10 @@ export type ListActions = readonly Action[] | Partial<Record<ActionPlacement, re
8
8
  */
9
9
  export declare function groupListActions(actions: ListActions | undefined): Record<ActionPlacement, Action[]>;
10
10
  /**
11
- * Whether an action is available on an item (decision 0011). Without abilities, the item allows
12
- * everything and the backend decides. With abilities, a link is allowed unless the item says
13
- * otherwise, and other actions only when the item lists their id.
11
+ * Whether an action is available on an item (decisions 0011 and 0040), as `isActionAllowedOn()`
12
+ * of `@panneau/core` says: the built-in item actions need their ability (`view`, `update`,
13
+ * `duplicate`, `delete`), even on an item without abilities. Other links are allowed unless the
14
+ * item says otherwise, and other actions when the item lists their id, or has no abilities.
14
15
  */
15
16
  export declare function isAllowedOn(action: Action, item: ListItem): boolean;
16
17
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/actions/actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,gGAAgG;AAChG,MAAM,MAAM,WAAW,GAAG,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;AAElG;;;GAGG;AACH,wBAAgB,gBAAgB,CAC5B,OAAO,EAAE,WAAW,GAAG,SAAS,GACjC,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC,CASnC;AAMD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAWnE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAW5E;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,CAEhF"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/actions/actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,gGAAgG;AAChG,MAAM,MAAM,WAAW,GAAG,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;AAElG;;;GAGG;AACH,wBAAgB,gBAAgB,CAC5B,OAAO,EAAE,WAAW,GAAG,SAAS,GACjC,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC,CASnC;AAMD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAEnE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAE5E;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,CAEhF"}
@@ -1,4 +1,4 @@
1
- import { canRunAction, groupActions } from "@panneau/core";
1
+ import { canRunAction, fillActionUrl, groupActions, isActionAllowedOn } from "@panneau/core";
2
2
  //#region src/actions/actions.ts
3
3
  /**
4
4
  * Groups actions by placement, without those the user can't run on the resource
@@ -24,27 +24,20 @@ function isActionList(actions) {
24
24
  return Array.isArray(actions);
25
25
  }
26
26
  /**
27
- * Whether an action is available on an item (decision 0011). Without abilities, the item allows
28
- * everything and the backend decides. With abilities, a link is allowed unless the item says
29
- * otherwise, and other actions only when the item lists their id.
27
+ * Whether an action is available on an item (decisions 0011 and 0040), as `isActionAllowedOn()`
28
+ * of `@panneau/core` says: the built-in item actions need their ability (`view`, `update`,
29
+ * `duplicate`, `delete`), even on an item without abilities. Other links are allowed unless the
30
+ * item says otherwise, and other actions when the item lists their id, or has no abilities.
30
31
  */
31
32
  function isAllowedOn(action, item) {
32
- if (!canRunAction(action)) return false;
33
- if (item.abilities === void 0) return true;
34
- if (action.kind === "link") return item.abilities[action.id] !== false;
35
- return item.abilities[action.id] === true;
33
+ return isActionAllowedOn(action, item);
36
34
  }
37
35
  /**
38
36
  * The link of a `link` action for an item: its `url` template with `{id}` (and other `{field}`
39
37
  * values of the item) filled in, or `null` for an action with a `route` or without an item.
40
38
  */
41
39
  function getActionHref(action, item) {
42
- if (action.kind !== "link" || action.url === void 0) return null;
43
- const { url } = action;
44
- return url.replace(/\{([^}]+)\}/g, (match, name) => {
45
- const value = item?.[name];
46
- return typeof value === "string" || typeof value === "number" ? encodeURIComponent(String(value)) : match;
47
- });
40
+ return fillActionUrl(action, item);
48
41
  }
49
42
  /** Whether an action's scope includes another one. */
50
43
  function hasScope(action, scope) {
@@ -1 +1 @@
1
- {"version":3,"file":"actions.js","names":[],"sources":["../../src/actions/actions.ts"],"sourcesContent":["import { canRunAction, groupActions } from '@panneau/core';\nimport type { Action, ActionPlacement } from '@panneau/protocol';\n\nimport type { ListItem } from '../types';\n\n/** Actions of a list: a list (grouped by their placements), or already grouped by placement. */\nexport type ListActions = readonly Action[] | Partial<Record<ActionPlacement, readonly Action[]>>;\n\n/**\n * Groups actions by placement, without those the user can't run on the resource\n * (`abilities.run`). Actions already grouped (as `resolveList()` does) are filtered the same way.\n */\nexport function groupListActions(\n actions: ListActions | undefined,\n): Record<ActionPlacement, Action[]> {\n if (actions === undefined) {\n return { row: [], toolbar: [], form: [], menu: [] };\n }\n if (isActionList(actions)) {\n return groupActions(actions);\n }\n const pick = (placement: ActionPlacement) => (actions[placement] ?? []).filter(canRunAction);\n return { row: pick('row'), toolbar: pick('toolbar'), form: pick('form'), menu: pick('menu') };\n}\n\nfunction isActionList(actions: ListActions): actions is readonly Action[] {\n return Array.isArray(actions);\n}\n\n/**\n * Whether an action is available on an item (decision 0011). Without abilities, the item allows\n * everything and the backend decides. With abilities, a link is allowed unless the item says\n * otherwise, and other actions only when the item lists their id.\n */\nexport function isAllowedOn(action: Action, item: ListItem): boolean {\n if (!canRunAction(action)) {\n return false;\n }\n if (item.abilities === undefined) {\n return true;\n }\n if (action.kind === 'link') {\n return item.abilities[action.id] !== false;\n }\n return item.abilities[action.id] === true;\n}\n\n/**\n * The link of a `link` action for an item: its `url` template with `{id}` (and other `{field}`\n * values of the item) filled in, or `null` for an action with a `route` or without an item.\n */\nexport function getActionHref(action: Action, item?: ListItem): string | null {\n if (action.kind !== 'link' || action.url === undefined) {\n return null;\n }\n const { url } = action;\n return url.replace(/\\{([^}]+)\\}/g, (match, name: string) => {\n const value = item?.[name];\n return typeof value === 'string' || typeof value === 'number'\n ? encodeURIComponent(String(value))\n : match;\n });\n}\n\n/** Whether an action's scope includes another one. */\nexport function hasScope(action: Action, scope: Action['scope'][number]): boolean {\n return action.scope.includes(scope);\n}\n"],"mappings":";;;;;;AAYA,SAAgB,iBACZ,SACiC;CACjC,IAAI,YAAY,KAAA,GACZ,OAAO;EAAE,KAAK,CAAA;EAAI,SAAS,CAAA;EAAI,MAAM,CAAA;EAAI,MAAM,CAAA;CAAG;CAEtD,IAAI,aAAa,OAAO,GACpB,OAAO,aAAa,OAAO;CAE/B,MAAM,QAAQ,eAAgC,QAAQ,cAAc,CAAA,EAAA,CAAI,OAAO,YAAY;CAC3F,OAAO;EAAE,KAAK,KAAK,KAAK;EAAG,SAAS,KAAK,SAAS;EAAG,MAAM,KAAK,MAAM;EAAG,MAAM,KAAK,MAAM;CAAE;AAChG;AAEA,SAAS,aAAa,SAAoD;CACtE,OAAO,MAAM,QAAQ,OAAO;AAChC;;;;;;AAOA,SAAgB,YAAY,QAAgB,MAAyB;CACjE,IAAI,CAAC,aAAa,MAAM,GACpB,OAAO;CAEX,IAAI,KAAK,cAAc,KAAA,GACnB,OAAO;CAEX,IAAI,OAAO,SAAS,QAChB,OAAO,KAAK,UAAU,OAAO,QAAQ;CAEzC,OAAO,KAAK,UAAU,OAAO,QAAQ;AACzC;;;;;AAMA,SAAgB,cAAc,QAAgB,MAAgC;CAC1E,IAAI,OAAO,SAAS,UAAU,OAAO,QAAQ,KAAA,GACzC,OAAO;CAEX,MAAM,EAAE,QAAQ;CAChB,OAAO,IAAI,QAAQ,iBAAiB,OAAO,SAAiB;EACxD,MAAM,QAAQ,OAAO;EACrB,OAAO,OAAO,UAAU,YAAY,OAAO,UAAU,WAC/C,mBAAmB,OAAO,KAAK,CAAC,IAChC;CACV,CAAC;AACL;;AAGA,SAAgB,SAAS,QAAgB,OAAyC;CAC9E,OAAO,OAAO,MAAM,SAAS,KAAK;AACtC"}
1
+ {"version":3,"file":"actions.js","names":["canRunAction","fillActionUrl","groupActions","isActionAllowedOn","Action","ActionPlacement","ListItem","ListActions","Partial","Record","groupListActions","actions","undefined","row","toolbar","form","menu","isActionList","pick","placement","filter","Array","isArray","isAllowedOn","action","item","getActionHref","hasScope","scope","includes"],"sources":["../../src/actions/actions.ts"],"sourcesContent":["import { canRunAction, fillActionUrl, groupActions, isActionAllowedOn } from '@panneau/core';\nimport type { Action, ActionPlacement } from '@panneau/protocol';\n\nimport type { ListItem } from '../types';\n\n/** Actions of a list: a list (grouped by their placements), or already grouped by placement. */\nexport type ListActions = readonly Action[] | Partial<Record<ActionPlacement, readonly Action[]>>;\n\n/**\n * Groups actions by placement, without those the user can't run on the resource\n * (`abilities.run`). Actions already grouped (as `resolveList()` does) are filtered the same way.\n */\nexport function groupListActions(\n actions: ListActions | undefined,\n): Record<ActionPlacement, Action[]> {\n if (actions === undefined) {\n return { row: [], toolbar: [], form: [], menu: [] };\n }\n if (isActionList(actions)) {\n return groupActions(actions);\n }\n const pick = (placement: ActionPlacement) => (actions[placement] ?? []).filter(canRunAction);\n return { row: pick('row'), toolbar: pick('toolbar'), form: pick('form'), menu: pick('menu') };\n}\n\nfunction isActionList(actions: ListActions): actions is readonly Action[] {\n return Array.isArray(actions);\n}\n\n/**\n * Whether an action is available on an item (decisions 0011 and 0040), as `isActionAllowedOn()`\n * of `@panneau/core` says: the built-in item actions need their ability (`view`, `update`,\n * `duplicate`, `delete`), even on an item without abilities. Other links are allowed unless the\n * item says otherwise, and other actions when the item lists their id, or has no abilities.\n */\nexport function isAllowedOn(action: Action, item: ListItem): boolean {\n return isActionAllowedOn(action, item);\n}\n\n/**\n * The link of a `link` action for an item: its `url` template with `{id}` (and other `{field}`\n * values of the item) filled in, or `null` for an action with a `route` or without an item.\n */\nexport function getActionHref(action: Action, item?: ListItem): string | null {\n return fillActionUrl(action, item);\n}\n\n/** Whether an action's scope includes another one. */\nexport function hasScope(action: Action, scope: Action['scope'][number]): boolean {\n return action.scope.includes(scope);\n}\n"],"mappings":";;;;;;AAYA,SAAgBU,iBACZC,SACiC;CACjC,IAAIA,YAAYC,KAAAA,GACZ,OAAO;EAAEC,KAAK,CAAA;EAAIC,SAAS,CAAA;EAAIC,MAAM,CAAA;EAAIC,MAAM,CAAA;CAAG;CAEtD,IAAIC,aAAaN,OAAO,GACpB,OAAOT,aAAaS,OAAO;CAE/B,MAAMO,QAAQC,eAAgCR,QAAQQ,cAAc,CAAA,EAAA,CAAIC,OAAOpB,YAAY;CAC3F,OAAO;EAAEa,KAAKK,KAAK,KAAK;EAAGJ,SAASI,KAAK,SAAS;EAAGH,MAAMG,KAAK,MAAM;EAAGF,MAAME,KAAK,MAAM;CAAE;AAChG;AAEA,SAASD,aAAaN,SAAoD;CACtE,OAAOU,MAAMC,QAAQX,OAAO;AAChC;;;;;;;AAQA,SAAgBY,YAAYC,QAAgBC,MAAyB;CACjE,OAAOtB,kBAAkBqB,QAAQC,IAAI;AACzC;;;;;AAMA,SAAgBC,cAAcF,QAAgBC,MAAgC;CAC1E,OAAOxB,cAAcuB,QAAQC,IAAI;AACrC;;AAGA,SAAgBE,SAASH,QAAgBI,OAAyC;CAC9E,OAAOJ,OAAOI,MAAMC,SAASD,KAAK;AACtC"}
@@ -1,5 +1,10 @@
1
- import { type LucideIcon } from 'lucide-react';
2
1
  import type { Action } from '@panneau/protocol';
3
- /** The icon of an action, for the built-in ones. */
4
- export declare function getActionIcon(action: Action): LucideIcon | undefined;
2
+ import { type IconComponent } from '@panneau/ui';
3
+ /** Icons of actions by action id, for actions written in code (`{ archive: Archive }`). */
4
+ export type ActionIcons = Readonly<Record<string, IconComponent>>;
5
+ /**
6
+ * The icon of an action: the one given for its id in `icons`, then the Lucide icon its `icon`
7
+ * names (`"send"`, loaded when it first renders), then the icon of a built-in action.
8
+ */
9
+ export declare function getActionIcon(action: Action, icons?: ActionIcons): IconComponent | undefined;
5
10
  //# sourceMappingURL=icons.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/actions/icons.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,UAAU,EAKlB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAgBhD,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAEpE"}
1
+ {"version":3,"file":"icons.d.ts","sourceRoot":"","sources":["../../src/actions/icons.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,KAAK,aAAa,EAAgB,MAAM,aAAa,CAAC;AAE/D,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;AAalE;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,SAAS,CAU5F"}