@panneau/lists 4.1.1 → 5.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/README.md +116 -0
  2. package/dist/List.d.ts +26 -0
  3. package/dist/List.d.ts.map +1 -0
  4. package/dist/List.js +38 -0
  5. package/dist/List.js.map +1 -0
  6. package/dist/ListView.css +101 -0
  7. package/dist/ListView.d.ts +76 -0
  8. package/dist/ListView.d.ts.map +1 -0
  9. package/dist/ListView.js +325 -0
  10. package/dist/ListView.js.map +1 -0
  11. package/dist/ListView.module.js +28 -0
  12. package/dist/ListView.module.js.map +1 -0
  13. package/dist/actions/ActionButton.d.ts +18 -0
  14. package/dist/actions/ActionButton.d.ts.map +1 -0
  15. package/dist/actions/ActionButton.js +34 -0
  16. package/dist/actions/ActionButton.js.map +1 -0
  17. package/dist/actions/Actions.css +58 -0
  18. package/dist/actions/Actions.module.js +20 -0
  19. package/dist/actions/Actions.module.js.map +1 -0
  20. package/dist/actions/ConfirmDialog.d.ts +15 -0
  21. package/dist/actions/ConfirmDialog.d.ts.map +1 -0
  22. package/dist/actions/ConfirmDialog.js +157 -0
  23. package/dist/actions/ConfirmDialog.js.map +1 -0
  24. package/dist/actions/RowActions.d.ts +20 -0
  25. package/dist/actions/RowActions.d.ts.map +1 -0
  26. package/dist/actions/RowActions.js +99 -0
  27. package/dist/actions/RowActions.js.map +1 -0
  28. package/dist/actions/actions.d.ts +23 -0
  29. package/dist/actions/actions.d.ts.map +1 -0
  30. package/dist/actions/actions.js +56 -0
  31. package/dist/actions/actions.js.map +1 -0
  32. package/dist/actions/icons.d.ts +10 -0
  33. package/dist/actions/icons.d.ts.map +1 -0
  34. package/dist/actions/icons.js +27 -0
  35. package/dist/actions/icons.js.map +1 -0
  36. package/dist/cx.d.ts +3 -0
  37. package/dist/cx.d.ts.map +1 -0
  38. package/dist/cx.js +9 -0
  39. package/dist/cx.js.map +1 -0
  40. package/dist/displays/Displays.css +71 -0
  41. package/dist/displays/Displays.module.js +30 -0
  42. package/dist/displays/Displays.module.js.map +1 -0
  43. package/dist/displays/displays.d.ts +36 -0
  44. package/dist/displays/displays.d.ts.map +1 -0
  45. package/dist/displays/displays.js +570 -0
  46. package/dist/displays/displays.js.map +1 -0
  47. package/dist/filters/Filters.css +71 -0
  48. package/dist/filters/Filters.d.ts +38 -0
  49. package/dist/filters/Filters.d.ts.map +1 -0
  50. package/dist/filters/Filters.js +240 -0
  51. package/dist/filters/Filters.js.map +1 -0
  52. package/dist/filters/Filters.module.js +24 -0
  53. package/dist/filters/Filters.module.js.map +1 -0
  54. package/dist/filters/controls.d.ts +23 -0
  55. package/dist/filters/controls.d.ts.map +1 -0
  56. package/dist/filters/controls.js +431 -0
  57. package/dist/filters/controls.js.map +1 -0
  58. package/dist/filters/format.d.ts +16 -0
  59. package/dist/filters/format.d.ts.map +1 -0
  60. package/dist/filters/format.js +46 -0
  61. package/dist/filters/format.js.map +1 -0
  62. package/dist/index.d.ts +19 -10
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +18 -66
  65. package/dist/layouts/CardsLayout.css +72 -0
  66. package/dist/layouts/CardsLayout.d.ts +4 -0
  67. package/dist/layouts/CardsLayout.d.ts.map +1 -0
  68. package/dist/layouts/CardsLayout.js +111 -0
  69. package/dist/layouts/CardsLayout.js.map +1 -0
  70. package/dist/layouts/CardsLayout.module.js +24 -0
  71. package/dist/layouts/CardsLayout.module.js.map +1 -0
  72. package/dist/layouts/ItemTitle.d.ts +10 -0
  73. package/dist/layouts/ItemTitle.d.ts.map +1 -0
  74. package/dist/layouts/ItemTitle.js +30 -0
  75. package/dist/layouts/ItemTitle.js.map +1 -0
  76. package/dist/layouts/TableLayout.css +177 -0
  77. package/dist/layouts/TableLayout.d.ts +9 -0
  78. package/dist/layouts/TableLayout.d.ts.map +1 -0
  79. package/dist/layouts/TableLayout.js +208 -0
  80. package/dist/layouts/TableLayout.js.map +1 -0
  81. package/dist/layouts/TableLayout.module.js +32 -0
  82. package/dist/layouts/TableLayout.module.js.map +1 -0
  83. package/dist/layouts/builtIn.d.ts +6 -0
  84. package/dist/layouts/builtIn.d.ts.map +1 -0
  85. package/dist/layouts/builtIn.js +12 -0
  86. package/dist/layouts/builtIn.js.map +1 -0
  87. package/dist/layouts/link.css +16 -0
  88. package/dist/layouts/link.module.js +8 -0
  89. package/dist/layouts/link.module.js.map +1 -0
  90. package/dist/messages.d.ts +2 -0
  91. package/dist/messages.d.ts.map +1 -0
  92. package/dist/messages.js +1 -0
  93. package/dist/plugin.d.ts +13 -0
  94. package/dist/plugin.d.ts.map +1 -0
  95. package/dist/plugin.js +19 -0
  96. package/dist/plugin.js.map +1 -0
  97. package/dist/query.d.ts +21 -0
  98. package/dist/query.d.ts.map +1 -0
  99. package/dist/query.js +70 -0
  100. package/dist/query.js.map +1 -0
  101. package/dist/selection.d.ts +9 -0
  102. package/dist/selection.d.ts.map +1 -0
  103. package/dist/selection.js +19 -0
  104. package/dist/selection.js.map +1 -0
  105. package/dist/toolbar/LayoutSwitch.d.ts +8 -0
  106. package/dist/toolbar/LayoutSwitch.d.ts.map +1 -0
  107. package/dist/toolbar/LayoutSwitch.js +108 -0
  108. package/dist/toolbar/LayoutSwitch.js.map +1 -0
  109. package/dist/toolbar/Pagination.d.ts +13 -0
  110. package/dist/toolbar/Pagination.d.ts.map +1 -0
  111. package/dist/toolbar/Pagination.js +62 -0
  112. package/dist/toolbar/Pagination.js.map +1 -0
  113. package/dist/toolbar/SearchField.d.ts +9 -0
  114. package/dist/toolbar/SearchField.d.ts.map +1 -0
  115. package/dist/toolbar/SearchField.js +64 -0
  116. package/dist/toolbar/SearchField.js.map +1 -0
  117. package/dist/toolbar/SortSelect.d.ts +9 -0
  118. package/dist/toolbar/SortSelect.d.ts.map +1 -0
  119. package/dist/toolbar/SortSelect.js +90 -0
  120. package/dist/toolbar/SortSelect.js.map +1 -0
  121. package/dist/toolbar/Toolbar.css +72 -0
  122. package/dist/toolbar/Toolbar.module.js +22 -0
  123. package/dist/toolbar/Toolbar.module.js.map +1 -0
  124. package/dist/types.d.ts +106 -0
  125. package/dist/types.d.ts.map +1 -0
  126. package/dist/useDraft.d.ts +11 -0
  127. package/dist/useDraft.d.ts.map +1 -0
  128. package/dist/useDraft.js +77 -0
  129. package/dist/useDraft.js.map +1 -0
  130. package/dist/useListState.d.ts +4 -0
  131. package/dist/useListState.d.ts.map +1 -0
  132. package/dist/useListState.js +10 -0
  133. package/dist/useListState.js.map +1 -0
  134. package/dist/values.d.ts +21 -0
  135. package/dist/values.d.ts.map +1 -0
  136. package/dist/values.js +52 -0
  137. package/dist/values.js.map +1 -0
  138. package/package.json +27 -57
@@ -0,0 +1,38 @@
1
+ import type { Field, Filter, FilterValue } from '@panneau/protocol';
2
+ import type { FilterEntry, ListColumn } from '../types';
3
+ /** Labels of filter values (relation ids), by filter id, for the chips. */
4
+ export type FilterLabels = Readonly<Record<string, Readonly<Record<string, string>>>>;
5
+ /** Remembers the labels of filter values, for the chips of active filters. */
6
+ export declare function useFilterLabels(): {
7
+ labels: FilterLabels;
8
+ remember: (filter: string, value: string, label: string) => void;
9
+ };
10
+ interface FilterContext {
11
+ columns: readonly ListColumn[];
12
+ fields: readonly Field[];
13
+ labels: FilterLabels;
14
+ }
15
+ export interface FilterControlsProps extends FilterContext {
16
+ filters: readonly Filter[];
17
+ /** The current filter values, by filter id. */
18
+ values: Readonly<Record<string, FilterValue>>;
19
+ onChange: (id: string, value: FilterValue | undefined) => void;
20
+ onLabel: (filter: string, value: string, label: string) => void;
21
+ /** Controls by filter type, over the built-in ones. */
22
+ controls?: Readonly<Record<string, FilterEntry>> | undefined;
23
+ }
24
+ /** A control for each filter of the list. */
25
+ export declare function FilterControls({ filters, values, onChange, onLabel, controls, columns, fields, labels, }: FilterControlsProps): import("react").JSX.Element;
26
+ export interface FilterChipsProps extends FilterContext {
27
+ filters: readonly Filter[];
28
+ values: Readonly<Record<string, FilterValue>>;
29
+ /** The search, shown as a chip too. */
30
+ q?: string | undefined;
31
+ onRemove: (id: string) => void;
32
+ onClearSearch: () => void;
33
+ onClear: () => void;
34
+ }
35
+ /** The active filters and the search, as chips that remove them, and a button to clear them all. */
36
+ export declare function FilterChips({ filters, values, q, onRemove, onClearSearch, onClear, columns, fields, labels, }: FilterChipsProps): import("react").JSX.Element | null;
37
+ export {};
38
+ //# sourceMappingURL=Filters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Filters.d.ts","sourceRoot":"","sources":["../../src/filters/Filters.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIpE,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAKxD,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAEtF,8EAA8E;AAC9E,wBAAgB,eAAe,IAAI;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpE,CAWA;AAED,UAAU,aAAa;IACnB,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IAC/B,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC;CACxB;AAED,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACtD,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,+CAA+C;IAC/C,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAC9C,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,SAAS,KAAK,IAAI,CAAC;IAC/D,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,uDAAuD;IACvD,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,GAAG,SAAS,CAAC;CAChE;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,EAC3B,OAAO,EACP,MAAM,EACN,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,OAAO,EACP,MAAM,EACN,MAAM,GACT,EAAE,mBAAmB,+BA6BrB;AAED,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACnD,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAC9C,uCAAuC;IACvC,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,oGAAoG;AACpG,wBAAgB,WAAW,CAAC,EACxB,OAAO,EACP,MAAM,EACN,CAAC,EACD,QAAQ,EACR,aAAa,EACb,OAAO,EACP,OAAO,EACP,MAAM,EACN,MAAM,GACT,EAAE,gBAAgB,sCAmElB"}
@@ -0,0 +1,240 @@
1
+ import { messages } from "../messages.js";
2
+ import Filters_module_default from "./Filters.module.js";
3
+ import { builtInFilters } from "./controls.js";
4
+ import { formatFilterValue, getFilterLabel, getFilterOptions } from "./format.js";
5
+ import { c } from "react/compiler-runtime";
6
+ import { Button, IconButton, usePanneauIntl } from "@panneau/ui";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { X } from "lucide-react";
9
+ import { useState } from "react";
10
+ //#region src/filters/Filters.tsx
11
+ /** Remembers the labels of filter values, for the chips of active filters. */
12
+ function useFilterLabels() {
13
+ const $ = c(4);
14
+ let t0;
15
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
16
+ t0 = {};
17
+ $[0] = t0;
18
+ } else t0 = $[0];
19
+ const [labels, setLabels] = useState(t0);
20
+ let t1;
21
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
22
+ t1 = (filter, value, label) => setLabels((current) => current[filter]?.[value] === label ? current : {
23
+ ...current,
24
+ [filter]: {
25
+ ...current[filter],
26
+ [value]: label
27
+ }
28
+ });
29
+ $[1] = t1;
30
+ } else t1 = $[1];
31
+ let t2;
32
+ if ($[2] !== labels) {
33
+ t2 = {
34
+ labels,
35
+ remember: t1
36
+ };
37
+ $[2] = labels;
38
+ $[3] = t2;
39
+ } else t2 = $[3];
40
+ return t2;
41
+ }
42
+ /** A control for each filter of the list. */
43
+ function FilterControls(t0) {
44
+ const $ = c(22);
45
+ const { filters, values, onChange, onLabel, controls, columns, fields, labels } = t0;
46
+ const intl = usePanneauIntl();
47
+ let t1;
48
+ if ($[0] !== intl) {
49
+ t1 = intl.formatMessage(messages.filters);
50
+ $[0] = intl;
51
+ $[1] = t1;
52
+ } else t1 = $[1];
53
+ let t2;
54
+ if ($[2] !== columns || $[3] !== controls || $[4] !== fields || $[5] !== filters || $[6] !== labels || $[7] !== onChange || $[8] !== onLabel || $[9] !== values) {
55
+ let t3;
56
+ if ($[11] !== columns || $[12] !== controls || $[13] !== fields || $[14] !== labels || $[15] !== onChange || $[16] !== onLabel || $[17] !== values) {
57
+ t3 = (filter) => {
58
+ const Control = controls?.[filter.type] ?? builtInFilters[filter.type] ?? builtInFilters.text;
59
+ if (Control === void 0) return null;
60
+ return /* @__PURE__ */ jsx(Control, {
61
+ filter,
62
+ label: getFilterLabel(filter, columns, fields),
63
+ options: getFilterOptions(filter, columns, fields),
64
+ value: values[filter.id],
65
+ onChange: (value) => onChange(filter.id, value),
66
+ onLabel: (value_0, label) => onLabel(filter.id, value_0, label),
67
+ getValueLabel: (value_1) => labels[filter.id]?.[value_1] ?? null
68
+ }, filter.id);
69
+ };
70
+ $[11] = columns;
71
+ $[12] = controls;
72
+ $[13] = fields;
73
+ $[14] = labels;
74
+ $[15] = onChange;
75
+ $[16] = onLabel;
76
+ $[17] = values;
77
+ $[18] = t3;
78
+ } else t3 = $[18];
79
+ t2 = filters.map(t3);
80
+ $[2] = columns;
81
+ $[3] = controls;
82
+ $[4] = fields;
83
+ $[5] = filters;
84
+ $[6] = labels;
85
+ $[7] = onChange;
86
+ $[8] = onLabel;
87
+ $[9] = values;
88
+ $[10] = t2;
89
+ } else t2 = $[10];
90
+ let t3;
91
+ if ($[19] !== t1 || $[20] !== t2) {
92
+ t3 = /* @__PURE__ */ jsx("div", {
93
+ role: "group",
94
+ "aria-label": t1,
95
+ className: Filters_module_default.filters,
96
+ children: t2
97
+ });
98
+ $[19] = t1;
99
+ $[20] = t2;
100
+ $[21] = t3;
101
+ } else t3 = $[21];
102
+ return t3;
103
+ }
104
+ /** The active filters and the search, as chips that remove them, and a button to clear them all. */
105
+ function FilterChips(t0) {
106
+ const $ = c(29);
107
+ const { filters, values, q, onRemove, onClearSearch, onClear, columns, fields, labels } = t0;
108
+ const intl = usePanneauIntl();
109
+ let t1;
110
+ if ($[0] !== columns || $[1] !== fields || $[2] !== filters || $[3] !== intl || $[4] !== labels || $[5] !== values) {
111
+ t1 = Object.entries(values).map((t2) => {
112
+ const [id, value] = t2;
113
+ const filter = filters.find((candidate) => candidate.id === id) ?? {
114
+ id,
115
+ type: "text"
116
+ };
117
+ return {
118
+ id,
119
+ label: getFilterLabel(filter, columns, fields),
120
+ text: filter.type === "toggle" ? null : formatFilterValue(filter, value, {
121
+ intl,
122
+ options: getFilterOptions(filter, columns, fields),
123
+ getValueLabel: (entry) => labels[id]?.[entry] ?? null
124
+ })
125
+ };
126
+ });
127
+ $[0] = columns;
128
+ $[1] = fields;
129
+ $[2] = filters;
130
+ $[3] = intl;
131
+ $[4] = labels;
132
+ $[5] = values;
133
+ $[6] = t1;
134
+ } else t1 = $[6];
135
+ const chips = t1;
136
+ const search = q !== void 0 && q !== "" ? q : null;
137
+ if (chips.length === 0 && search === null) return null;
138
+ let t2;
139
+ if ($[7] !== intl) {
140
+ t2 = intl.formatMessage(messages.activeFilters);
141
+ $[7] = intl;
142
+ $[8] = t2;
143
+ } else t2 = $[8];
144
+ let t3;
145
+ if ($[9] !== intl || $[10] !== onClearSearch || $[11] !== search) {
146
+ t3 = search !== null ? /* @__PURE__ */ jsxs("li", {
147
+ className: Filters_module_default.chip,
148
+ children: [/* @__PURE__ */ jsx("span", {
149
+ className: Filters_module_default.chipText,
150
+ children: intl.formatMessage(messages.searchChip, { q: search })
151
+ }), /* @__PURE__ */ jsx(IconButton, {
152
+ icon: X,
153
+ size: "sm",
154
+ showTooltip: false,
155
+ label: intl.formatMessage(messages.removeFilter, { filter: intl.formatMessage(messages.searchChip, { q: search }) }),
156
+ onPress: onClearSearch
157
+ })]
158
+ }) : null;
159
+ $[9] = intl;
160
+ $[10] = onClearSearch;
161
+ $[11] = search;
162
+ $[12] = t3;
163
+ } else t3 = $[12];
164
+ let t4;
165
+ if ($[13] !== chips || $[14] !== intl || $[15] !== onRemove) {
166
+ t4 = chips.map((t5) => {
167
+ const { id: id_0, label: label_0, text: text_0 } = t5;
168
+ const name = text_0 !== null ? `${label_0}: ${text_0}` : label_0;
169
+ return /* @__PURE__ */ jsxs("li", {
170
+ className: Filters_module_default.chip,
171
+ children: [/* @__PURE__ */ jsx("span", {
172
+ className: Filters_module_default.chipText,
173
+ children: text_0 !== null ? /* @__PURE__ */ jsxs(Fragment, { children: [
174
+ /* @__PURE__ */ jsxs("span", {
175
+ className: Filters_module_default.chipLabel,
176
+ children: [label_0, ":"]
177
+ }),
178
+ " ",
179
+ text_0
180
+ ] }) : label_0
181
+ }), /* @__PURE__ */ jsx(IconButton, {
182
+ icon: X,
183
+ size: "sm",
184
+ showTooltip: false,
185
+ label: intl.formatMessage(messages.removeFilter, { filter: name }),
186
+ onPress: () => onRemove(id_0)
187
+ })]
188
+ }, id_0);
189
+ });
190
+ $[13] = chips;
191
+ $[14] = intl;
192
+ $[15] = onRemove;
193
+ $[16] = t4;
194
+ } else t4 = $[16];
195
+ let t5;
196
+ if ($[17] !== t2 || $[18] !== t3 || $[19] !== t4) {
197
+ t5 = /* @__PURE__ */ jsxs("ul", {
198
+ "aria-label": t2,
199
+ className: Filters_module_default.chips,
200
+ children: [t3, t4]
201
+ });
202
+ $[17] = t2;
203
+ $[18] = t3;
204
+ $[19] = t4;
205
+ $[20] = t5;
206
+ } else t5 = $[20];
207
+ let t6;
208
+ if ($[21] !== intl) {
209
+ t6 = intl.formatMessage(messages.clearFilters);
210
+ $[21] = intl;
211
+ $[22] = t6;
212
+ } else t6 = $[22];
213
+ let t7;
214
+ if ($[23] !== onClear || $[24] !== t6) {
215
+ t7 = /* @__PURE__ */ jsx(Button, {
216
+ variant: "ghost",
217
+ size: "sm",
218
+ onPress: onClear,
219
+ children: t6
220
+ });
221
+ $[23] = onClear;
222
+ $[24] = t6;
223
+ $[25] = t7;
224
+ } else t7 = $[25];
225
+ let t8;
226
+ if ($[26] !== t5 || $[27] !== t7) {
227
+ t8 = /* @__PURE__ */ jsxs("div", {
228
+ className: Filters_module_default.chips,
229
+ children: [t5, t7]
230
+ });
231
+ $[26] = t5;
232
+ $[27] = t7;
233
+ $[28] = t8;
234
+ } else t8 = $[28];
235
+ return t8;
236
+ }
237
+ //#endregion
238
+ export { FilterChips, FilterControls, useFilterLabels };
239
+
240
+ //# sourceMappingURL=Filters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Filters.js","names":["filter","value","X","onClearSearch","text","label","id","onClear","_c","styles","_Fragment"],"sources":["../../src/filters/Filters.tsx"],"sourcesContent":["import { X } from 'lucide-react';\nimport { useState } from 'react';\n\nimport type { Field, Filter, FilterValue } from '@panneau/protocol';\nimport { Button, IconButton, usePanneauIntl } from '@panneau/ui';\n\nimport { messages } from '../messages';\nimport type { FilterEntry, ListColumn } from '../types';\nimport styles from './Filters.module.css';\nimport { builtInFilters } from './controls';\nimport { formatFilterValue, getFilterLabel, getFilterOptions } from './format';\n\n/** Labels of filter values (relation ids), by filter id, for the chips. */\nexport type FilterLabels = Readonly<Record<string, Readonly<Record<string, string>>>>;\n\n/** Remembers the labels of filter values, for the chips of active filters. */\nexport function useFilterLabels(): {\n labels: FilterLabels;\n remember: (filter: string, value: string, label: string) => void;\n} {\n const [labels, setLabels] = useState<FilterLabels>({});\n return {\n labels,\n remember: (filter, value, label) =>\n setLabels((current) =>\n current[filter]?.[value] === label\n ? current\n : { ...current, [filter]: { ...current[filter], [value]: label } },\n ),\n };\n}\n\ninterface FilterContext {\n columns: readonly ListColumn[];\n fields: readonly Field[];\n labels: FilterLabels;\n}\n\nexport interface FilterControlsProps extends FilterContext {\n filters: readonly Filter[];\n /** The current filter values, by filter id. */\n values: Readonly<Record<string, FilterValue>>;\n onChange: (id: string, value: FilterValue | undefined) => void;\n onLabel: (filter: string, value: string, label: string) => void;\n /** Controls by filter type, over the built-in ones. */\n controls?: Readonly<Record<string, FilterEntry>> | undefined;\n}\n\n/** A control for each filter of the list. */\nexport function FilterControls({\n filters,\n values,\n onChange,\n onLabel,\n controls,\n columns,\n fields,\n labels,\n}: FilterControlsProps) {\n const intl = usePanneauIntl();\n return (\n <div\n role=\"group\"\n aria-label={intl.formatMessage(messages.filters)}\n className={styles.filters}\n >\n {filters.map((filter) => {\n const Control =\n controls?.[filter.type] ?? builtInFilters[filter.type] ?? builtInFilters.text;\n if (Control === undefined) {\n return null;\n }\n return (\n <Control\n key={filter.id}\n filter={filter}\n label={getFilterLabel(filter, columns, fields)}\n options={getFilterOptions(filter, columns, fields)}\n value={values[filter.id]}\n onChange={(value) => onChange(filter.id, value)}\n onLabel={(value, label) => onLabel(filter.id, value, label)}\n getValueLabel={(value) => labels[filter.id]?.[value] ?? null}\n />\n );\n })}\n </div>\n );\n}\n\nexport interface FilterChipsProps extends FilterContext {\n filters: readonly Filter[];\n values: Readonly<Record<string, FilterValue>>;\n /** The search, shown as a chip too. */\n q?: string | undefined;\n onRemove: (id: string) => void;\n onClearSearch: () => void;\n onClear: () => void;\n}\n\n/** The active filters and the search, as chips that remove them, and a button to clear them all. */\nexport function FilterChips({\n filters,\n values,\n q,\n onRemove,\n onClearSearch,\n onClear,\n columns,\n fields,\n labels,\n}: FilterChipsProps) {\n const intl = usePanneauIntl();\n const chips = Object.entries(values).map(([id, value]) => {\n const filter = filters.find((candidate) => candidate.id === id) ?? { id, type: 'text' };\n const label = getFilterLabel(filter, columns, fields);\n const text =\n filter.type === 'toggle'\n ? null\n : formatFilterValue(filter, value, {\n intl,\n options: getFilterOptions(filter, columns, fields),\n getValueLabel: (entry) => labels[id]?.[entry] ?? null,\n });\n return { id, label, text };\n });\n const search = q !== undefined && q !== '' ? q : null;\n if (chips.length === 0 && search === null) {\n return null;\n }\n return (\n <div className={styles.chips}>\n <ul aria-label={intl.formatMessage(messages.activeFilters)} className={styles.chips}>\n {search !== null ? (\n <li className={styles.chip}>\n <span className={styles.chipText}>\n {intl.formatMessage(messages.searchChip, { q: search })}\n </span>\n <IconButton\n icon={X}\n size=\"sm\"\n showTooltip={false}\n label={intl.formatMessage(messages.removeFilter, {\n filter: intl.formatMessage(messages.searchChip, { q: search }),\n })}\n onPress={onClearSearch}\n />\n </li>\n ) : null}\n {chips.map(({ id, label, text }) => {\n const name = text !== null ? `${label}: ${text}` : label;\n return (\n <li key={id} className={styles.chip}>\n <span className={styles.chipText}>\n {text !== null ? (\n <>\n <span className={styles.chipLabel}>{label}:</span> {text}\n </>\n ) : (\n label\n )}\n </span>\n <IconButton\n icon={X}\n size=\"sm\"\n showTooltip={false}\n label={intl.formatMessage(messages.removeFilter, { filter: name })}\n onPress={() => onRemove(id)}\n />\n </li>\n );\n })}\n </ul>\n <Button variant=\"ghost\" size=\"sm\" onPress={onClear}>\n {intl.formatMessage(messages.clearFilters)}\n </Button>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import "./Filters.css";
2
+ //#region src/filters/Filters.module.css
3
+ var filters = "panneau-filters-9H41r8";
4
+ var control = "panneau-control-vD-jl2";
5
+ var toggle = "panneau-toggle-aBWzSX";
6
+ var range = "panneau-range-lY9OdJ";
7
+ var chips = "panneau-chips-zPj5hD";
8
+ var chip = "panneau-chip-RQRPo6";
9
+ var chipText = "panneau-chipText-Uofas9";
10
+ var chipLabel = "panneau-chipLabel-QsALcI";
11
+ var Filters_module_default = {
12
+ filters,
13
+ control,
14
+ toggle,
15
+ range,
16
+ chips,
17
+ chip,
18
+ chipText,
19
+ chipLabel
20
+ };
21
+ //#endregion
22
+ export { chip, chipLabel, chipText, chips, control, Filters_module_default as default, filters, range, toggle };
23
+
24
+ //# sourceMappingURL=Filters.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Filters.module.js","names":[],"sources":["../../src/filters/Filters.module.css"],"sourcesContent":[".filters {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-end;\n gap: var(--panneau-space-3);\n}\n\n.control {\n width: 12rem;\n max-width: 100%;\n}\n\n.toggle {\n align-self: center;\n min-height: var(--panneau-control-height);\n display: flex;\n align-items: center;\n}\n\n.range {\n display: flex;\n flex-wrap: wrap;\n gap: var(--panneau-space-2);\n max-width: 100%;\n}\n\n.range > :not(legend) {\n width: 11rem;\n max-width: 100%;\n}\n\n.chips {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--panneau-space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n gap: var(--panneau-space-1);\n max-width: 100%;\n padding-inline-start: var(--panneau-space-3);\n font-size: var(--panneau-font-size-sm);\n background-color: var(--panneau-color-surface-sunken);\n border: var(--panneau-border-width) solid var(--panneau-color-border);\n border-radius: var(--panneau-radius-full);\n}\n\n.chipText {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.chipLabel {\n color: var(--panneau-color-text-muted);\n}\n\n@container panneau-list (max-width: 40rem) {\n .filters,\n .control,\n .range,\n .range > :not(legend) {\n width: 100%;\n }\n}\n"],"mappings":""}
@@ -0,0 +1,23 @@
1
+ import type { FilterControlProps, FilterEntry } from '../types';
2
+ /** A text filter: the list changes once the user stops typing. */
3
+ export declare function TextFilter({ label, value, onChange }: FilterControlProps): import("react").JSX.Element;
4
+ /** A choice among the options, or several with `multiple`. */
5
+ export declare function SelectFilter({ filter, label, options, value, onChange }: FilterControlProps): import("react").JSX.Element;
6
+ /** On or off: on filters with `true`, off removes the filter. */
7
+ export declare function ToggleFilter({ label, value, onChange }: FilterControlProps): import("react").JSX.Element;
8
+ /** A day (`2026-10-15`). */
9
+ export declare function DateFilter({ label, value, onChange }: FilterControlProps): import("react").JSX.Element;
10
+ /**
11
+ * A range of days, sent as its bounds (`filter[published_at][from]=2026-01-01&…[to]=…`). Either end
12
+ * can be open: it is left out.
13
+ */
14
+ export declare function DateRangeFilter({ label, value, onChange }: FilterControlProps): import("react").JSX.Element;
15
+ /**
16
+ * An item of another resource (`resource`), or several with `multiple`, picked with the relation
17
+ * source of the fields context. The filter keeps their ids; their labels are remembered for the
18
+ * chips.
19
+ */
20
+ export declare function RelationFilter({ filter, label, value, onChange, onLabel, getValueLabel, }: FilterControlProps): import("react").JSX.Element;
21
+ /** The built-in filter controls, by filter type. Unknown types are text filters. */
22
+ export declare const builtInFilters: Readonly<Record<string, FilterEntry>>;
23
+ //# sourceMappingURL=controls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controls.d.ts","sourceRoot":"","sources":["../../src/filters/controls.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAchE,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAmBxE;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAgC3F;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAU1E;AAED,4BAA4B;AAC5B,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BASxE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BA4B7E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC3B,MAAM,EACN,KAAK,EACL,KAAK,EACL,QAAQ,EACR,OAAO,EACP,aAAa,GAChB,EAAE,kBAAkB,+BA8CpB;AAED,oFAAoF;AACpF,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAOhE,CAAC"}