@cosmicdrift/kumiko-renderer 0.290.0 → 0.292.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.
@@ -48,6 +48,14 @@ export type ListUrlStateApi = ListUrlState & {
48
48
  readonly setFilter: (field: string, values: readonly string[]) => void;
49
49
  /** Löscht alle aktiven Faceted-Filter (Reset-Button). */
50
50
  readonly clearFilters: () => void;
51
+ /** Sets both bounds of a dateRange facet in ONE params update — two
52
+ * setFilter calls would overwrite each other, since the second still sees
53
+ * the old searchParams. An empty string clears that bound. Resets the page
54
+ * like setFilter. */
55
+ readonly setDateRange: (
56
+ field: string,
57
+ next: { readonly from: string; readonly to: string },
58
+ ) => void;
51
59
  };
52
60
 
53
61
  // `.` als Trenner: lesbar (`?orders.sort=name`), kollidiert nicht mit
@@ -142,11 +150,22 @@ export function useListUrlState(screenId: string): ListUrlStateApi {
142
150
  [nav, screenId],
143
151
  );
144
152
 
153
+ const setDateRange = useCallback(
154
+ (field: string, next: { readonly from: string; readonly to: string }) => {
155
+ nav.setSearchParams({
156
+ [key(screenId, `f.${field}.from`)]: next.from === "" ? null : next.from,
157
+ [key(screenId, `f.${field}.to`)]: next.to === "" ? null : next.to,
158
+ [key(screenId, "page")]: null,
159
+ });
160
+ },
161
+ [nav, screenId],
162
+ );
163
+
145
164
  const clearFilters = useCallback(() => {
146
165
  const updates: Record<string, string | null> = { [key(screenId, "page")]: null };
147
166
  for (const field of Object.keys(filters)) updates[key(screenId, `f.${field}`)] = null;
148
167
  nav.setSearchParams(updates);
149
168
  }, [nav, screenId, filters]);
150
169
 
151
- return { sort, q, page, filters, setSort, setQ, setPage, setFilter, clearFilters };
170
+ return { sort, q, page, filters, setSort, setQ, setPage, setFilter, clearFilters, setDateRange };
152
171
  }
@@ -67,6 +67,7 @@ export const kumikoDefaultTranslations: TranslationsByLocale = {
67
67
  "kumiko.list.related-list-truncated":
68
68
  "Showing the first {count} entries. More are available but not loaded — this list does not paginate.",
69
69
  "kumiko.reference.system-tenant": "System",
70
+ "kumiko.reference.system-user": "System",
70
71
 
71
72
  "kumiko.pager.status": "{from}–{to} of {total}",
72
73
  "kumiko.pager.previousPage": "Previous page",
package/src/i18n.tsx CHANGED
@@ -205,6 +205,17 @@ export function useOptionalLocale(): string | undefined {
205
205
  return ctx === undefined ? undefined : ctx.resolver.locale();
206
206
  }
207
207
 
208
+ /** Non-throwing time-zone read — "UTC" outside LocaleProvider, matching
209
+ * createStaticLocaleResolver's own default. */
210
+ export function useOptionalTimeZone(): string {
211
+ const ctx = useContext(LocaleContext);
212
+ return useSyncExternalStore(
213
+ (onStoreChange) => (ctx ? ctx.resolver.subscribe(onStoreChange) : () => {}),
214
+ () => (ctx ? ctx.resolver.timeZone() : "UTC"),
215
+ () => (ctx ? ctx.resolver.timeZone() : "UTC"),
216
+ );
217
+ }
218
+
208
219
  /** Non-throwing translate — undefined outside LocaleProvider. */
209
220
  export function useOptionalTranslation():
210
221
  | ((key: string, params?: Readonly<Record<string, unknown>>) => string)
package/src/index.ts CHANGED
@@ -64,6 +64,13 @@ export type {
64
64
  export { isAppSchema, toAppSchema } from "./app/feature-schema";
65
65
  export type { KumikoScreenProps } from "./app/kumiko-screen";
66
66
  export { KumikoScreen, qualifyNavId, qualifyScreenId } from "./app/kumiko-screen";
67
+ export type { DateRangeBound, DateRangeValue, ResolvedDateRangeFacet } from "./app/list-facets";
68
+ export {
69
+ buildDateRangePayload,
70
+ clampDateRange,
71
+ readDateRange,
72
+ resolveDateRangeFacets,
73
+ } from "./app/list-facets";
67
74
  export type {
68
75
  NavApi,
69
76
  NavProviderProps,
@@ -82,12 +89,15 @@ export {
82
89
  useNavigateWithInitialValues,
83
90
  } from "./app/nav";
84
91
  export { lastSegment } from "./app/qn";
85
- export type { ReturnHost } from "./app/return-to";
92
+ export type { ReturnHost, ReturnTo } from "./app/return-to";
86
93
  export {
94
+ navigateToReturn,
95
+ navigateToReturnOr,
87
96
  navigateWithReturnTo,
88
97
  RETURN_TO_PARAM,
89
98
  ReturnHostProvider,
90
99
  resolveReturnTarget,
100
+ splitReturnTo,
91
101
  useReturnHost,
92
102
  useReturnTarget,
93
103
  } from "./app/return-to";
@@ -185,6 +195,7 @@ export type {
185
195
  CardProps,
186
196
  CardSlots,
187
197
  CorePrimitives,
198
+ DataTableDateRangeFacet,
188
199
  DataTableFacet,
189
200
  DataTableProps,
190
201
  DataTableRowAction,
@@ -572,6 +572,18 @@ export type DataTableFacet = {
572
572
  readonly options: readonly { readonly value: string; readonly label: string }[];
573
573
  };
574
574
 
575
+ // Time-range filter slot in the toolbar (fw#3104): two date inputs
576
+ // (from/to) instead of an options dropdown. Values are `YYYY-MM-DD` or ""
577
+ // (bound open) — the caller converts them into query params.
578
+ export type DataTableDateRangeFacet = {
579
+ /** The facet's namespace (its date field) — a key, not a filter value. */
580
+ readonly field: string;
581
+ /** Translated label ("When"). */
582
+ readonly label: string;
583
+ readonly from: string;
584
+ readonly to: string;
585
+ };
586
+
575
587
  export type DataTableProps = {
576
588
  readonly columns: readonly ListColumnViewModel[];
577
589
  readonly rows: readonly ListRowViewModel[];
@@ -622,6 +634,10 @@ export type DataTableProps = {
622
634
  /** Reset-Button: löscht alle aktiven Facets. Renderer zeigt ihn nur
623
635
  * wenn mindestens ein Facet aktiv ist. */
624
636
  readonly onFilterReset?: () => void;
637
+ /** Time-range filters beside the facet dropdowns (fw#3104). */
638
+ readonly dateRangeFacets?: readonly DataTableDateRangeFacet[];
639
+ /** One bound changed ("" clears it) → caller writes URL state + refetch. */
640
+ readonly onDateRangeChange?: (field: string, bound: "from" | "to", value: string) => void;
625
641
  /** Pagination-State + Callback. Wenn gesetzt, rendert der Renderer
626
642
  * einen Pager unter der Tabelle (Web: Footer-Bar mit ← 1 ... N →).
627
643
  * total/limit/page sind 1-basiert für die UI; Server-Translation