@arqel-dev/ui 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ArqelEditPage-7OFWPULE.js +12 -0
- package/dist/{ArqelEditPage-RRYFYOTC.js.map → ArqelEditPage-7OFWPULE.js.map} +1 -1
- package/dist/ArqelIndexPage-ZAVCCM6V.js +14 -0
- package/dist/{ArqelIndexPage-J2EUV2PI.js.map → ArqelIndexPage-ZAVCCM6V.js.map} +1 -1
- package/dist/ArqelNotificationsPage-MBJBYFHW.js +6 -0
- package/dist/ArqelNotificationsPage-MBJBYFHW.js.map +1 -0
- package/dist/{UserMenu-B5XbC_Gy.d.ts → UserMenu-QlwvvZRU.d.ts} +2 -1
- package/dist/action.js +2 -1
- package/dist/{chunk-SK6H7ARE.js → chunk-3E66JNQO.js} +3 -18
- package/dist/chunk-3E66JNQO.js.map +1 -0
- package/dist/chunk-53J74IYR.js +22 -0
- package/dist/chunk-53J74IYR.js.map +1 -0
- package/dist/chunk-6YGRTXEL.js +87 -0
- package/dist/chunk-6YGRTXEL.js.map +1 -0
- package/dist/{chunk-SLLTFOOS.js → chunk-7NGUPQON.js} +5 -192
- package/dist/chunk-7NGUPQON.js.map +1 -0
- package/dist/chunk-CH7YLELO.js +137 -0
- package/dist/chunk-CH7YLELO.js.map +1 -0
- package/dist/{chunk-K7QY56XN.js → chunk-D2MUCHFN.js} +5 -119
- package/dist/chunk-D2MUCHFN.js.map +1 -0
- package/dist/chunk-DO3PRGVV.js +198 -0
- package/dist/chunk-DO3PRGVV.js.map +1 -0
- package/dist/{chunk-X4ZFKOPX.js → chunk-DOQUHQND.js} +4 -4
- package/dist/{chunk-X4ZFKOPX.js.map → chunk-DOQUHQND.js.map} +1 -1
- package/dist/{chunk-X2X6YDOX.js → chunk-EXA6DWLB.js} +11 -3
- package/dist/chunk-EXA6DWLB.js.map +1 -0
- package/dist/{chunk-S5UNPCMQ.js → chunk-JKD6SE75.js} +3 -269
- package/dist/chunk-JKD6SE75.js.map +1 -0
- package/dist/{chunk-EG2DASKR.js → chunk-KGAY2AZH.js} +4 -3
- package/dist/chunk-KGAY2AZH.js.map +1 -0
- package/dist/chunk-U4MPY2XT.js +91 -0
- package/dist/chunk-U4MPY2XT.js.map +1 -0
- package/dist/chunk-WKIYS2FQ.js +509 -0
- package/dist/chunk-WKIYS2FQ.js.map +1 -0
- package/dist/chunk-XK2P6CSK.js +8 -0
- package/dist/chunk-XK2P6CSK.js.map +1 -0
- package/dist/chunk-YEPQWAD6.js +275 -0
- package/dist/chunk-YEPQWAD6.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +11 -7
- package/dist/pages.d.ts +26 -1
- package/dist/pages.js +14 -8
- package/dist/pages.js.map +1 -1
- package/dist/primitives.js +3 -2
- package/dist/resource.js +3 -2
- package/dist/shell.d.ts +37 -3
- package/dist/shell.js +166 -7
- package/dist/shell.js.map +1 -1
- package/dist/table.js +2 -1
- package/dist/utility.js +2 -1
- package/dist/utils.d.ts +16 -1
- package/dist/utils.js +1 -0
- package/package.json +6 -6
- package/dist/ArqelEditPage-RRYFYOTC.js +0 -8
- package/dist/ArqelIndexPage-J2EUV2PI.js +0 -12
- package/dist/chunk-EG2DASKR.js.map +0 -1
- package/dist/chunk-K7QY56XN.js.map +0 -1
- package/dist/chunk-R4BOUU6Y.js +0 -55
- package/dist/chunk-R4BOUU6Y.js.map +0 -1
- package/dist/chunk-S5UNPCMQ.js.map +0 -1
- package/dist/chunk-SK6H7ARE.js.map +0 -1
- package/dist/chunk-SLLTFOOS.js.map +0 -1
- package/dist/chunk-X2X6YDOX.js.map +0 -1
- package/dist/chunk-YQ6KXR3U.js +0 -55
- package/dist/chunk-YQ6KXR3U.js.map +0 -1
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { Button } from './chunk-H23VX3RR.js';
|
|
2
|
+
import { cn } from './chunk-B7ULUJVO.js';
|
|
3
|
+
import { useArqelTranslations, useArqelLocale } from '@arqel-dev/react/utils';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
import { useMemo } from 'react';
|
|
6
|
+
|
|
7
|
+
function TableFilters({
|
|
8
|
+
filters,
|
|
9
|
+
values,
|
|
10
|
+
onChange,
|
|
11
|
+
onClearAll,
|
|
12
|
+
className
|
|
13
|
+
}) {
|
|
14
|
+
const t = useArqelTranslations();
|
|
15
|
+
if (filters.length === 0) return null;
|
|
16
|
+
const activeCount = filters.reduce((acc, f) => {
|
|
17
|
+
const v = values[f.name];
|
|
18
|
+
return v !== void 0 && v !== null && v !== "" ? acc + 1 : acc;
|
|
19
|
+
}, 0);
|
|
20
|
+
return /* @__PURE__ */ jsxs("fieldset", { className: cn("flex flex-wrap items-end gap-2 border-0 p-0", className), children: [
|
|
21
|
+
/* @__PURE__ */ jsx("legend", { className: "sr-only", children: t("table.filters.legend", "Filters") }),
|
|
22
|
+
filters.map((filter) => /* @__PURE__ */ jsx(
|
|
23
|
+
FilterControl,
|
|
24
|
+
{
|
|
25
|
+
filter,
|
|
26
|
+
value: values[filter.name],
|
|
27
|
+
onChange: (v) => onChange(filter.name, v)
|
|
28
|
+
},
|
|
29
|
+
filter.name
|
|
30
|
+
)),
|
|
31
|
+
activeCount > 0 && onClearAll && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: onClearAll, children: t("table.filters.clear", `Clear filters (${activeCount})`, { count: activeCount }) })
|
|
32
|
+
] });
|
|
33
|
+
}
|
|
34
|
+
function FilterControl({
|
|
35
|
+
filter,
|
|
36
|
+
value,
|
|
37
|
+
onChange
|
|
38
|
+
}) {
|
|
39
|
+
switch (filter.type) {
|
|
40
|
+
case "select":
|
|
41
|
+
return /* @__PURE__ */ jsx(SelectFilter, { filter, value, onChange });
|
|
42
|
+
case "multiSelect":
|
|
43
|
+
return /* @__PURE__ */ jsx(MultiSelectFilter, { filter, value, onChange });
|
|
44
|
+
case "text":
|
|
45
|
+
return /* @__PURE__ */ jsx(TextFilter, { filter, value, onChange });
|
|
46
|
+
case "ternary":
|
|
47
|
+
return /* @__PURE__ */ jsx(TernaryFilter, { filter, value, onChange });
|
|
48
|
+
case "dateRange":
|
|
49
|
+
case "scope":
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function controlClasses() {
|
|
54
|
+
return cn(
|
|
55
|
+
// 44px touch target on mobile (WCAG 2.5.5); dense 36px on >=md.
|
|
56
|
+
"h-11 rounded-sm border border-[var(--input)] md:h-9",
|
|
57
|
+
"bg-background px-3 text-sm",
|
|
58
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
function SelectFilter({
|
|
62
|
+
filter,
|
|
63
|
+
value,
|
|
64
|
+
onChange
|
|
65
|
+
}) {
|
|
66
|
+
const t = useArqelTranslations();
|
|
67
|
+
return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
|
|
68
|
+
filter.label ?? filter.name,
|
|
69
|
+
/* @__PURE__ */ jsxs(
|
|
70
|
+
"select",
|
|
71
|
+
{
|
|
72
|
+
className: controlClasses(),
|
|
73
|
+
value: value === void 0 || value === null ? "" : String(value),
|
|
74
|
+
onChange: (e) => onChange(e.target.value === "" ? null : e.target.value),
|
|
75
|
+
children: [
|
|
76
|
+
/* @__PURE__ */ jsx("option", { value: "", children: t("table.filters.all", "All") }),
|
|
77
|
+
filter.props.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
] });
|
|
82
|
+
}
|
|
83
|
+
function MultiSelectFilter({
|
|
84
|
+
filter,
|
|
85
|
+
value,
|
|
86
|
+
onChange
|
|
87
|
+
}) {
|
|
88
|
+
const arr = Array.isArray(value) ? value : [];
|
|
89
|
+
return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
|
|
90
|
+
filter.label ?? filter.name,
|
|
91
|
+
/* @__PURE__ */ jsx(
|
|
92
|
+
"select",
|
|
93
|
+
{
|
|
94
|
+
multiple: true,
|
|
95
|
+
className: cn(controlClasses(), "h-auto min-h-11 py-1 md:min-h-[2.25rem]"),
|
|
96
|
+
value: arr.map(String),
|
|
97
|
+
onChange: (e) => {
|
|
98
|
+
const next = Array.from(e.target.selectedOptions, (o) => o.value);
|
|
99
|
+
onChange(next.length === 0 ? null : next);
|
|
100
|
+
},
|
|
101
|
+
children: filter.props.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
] });
|
|
105
|
+
}
|
|
106
|
+
function TextFilter({
|
|
107
|
+
filter,
|
|
108
|
+
value,
|
|
109
|
+
onChange
|
|
110
|
+
}) {
|
|
111
|
+
return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
|
|
112
|
+
filter.label ?? filter.name,
|
|
113
|
+
/* @__PURE__ */ jsx(
|
|
114
|
+
"input",
|
|
115
|
+
{
|
|
116
|
+
type: "text",
|
|
117
|
+
className: controlClasses(),
|
|
118
|
+
value: typeof value === "string" ? value : "",
|
|
119
|
+
onChange: (e) => onChange(e.target.value === "" ? null : e.target.value)
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
] });
|
|
123
|
+
}
|
|
124
|
+
function TernaryFilter({
|
|
125
|
+
filter,
|
|
126
|
+
value,
|
|
127
|
+
onChange
|
|
128
|
+
}) {
|
|
129
|
+
const t = useArqelTranslations();
|
|
130
|
+
const current = value === void 0 || value === null ? "all" : String(value);
|
|
131
|
+
return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1 text-xs text-muted-foreground", children: [
|
|
132
|
+
filter.label ?? filter.name,
|
|
133
|
+
/* @__PURE__ */ jsxs(
|
|
134
|
+
"select",
|
|
135
|
+
{
|
|
136
|
+
className: controlClasses(),
|
|
137
|
+
value: current,
|
|
138
|
+
onChange: (e) => {
|
|
139
|
+
const v = e.target.value;
|
|
140
|
+
onChange(v === "all" ? null : v);
|
|
141
|
+
},
|
|
142
|
+
children: [
|
|
143
|
+
/* @__PURE__ */ jsx("option", { value: "all", children: filter.props.allLabel ?? t("table.filters.all", "All") }),
|
|
144
|
+
/* @__PURE__ */ jsx("option", { value: "true", children: filter.props.trueLabel ?? t("table.filters.yes", "Yes") }),
|
|
145
|
+
/* @__PURE__ */ jsx("option", { value: "false", children: filter.props.falseLabel ?? t("table.filters.no", "No") })
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
] });
|
|
150
|
+
}
|
|
151
|
+
function TablePagination({
|
|
152
|
+
meta,
|
|
153
|
+
onPageChange,
|
|
154
|
+
onPerPageChange,
|
|
155
|
+
perPageOptions = [10, 25, 50, 100],
|
|
156
|
+
className
|
|
157
|
+
}) {
|
|
158
|
+
const t = useArqelTranslations();
|
|
159
|
+
const locale = useArqelLocale();
|
|
160
|
+
const numberFormatter = useMemo(() => new Intl.NumberFormat(locale), [locale]);
|
|
161
|
+
const fromRaw = (meta.currentPage - 1) * meta.perPage + 1;
|
|
162
|
+
const toRaw = Math.min(meta.currentPage * meta.perPage, meta.total);
|
|
163
|
+
const from = numberFormatter.format(fromRaw);
|
|
164
|
+
const to = numberFormatter.format(toRaw);
|
|
165
|
+
const total = numberFormatter.format(meta.total);
|
|
166
|
+
const isFirst = meta.currentPage <= 1;
|
|
167
|
+
const isLast = meta.currentPage >= meta.lastPage;
|
|
168
|
+
return /* @__PURE__ */ jsxs(
|
|
169
|
+
"nav",
|
|
170
|
+
{
|
|
171
|
+
className: cn(
|
|
172
|
+
"flex flex-wrap items-center justify-between gap-2 border-t border-border px-3 py-2 text-sm",
|
|
173
|
+
className
|
|
174
|
+
),
|
|
175
|
+
"aria-label": t("table.pagination.label", "Pagination"),
|
|
176
|
+
children: [
|
|
177
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: meta.total === 0 ? t("table.empty", "No records found.") : t(
|
|
178
|
+
"table.pagination.showing",
|
|
179
|
+
// Fallback is rendered verbatim when the key is missing, so it must
|
|
180
|
+
// already carry the interpolated values (the replacements map only
|
|
181
|
+
// applies to a resolved dictionary string).
|
|
182
|
+
`Showing ${from} to ${to} of ${total} results`,
|
|
183
|
+
{ from, to, total }
|
|
184
|
+
) }),
|
|
185
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
186
|
+
onPerPageChange && /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
187
|
+
t("table.per_page", "Per page"),
|
|
188
|
+
/* @__PURE__ */ jsx(
|
|
189
|
+
"select",
|
|
190
|
+
{
|
|
191
|
+
className: "h-11 rounded-sm border border-[var(--input)] bg-background px-2 md:h-8",
|
|
192
|
+
value: meta.perPage,
|
|
193
|
+
onChange: (e) => onPerPageChange(Number(e.target.value)),
|
|
194
|
+
children: perPageOptions.map((n) => /* @__PURE__ */ jsx("option", { value: n, children: n }, n))
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
] }),
|
|
198
|
+
/* @__PURE__ */ jsx(
|
|
199
|
+
Button,
|
|
200
|
+
{
|
|
201
|
+
variant: "outline",
|
|
202
|
+
size: "sm",
|
|
203
|
+
className: "h-11 md:h-8",
|
|
204
|
+
disabled: isFirst,
|
|
205
|
+
onClick: () => onPageChange(meta.currentPage - 1),
|
|
206
|
+
"aria-label": t("table.pagination.previous_page", "Previous page"),
|
|
207
|
+
children: t("table.pagination.previous", "Prev")
|
|
208
|
+
}
|
|
209
|
+
),
|
|
210
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
211
|
+
numberFormatter.format(meta.currentPage),
|
|
212
|
+
" / ",
|
|
213
|
+
numberFormatter.format(meta.lastPage)
|
|
214
|
+
] }),
|
|
215
|
+
/* @__PURE__ */ jsx(
|
|
216
|
+
Button,
|
|
217
|
+
{
|
|
218
|
+
variant: "outline",
|
|
219
|
+
size: "sm",
|
|
220
|
+
className: "h-11 md:h-8",
|
|
221
|
+
disabled: isLast,
|
|
222
|
+
onClick: () => onPageChange(meta.currentPage + 1),
|
|
223
|
+
"aria-label": t("table.pagination.next_page", "Next page"),
|
|
224
|
+
children: t("table.pagination.next", "Next")
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
] })
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
function TableToolbar({
|
|
233
|
+
search,
|
|
234
|
+
filters,
|
|
235
|
+
selectedCount = 0,
|
|
236
|
+
bulkActions,
|
|
237
|
+
onClearSelection,
|
|
238
|
+
className
|
|
239
|
+
}) {
|
|
240
|
+
const t = useArqelTranslations();
|
|
241
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3 px-3 py-3", className), children: [
|
|
242
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-2", children: [
|
|
243
|
+
search,
|
|
244
|
+
filters
|
|
245
|
+
] }),
|
|
246
|
+
selectedCount > 0 && /* @__PURE__ */ jsxs(
|
|
247
|
+
"section",
|
|
248
|
+
{
|
|
249
|
+
className: "flex flex-wrap items-center gap-2 rounded-sm border border-border bg-muted px-3 py-2",
|
|
250
|
+
"aria-label": t("table.bulk.label", "Bulk actions"),
|
|
251
|
+
children: [
|
|
252
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("table.bulk.selected", "{one} :count selected|{other} :count selected", {
|
|
253
|
+
count: selectedCount
|
|
254
|
+
}) }),
|
|
255
|
+
/* @__PURE__ */ jsxs("div", { className: "ml-auto flex flex-wrap items-center gap-2", children: [
|
|
256
|
+
bulkActions,
|
|
257
|
+
onClearSelection && /* @__PURE__ */ jsx(
|
|
258
|
+
"button",
|
|
259
|
+
{
|
|
260
|
+
type: "button",
|
|
261
|
+
className: "text-sm text-muted-foreground hover:underline",
|
|
262
|
+
onClick: onClearSelection,
|
|
263
|
+
children: t("table.bulk.clear", "Clear")
|
|
264
|
+
}
|
|
265
|
+
)
|
|
266
|
+
] })
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
] });
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export { TableFilters, TablePagination, TableToolbar };
|
|
274
|
+
//# sourceMappingURL=chunk-YEPQWAD6.js.map
|
|
275
|
+
//# sourceMappingURL=chunk-YEPQWAD6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/table/TableFilters.tsx","../src/table/TablePagination.tsx","../src/table/TableToolbar.tsx"],"names":["useArqelTranslations","jsxs","jsx"],"mappings":"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","file":"chunk-YEPQWAD6.js","sourcesContent":["/**\n * `<TableFilters>` — renders one input per `FilterSchema` and emits\n * a single `onChange(name, value)` callback. Active values render as\n * dismissible chips so users can read state without re-opening menus.\n *\n * Phase 1 covers the four most-used filter types (select, multiSelect,\n * text, ternary). dateRange / scope land alongside FieldRenderer in\n * UI-004, where the date primitives ship.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type {\n FilterSchema,\n MultiSelectFilterSchema,\n SelectFilterSchema,\n TernaryFilterSchema,\n TextFilterSchema,\n} from '@arqel-dev/types/tables';\nimport { Button } from '../action/Button.js';\nimport { cn } from '../utils/cn.js';\n\nexport interface TableFiltersProps {\n filters: FilterSchema[];\n values: Record<string, unknown>;\n onChange: (name: string, value: unknown) => void;\n onClearAll?: (() => void) | undefined;\n className?: string | undefined;\n}\n\nexport function TableFilters({\n filters,\n values,\n onChange,\n onClearAll,\n className,\n}: TableFiltersProps) {\n const t = useArqelTranslations();\n if (filters.length === 0) return null;\n\n const activeCount = filters.reduce((acc, f) => {\n const v = values[f.name];\n return v !== undefined && v !== null && v !== '' ? acc + 1 : acc;\n }, 0);\n\n return (\n <fieldset className={cn('flex flex-wrap items-end gap-2 border-0 p-0', className)}>\n <legend className=\"sr-only\">{t('table.filters.legend', 'Filters')}</legend>\n {filters.map((filter) => (\n <FilterControl\n key={filter.name}\n filter={filter}\n value={values[filter.name]}\n onChange={(v) => onChange(filter.name, v)}\n />\n ))}\n {activeCount > 0 && onClearAll && (\n <Button variant=\"ghost\" size=\"sm\" onClick={onClearAll}>\n {t('table.filters.clear', `Clear filters (${activeCount})`, { count: activeCount })}\n </Button>\n )}\n </fieldset>\n );\n}\n\nfunction FilterControl({\n filter,\n value,\n onChange,\n}: {\n filter: FilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n switch (filter.type) {\n case 'select':\n return <SelectFilter filter={filter} value={value} onChange={onChange} />;\n case 'multiSelect':\n return <MultiSelectFilter filter={filter} value={value} onChange={onChange} />;\n case 'text':\n return <TextFilter filter={filter} value={value} onChange={onChange} />;\n case 'ternary':\n return <TernaryFilter filter={filter} value={value} onChange={onChange} />;\n case 'dateRange':\n case 'scope':\n return null;\n }\n}\n\nfunction controlClasses() {\n return cn(\n // 44px touch target on mobile (WCAG 2.5.5); dense 36px on >=md.\n 'h-11 rounded-sm border border-[var(--input)] md:h-9',\n 'bg-background px-3 text-sm',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n );\n}\n\nfunction SelectFilter({\n filter,\n value,\n onChange,\n}: {\n filter: SelectFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n const t = useArqelTranslations();\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <select\n className={controlClasses()}\n value={value === undefined || value === null ? '' : String(value)}\n onChange={(e) => onChange(e.target.value === '' ? null : e.target.value)}\n >\n <option value=\"\">{t('table.filters.all', 'All')}</option>\n {filter.props.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n );\n}\n\nfunction MultiSelectFilter({\n filter,\n value,\n onChange,\n}: {\n filter: MultiSelectFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n const arr = Array.isArray(value) ? (value as Array<string | number>) : [];\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <select\n multiple\n className={cn(controlClasses(), 'h-auto min-h-11 py-1 md:min-h-[2.25rem]')}\n value={arr.map(String)}\n onChange={(e) => {\n const next = Array.from(e.target.selectedOptions, (o) => o.value);\n onChange(next.length === 0 ? null : next);\n }}\n >\n {filter.props.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n );\n}\n\nfunction TextFilter({\n filter,\n value,\n onChange,\n}: {\n filter: TextFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <input\n type=\"text\"\n className={controlClasses()}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value === '' ? null : e.target.value)}\n />\n </label>\n );\n}\n\nfunction TernaryFilter({\n filter,\n value,\n onChange,\n}: {\n filter: TernaryFilterSchema;\n value: unknown;\n onChange: (value: unknown) => void;\n}) {\n const t = useArqelTranslations();\n const current = value === undefined || value === null ? 'all' : String(value);\n return (\n <label className=\"flex flex-col gap-1 text-xs text-muted-foreground\">\n {filter.label ?? filter.name}\n <select\n className={controlClasses()}\n value={current}\n onChange={(e) => {\n const v = e.target.value;\n onChange(v === 'all' ? null : v);\n }}\n >\n <option value=\"all\">{filter.props.allLabel ?? t('table.filters.all', 'All')}</option>\n <option value=\"true\">{filter.props.trueLabel ?? t('table.filters.yes', 'Yes')}</option>\n <option value=\"false\">{filter.props.falseLabel ?? t('table.filters.no', 'No')}</option>\n </select>\n </label>\n );\n}\n","/**\n * `<TablePagination>` — prev/next + range + per-page picker.\n *\n * Stateless: parent owns `currentPage` / `perPage` and handles transitions\n * (typically via Inertia `router.get` with `preserveState: true`).\n */\n\nimport { useArqelLocale, useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { PaginationMeta } from '@arqel-dev/types/resources';\nimport { useMemo } from 'react';\nimport { Button } from '../action/Button.js';\nimport { cn } from '../utils/cn.js';\n\nexport interface TablePaginationProps {\n meta: PaginationMeta;\n onPageChange: (page: number) => void;\n onPerPageChange?: ((perPage: number) => void) | undefined;\n perPageOptions?: number[];\n className?: string;\n}\n\nexport function TablePagination({\n meta,\n onPageChange,\n onPerPageChange,\n perPageOptions = [10, 25, 50, 100],\n className,\n}: TablePaginationProps) {\n const t = useArqelTranslations();\n const locale = useArqelLocale();\n const numberFormatter = useMemo(() => new Intl.NumberFormat(locale), [locale]);\n const fromRaw = (meta.currentPage - 1) * meta.perPage + 1;\n const toRaw = Math.min(meta.currentPage * meta.perPage, meta.total);\n // Interpolated counts are locale number-grouped (12,345 / 12.345) before they\n // reach the translator, whose applyReplacements does plain String() substitution.\n const from = numberFormatter.format(fromRaw);\n const to = numberFormatter.format(toRaw);\n const total = numberFormatter.format(meta.total);\n const isFirst = meta.currentPage <= 1;\n const isLast = meta.currentPage >= meta.lastPage;\n\n return (\n <nav\n className={cn(\n 'flex flex-wrap items-center justify-between gap-2 border-t border-border px-3 py-2 text-sm',\n className,\n )}\n aria-label={t('table.pagination.label', 'Pagination')}\n >\n <span className=\"text-muted-foreground\">\n {meta.total === 0\n ? t('table.empty', 'No records found.')\n : t(\n 'table.pagination.showing',\n // Fallback is rendered verbatim when the key is missing, so it must\n // already carry the interpolated values (the replacements map only\n // applies to a resolved dictionary string).\n `Showing ${from} to ${to} of ${total} results`,\n { from, to, total },\n )}\n </span>\n <div className=\"flex items-center gap-2\">\n {onPerPageChange && (\n <label className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n {t('table.per_page', 'Per page')}\n {/* 44px touch target on mobile (WCAG 2.5.5); dense 32px on >=md. */}\n <select\n className=\"h-11 rounded-sm border border-[var(--input)] bg-background px-2 md:h-8\"\n value={meta.perPage}\n onChange={(e) => onPerPageChange(Number(e.target.value))}\n >\n {perPageOptions.map((n) => (\n <option key={n} value={n}>\n {n}\n </option>\n ))}\n </select>\n </label>\n )}\n {/* Buttons use size=\"sm\" (h-8) for the dense desktop bar; the responsive\n h-11 override lifts them to a 44px touch target below md. */}\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-8\"\n disabled={isFirst}\n onClick={() => onPageChange(meta.currentPage - 1)}\n aria-label={t('table.pagination.previous_page', 'Previous page')}\n >\n {t('table.pagination.previous', 'Prev')}\n </Button>\n <span className=\"text-xs text-muted-foreground\">\n {numberFormatter.format(meta.currentPage)} / {numberFormatter.format(meta.lastPage)}\n </span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n className=\"h-11 md:h-8\"\n disabled={isLast}\n onClick={() => onPageChange(meta.currentPage + 1)}\n aria-label={t('table.pagination.next_page', 'Next page')}\n >\n {t('table.pagination.next', 'Next')}\n </Button>\n </div>\n </nav>\n );\n}\n","/**\n * `<TableToolbar>` — search input + filters + bulk-action bar slot.\n *\n * The bulk-action bar appears only when `selectedCount > 0`. ResourceIndex\n * passes `bulkActions` rendered as a row of buttons; the toolbar just\n * positions them.\n */\n\nimport { useArqelTranslations } from '@arqel-dev/react/utils';\nimport type { ReactNode } from 'react';\nimport { cn } from '../utils/cn.js';\n\nexport interface TableToolbarProps {\n search?: ReactNode;\n filters?: ReactNode;\n selectedCount?: number;\n bulkActions?: ReactNode;\n onClearSelection?: (() => void) | undefined;\n className?: string;\n}\n\nexport function TableToolbar({\n search,\n filters,\n selectedCount = 0,\n bulkActions,\n onClearSelection,\n className,\n}: TableToolbarProps) {\n const t = useArqelTranslations();\n return (\n <div className={cn('flex flex-col gap-3 px-3 py-3', className)}>\n <div className=\"flex flex-wrap items-end gap-2\">\n {search}\n {filters}\n </div>\n {selectedCount > 0 && (\n <section\n className=\"flex flex-wrap items-center gap-2 rounded-sm border border-border bg-muted px-3 py-2\"\n aria-label={t('table.bulk.label', 'Bulk actions')}\n >\n <span className=\"text-sm font-medium\">\n {t('table.bulk.selected', '{one} :count selected|{other} :count selected', {\n count: selectedCount,\n })}\n </span>\n <div className=\"ml-auto flex flex-wrap items-center gap-2\">\n {bulkActions}\n {onClearSelection && (\n <button\n type=\"button\"\n className=\"text-sm text-muted-foreground hover:underline\"\n onClick={onClearSelection}\n >\n {t('table.bulk.clear', 'Clear')}\n </button>\n )}\n </div>\n </section>\n )}\n </div>\n );\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { F as FieldComponent, a as FieldRenderer, b as FieldRendererProps, c as
|
|
|
5
5
|
export { CommandPalette, CommandPaletteProps, PaletteCommand } from './palette.js';
|
|
6
6
|
export { Alert, AlertDescription, AlertTitle, Badge, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Input, Label, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, Skeleton, Textarea, badgeVariants } from './primitives.js';
|
|
7
7
|
export { ResourceIndex, ResourceIndexUIProps } from './resource.js';
|
|
8
|
-
export { A as AppShell, a as AppShellProps, b as AppShellVariant, F as Footer, c as FooterProps, M as MainContent, d as MainContentMaxWidth, e as MainContentProps, S as Sidebar, f as SidebarProps, T as Topbar, g as TopbarProps, U as UserMenu, h as UserMenuProps } from './UserMenu-
|
|
8
|
+
export { A as AppShell, a as AppShellProps, b as AppShellVariant, F as Footer, c as FooterProps, M as MainContent, d as MainContentMaxWidth, e as MainContentProps, S as Sidebar, f as SidebarProps, T as Topbar, g as TopbarProps, U as UserMenu, h as UserMenuProps } from './UserMenu-QlwvvZRU.js';
|
|
9
9
|
export { D as DataTable, a as DataTableProps, b as DataTableRecord, T as TableFilters, c as TableFiltersProps, d as TablePagination, e as TablePaginationProps, f as TableToolbar, g as TableToolbarProps } from './TableToolbar-POLdlSgC.js';
|
|
10
10
|
export { BreadcrumbItem, Breadcrumbs, BreadcrumbsProps, EmptyState, EmptyStateProps, ErrorState, ErrorStateProps, LoadingSkeleton, LoadingSkeletonProps, PageHeader, PageHeaderProps, SkeletonVariant } from './utility.js';
|
|
11
11
|
export { c as cn } from './cn-By8XWiSA.js';
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
export { Breadcrumbs, EmptyState,
|
|
1
|
+
export { Breadcrumbs, EmptyState, LoadingSkeleton } from './chunk-3E66JNQO.js';
|
|
2
|
+
export { ErrorState } from './chunk-53J74IYR.js';
|
|
2
3
|
export { StatCard, WidgetWrapper } from './chunk-WMOBLT3Z.js';
|
|
3
|
-
export { Alert, AlertDescription, AlertTitle,
|
|
4
|
+
export { Alert, AlertDescription, AlertTitle, Checkbox, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Label, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Textarea } from './chunk-D2MUCHFN.js';
|
|
5
|
+
export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-6YGRTXEL.js';
|
|
4
6
|
export { PageHeader } from './chunk-MXUXMHOK.js';
|
|
5
|
-
export { AppShell, Footer, MainContent, Sidebar, Topbar, UserMenu } from './chunk-
|
|
7
|
+
export { AppShell, Footer, MainContent, Sidebar, Topbar, UserMenu } from './chunk-EXA6DWLB.js';
|
|
6
8
|
export { CommandPalette } from './chunk-HNUUZEOL.js';
|
|
7
|
-
export { Input, Separator, Skeleton } from './chunk-
|
|
8
|
-
export { ResourceIndex } from './chunk-
|
|
9
|
-
export {
|
|
9
|
+
export { Badge, Input, Separator, Skeleton, badgeVariants } from './chunk-U4MPY2XT.js';
|
|
10
|
+
export { ResourceIndex } from './chunk-KGAY2AZH.js';
|
|
11
|
+
export { TableFilters, TablePagination, TableToolbar } from './chunk-YEPQWAD6.js';
|
|
12
|
+
export { DataTable } from './chunk-JKD6SE75.js';
|
|
10
13
|
import './chunk-RMPOR2YZ.js';
|
|
11
|
-
export { ActionButton, ActionFormModal, ActionMenu
|
|
14
|
+
export { ActionButton, ActionFormModal, ActionMenu } from './chunk-7NGUPQON.js';
|
|
15
|
+
export { ConfirmDialog } from './chunk-DO3PRGVV.js';
|
|
12
16
|
import './chunk-VKZY6J6G.js';
|
|
13
17
|
export { FormActions } from './chunk-MZMYV43C.js';
|
|
14
18
|
export { FieldRenderer, FormRenderer, clearFieldRegistry, getFieldComponent, registerField } from './chunk-CMNZLA32.js';
|
package/dist/pages.d.ts
CHANGED
|
@@ -64,6 +64,31 @@ declare function ArqelEditPage<TRecord extends RecordType = RecordType>(): JSX.E
|
|
|
64
64
|
|
|
65
65
|
declare function ArqelIndexPage<TRecord extends RecordType = RecordType>(): JSX.Element;
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Default Inertia page for `arqel::notifications`.
|
|
69
|
+
*
|
|
70
|
+
* Renders the paginated notification history emitted by
|
|
71
|
+
* `Arqel\Core\Http\Controllers\NotificationController::index`
|
|
72
|
+
* (`{ history: paginator, filter: 'all' | 'unread' }`). The page-prop
|
|
73
|
+
* is named `history` — *not* `notifications` — because `notifications`
|
|
74
|
+
* is already a shared Inertia prop (`{unread_count, recent}`, see
|
|
75
|
+
* `HandleArqelInertiaRequests`) consumed by the `<NotificationBell>`
|
|
76
|
+
* mounted on every page's topbar. Reusing that key here would let this
|
|
77
|
+
* page's paginator silently overwrite the shared prop and break the
|
|
78
|
+
* bell (see branch review, milestone 0.19).
|
|
79
|
+
*
|
|
80
|
+
* The paginator serializes each item as `{id, type, data, read_at,
|
|
81
|
+
* created_at}` — same shape as the `notifications.recent` array the
|
|
82
|
+
* `<NotificationBell>` dropdown consumes, so titles/bodies follow the
|
|
83
|
+
* same `data.title` / `data.body` convention.
|
|
84
|
+
*
|
|
85
|
+
* Per-item actions do scoped Inertia visits (`only: ['history']` for
|
|
86
|
+
* mark-as-read, a plain reload for delete) so the list refreshes
|
|
87
|
+
* without a full page navigation.
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
declare function ArqelNotificationsPage(): JSX.Element;
|
|
91
|
+
|
|
67
92
|
/**
|
|
68
93
|
* Default Inertia page for `arqel::show`.
|
|
69
94
|
*
|
|
@@ -101,4 +126,4 @@ type LazyPage = () => Promise<{
|
|
|
101
126
|
}>;
|
|
102
127
|
declare const arqelPages: Record<string, LazyPage>;
|
|
103
128
|
|
|
104
|
-
export { ArqelCreatePage, ArqelDashboardPage, ArqelEditPage, ArqelIndexPage, ArqelShowPage, arqelPages };
|
|
129
|
+
export { ArqelCreatePage, ArqelDashboardPage, ArqelEditPage, ArqelIndexPage, ArqelNotificationsPage, ArqelShowPage, arqelPages };
|
package/dist/pages.js
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
export { ArqelNotificationsPage } from './chunk-CH7YLELO.js';
|
|
1
2
|
export { ArqelShowPage } from './chunk-Q7WGPKUN.js';
|
|
2
3
|
export { ArqelDashboardPage } from './chunk-3VSDQCFO.js';
|
|
3
|
-
export { ArqelEditPage } from './chunk-
|
|
4
|
-
export { ArqelIndexPage } from './chunk-
|
|
4
|
+
export { ArqelEditPage } from './chunk-WKIYS2FQ.js';
|
|
5
|
+
export { ArqelIndexPage } from './chunk-DOQUHQND.js';
|
|
5
6
|
import './chunk-YYQ45W25.js';
|
|
6
7
|
export { ArqelCreatePage } from './chunk-IO6RMVUF.js';
|
|
8
|
+
import './chunk-53J74IYR.js';
|
|
7
9
|
import './chunk-WMOBLT3Z.js';
|
|
10
|
+
import './chunk-6YGRTXEL.js';
|
|
8
11
|
import './chunk-MXUXMHOK.js';
|
|
9
|
-
import './chunk-
|
|
10
|
-
import './chunk-
|
|
12
|
+
import './chunk-KGAY2AZH.js';
|
|
13
|
+
import './chunk-YEPQWAD6.js';
|
|
14
|
+
import './chunk-JKD6SE75.js';
|
|
11
15
|
import './chunk-RMPOR2YZ.js';
|
|
12
|
-
import './chunk-
|
|
16
|
+
import './chunk-7NGUPQON.js';
|
|
17
|
+
import './chunk-DO3PRGVV.js';
|
|
13
18
|
import './chunk-VKZY6J6G.js';
|
|
14
19
|
import './chunk-MZMYV43C.js';
|
|
15
20
|
import './chunk-CMNZLA32.js';
|
|
@@ -18,11 +23,12 @@ import './chunk-B7ULUJVO.js';
|
|
|
18
23
|
|
|
19
24
|
// src/pages/index.ts
|
|
20
25
|
var arqelPages = {
|
|
21
|
-
"arqel::index": () => import('./ArqelIndexPage-
|
|
26
|
+
"arqel::index": () => import('./ArqelIndexPage-ZAVCCM6V.js'),
|
|
22
27
|
"arqel::create": () => import('./ArqelCreatePage-UZAHV4DK.js'),
|
|
23
|
-
"arqel::edit": () => import('./ArqelEditPage-
|
|
28
|
+
"arqel::edit": () => import('./ArqelEditPage-7OFWPULE.js'),
|
|
24
29
|
"arqel::show": () => import('./ArqelShowPage-TVCJAV2F.js'),
|
|
25
|
-
"arqel::dashboard": () => import('./ArqelDashboardPage-Z5R4XSH4.js')
|
|
30
|
+
"arqel::dashboard": () => import('./ArqelDashboardPage-Z5R4XSH4.js'),
|
|
31
|
+
"arqel::notifications": () => import('./ArqelNotificationsPage-MBJBYFHW.js')
|
|
26
32
|
};
|
|
27
33
|
|
|
28
34
|
export { arqelPages };
|
package/dist/pages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pages/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/pages/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA0BO,IAAM,UAAA,GAAuC;AAAA,EAClD,cAAA,EAAgB,MACd,OAAO,8BAAqB,CAAA;AAAA,EAC9B,eAAA,EAAiB,MACf,OAAO,+BAAsB,CAAA;AAAA,EAC/B,aAAA,EAAe,MAAM,OAAO,6BAAoB,CAAA;AAAA,EAChD,aAAA,EAAe,MAAM,OAAO,6BAAoB,CAAA;AAAA,EAChD,kBAAA,EAAoB,MAClB,OAAO,kCAAyB,CAAA;AAAA,EAClC,sBAAA,EAAwB,MACtB,OAAO,sCAA6B;AACxC","file":"pages.js","sourcesContent":["/**\n * Built-in Inertia page registry for `arqel::*`.\n *\n * `createArqelApp({ pages })` from `@arqel-dev/react/inertia` accepts\n * one or more `PageRegistry` records — merge `arqelPages` first so\n * user-defined pages can override per-resource:\n *\n * ```ts\n * import { arqelPages } from '@arqel-dev/ui/pages';\n * import { createArqelApp } from '@arqel-dev/react/inertia';\n *\n * const userPages = import.meta.glob('./Pages/**\\/*.tsx');\n *\n * createArqelApp({\n * pages: { ...arqelPages, ...userPages },\n * });\n * ```\n *\n * Names match what `ResourceController` emits via\n * `Inertia::render('arqel::index', ...)`.\n */\n\nimport type { ComponentType } from 'react';\n\ntype LazyPage = () => Promise<{ default: ComponentType<unknown> }>;\n\nexport const arqelPages: Record<string, LazyPage> = {\n 'arqel::index': () =>\n import('./ArqelIndexPage.js') as Promise<{ default: ComponentType<unknown> }>,\n 'arqel::create': () =>\n import('./ArqelCreatePage.js') as Promise<{ default: ComponentType<unknown> }>,\n 'arqel::edit': () => import('./ArqelEditPage.js') as Promise<{ default: ComponentType<unknown> }>,\n 'arqel::show': () => import('./ArqelShowPage.js') as Promise<{ default: ComponentType<unknown> }>,\n 'arqel::dashboard': () =>\n import('./ArqelDashboardPage.js') as Promise<{ default: ComponentType<unknown> }>,\n 'arqel::notifications': () =>\n import('./ArqelNotificationsPage.js') as Promise<{ default: ComponentType<unknown> }>,\n};\n\nexport { default as ArqelCreatePage } from './ArqelCreatePage.js';\nexport { default as ArqelDashboardPage } from './ArqelDashboardPage.js';\nexport { default as ArqelEditPage } from './ArqelEditPage.js';\nexport { default as ArqelIndexPage } from './ArqelIndexPage.js';\nexport { default as ArqelNotificationsPage } from './ArqelNotificationsPage.js';\nexport { default as ArqelShowPage } from './ArqelShowPage.js';\n"]}
|
package/dist/primitives.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { Alert, AlertDescription, AlertTitle,
|
|
2
|
-
export {
|
|
1
|
+
export { Alert, AlertDescription, AlertTitle, Checkbox, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Label, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Textarea } from './chunk-D2MUCHFN.js';
|
|
2
|
+
export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-6YGRTXEL.js';
|
|
3
|
+
export { Badge, Input, Separator, Skeleton, badgeVariants } from './chunk-U4MPY2XT.js';
|
|
3
4
|
import './chunk-B7ULUJVO.js';
|
|
4
5
|
//# sourceMappingURL=primitives.js.map
|
|
5
6
|
//# sourceMappingURL=primitives.js.map
|
package/dist/resource.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { ResourceIndex } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
export { ResourceIndex } from './chunk-KGAY2AZH.js';
|
|
2
|
+
import './chunk-YEPQWAD6.js';
|
|
3
|
+
import './chunk-JKD6SE75.js';
|
|
3
4
|
import './chunk-RMPOR2YZ.js';
|
|
4
5
|
import './chunk-H23VX3RR.js';
|
|
5
6
|
import './chunk-B7ULUJVO.js';
|
package/dist/shell.d.ts
CHANGED
|
@@ -1,9 +1,43 @@
|
|
|
1
|
-
export { A as AppShell, a as AppShellProps, b as AppShellVariant, F as Footer, c as FooterProps, M as MainContent, d as MainContentMaxWidth, e as MainContentProps, S as Sidebar, f as SidebarProps, T as Topbar, g as TopbarProps, U as UserMenu, h as UserMenuProps } from './UserMenu-
|
|
2
|
-
import { TenantSummary } from '@arqel-dev/types/tenant';
|
|
1
|
+
export { A as AppShell, a as AppShellProps, b as AppShellVariant, F as Footer, c as FooterProps, M as MainContent, d as MainContentMaxWidth, e as MainContentProps, S as Sidebar, f as SidebarProps, T as Topbar, g as TopbarProps, U as UserMenu, h as UserMenuProps } from './UserMenu-QlwvvZRU.js';
|
|
3
2
|
import { JSX } from 'react';
|
|
3
|
+
import { NotificationItem } from '@arqel-dev/types/inertia';
|
|
4
|
+
import { TenantSummary } from '@arqel-dev/types/tenant';
|
|
4
5
|
import 'react/jsx-runtime';
|
|
5
6
|
import '@arqel-dev/hooks';
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* `<NotificationBell>` — database-notifications trigger for the Topbar
|
|
10
|
+
* `notifications` slot.
|
|
11
|
+
*
|
|
12
|
+
* Reads the shared `notifications` prop (`NotificationPayload | null`,
|
|
13
|
+
* see `HandleArqelInertiaRequests`) via `usePage()`. Mounts a bell icon
|
|
14
|
+
* with an unread-count `Badge` (shown only when `unread_count > 0`) and
|
|
15
|
+
* a `DropdownMenu` listing the `recent` notifications. Marking a single
|
|
16
|
+
* notification read, or all of them, does a scoped Inertia partial
|
|
17
|
+
* reload (`only: ['notifications']`) — no full page reload.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
interface NotificationBellProps {
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
declare function NotificationBell({ className }: NotificationBellProps): JSX.Element;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* `<NotificationList>` — renders the `recent` notifications inside the
|
|
27
|
+
* `<NotificationBell>` dropdown content.
|
|
28
|
+
*
|
|
29
|
+
* Extracted from `NotificationBell` so it can be exercised directly in
|
|
30
|
+
* tests without depending on Radix `DropdownMenu` mounting its portal
|
|
31
|
+
* content in jsdom.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
interface NotificationListProps {
|
|
35
|
+
items: ReadonlyArray<NotificationItem>;
|
|
36
|
+
emptyLabel: string;
|
|
37
|
+
onItemClick: (item: NotificationItem) => void;
|
|
38
|
+
}
|
|
39
|
+
declare function NotificationList({ items, emptyLabel, onItemClick, }: NotificationListProps): JSX.Element;
|
|
40
|
+
|
|
7
41
|
/**
|
|
8
42
|
* `<TenantSwitcher>` — dropdown that lists tenants the user can
|
|
9
43
|
* access and dispatches `POST /admin/tenants/{id}/switch` via
|
|
@@ -27,4 +61,4 @@ interface TenantSwitcherProps {
|
|
|
27
61
|
}
|
|
28
62
|
declare function TenantSwitcher({ current, available, switchUrl, }: TenantSwitcherProps): JSX.Element | null;
|
|
29
63
|
|
|
30
|
-
export { TenantSwitcher, type TenantSwitcherProps };
|
|
64
|
+
export { NotificationBell, type NotificationBellProps, NotificationList, type NotificationListProps, TenantSwitcher, type TenantSwitcherProps };
|