@declarion/react 0.23.0 → 0.25.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.
@@ -1,5 +1,5 @@
1
1
  import { s as e } from "./DynamicIcon-DCRdxxZ7.js";
2
- import { Dn as t, gn as n, m as r, nr as i, p as a, tr as o } from "./ActionRunner-C2A73D9b.js";
2
+ import { ar as t, jn as n, m as r, or as i, p as a, yn as o } from "./ActionRunner-eixtbT5K.js";
3
3
  import { n as s, r as c, t as l } from "./dataTableStyles-vwD1mVOP.js";
4
4
  import { useCallback as u, useMemo as d, useRef as f } from "react";
5
5
  import { jsx as p, jsxs as m } from "react/jsx-runtime";
@@ -7,65 +7,65 @@ import { DndContext as h, PointerSensor as g, closestCenter as _, useSensor as v
7
7
  import { SortableContext as b, useSortable as x, verticalListSortingStrategy as S } from "@dnd-kit/sortable";
8
8
  import { CSS as C } from "@dnd-kit/utilities";
9
9
  //#region src/components/detail-layout/DraggableChildrenTable.tsx
10
- function w({ config: t, childEntity: r, schema: a, rows: o, onChange: l, validationErrors: x, refs: C }) {
10
+ function w({ config: t, childEntity: n, schema: r, rows: a, onChange: l, validationErrors: x, refs: C }) {
11
11
  let w = f(null), E = t.position_field, D = t.columns, O = y(v(g, { activationConstraint: { distance: 5 } })), k = new Set(Array.isArray(t.foreign_key) ? t.foreign_key : [t.foreign_key]), A = D.filter((e) => {
12
12
  if (k.has(e) || e === E) return !1;
13
- let t = r.fields.get(e);
13
+ let t = n.fields.get(e);
14
14
  return !(!t || t.auto || t.primary || t.source);
15
15
  }), j = new Set(D.filter((e) => {
16
16
  if (e === E) return !0;
17
- let t = r.fields.get(e);
17
+ let t = n.fields.get(e);
18
18
  return t && (t.auto || t.primary || t.source);
19
- })), M = D.filter((e) => e !== E), N = d(() => o.filter((e) => !e._deleted).map((e) => e._key), [o]), P = u((e, t, n) => {
20
- l(o.map((r) => r._key === e ? {
19
+ })), M = D.filter((e) => e !== E), N = d(() => a.filter((e) => !e._deleted).map((e) => e._key), [a]), P = u((e, t, n) => {
20
+ l(a.map((r) => r._key === e ? {
21
21
  ...r,
22
22
  [t]: n,
23
23
  _dirty: !0
24
24
  } : r));
25
- }, [o, l]), F = u(() => {
26
- let e = o.filter((e) => !e._deleted).reduce((e, t) => {
25
+ }, [a, l]), F = u(() => {
26
+ let e = a.filter((e) => !e._deleted).reduce((e, t) => {
27
27
  let n = typeof t[E] == "number" ? t[E] : -1;
28
28
  return Math.max(e, n);
29
- }, -1), n = {
29
+ }, -1), r = {
30
30
  _key: crypto.randomUUID(),
31
31
  _dirty: !0,
32
32
  [E]: e + 1
33
33
  }, i = t.quick_add?.defaults ?? {};
34
34
  for (let e of A) {
35
- let t = r.fields.get(e);
36
- t && (i[e] === void 0 ? t.default === void 0 ? t.type === "bool" && (n[e] = !1) : n[e] = t.default : n[e] = i[e]);
35
+ let t = n.fields.get(e);
36
+ t && (i[e] === void 0 ? t.default === void 0 ? t.type === "bool" && (r[e] = !1) : r[e] = t.default : r[e] = i[e]);
37
37
  }
38
- l([...o, n]);
38
+ l([...a, r]);
39
39
  }, [
40
- o,
40
+ a,
41
41
  l,
42
42
  A,
43
- r,
43
+ n,
44
44
  t.quick_add?.defaults,
45
45
  E
46
46
  ]), I = u((e) => {
47
- l(o.map((t) => t._key === e ? {
47
+ l(a.map((t) => t._key === e ? {
48
48
  ...t,
49
49
  _deleted: !0
50
50
  } : t));
51
- }, [o, l]), L = u((e) => {
52
- l(o.map((t) => t._key === e ? {
51
+ }, [a, l]), L = u((e) => {
52
+ l(a.map((t) => t._key === e ? {
53
53
  ...t,
54
54
  _deleted: !1
55
55
  } : t));
56
- }, [o, l]), R = u((e) => {
56
+ }, [a, l]), R = u((e) => {
57
57
  let { active: t, over: n } = e;
58
58
  if (!n || t.id === n.id) return;
59
- let r = o.filter((e) => !e._deleted), i = o.filter((e) => e._deleted), a = r.findIndex((e) => e._key === String(t.id)), s = r.findIndex((e) => e._key === String(n.id));
60
- if (a === -1 || s === -1) return;
61
- let c = [...r], [u] = c.splice(a, 1);
59
+ let r = a.filter((e) => !e._deleted), i = a.filter((e) => e._deleted), o = r.findIndex((e) => e._key === String(t.id)), s = r.findIndex((e) => e._key === String(n.id));
60
+ if (o === -1 || s === -1) return;
61
+ let c = [...r], [u] = c.splice(o, 1);
62
62
  c.splice(s, 0, u), l([...c.map((e, t) => ({
63
63
  ...e,
64
64
  [E]: t,
65
65
  _dirty: e[E] === t ? e._dirty : !0
66
66
  })), ...i]);
67
67
  }, [
68
- o,
68
+ a,
69
69
  l,
70
70
  E
71
71
  ]), z = u((e) => {
@@ -118,10 +118,10 @@ function w({ config: t, childEntity: r, schema: a, rows: o, onChange: l, validat
118
118
  padding: "0 4px"
119
119
  } }),
120
120
  M.map((e) => {
121
- let t = r.fields.get(e);
121
+ let t = n.fields.get(e);
122
122
  return /* @__PURE__ */ p("th", {
123
123
  style: B,
124
- children: t ? n(t, e, a.entities) : e
124
+ children: t ? o(t, e, r.entities) : e
125
125
  }, e);
126
126
  }),
127
127
  /* @__PURE__ */ p("th", { style: {
@@ -131,12 +131,12 @@ function w({ config: t, childEntity: r, schema: a, rows: o, onChange: l, validat
131
131
  ] }) }), /* @__PURE__ */ p(b, {
132
132
  items: N,
133
133
  strategy: S,
134
- children: /* @__PURE__ */ p("tbody", { children: o.map((e) => /* @__PURE__ */ p(T, {
134
+ children: /* @__PURE__ */ p("tbody", { children: a.map((e) => /* @__PURE__ */ p(T, {
135
135
  row: e,
136
136
  columns: M,
137
137
  editableColumns: A,
138
138
  displayOnlyColumns: j,
139
- childEntity: r,
139
+ childEntity: n,
140
140
  validationErrors: x,
141
141
  refs: C,
142
142
  onCellChange: P,
@@ -157,9 +157,9 @@ function w({ config: t, childEntity: r, schema: a, rows: o, onChange: l, validat
157
157
  })
158
158
  })] });
159
159
  }
160
- function T({ row: n, columns: i, editableColumns: s, displayOnlyColumns: c, childEntity: u, validationErrors: d, refs: f, onCellChange: h, onDelete: g, onUndoDelete: _ }) {
161
- let v = a(), y = !!n._deleted, b = d?.[n._key], { attributes: S, listeners: w, setNodeRef: T, transform: E, transition: D, isDragging: O } = x({
162
- id: n._key,
160
+ function T({ row: i, columns: o, editableColumns: s, displayOnlyColumns: c, childEntity: u, validationErrors: d, refs: f, onCellChange: h, onDelete: g, onUndoDelete: _ }) {
161
+ let v = a(), y = !!i._deleted, b = d?.[i._key], { attributes: S, listeners: w, setNodeRef: T, transform: E, transition: D, isDragging: O } = x({
162
+ id: i._key,
163
163
  disabled: y
164
164
  }), k = {
165
165
  transform: C.Translate.toString(E),
@@ -200,22 +200,22 @@ function T({ row: n, columns: i, editableColumns: s, displayOnlyColumns: c, chil
200
200
  children: /* @__PURE__ */ p(e.grid, { size: 14 })
201
201
  })
202
202
  }),
203
- i.map((e) => {
204
- let i = u.fields.get(e), a = b?.includes(e), o = c.has(e), l = s.includes(e);
203
+ o.map((e) => {
204
+ let t = u.fields.get(e), a = b?.includes(e), o = c.has(e), l = s.includes(e);
205
205
  return y || o || !l ? /* @__PURE__ */ p("td", {
206
206
  style: {
207
207
  ...A,
208
208
  textDecoration: y ? "line-through" : "none"
209
209
  },
210
- children: i ? r({
211
- field: i,
210
+ children: t ? r({
211
+ field: t,
212
212
  fieldName: e,
213
- value: n[e],
213
+ value: i[e],
214
214
  mode: "display",
215
- record: n,
215
+ record: i,
216
216
  refs: f,
217
217
  locale: v
218
- }) : t(n[e])
218
+ }) : n(i[e])
219
219
  }, e) : /* @__PURE__ */ p("td", {
220
220
  style: {
221
221
  ...j,
@@ -224,16 +224,16 @@ function T({ row: n, columns: i, editableColumns: s, displayOnlyColumns: c, chil
224
224
  borderRadius: a ? 4 : 0
225
225
  },
226
226
  title: a ? `${e} is required` : void 0,
227
- children: i ? r({
228
- field: i,
227
+ children: t ? r({
228
+ field: t,
229
229
  fieldName: e,
230
- value: n[e],
230
+ value: i[e],
231
231
  mode: "edit",
232
- onChange: (t) => h(n._key, e, t),
233
- record: n,
232
+ onChange: (t) => h(i._key, e, t),
233
+ record: i,
234
234
  refs: f,
235
235
  locale: v
236
- }) : t(n[e])
236
+ }) : n(i[e])
237
237
  }, e);
238
238
  }),
239
239
  /* @__PURE__ */ p("td", {
@@ -242,15 +242,15 @@ function T({ row: n, columns: i, editableColumns: s, displayOnlyColumns: c, chil
242
242
  borderBottom: "1px solid var(--divider)",
243
243
  verticalAlign: "middle"
244
244
  },
245
- children: y ? /* @__PURE__ */ p(o, {
245
+ children: y ? /* @__PURE__ */ p(t, {
246
246
  size: 24,
247
247
  icon: /* @__PURE__ */ p(e.refresh, { size: 12 }),
248
- onClick: () => _(n._key),
248
+ onClick: () => _(i._key),
249
249
  title: "Undo delete"
250
- }) : /* @__PURE__ */ p(o, {
250
+ }) : /* @__PURE__ */ p(t, {
251
251
  size: 24,
252
252
  icon: /* @__PURE__ */ p(e.trash, { size: 12 }),
253
- onClick: () => g(n._key),
253
+ onClick: () => g(i._key),
254
254
  title: "Delete row"
255
255
  })
256
256
  })
@@ -1,4 +1,4 @@
1
- import { D as e, E as t, F as n, I as r, L as i, M as a, R as o, j as s, k as c, z as l } from "./ActionRunner-C2A73D9b.js";
1
+ import { D as e, E as t, F as n, I as r, L as i, M as a, R as o, j as s, k as c, z as l } from "./ActionRunner-eixtbT5K.js";
2
2
  import { useCallback as u, useEffect as d, useMemo as f, useRef as p, useState as m } from "react";
3
3
  import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
4
4
  import { DndContext as v, PointerSensor as y, closestCenter as b, useSensor as x, useSensors as ee } from "@dnd-kit/core";
@@ -1,4 +1,4 @@
1
- import { U as e } from "./ActionRunner-C2A73D9b.js";
1
+ import { U as e } from "./ActionRunner-eixtbT5K.js";
2
2
  import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
3
  import r, { defaultUrlTransform as i } from "react-markdown";
4
4
  import a from "remark-breaks";
@@ -0,0 +1,45 @@
1
+ import type { RefConfig, FilterSpecialValue } from "../../types/schema";
2
+ import type { Refs } from "../../types/api";
3
+ export interface RefComboboxProps {
4
+ /** Structured ref configuration (entity, optional lookup field, display). */
5
+ ref: RefConfig | undefined;
6
+ /** Current stored ref target value (the `ref.field` value, or target PK). */
7
+ value: unknown;
8
+ onChange: (value: string | null) => void;
9
+ /**
10
+ * Server-embedded `$refs` enrichment map, keyed by the stored ref value.
11
+ * Used to label the current selection when it is outside the loaded page.
12
+ */
13
+ refs?: Refs;
14
+ /** FieldDisplay-level display override (`field.display.ref_display_field`). */
15
+ displayFieldOverride?: string;
16
+ id?: string;
17
+ labelId?: string;
18
+ /** Accessible name when there is no associated <label> (e.g. the filter editor). */
19
+ ariaLabel?: string;
20
+ required?: boolean;
21
+ placeholder?: string;
22
+ /** Filter-only declared options (e.g. "Myself" -> $user.id) rendered as a
23
+ * "Special values" group above the relation results. Selecting one stores its
24
+ * `code` verbatim (a `$user.*` token is NOT resolved locally). Filter use only. */
25
+ specialValues?: FilterSpecialValue[];
26
+ }
27
+ /**
28
+ * RefCombobox is the ONE relation picker shared by every surface that selects a
29
+ * referenced record: SmartDetailPage create/edit ref fields, the list filter
30
+ * value editor, ActionDialog `type: ref` params, and inline-edit table ref
31
+ * cells. It loads a bounded page of accessible referenced rows through the
32
+ * normal data API (so RBAC/ABAC/tenant scoping all apply) and labels them via
33
+ * the canonical ref-label resolver.
34
+ *
35
+ * It stores the RESOLVED ref target value: `ref.field` when declared, otherwise
36
+ * the target entity's primary-key object id. (The legacy per-surface code stored
37
+ * the PK unconditionally and ignored `ref.field`.)
38
+ *
39
+ * Typed search hits the SERVER (debounced 300ms, via the `?search=` API over the
40
+ * entity's search fields), so a record past the bounded first page is findable;
41
+ * the `Select` primitive runs in server mode (`onSearchChange`) and renders the
42
+ * returned options without re-filtering them client-side. An empty search loads
43
+ * the default sorted page.
44
+ */
45
+ export declare function RefCombobox({ ref: refConfig, value, onChange, refs, displayFieldOverride, id, labelId, ariaLabel, required, placeholder, specialValues, }: RefComboboxProps): import("react").JSX.Element;
@@ -1,10 +1,14 @@
1
- import { type FilterNode } from "../../lib/filters";
1
+ import { type FilterNode, type FilterValueResolver } from "../../lib/filters";
2
2
  interface FilterChipsProps {
3
3
  filters: FilterNode[];
4
4
  onRemove: (field: string) => void;
5
5
  onClearAll: () => void;
6
6
  onChipClick?: () => void;
7
7
  fieldLabel?: (field: string) => string;
8
+ /** Humanizes each chip VALUE (special -> label, enum/status -> label, ref ->
9
+ * record label, with a skeleton while a ref label loads). Absent -> raw
10
+ * values, so FilterChips stays usable standalone / in tests. */
11
+ resolveValue?: FilterValueResolver;
8
12
  }
9
- export declare function FilterChips({ filters, onRemove, onClearAll, onChipClick, fieldLabel, }: FilterChipsProps): import("react").JSX.Element | null;
13
+ export declare function FilterChips({ filters, onRemove, onClearAll, onChipClick, fieldLabel, resolveValue, }: FilterChipsProps): import("react").JSX.Element | null;
10
14
  export {};
@@ -1,4 +1,6 @@
1
1
  import { type FilterNode, type FilterOp } from "../../lib/filters";
2
+ import type { RefConfig, FilterSpecialValue } from "../../types/schema";
3
+ import type { Refs } from "../../types/api";
2
4
  export interface FilterFieldMeta {
3
5
  code: string;
4
6
  label: string;
@@ -9,6 +11,8 @@ export interface FilterFieldMeta {
9
11
  label: string;
10
12
  color?: string;
11
13
  }[];
14
+ ref?: RefConfig;
15
+ specialValues?: FilterSpecialValue[];
12
16
  }
13
17
  interface FilterDrawerProps {
14
18
  open: boolean;
@@ -16,6 +20,13 @@ interface FilterDrawerProps {
16
20
  filters: FilterNode[];
17
21
  onApply: (filters: FilterNode[]) => void;
18
22
  availableFields: FilterFieldMeta[];
23
+ /** Screen `default_filters`: field codes pre-seeded as empty-valued rows when
24
+ * the panel opens with no active filters. Never pre-applies a value. */
25
+ defaultFilters?: string[];
26
+ /** Shared resolved-ref map (from the list page's filter-value resolver),
27
+ * passed to each ref editor's RefCombobox so it labels the selected value
28
+ * from this cache instead of firing its own per-value hydration fetch. */
29
+ refs?: Refs;
19
30
  }
20
- export declare function FilterDrawer({ open, onClose, filters, onApply, availableFields, }: FilterDrawerProps): import("react").JSX.Element | null;
31
+ export declare function FilterDrawer({ open, onClose, filters, onApply, availableFields, defaultFilters, refs, }: FilterDrawerProps): import("react").JSX.Element | null;
21
32
  export {};
@@ -1,9 +1,10 @@
1
- import type { Entity } from "../../../types/schema";
1
+ import type { Entity, ScreenFilterSpecialValues } from "../../../types/schema";
2
2
  import type { FilterFieldMeta } from "../../../components/filters/FilterDrawer";
3
3
  import type { FilterOp } from "../../../lib/filters";
4
4
  /** Build FilterFieldMeta array from screen + entity for the FilterDrawer. */
5
5
  export declare function buildFilterFieldMeta(screen: {
6
6
  filters?: string[];
7
+ filter_special_values?: Record<string, ScreenFilterSpecialValues>;
7
8
  } | undefined, entity: Pick<Entity, "fields" | "status_groups" | "properties"> | undefined, entities?: Record<string, Entity>): FilterFieldMeta[];
8
9
  /** Map field type to available filter operators. */
9
10
  export declare function fieldTypeToOperators(type: string): FilterOp[];
@@ -0,0 +1,24 @@
1
+ import { type FilterNode, type FilterValueResolver } from "../../../lib/filters";
2
+ import type { Entity } from "../../../types/schema";
3
+ import type { FilterFieldMeta } from "../../../components/filters/FilterDrawer";
4
+ import type { Refs } from "../../../types/api";
5
+ /**
6
+ * useFilterValueLabels - the single source of human labels for stored filter
7
+ * values, shared by the chip strip and the filter drawer's RefCombobox.
8
+ *
9
+ * Per value it resolves, in order: a declared special value (code -> label,
10
+ * synchronous), an enum/$status code (code -> label from the field's options,
11
+ * synchronous), a ref (value -> referenced record label, from the list `$refs`
12
+ * or a batched fetch), else a plain literal (rendered raw). Refs absent from
13
+ * `$refs` are fetched in ONE `in` query per referenced entity through the
14
+ * normal read API; identical queries dedupe in the query cache, so switching a
15
+ * view or reopening the drawer does not re-fetch a label already in hand.
16
+ *
17
+ * Returns `labelFor` (consumed by the chip strip) and a `Refs`-shaped map of
18
+ * resolved records (passed to the drawer's RefCombobox via its `refs` prop, so
19
+ * the combobox reuses this cache instead of its own per-value hydration).
20
+ */
21
+ export declare function useFilterValueLabels(meta: FilterFieldMeta[], filters: FilterNode[], listRefs: Refs | undefined, entities: Record<string, Entity> | undefined): {
22
+ labelFor: FilterValueResolver;
23
+ refs: Refs;
24
+ };
@@ -27,14 +27,24 @@ export declare function TextArea({ value, onChange, placeholder, rows, fill, id,
27
27
  export type SelectOption = {
28
28
  value: string;
29
29
  label: ReactNode;
30
+ heading?: boolean;
31
+ divider?: boolean;
30
32
  };
31
33
  export type SelectProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "value" | "onChange"> & {
32
34
  value?: string;
33
35
  options: SelectOption[];
34
36
  onChange: (v: string) => void;
35
37
  placeholder?: string;
38
+ /**
39
+ * Server-search mode. When set, the typed query is reported here (instead of
40
+ * filtering the options client-side) so the parent can fetch matching
41
+ * options from the server; the dropdown renders the given `options` as-is.
42
+ * The search input is always shown in this mode. Absent -> client-side
43
+ * filtering over `options`, as before.
44
+ */
45
+ onSearchChange?: (query: string) => void;
36
46
  };
37
- export declare function Select({ value, options, onChange, placeholder, ...rest }: SelectProps): import("react").JSX.Element;
47
+ export declare function Select({ value, options, onChange, placeholder, onSearchChange, ...rest }: SelectProps): import("react").JSX.Element;
38
48
  export type DateInputProps = {
39
49
  value?: string | null;
40
50
  onChange?: (v: string) => void;
@@ -55,3 +55,11 @@ export declare function useCursorEntityData(entity: string | undefined, params:
55
55
  reset: boolean;
56
56
  }, unknown>, Error>>;
57
57
  };
58
+ /**
59
+ * CursorEntityDataResult is the public return contract of useCursorEntityData -
60
+ * the digested infinite-list shape (accumulated `rows`, `hasMore` +
61
+ * `fetchNextPage` for scroll, the first-window `total`/`countUnknown`, and the
62
+ * react-query status flags). Named (not inferred) so SDK consumers have a stable
63
+ * type to annotate against. Derived from the hook so it never drifts.
64
+ */
65
+ export type CursorEntityDataResult = ReturnType<typeof useCursorEntityData>;
@@ -17,6 +17,8 @@ export { useEntity } from "./hooks/useEntity";
17
17
  export { useScreen } from "./hooks/useScreen";
18
18
  export { useAuth } from "./hooks/useAuth";
19
19
  export { useEntityData, useEntityCount } from "./hooks/useEntityData";
20
+ export { useCursorEntityData } from "./hooks/useCursorEntityData";
21
+ export type { CursorEntityDataParams, CursorEntityDataResult, } from "./hooks/useCursorEntityData";
20
22
  export { useAllEntityData } from "./hooks/useAllEntityData";
21
23
  export { useEntityItem } from "./hooks/useEntityItem";
22
24
  export { useCreateEntity, useUpdateEntity, useDeleteEntity } from "./hooks/useMutations";