@optiaxiom/proteus 3.1.0 → 3.2.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/esm/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { ProteusDataTableRow } from "./proteus-data-table-row/ProteusDataTableRow.js";
1
2
  import { ProteusAction } from "./proteus-action/ProteusAction.js";
2
3
  import { ProteusBridge } from "./proteus-bridge/ProteusBridge.js";
3
4
  import { ProteusChart } from "./proteus-chart/ProteusChart.js";
@@ -21,4 +22,4 @@ import { ProteusShow } from "./proteus-show/ProteusShow.js";
21
22
  import { ProteusTextarea } from "./proteus-textarea/ProteusTextarea.js";
22
23
  import { ProteusDocumentShell } from "./proteus-document/ProteusDocumentShell.js";
23
24
  import { ProteusDocumentRenderer } from "./proteus-document/ProteusDocumentRenderer.js";
24
- export { ProteusAction, ProteusBridge, ProteusChart, ProteusDataTable, ProteusDateInput, ProteusDocumentRenderer, ProteusDocumentShell, ProteusFederated, ProteusFileUpload, ProteusImage, ProteusImageCarousel, ProteusInput, ProteusLength, ProteusMap, ProteusMapIndex, ProteusMarkdown, ProteusPillMenu, ProteusRichTextEditor, ProteusSelect, ProteusShow, ProteusTextarea, safeParseDocument, useProteusValue };
25
+ export { ProteusAction, ProteusBridge, ProteusChart, ProteusDataTable, ProteusDataTableRow, ProteusDateInput, ProteusDocumentRenderer, ProteusDocumentShell, ProteusFederated, ProteusFileUpload, ProteusImage, ProteusImageCarousel, ProteusInput, ProteusLength, ProteusMap, ProteusMapIndex, ProteusMarkdown, ProteusPillMenu, ProteusRichTextEditor, ProteusSelect, ProteusShow, ProteusTextarea, safeParseDocument, useProteusValue };
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { applyFormatter } from "../proteus-document/getProteusValue.js";
3
3
  import { DataTable, DataTableBody } from "@optiaxiom/react";
4
+ import "react";
4
5
  import { get } from "jsonpointer";
5
6
  import { jsx } from "react/jsx-runtime";
6
7
  import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table";
@@ -18,7 +19,8 @@ const ProteusDataTable = ({ columns, data }) => {
18
19
  }, {
19
20
  header: col.header,
20
21
  id: col.accessorKey,
21
- size: col.size
22
+ size: col.size,
23
+ ...col.cell && { cell: ({ row }) => col.cell?.(row.original) }
22
24
  });
23
25
  }),
24
26
  data: tableData,
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { useProteusDataTableRowContext } from "../proteus-document/ProteusDataTableRowContext.js";
3
+ import { get } from "jsonpointer";
4
+ //#region src/proteus-data-table-row/ProteusDataTableRow.tsx
5
+ function ProteusDataTableRow({ path }) {
6
+ const { row } = useProteusDataTableRowContext("@optiaxiom/proteus/ProteusDataTableRow");
7
+ const value = getDataTableRowValue(row, path);
8
+ return value == null || typeof value === "object" ? null : String(value);
9
+ }
10
+ ProteusDataTableRow.displayName = "@optiaxiom/proteus/ProteusDataTableRow";
11
+ /**
12
+ * Reads a value out of a `DataTable` row for the `DataTableRow` element and
13
+ * expression. With no `path`, returns the whole row; otherwise reads the field
14
+ * at `path` (leading `/` optional).
15
+ */
16
+ function getDataTableRowValue(row, path) {
17
+ if (!row) return;
18
+ if (!path) return row;
19
+ try {
20
+ return get(row, path.startsWith("/") ? path : `/${path}`);
21
+ } catch {
22
+ return;
23
+ }
24
+ }
25
+ //#endregion
26
+ export { ProteusDataTableRow, getDataTableRowValue };
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ "use client";
3
+ import { createContext } from "@radix-ui/react-context";
4
+ //#region src/proteus-document/ProteusDataTableRowContext.ts
5
+ /**
6
+ * Holds the current `DataTable` row while a column's `cell` template renders.
7
+ * `DataTableRow` reads from here to give the cell pointer access to its row,
8
+ * the same way `MapIndex` exposes the current index inside a `Map`.
9
+ */
10
+ const [ProteusDataTableRowProvider, useProteusDataTableRowContext] = createContext("@optiaxiom/proteus/ProteusDataTableRow", { row: void 0 });
11
+ //#endregion
12
+ export { ProteusDataTableRowProvider, useProteusDataTableRowContext };
@@ -1,19 +1,21 @@
1
1
  "use client";
2
+ import { getDataTableRowValue } from "../proteus-data-table-row/ProteusDataTableRow.js";
2
3
  import { getProteusValue } from "./getProteusValue.js";
3
4
  import { evaluateCondition } from "./resolveProteusValue.js";
4
5
  import { ProteusElement } from "../proteus-element/ProteusElement.js";
5
6
  import { jsx } from "react/jsx-runtime";
6
7
  //#region src/proteus-document/resolveProteusProp.tsx
7
- function resolveProteusProp(value, data, parentPath, mapIndices = []) {
8
+ function resolveProteusProp(value, data, parentPath, mapIndices = [], dataTableRow) {
8
9
  if (typeof value !== "object" || value === null) return value;
9
10
  if ("$type" in value && value.$type === "MapIndex") return mapIndices.at(-1);
11
+ if ("$type" in value && value.$type === "DataTableRow") return getDataTableRowValue(dataTableRow, "path" in value && typeof value.path === "string" ? value.path : void 0);
10
12
  if ("$type" in value && value.$type === "Value" && "path" in value && typeof value.path === "string") return getProteusValue(data, value, parentPath);
11
13
  if ("$type" in value && value.$type === "Zip" && "sources" in value) {
12
14
  const sources = value.sources;
13
15
  const resolved = {};
14
16
  let length = 0;
15
17
  for (const [k, v] of Object.entries(sources)) {
16
- const arr = resolveProteusProp(v, data, parentPath, mapIndices);
18
+ const arr = resolveProteusProp(v, data, parentPath, mapIndices, dataTableRow);
17
19
  if (Array.isArray(arr)) {
18
20
  resolved[k] = arr;
19
21
  length = Math.max(length, arr.length);
@@ -25,10 +27,7 @@ function resolveProteusProp(value, data, parentPath, mapIndices = []) {
25
27
  return row;
26
28
  });
27
29
  }
28
- if ("$type" in value && value.$type === "Show" && "when" in value && "children" in value) {
29
- if (!(Array.isArray(value.when) ? value.when : [value.when]).every((condition) => evaluateCondition(condition, data, parentPath, mapIndices))) return;
30
- return resolveProteusProp(value.children, data, parentPath, mapIndices);
31
- }
30
+ if ("$type" in value && value.$type === "Show" && "when" in value && "children" in value) return resolveProteusProp((Array.isArray(value.when) ? value.when : [value.when]).every((condition) => evaluateCondition(condition, data, parentPath, mapIndices, dataTableRow)) ? value.children : "else" in value ? value.else : void 0, data, parentPath, mapIndices, dataTableRow);
32
31
  return "$type" in value || Array.isArray(value) && value.some((v) => v && typeof v === "object" && "$type" in v) ? /* @__PURE__ */ jsx(ProteusElement, { element: value }) : value;
33
32
  }
34
33
  //#endregion
@@ -1,45 +1,47 @@
1
1
  "use client";
2
+ import { getDataTableRowValue } from "../proteus-data-table-row/ProteusDataTableRow.js";
2
3
  import { getProteusValue } from "./getProteusValue.js";
3
4
  //#region src/proteus-document/resolveProteusValue.tsx
4
- function evaluateCondition(condition, data, parentPath, mapIndices = []) {
5
+ function evaluateCondition(condition, data, parentPath, mapIndices = [], dataTableRow) {
5
6
  if (!condition) return true;
6
- if ("and" in condition) return condition.and.every((cond) => evaluateCondition(cond, data, parentPath, mapIndices));
7
- if ("or" in condition) return condition.or.some((cond) => evaluateCondition(cond, data, parentPath, mapIndices));
8
- if ("!!" in condition) return !!resolveProteusValue(condition["!!"], data, parentPath, mapIndices);
9
- if ("!" in condition) return !resolveProteusValue(condition["!"], data, parentPath, mapIndices);
7
+ if ("and" in condition) return condition.and.every((cond) => evaluateCondition(cond, data, parentPath, mapIndices, dataTableRow));
8
+ if ("or" in condition) return condition.or.some((cond) => evaluateCondition(cond, data, parentPath, mapIndices, dataTableRow));
9
+ if ("!!" in condition) return !!resolveProteusValue(condition["!!"], data, parentPath, mapIndices, dataTableRow);
10
+ if ("!" in condition) return !resolveProteusValue(condition["!"], data, parentPath, mapIndices, dataTableRow);
10
11
  if ("==" in condition) {
11
12
  const [left, right] = condition["=="];
12
- return resolveProteusValue(left, data, parentPath, mapIndices) === resolveProteusValue(right, data, parentPath, mapIndices);
13
+ return resolveProteusValue(left, data, parentPath, mapIndices, dataTableRow) === resolveProteusValue(right, data, parentPath, mapIndices, dataTableRow);
13
14
  } else if ("!=" in condition) {
14
15
  const [left, right] = condition["!="];
15
- return resolveProteusValue(left, data, parentPath, mapIndices) !== resolveProteusValue(right, data, parentPath, mapIndices);
16
+ return resolveProteusValue(left, data, parentPath, mapIndices, dataTableRow) !== resolveProteusValue(right, data, parentPath, mapIndices, dataTableRow);
16
17
  } else if ("<" in condition) {
17
18
  const [left, right] = condition["<"];
18
- const leftVal = resolveProteusValue(left, data, parentPath, mapIndices);
19
- const rightVal = resolveProteusValue(right, data, parentPath, mapIndices);
19
+ const leftVal = resolveProteusValue(left, data, parentPath, mapIndices, dataTableRow);
20
+ const rightVal = resolveProteusValue(right, data, parentPath, mapIndices, dataTableRow);
20
21
  return typeof leftVal === "number" && typeof rightVal === "number" && leftVal < rightVal;
21
22
  } else if ("<=" in condition) {
22
23
  const [left, right] = condition["<="];
23
- const leftVal = resolveProteusValue(left, data, parentPath, mapIndices);
24
- const rightVal = resolveProteusValue(right, data, parentPath, mapIndices);
24
+ const leftVal = resolveProteusValue(left, data, parentPath, mapIndices, dataTableRow);
25
+ const rightVal = resolveProteusValue(right, data, parentPath, mapIndices, dataTableRow);
25
26
  return typeof leftVal === "number" && typeof rightVal === "number" && leftVal <= rightVal;
26
27
  } else if (">" in condition) {
27
28
  const [left, right] = condition[">"];
28
- const leftVal = resolveProteusValue(left, data, parentPath, mapIndices);
29
- const rightVal = resolveProteusValue(right, data, parentPath, mapIndices);
29
+ const leftVal = resolveProteusValue(left, data, parentPath, mapIndices, dataTableRow);
30
+ const rightVal = resolveProteusValue(right, data, parentPath, mapIndices, dataTableRow);
30
31
  return typeof leftVal === "number" && typeof rightVal === "number" && leftVal > rightVal;
31
32
  } else if (">=" in condition) {
32
33
  const [left, right] = condition[">="];
33
- const leftVal = resolveProteusValue(left, data, parentPath, mapIndices);
34
- const rightVal = resolveProteusValue(right, data, parentPath, mapIndices);
34
+ const leftVal = resolveProteusValue(left, data, parentPath, mapIndices, dataTableRow);
35
+ const rightVal = resolveProteusValue(right, data, parentPath, mapIndices, dataTableRow);
35
36
  return typeof leftVal === "number" && typeof rightVal === "number" && leftVal >= rightVal;
36
37
  }
37
38
  return false;
38
39
  }
39
- function resolveProteusValue(value, data, parentPath, mapIndices = []) {
40
+ function resolveProteusValue(value, data, parentPath, mapIndices = [], dataTableRow) {
40
41
  if (typeof value !== "object" || value === null) return value;
41
42
  if ("$type" in value) {
42
43
  if (value.$type === "MapIndex") return mapIndices.at(-1);
44
+ if (value.$type === "DataTableRow") return getDataTableRowValue(dataTableRow, "path" in value && typeof value.path === "string" ? value.path : void 0);
43
45
  if (value.$type === "Value" && "path" in value && typeof value.path === "string") return getProteusValue(data, value, parentPath);
44
46
  if (value.$type === "Length" && "path" in value && typeof value.path === "string") {
45
47
  const arr = getProteusValue(data, { path: value.path }, parentPath);
@@ -49,28 +51,29 @@ function resolveProteusValue(value, data, parentPath, mapIndices = []) {
49
51
  const array = getProteusValue(data, { path: value.path }, parentPath);
50
52
  if (!Array.isArray(array)) return value;
51
53
  const resolvedPath = value.path.startsWith("/") ? value.path : `${parentPath}/${value.path}`;
52
- const items = array.map((_, index) => resolveProteusValue(value.children, data, `${resolvedPath}/${index}`, [...mapIndices, index])).filter((v) => v !== void 0);
54
+ const items = array.map((_, index) => resolveProteusValue(value.children, data, `${resolvedPath}/${index}`, [...mapIndices, index], dataTableRow)).filter((v) => v !== void 0);
53
55
  const result = "flat" in value && value.flat ? items.flat() : items;
54
56
  if ("separator" in value) {
55
- const sep = resolveProteusValue(value.separator, data, parentPath, mapIndices);
57
+ const sep = resolveProteusValue(value.separator, data, parentPath, mapIndices, dataTableRow);
56
58
  return result.join(typeof sep === "string" ? sep : "");
57
59
  }
58
60
  return result;
59
61
  }
60
62
  if (value.$type === "Show" && "when" in value && "children" in value) {
61
- if (!(Array.isArray(value.when) ? value.when : [value.when]).every((condition) => evaluateCondition(condition, data, parentPath, mapIndices))) return;
62
- return resolveProteusValue(value.children, data, parentPath, mapIndices);
63
+ const branch = (Array.isArray(value.when) ? value.when : [value.when]).every((condition) => evaluateCondition(condition, data, parentPath, mapIndices, dataTableRow)) ? value.children : "else" in value ? value.else : void 0;
64
+ if (branch === void 0) return;
65
+ return resolveProteusValue(branch, data, parentPath, mapIndices, dataTableRow);
63
66
  }
64
67
  if (value.$type === "Concat" && "children" in value) {
65
68
  if (!Array.isArray(value.children)) return value;
66
- return value.children.map((child) => resolveProteusValue(child, data, parentPath, mapIndices)).filter((v) => v !== void 0).join("");
69
+ return value.children.map((child) => resolveProteusValue(child, data, parentPath, mapIndices, dataTableRow)).filter((v) => v !== void 0).join("");
67
70
  }
68
71
  return value;
69
72
  }
70
- if (Array.isArray(value)) return value.map((v) => resolveProteusValue(v, data, parentPath, mapIndices)).filter((v) => v !== void 0);
73
+ if (Array.isArray(value)) return value.map((v) => resolveProteusValue(v, data, parentPath, mapIndices, dataTableRow)).filter((v) => v !== void 0);
71
74
  const resolved = {};
72
75
  for (const [k, v] of Object.entries(value)) {
73
- const r = resolveProteusValue(v, data, parentPath, mapIndices);
76
+ const r = resolveProteusValue(v, data, parentPath, mapIndices, dataTableRow);
74
77
  if (r !== void 0) resolved[k] = r;
75
78
  }
76
79
  return resolved;
@@ -1,12 +1,14 @@
1
1
  import { useProteusDocumentContext } from "./ProteusDocumentContext.js";
2
2
  import { useProteusDocumentPathContext } from "./ProteusDocumentPathContext.js";
3
+ import { useProteusDataTableRowContext } from "./ProteusDataTableRowContext.js";
3
4
  import { resolveProteusValue } from "./resolveProteusValue.js";
4
5
  //#region src/proteus-document/useResolveProteusValues.ts
5
6
  function useResolveProteusValues(props) {
6
7
  const { data } = useProteusDocumentContext("@optiaxiom/react/useResolveProteusValues");
7
8
  const { mapIndices, path: parentPath } = useProteusDocumentPathContext("@optiaxiom/react/useResolveProteusValues");
9
+ const { row: dataTableRow } = useProteusDataTableRowContext("@optiaxiom/react/useResolveProteusValues");
8
10
  const resolved = {};
9
- for (const [key, value] of Object.entries(props)) resolved[key] = resolveProteusValue(value, data, parentPath, mapIndices);
11
+ for (const [key, value] of Object.entries(props)) resolved[key] = resolveProteusValue(value, data, parentPath, mapIndices, dataTableRow);
10
12
  return resolved;
11
13
  }
12
14
  //#endregion
@@ -1,6 +1,8 @@
1
1
  "use client";
2
2
  import { useProteusDocumentContext } from "../proteus-document/ProteusDocumentContext.js";
3
3
  import { useProteusDocumentPathContext } from "../proteus-document/ProteusDocumentPathContext.js";
4
+ import { ProteusDataTableRowProvider, useProteusDataTableRowContext } from "../proteus-document/ProteusDataTableRowContext.js";
5
+ import { ProteusDataTableRow } from "../proteus-data-table-row/ProteusDataTableRow.js";
4
6
  import { ProteusAction } from "../proteus-action/ProteusAction.js";
5
7
  import { ProteusBridge } from "../proteus-bridge/ProteusBridge.js";
6
8
  import { ProteusDataTable } from "../proteus-data-table/ProteusDataTable.js";
@@ -37,6 +39,7 @@ const ProteusChart = lazy(async () => {
37
39
  const ProteusElement = ({ element: elementProp }) => {
38
40
  const { data, icons, strict } = useProteusDocumentContext("@optiaxiom/proteus/ProteusElement");
39
41
  const { mapIndices, path: parentPath } = useProteusDocumentPathContext("@optiaxiom/proteus/ProteusElement");
42
+ const { row: dataTableRow } = useProteusDataTableRowContext("@optiaxiom/proteus/ProteusElement");
40
43
  if (!elementProp) return null;
41
44
  else if (typeof elementProp === "string" || typeof elementProp === "number") return elementProp;
42
45
  else if (Array.isArray(elementProp)) return /* @__PURE__ */ jsx(Fragment, { children: elementProp.map((element, index) => /* @__PURE__ */ jsx(ProteusElement, { element }, index)) });
@@ -49,7 +52,7 @@ const ProteusElement = ({ element: elementProp }) => {
49
52
  const resolve = (obj) => {
50
53
  const { $type: _$type, ...rest } = obj;
51
54
  const resolved = {};
52
- for (const [key, value] of Object.entries(rest)) resolved[key] = resolveProteusProp(value, data, parentPath, mapIndices);
55
+ for (const [key, value] of Object.entries(rest)) resolved[key] = resolveProteusProp(value, data, parentPath, mapIndices, dataTableRow);
53
56
  return resolved;
54
57
  };
55
58
  switch (element.$type) {
@@ -67,7 +70,14 @@ const ProteusElement = ({ element: elementProp }) => {
67
70
  fallback: null,
68
71
  children: /* @__PURE__ */ jsx(ProteusChart, { ...resolve(element) })
69
72
  });
70
- case "DataTable": return /* @__PURE__ */ jsx(ProteusDataTable, { ...resolve(element) });
73
+ case "DataTable": {
74
+ const { columns, ...props } = resolve(element);
75
+ return /* @__PURE__ */ jsx(ProteusDataTable, {
76
+ ...props,
77
+ columns: wireCellTemplates(columns)
78
+ });
79
+ }
80
+ case "DataTableRow": return /* @__PURE__ */ jsx(ProteusDataTableRow, { ...resolve(element) });
71
81
  case "DateInput": return /* @__PURE__ */ jsx(ProteusDateInput, { ...resolve(element) });
72
82
  case "Disclosure": return /* @__PURE__ */ jsx(Disclosure, { ...resolve(element) });
73
83
  case "DisclosureContent": return /* @__PURE__ */ jsx(DisclosureContent, { ...resolve(element) });
@@ -129,5 +139,24 @@ const ProteusElement = ({ element: elementProp }) => {
129
139
  }
130
140
  };
131
141
  ProteusElement.displayName = "@optiaxiom/proteus/ProteusElement";
142
+ /**
143
+ * Turns each column's raw `cell` template into a render function that renders it
144
+ * (via `ProteusElement`) with the row exposed through context, so `DataTableRow`
145
+ * can read the row. Keeps `ProteusDataTable` free of any `ProteusElement`
146
+ * dependency (avoids bundling the whole element graph into its chunk).
147
+ */
148
+ function wireCellTemplates(columns) {
149
+ return columns?.map((column) => {
150
+ const cell = column.cell;
151
+ if (cell == null) return column;
152
+ return {
153
+ ...column,
154
+ cell: (row) => /* @__PURE__ */ jsx(ProteusDataTableRowProvider, {
155
+ row,
156
+ children: /* @__PURE__ */ jsx(ProteusElement, { element: cell })
157
+ })
158
+ };
159
+ });
160
+ }
132
161
  //#endregion
133
162
  export { ProteusElement };
@@ -35,6 +35,7 @@ const INVOKE_TIMEOUT_MS = 5e3;
35
35
  function useProteusScripts({ data, onEmit, scripts }) {
36
36
  const dataRef = useRef(data);
37
37
  dataRef.current = data;
38
+ const initialDataRef = useRef(data);
38
39
  const emit = useEffectEvent(onEmit);
39
40
  const hasScripts = !!scripts && Object.keys(scripts).length > 0;
40
41
  const pending = useRef(/* @__PURE__ */ new Map()).current;
@@ -47,6 +48,32 @@ function useProteusScripts({ data, onEmit, scripts }) {
47
48
  const seedWatchers = useEffectEvent((data) => {
48
49
  lastEval.current = watchedPaths.current.map((path) => JSON.stringify(getByPointer(data, path) ?? null));
49
50
  });
51
+ /**
52
+ * Compare each watched path in `data` against its `lastEval` baseline and post
53
+ * `runWatcher` for any that changed, advancing the baseline. Shared by the
54
+ * data-change effect and the `watchers` message handler (so a watcher that
55
+ * registers after the user already changed data still catches that edge).
56
+ */
57
+ const runEdgeDetect = useEffectEvent((data) => {
58
+ const worker = workerRef.current;
59
+ if (!worker) return;
60
+ watchedPaths.current.forEach((path, watchId) => {
61
+ const current = getByPointer(data, path) ?? null;
62
+ const serialized = JSON.stringify(current);
63
+ const prevSerialized = lastEval.current[watchId];
64
+ if (serialized !== prevSerialized) {
65
+ lastEval.current[watchId] = serialized;
66
+ const previous = prevSerialized === void 0 ? void 0 : JSON.parse(prevSerialized);
67
+ worker.postMessage({
68
+ current,
69
+ data,
70
+ previous,
71
+ type: "runWatcher",
72
+ watchId
73
+ });
74
+ }
75
+ });
76
+ });
50
77
  /** Resolve a pending run (if still pending) and clear its timeout. */
51
78
  const settle = useEffectEvent((invokeId, result) => {
52
79
  const entry = pending.get(invokeId);
@@ -81,7 +108,8 @@ function useProteusScripts({ data, onEmit, scripts }) {
81
108
  } else if (msg.type === "invokeResult") settle(msg.invokeId, msg.result);
82
109
  else if (msg.type === "watchers") {
83
110
  watchedPaths.current = msg.paths;
84
- seedWatchers(dataRef.current);
111
+ seedWatchers(initialDataRef.current);
112
+ runEdgeDetect(dataRef.current);
85
113
  }
86
114
  });
87
115
  return instance;
@@ -105,28 +133,12 @@ function useProteusScripts({ data, onEmit, scripts }) {
105
133
  return teardown;
106
134
  }, [scripts, hasScripts]);
107
135
  useEffect(() => {
108
- const worker = workerRef.current;
109
- if (!worker || watchedPaths.current.length === 0) return;
136
+ if (!workerRef.current || watchedPaths.current.length === 0) return;
110
137
  if (emitDepth.current > 0) {
111
138
  seedWatchers(data);
112
139
  return;
113
140
  }
114
- watchedPaths.current.forEach((path, watchId) => {
115
- const current = getByPointer(data, path) ?? null;
116
- const serialized = JSON.stringify(current);
117
- const prevSerialized = lastEval.current[watchId];
118
- if (serialized !== prevSerialized) {
119
- lastEval.current[watchId] = serialized;
120
- const previous = prevSerialized === void 0 ? void 0 : JSON.parse(prevSerialized);
121
- worker.postMessage({
122
- current,
123
- data,
124
- previous,
125
- type: "runWatcher",
126
- watchId
127
- });
128
- }
129
- });
141
+ runEdgeDetect(data);
130
142
  }, [data]);
131
143
  return useEffectEvent((handler, params) => {
132
144
  if (!hasScripts) return Promise.resolve(void 0);
@@ -1,14 +1,15 @@
1
1
  "use client";
2
2
  import { useProteusDocumentContext } from "../proteus-document/ProteusDocumentContext.js";
3
3
  import { useProteusDocumentPathContext } from "../proteus-document/ProteusDocumentPathContext.js";
4
+ import { useProteusDataTableRowContext } from "../proteus-document/ProteusDataTableRowContext.js";
4
5
  import { evaluateCondition } from "../proteus-document/resolveProteusValue.js";
5
6
  import { Fragment, jsx } from "react/jsx-runtime";
6
7
  //#region src/proteus-show/ProteusShow.tsx
7
- function ProteusShow({ children, when }) {
8
+ function ProteusShow({ children, else: fallback, when }) {
8
9
  const { data } = useProteusDocumentContext("@optiaxiom/proteus/ProteusShow");
9
10
  const { mapIndices, path: parentPath } = useProteusDocumentPathContext("@optiaxiom/proteus/ProteusShow");
10
- if (!(Array.isArray(when) ? when : [when]).every((condition) => evaluateCondition(condition, data, parentPath, mapIndices))) return null;
11
- return /* @__PURE__ */ jsx(Fragment, { children });
11
+ const { row: dataTableRow } = useProteusDataTableRowContext("@optiaxiom/proteus/ProteusShow");
12
+ return /* @__PURE__ */ jsx(Fragment, { children: (Array.isArray(when) ? when : [when]).every((condition) => evaluateCondition(condition, data, parentPath, mapIndices, dataTableRow)) ? children : fallback });
12
13
  }
13
14
  ProteusShow.displayName = "@optiaxiom/proteus/ProteusShow";
14
15
  //#endregion
@@ -921,6 +921,7 @@ var public_schema_default = {
921
921
  { "type": "number" },
922
922
  { "type": "boolean" },
923
923
  { "type": "null" },
924
+ { "$ref": "#/definitions/ProteusDataTableRow" },
924
925
  { "$ref": "#/definitions/ProteusLength" },
925
926
  { "$ref": "#/definitions/ProteusMapIndex" },
926
927
  { "$ref": "#/definitions/ProteusValue" }
@@ -941,6 +942,7 @@ var public_schema_default = {
941
942
  { "type": "number" },
942
943
  { "type": "boolean" },
943
944
  { "type": "null" },
945
+ { "$ref": "#/definitions/ProteusDataTableRow" },
944
946
  { "$ref": "#/definitions/ProteusLength" },
945
947
  { "$ref": "#/definitions/ProteusMapIndex" },
946
948
  { "$ref": "#/definitions/ProteusValue" }
@@ -961,6 +963,7 @@ var public_schema_default = {
961
963
  { "type": "number" },
962
964
  { "type": "boolean" },
963
965
  { "type": "null" },
966
+ { "$ref": "#/definitions/ProteusDataTableRow" },
964
967
  { "$ref": "#/definitions/ProteusLength" },
965
968
  { "$ref": "#/definitions/ProteusMapIndex" },
966
969
  { "$ref": "#/definitions/ProteusValue" }
@@ -981,6 +984,7 @@ var public_schema_default = {
981
984
  { "type": "number" },
982
985
  { "type": "boolean" },
983
986
  { "type": "null" },
987
+ { "$ref": "#/definitions/ProteusDataTableRow" },
984
988
  { "$ref": "#/definitions/ProteusLength" },
985
989
  { "$ref": "#/definitions/ProteusMapIndex" },
986
990
  { "$ref": "#/definitions/ProteusValue" }
@@ -1001,6 +1005,7 @@ var public_schema_default = {
1001
1005
  { "type": "number" },
1002
1006
  { "type": "boolean" },
1003
1007
  { "type": "null" },
1008
+ { "$ref": "#/definitions/ProteusDataTableRow" },
1004
1009
  { "$ref": "#/definitions/ProteusLength" },
1005
1010
  { "$ref": "#/definitions/ProteusMapIndex" },
1006
1011
  { "$ref": "#/definitions/ProteusValue" }
@@ -1021,6 +1026,7 @@ var public_schema_default = {
1021
1026
  { "type": "number" },
1022
1027
  { "type": "boolean" },
1023
1028
  { "type": "null" },
1029
+ { "$ref": "#/definitions/ProteusDataTableRow" },
1024
1030
  { "$ref": "#/definitions/ProteusLength" },
1025
1031
  { "$ref": "#/definitions/ProteusMapIndex" },
1026
1032
  { "$ref": "#/definitions/ProteusValue" }
@@ -1040,6 +1046,7 @@ var public_schema_default = {
1040
1046
  { "type": "number" },
1041
1047
  { "type": "boolean" },
1042
1048
  { "type": "null" },
1049
+ { "$ref": "#/definitions/ProteusDataTableRow" },
1043
1050
  { "$ref": "#/definitions/ProteusLength" },
1044
1051
  { "$ref": "#/definitions/ProteusMapIndex" },
1045
1052
  { "$ref": "#/definitions/ProteusValue" }
@@ -1057,6 +1064,7 @@ var public_schema_default = {
1057
1064
  { "type": "number" },
1058
1065
  { "type": "boolean" },
1059
1066
  { "type": "null" },
1067
+ { "$ref": "#/definitions/ProteusDataTableRow" },
1060
1068
  { "$ref": "#/definitions/ProteusLength" },
1061
1069
  { "$ref": "#/definitions/ProteusMapIndex" },
1062
1070
  { "$ref": "#/definitions/ProteusValue" }
@@ -1314,6 +1322,7 @@ var public_schema_default = {
1314
1322
  { "$ref": "#/definitions/ProteusChart" },
1315
1323
  { "$ref": "#/definitions/ProteusConcat" },
1316
1324
  { "$ref": "#/definitions/ProteusDataTable" },
1325
+ { "$ref": "#/definitions/ProteusDataTableRow" },
1317
1326
  { "$ref": "#/definitions/ProteusDateInput" },
1318
1327
  { "$ref": "#/definitions/ProteusDisclosure" },
1319
1328
  { "$ref": "#/definitions/ProteusDisclosureContent" },
@@ -1513,6 +1522,7 @@ var public_schema_default = {
1513
1522
  },
1514
1523
  "ProteusExpression": {
1515
1524
  "anyOf": [
1525
+ { "$ref": "#/definitions/ProteusDataTableRow" },
1516
1526
  { "$ref": "#/definitions/ProteusLength" },
1517
1527
  { "$ref": "#/definitions/ProteusMap" },
1518
1528
  { "$ref": "#/definitions/ProteusMapIndex" },
@@ -2552,6 +2562,10 @@ var public_schema_default = {
2552
2562
  "description": "Key in data objects",
2553
2563
  "type": "string"
2554
2564
  },
2565
+ "cell": {
2566
+ "$ref": "#/definitions/ProteusNode",
2567
+ "description": "A Proteus node template rendered for each cell in this column. Read the current row with DataTableRow (e.g. { $type: 'DataTableRow', path: 'status' } reads the row's 'status', or omit 'path' for the whole row). Can be a single element or an array — use Show elements to conditionally render (e.g. a Badge whose intent depends on the row value). When set, takes precedence over 'format'."
2568
+ },
2555
2569
  "format": {
2556
2570
  "anyOf": [{
2557
2571
  "description": "Formatter name",
@@ -2594,6 +2608,22 @@ var public_schema_default = {
2594
2608
  "required": ["$type"],
2595
2609
  "type": "object"
2596
2610
  },
2611
+ "ProteusDataTableRow": {
2612
+ "additionalProperties": false,
2613
+ "examples": [{
2614
+ "$type": "DataTableRow",
2615
+ "path": "status"
2616
+ }],
2617
+ "properties": {
2618
+ "$type": { "const": "DataTableRow" },
2619
+ "path": {
2620
+ "description": "JSON pointer path to a field within the current row (e.g. 'status' or '/status'). When omitted, resolves to the whole row object. Only meaningful inside a DataTable column's `cell`.",
2621
+ "type": "string"
2622
+ }
2623
+ },
2624
+ "required": ["$type"],
2625
+ "type": "object"
2626
+ },
2597
2627
  "ProteusDateInput": {
2598
2628
  "additionalProperties": false,
2599
2629
  "examples": [{
@@ -4358,6 +4388,10 @@ var public_schema_default = {
4358
4388
  "$ref": "#/definitions/ProteusNode",
4359
4389
  "description": "Content to show when condition is true"
4360
4390
  },
4391
+ "else": {
4392
+ "$ref": "#/definitions/ProteusNode",
4393
+ "description": "Content to render when the condition is false. Omitting it renders nothing. Chain nested Show/else to express multi-way choices (e.g. mapping a value to one of several outputs)."
4394
+ },
4361
4395
  "when": {
4362
4396
  "anyOf": [{ "$ref": "#/definitions/ProteusCondition" }, {
4363
4397
  "items": { "$ref": "#/definitions/ProteusCondition" },
@@ -918,6 +918,7 @@ var definitions = {
918
918
  { "type": "number" },
919
919
  { "type": "boolean" },
920
920
  { "type": "null" },
921
+ { "$ref": "#/definitions/ProteusDataTableRow" },
921
922
  { "$ref": "#/definitions/ProteusLength" },
922
923
  { "$ref": "#/definitions/ProteusMapIndex" },
923
924
  { "$ref": "#/definitions/ProteusValue" }
@@ -937,6 +938,7 @@ var definitions = {
937
938
  { "type": "number" },
938
939
  { "type": "boolean" },
939
940
  { "type": "null" },
941
+ { "$ref": "#/definitions/ProteusDataTableRow" },
940
942
  { "$ref": "#/definitions/ProteusLength" },
941
943
  { "$ref": "#/definitions/ProteusMapIndex" },
942
944
  { "$ref": "#/definitions/ProteusValue" }
@@ -956,6 +958,7 @@ var definitions = {
956
958
  { "type": "number" },
957
959
  { "type": "boolean" },
958
960
  { "type": "null" },
961
+ { "$ref": "#/definitions/ProteusDataTableRow" },
959
962
  { "$ref": "#/definitions/ProteusLength" },
960
963
  { "$ref": "#/definitions/ProteusMapIndex" },
961
964
  { "$ref": "#/definitions/ProteusValue" }
@@ -975,6 +978,7 @@ var definitions = {
975
978
  { "type": "number" },
976
979
  { "type": "boolean" },
977
980
  { "type": "null" },
981
+ { "$ref": "#/definitions/ProteusDataTableRow" },
978
982
  { "$ref": "#/definitions/ProteusLength" },
979
983
  { "$ref": "#/definitions/ProteusMapIndex" },
980
984
  { "$ref": "#/definitions/ProteusValue" }
@@ -994,6 +998,7 @@ var definitions = {
994
998
  { "type": "number" },
995
999
  { "type": "boolean" },
996
1000
  { "type": "null" },
1001
+ { "$ref": "#/definitions/ProteusDataTableRow" },
997
1002
  { "$ref": "#/definitions/ProteusLength" },
998
1003
  { "$ref": "#/definitions/ProteusMapIndex" },
999
1004
  { "$ref": "#/definitions/ProteusValue" }
@@ -1013,6 +1018,7 @@ var definitions = {
1013
1018
  { "type": "number" },
1014
1019
  { "type": "boolean" },
1015
1020
  { "type": "null" },
1021
+ { "$ref": "#/definitions/ProteusDataTableRow" },
1016
1022
  { "$ref": "#/definitions/ProteusLength" },
1017
1023
  { "$ref": "#/definitions/ProteusMapIndex" },
1018
1024
  { "$ref": "#/definitions/ProteusValue" }
@@ -1031,6 +1037,7 @@ var definitions = {
1031
1037
  { "type": "number" },
1032
1038
  { "type": "boolean" },
1033
1039
  { "type": "null" },
1040
+ { "$ref": "#/definitions/ProteusDataTableRow" },
1034
1041
  { "$ref": "#/definitions/ProteusLength" },
1035
1042
  { "$ref": "#/definitions/ProteusMapIndex" },
1036
1043
  { "$ref": "#/definitions/ProteusValue" }
@@ -1047,6 +1054,7 @@ var definitions = {
1047
1054
  { "type": "number" },
1048
1055
  { "type": "boolean" },
1049
1056
  { "type": "null" },
1057
+ { "$ref": "#/definitions/ProteusDataTableRow" },
1050
1058
  { "$ref": "#/definitions/ProteusLength" },
1051
1059
  { "$ref": "#/definitions/ProteusMapIndex" },
1052
1060
  { "$ref": "#/definitions/ProteusValue" }
@@ -1301,6 +1309,7 @@ var definitions = {
1301
1309
  { "$ref": "#/definitions/ProteusChart" },
1302
1310
  { "$ref": "#/definitions/ProteusConcat" },
1303
1311
  { "$ref": "#/definitions/ProteusDataTable" },
1312
+ { "$ref": "#/definitions/ProteusDataTableRow" },
1304
1313
  { "$ref": "#/definitions/ProteusDateInput" },
1305
1314
  { "$ref": "#/definitions/ProteusDisclosure" },
1306
1315
  { "$ref": "#/definitions/ProteusDisclosureContent" },
@@ -1491,6 +1500,7 @@ var definitions = {
1491
1500
  },
1492
1501
  "ProteusExpression": {
1493
1502
  "anyOf": [
1503
+ { "$ref": "#/definitions/ProteusDataTableRow" },
1494
1504
  { "$ref": "#/definitions/ProteusLength" },
1495
1505
  { "$ref": "#/definitions/ProteusMap" },
1496
1506
  { "$ref": "#/definitions/ProteusMapIndex" },
@@ -2511,6 +2521,10 @@ var definitions = {
2511
2521
  "description": "Key in data objects",
2512
2522
  "type": "string"
2513
2523
  },
2524
+ "cell": {
2525
+ "$ref": "#/definitions/ProteusNode",
2526
+ "description": "A Proteus node template rendered for each cell in this column. Read the current row with DataTableRow (e.g. { $type: 'DataTableRow', path: 'status' } reads the row's 'status', or omit 'path' for the whole row). Can be a single element or an array — use Show elements to conditionally render (e.g. a Badge whose intent depends on the row value). When set, takes precedence over 'format'."
2527
+ },
2514
2528
  "format": {
2515
2529
  "anyOf": [{
2516
2530
  "description": "Formatter name",
@@ -2553,6 +2567,21 @@ var definitions = {
2553
2567
  "required": ["$type"],
2554
2568
  "type": "object"
2555
2569
  },
2570
+ "ProteusDataTableRow": {
2571
+ "examples": [{
2572
+ "$type": "DataTableRow",
2573
+ "path": "status"
2574
+ }],
2575
+ "properties": {
2576
+ "$type": { "const": "DataTableRow" },
2577
+ "path": {
2578
+ "description": "JSON pointer path to a field within the current row (e.g. 'status' or '/status'). When omitted, resolves to the whole row object. Only meaningful inside a DataTable column's `cell`.",
2579
+ "type": "string"
2580
+ }
2581
+ },
2582
+ "required": ["$type"],
2583
+ "type": "object"
2584
+ },
2556
2585
  "ProteusDateInput": {
2557
2586
  "examples": [{
2558
2587
  "$type": "DateInput",
@@ -4285,6 +4314,10 @@ var definitions = {
4285
4314
  "$ref": "#/definitions/ProteusNode",
4286
4315
  "description": "Content to show when condition is true"
4287
4316
  },
4317
+ "else": {
4318
+ "$ref": "#/definitions/ProteusNode",
4319
+ "description": "Content to render when the condition is false. Omitting it renders nothing. Chain nested Show/else to express multi-way choices (e.g. mapping a value to one of several outputs)."
4320
+ },
4288
4321
  "when": {
4289
4322
  "anyOf": [{ "$ref": "#/definitions/ProteusCondition" }, {
4290
4323
  "items": { "$ref": "#/definitions/ProteusCondition" },
package/dist/index.d.ts CHANGED
@@ -64,6 +64,21 @@ declare namespace ProteusChart {
64
64
  var displayName: string;
65
65
  }
66
66
  //#endregion
67
+ //#region src/proteus-data-table-row/ProteusDataTableRow.d.ts
68
+ type ProteusDataTableRowProps = {
69
+ /**
70
+ * JSON pointer path to a field within the current row (e.g. `type` or
71
+ * `/type`). When omitted, resolves to the whole row object.
72
+ */
73
+ path?: string;
74
+ };
75
+ declare function ProteusDataTableRow({
76
+ path
77
+ }: ProteusDataTableRowProps): string | null;
78
+ declare namespace ProteusDataTableRow {
79
+ var displayName: string;
80
+ }
81
+ //#endregion
67
82
  //#region src/proteus-data-table/ProteusDataTable.d.ts
68
83
  type ProteusDataTableProps = {
69
84
  /**
@@ -77,6 +92,12 @@ type ProteusDataTableProps = {
77
92
  };
78
93
  type ColumnDef = {
79
94
  accessorKey: string;
95
+ /**
96
+ * Renders a cell for this column from the row's data. When set, takes
97
+ * precedence over `format`. Wired up from a Proteus `cell` template by
98
+ * `ProteusElement`.
99
+ */
100
+ cell?: (row: Record<string, unknown>) => ReactNode;
80
101
  format?: string | {
81
102
  options?: Record<string, unknown>;
82
103
  type: string;
@@ -348,6 +369,9 @@ type ProteusCondition = {
348
369
  or: ProteusCondition[];
349
370
  };
350
371
  type ComparisonValue = boolean | null | number | string | {
372
+ $type: "DataTableRow";
373
+ path?: string;
374
+ } | {
351
375
  $type: "Length";
352
376
  path: string;
353
377
  } | {
@@ -360,6 +384,10 @@ type ComparisonValue = boolean | null | number | string | {
360
384
  //#region src/proteus-show/ProteusShow.d.ts
361
385
  type ProteusShowProps = {
362
386
  children?: ReactNode;
387
+ /**
388
+ * Content to render when the condition is false. Omitting it renders nothing.
389
+ */
390
+ else?: ReactNode;
363
391
  /**
364
392
  * Single condition or array of conditions (AND logic). Each condition is an
365
393
  * object with one operator key.
@@ -368,8 +396,9 @@ type ProteusShowProps = {
368
396
  };
369
397
  declare function ProteusShow({
370
398
  children,
399
+ else: fallback,
371
400
  when
372
- }: ProteusShowProps): import("react/jsx-runtime").JSX.Element | null;
401
+ }: ProteusShowProps): import("react/jsx-runtime").JSX.Element;
373
402
  declare namespace ProteusShow {
374
403
  var displayName: string;
375
404
  }
@@ -664,4 +693,4 @@ declare namespace ProteusTextarea {
664
693
  //#region src/use-proteus-value/useProteusValue.d.ts
665
694
  declare function useProteusValue(element: ProteusValueProps): any;
666
695
  //#endregion
667
- export { type FileUploadMetadata, ProteusAction, ProteusBridge, ProteusChart, ProteusDataTable, ProteusDateInput, ProteusDocumentRenderer, ProteusDocumentRendererProps, ProteusDocumentShell, ProteusDocumentShellProps, ProteusFederated, ProteusFileUpload, ProteusFileUploadProps, ProteusImage, ProteusImageCarousel, ProteusInput, ProteusLength, ProteusMap, ProteusMapIndex, ProteusMarkdown, ProteusPillMenu, ProteusPillMenuProps, type ProteusPreviewFile, ProteusRichTextEditor, ProteusSelect, ProteusShow, ProteusTextarea, type StructuredMessage, type UploadFile, safeParseDocument, useProteusValue };
696
+ export { type FileUploadMetadata, ProteusAction, ProteusBridge, ProteusChart, ProteusDataTable, ProteusDataTableRow, ProteusDateInput, ProteusDocumentRenderer, ProteusDocumentRendererProps, ProteusDocumentShell, ProteusDocumentShellProps, ProteusFederated, ProteusFileUpload, ProteusFileUploadProps, ProteusImage, ProteusImageCarousel, ProteusInput, ProteusLength, ProteusMap, ProteusMapIndex, ProteusMarkdown, ProteusPillMenu, ProteusPillMenuProps, type ProteusPreviewFile, ProteusRichTextEditor, ProteusSelect, ProteusShow, ProteusTextarea, type StructuredMessage, type UploadFile, safeParseDocument, useProteusValue };
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "url": "git+https://github.com/optimizely-axiom/optiaxiom.git"
8
8
  },
9
9
  "type": "module",
10
- "version": "3.1.0",
10
+ "version": "3.2.0",
11
11
  "files": [
12
12
  "dist/**",
13
13
  "LICENSE"
@@ -41,8 +41,8 @@
41
41
  "react-markdown": "^10.1.0",
42
42
  "recharts": "^3.8.1",
43
43
  "remark-gfm": "^4.0.1",
44
- "@optiaxiom/icons": "^1.3.0",
45
- "@optiaxiom/react": "^3.1.4"
44
+ "@optiaxiom/react": "^3.1.4",
45
+ "@optiaxiom/icons": "^1.3.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@emotion/hash": "^0.9.2",