@optiaxiom/proteus 3.0.6 → 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.
Files changed (30) hide show
  1. package/dist/esm/assets/src/proteus-chart/{ProteusChart.css.ts.vanilla-ByPSKREp.css → ProteusChart.css.ts.vanilla-BcGBUwbD.css} +2 -2
  2. package/dist/esm/assets/src/proteus-chart/{ProteusChartTooltipContent.css.ts.vanilla-DnR_C5ly.css → ProteusChartTooltipContent.css.ts.vanilla-BthlShlk.css} +2 -2
  3. package/dist/esm/assets/src/proteus-document/{ProteusDocumentShell.css.ts.vanilla-CVOes7es.css → ProteusDocumentShell.css.ts.vanilla-BugeP59E.css} +2 -2
  4. package/dist/esm/assets/src/proteus-image-carousel/{ProteusImageCarousel.css.ts.vanilla-DXF3wHYt.css → ProteusImageCarousel.css.ts.vanilla-DhXdg25-.css} +2 -2
  5. package/dist/esm/assets/src/proteus-markdown/{ProteusMarkdown.css.ts.vanilla-Cjmk3X5z.css → ProteusMarkdown.css.ts.vanilla-BM9-lPyj.css} +2 -2
  6. package/dist/esm/assets/src/proteus-question/{ProteusQuestion.css.ts.vanilla-DVFRsIPp.css → ProteusQuestion.css.ts.vanilla-1u353vmb.css} +2 -2
  7. package/dist/esm/index.js +2 -1
  8. package/dist/esm/proteus-action/ProteusAction.js +1 -1
  9. package/dist/esm/proteus-chart/ProteusChart-css.js +1 -1
  10. package/dist/esm/proteus-chart/ProteusChartTooltipContent-css.js +1 -1
  11. package/dist/esm/proteus-data-table/ProteusDataTable.js +3 -1
  12. package/dist/esm/proteus-data-table-row/ProteusDataTableRow.js +26 -0
  13. package/dist/esm/proteus-document/ProteusDataTableRowContext.js +12 -0
  14. package/dist/esm/proteus-document/ProteusDocumentShell-css.js +1 -1
  15. package/dist/esm/proteus-document/ProteusDocumentShell.js +70 -49
  16. package/dist/esm/proteus-document/isSafeUrl.js +22 -0
  17. package/dist/esm/proteus-document/resolveProteusProp.js +5 -6
  18. package/dist/esm/proteus-document/resolveProteusValue.js +26 -23
  19. package/dist/esm/proteus-document/useResolveProteusValues.js +3 -1
  20. package/dist/esm/proteus-element/ProteusElement.js +41 -3
  21. package/dist/esm/proteus-image-carousel/ProteusImageCarousel-css.js +1 -1
  22. package/dist/esm/proteus-markdown/ProteusMarkdown-css.js +1 -1
  23. package/dist/esm/proteus-question/ProteusQuestion-css.js +1 -1
  24. package/dist/esm/proteus-script/useProteusScripts.js +176 -0
  25. package/dist/esm/proteus-script/workerScript.js +149 -0
  26. package/dist/esm/proteus-show/ProteusShow.js +4 -3
  27. package/dist/esm/schema/public-schema.js +100 -0
  28. package/dist/esm/schema/runtime-schema.js +97 -0
  29. package/dist/index.d.ts +42 -2
  30. package/package.json +3 -3
@@ -1,5 +1,5 @@
1
- @layer optiaxiom._1dfr2ib;
2
- @layer optiaxiom._1dfr2ib {
1
+ @layer optiaxiom.st6wia;
2
+ @layer optiaxiom.st6wia {
3
3
  .ProteusChart__jmlqij1 {
4
4
  border-radius: 16px;
5
5
  }
@@ -1,5 +1,5 @@
1
- @layer optiaxiom._1dfr2ib;
2
- @layer optiaxiom._1dfr2ib {
1
+ @layer optiaxiom.st6wia;
2
+ @layer optiaxiom.st6wia {
3
3
  .ProteusChartTooltipContent__1gsvq810 {
4
4
  min-width: 128px;
5
5
  position: absolute;
@@ -1,5 +1,5 @@
1
- @layer optiaxiom._1dfr2ib;
2
- @layer optiaxiom._1dfr2ib {
1
+ @layer optiaxiom.st6wia;
2
+ @layer optiaxiom.st6wia {
3
3
  .ProteusDocumentShell__vpuvfj1 {
4
4
  margin: -4px;
5
5
  }
@@ -1,5 +1,5 @@
1
- @layer optiaxiom._1dfr2ib;
2
- @layer optiaxiom._1dfr2ib {
1
+ @layer optiaxiom.st6wia;
2
+ @layer optiaxiom.st6wia {
3
3
  .ProteusImageCarousel__1t6qej70 {
4
4
  outline: none;
5
5
  user-select: none;
@@ -1,5 +1,5 @@
1
- @layer optiaxiom._1dfr2ib;
2
- @layer optiaxiom._1dfr2ib {
1
+ @layer optiaxiom.st6wia;
2
+ @layer optiaxiom.st6wia {
3
3
  .ProteusMarkdown__1ibq5ae0 > * {
4
4
  margin-bottom: 1em;
5
5
  margin-top: 0;
@@ -1,5 +1,5 @@
1
- @layer optiaxiom._1dfr2ib;
2
- @layer optiaxiom._1dfr2ib {
1
+ @layer optiaxiom.st6wia;
2
+ @layer optiaxiom.st6wia {
3
3
  .ProteusQuestion__8f590p0 {
4
4
  outline: none;
5
5
  }
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 };
@@ -33,7 +33,7 @@ function ProteusAction({ children, onClick, type = "button", ...props }) {
33
33
  * available — so the document-root event handler can apply it unambiguously.
34
34
  */
35
35
  function resolveEventPath(event, parentPath) {
36
- if (event && typeof event === "object" && "action" in event && (event.action === "pushValue" || event.action === "removeValue")) {
36
+ if (event && typeof event === "object" && "action" in event && (event.action === "pushValue" || event.action === "removeValue" || event.action === "setValue")) {
37
37
  const { path } = event;
38
38
  const resolved = path === "" ? parentPath : path.startsWith("/") ? path : `${parentPath}/${path}`;
39
39
  return {
@@ -1,4 +1,4 @@
1
- import "./../assets/src/proteus-chart/ProteusChart.css.ts.vanilla-ByPSKREp.css";
1
+ import "./../assets/src/proteus-chart/ProteusChart.css.ts.vanilla-BcGBUwbD.css";
2
2
  import { recipe } from "@optiaxiom/react/css-runtime";
3
3
  //#region src/proteus-chart/ProteusChart.css.ts
4
4
  var chart = recipe({ base: [
@@ -1,5 +1,5 @@
1
1
  import { recipe } from "@optiaxiom/react/css-runtime";
2
- import "./../assets/src/proteus-chart/ProteusChartTooltipContent.css.ts.vanilla-DnR_C5ly.css";
2
+ import "./../assets/src/proteus-chart/ProteusChartTooltipContent.css.ts.vanilla-BthlShlk.css";
3
3
  //#region src/proteus-chart/ProteusChartTooltipContent.css.ts
4
4
  var tooltip = recipe({ base: [{
5
5
  bg: "bg.default",
@@ -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,5 +1,5 @@
1
1
  import { recipe } from "@optiaxiom/react/css-runtime";
2
- import "./../assets/src/proteus-document/ProteusDocumentShell.css.ts.vanilla-CVOes7es.css";
2
+ import "./../assets/src/proteus-document/ProteusDocumentShell.css.ts.vanilla-BugeP59E.css";
3
3
  //#region src/proteus-document/ProteusDocumentShell.css.ts
4
4
  var body = recipe({
5
5
  base: [{
@@ -3,6 +3,8 @@ import { ProteusDocumentProvider } from "./ProteusDocumentContext.js";
3
3
  import { resolveProteusValue } from "./resolveProteusValue.js";
4
4
  import { useEffectEvent } from "../hooks/useEffectEvent.js";
5
5
  import { downloadFile } from "../proteus-image/downloadFile.js";
6
+ import { useProteusScripts } from "../proteus-script/useProteusScripts.js";
7
+ import { isSafeUrl } from "./isSafeUrl.js";
6
8
  import { body, scrollIndicator } from "./ProteusDocumentShell-css.js";
7
9
  import { Box, Disclosure, DisclosureContent, DisclosureTrigger, Group, Heading, Text, Tooltip } from "@optiaxiom/react";
8
10
  import { useEffect, useRef, useState } from "react";
@@ -41,6 +43,73 @@ function ProteusDocumentShell({ collapsible: collapsibleProp, data = {}, default
41
43
  const collapsible = collapsibleProp && element.appName;
42
44
  const Trigger = collapsible ? DisclosureTrigger : Box;
43
45
  const inline = resolveProteusValue(element.appearance, data, "", []) === "inline";
46
+ const onEvent = useEffectEvent(async (event) => {
47
+ if ("interaction" in event) return await onInteraction?.(event.interaction, event.params);
48
+ else if ("message" in event) await onMessage?.(event.message);
49
+ else if ("script" in event) return await runScript(event.script, event.params);
50
+ else if (event.action === "download") {
51
+ const urls = [];
52
+ if (typeof event.url === "string") urls.push(event.url);
53
+ else if (Array.isArray(event.url)) for (const u of event.url) {
54
+ if (typeof u !== "string") throw new Error("Invalid URL in download array");
55
+ urls.push(u);
56
+ }
57
+ else throw new Error("Invalid URL for download action");
58
+ for (const u of urls) if (!isSafeUrl(u)) {
59
+ if (strict) throw new Error(`download: unsafe URL "${u}"`);
60
+ return;
61
+ }
62
+ if (onDownload) await onDownload(urls);
63
+ else await Promise.all(urls.map((u) => downloadFile(u)));
64
+ } else if (event.action === "openLink") {
65
+ if (isSafeUrl(event.url)) window.open(event.url, "_blank", "noopener,noreferrer");
66
+ else if (strict) throw new Error(`openLink: unsafe URL "${String(event.url)}"`);
67
+ } else if (event.action === "preview") await onPreview?.(event.file);
68
+ else if (event.action === "pushValue") {
69
+ const { path, value } = event;
70
+ onDataChange?.((prev) => {
71
+ const next = structuredClone(prev);
72
+ const current = get(next, path);
73
+ if (current !== void 0 && !Array.isArray(current)) {
74
+ if (strict) throw new Error(`pushValue: expected array at "${path}"`);
75
+ return prev;
76
+ }
77
+ set(next, path, [...current ?? [], value]);
78
+ return next;
79
+ });
80
+ } else if (event.action === "removeValue") {
81
+ const { path } = event;
82
+ const slash = path.lastIndexOf("/");
83
+ const parent = slash > 0 ? path.slice(0, slash) : "";
84
+ const index = Number(path.slice(slash + 1));
85
+ if (!parent || !Number.isInteger(index)) {
86
+ if (strict) throw new Error(`removeValue: "${path}" is not an array index`);
87
+ return;
88
+ }
89
+ onDataChange?.((prev) => {
90
+ const next = structuredClone(prev);
91
+ const arr = get(next, parent);
92
+ if (!Array.isArray(arr)) {
93
+ if (strict) throw new Error(`removeValue: "${parent}" is not an array`);
94
+ return prev;
95
+ }
96
+ set(next, parent, arr.filter((_, i) => i !== index));
97
+ return next;
98
+ });
99
+ } else if (event.action === "setValue") {
100
+ const { path, value } = event;
101
+ onDataChange?.((prev) => {
102
+ const next = structuredClone(prev);
103
+ set(next, path, value);
104
+ return next;
105
+ });
106
+ }
107
+ });
108
+ const runScript = useProteusScripts({
109
+ data,
110
+ onEmit: onEvent,
111
+ scripts: element.scripts
112
+ });
44
113
  return /* @__PURE__ */ jsx(ProteusDocumentProvider, {
45
114
  data,
46
115
  icons,
@@ -51,55 +120,7 @@ function ProteusDocumentShell({ collapsible: collapsibleProp, data = {}, default
51
120
  return next;
52
121
  });
53
122
  }),
54
- onEvent: useEffectEvent(async (event) => {
55
- if ("interaction" in event) return await onInteraction?.(event.interaction, event.params);
56
- else if ("message" in event) await onMessage?.(event.message);
57
- else if (event.action === "download") {
58
- const urls = [];
59
- if (typeof event.url === "string") urls.push(event.url);
60
- else if (Array.isArray(event.url)) for (const u of event.url) {
61
- if (typeof u !== "string") throw new Error("Invalid URL in download array");
62
- urls.push(u);
63
- }
64
- else throw new Error("Invalid URL for download action");
65
- if (onDownload) await onDownload(urls);
66
- else await Promise.all(urls.map((u) => downloadFile(u)));
67
- } else if (event.action === "openLink") {
68
- if (typeof event.url === "string") window.open(event.url, "_blank", "noopener,noreferrer");
69
- } else if (event.action === "preview") await onPreview?.(event.file);
70
- else if (event.action === "pushValue") {
71
- const { path, value } = event;
72
- onDataChange?.((prev) => {
73
- const next = structuredClone(prev);
74
- const current = get(next, path);
75
- if (current !== void 0 && !Array.isArray(current)) {
76
- if (strict) throw new Error(`pushValue: expected array at "${path}"`);
77
- return prev;
78
- }
79
- set(next, path, [...current ?? [], value]);
80
- return next;
81
- });
82
- } else if (event.action === "removeValue") {
83
- const { path } = event;
84
- const slash = path.lastIndexOf("/");
85
- const parent = slash > 0 ? path.slice(0, slash) : "";
86
- const index = Number(path.slice(slash + 1));
87
- if (!parent || !Number.isInteger(index)) {
88
- if (strict) throw new Error(`removeValue: "${path}" is not an array index`);
89
- return;
90
- }
91
- onDataChange?.((prev) => {
92
- const next = structuredClone(prev);
93
- const arr = get(next, parent);
94
- if (!Array.isArray(arr)) {
95
- if (strict) throw new Error(`removeValue: "${parent}" is not an array`);
96
- return prev;
97
- }
98
- set(next, parent, arr.filter((_, i) => i !== index));
99
- return next;
100
- });
101
- }
102
- }),
123
+ onEvent,
103
124
  onTrack: useEffectEvent((event, properties) => {
104
125
  onTrack?.(event, properties);
105
126
  }),
@@ -0,0 +1,22 @@
1
+ //#region src/proteus-document/isSafeUrl.ts
2
+ /**
3
+ * Whether a URL is safe to hand to `window.open` from a document-triggered
4
+ * action (`openLink` / `download`).
5
+ *
6
+ * Documents — and now scripts, via `ctx.emit` — supply these URLs, so we only
7
+ * allow navigable web schemes and reject dangerous ones like `javascript:`
8
+ * (script injection) and `data:` (can host arbitrary HTML/JS in a new tab).
9
+ * Relative URLs are resolved against the current document.
10
+ */
11
+ function isSafeUrl(url) {
12
+ if (typeof url !== "string") return false;
13
+ let parsed;
14
+ try {
15
+ parsed = new URL(url, window.location.href);
16
+ } catch {
17
+ return false;
18
+ }
19
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
20
+ }
21
+ //#endregion
22
+ export { isSafeUrl };
@@ -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) });
@@ -82,7 +92,16 @@ const ProteusElement = ({ element: elementProp }) => {
82
92
  const { filled, name, ...rest } = resolve(element);
83
93
  const IconComp = icons?.[name];
84
94
  if (!IconComp) {
85
- if (strict) throw new Error(`Icon "${name}" not registered. Pass it via the \`icons\` prop on ProteusDocumentRenderer.`);
95
+ if (typeof name === "string" && /^(?:https?:\/\/|data:)/.test(name)) return /* @__PURE__ */ jsx(Box, {
96
+ asChild: true,
97
+ ...rest,
98
+ children: /* @__PURE__ */ jsx("img", {
99
+ alt: "",
100
+ "aria-hidden": "true",
101
+ src: name
102
+ })
103
+ });
104
+ if (strict) throw new Error(`Icon "${name}" not registered and not a URL. Pass it via the \`icons\` prop on ProteusDocumentRenderer, or use an http(s):// or data: URL.`);
86
105
  return null;
87
106
  }
88
107
  return /* @__PURE__ */ jsx(Box, {
@@ -120,5 +139,24 @@ const ProteusElement = ({ element: elementProp }) => {
120
139
  }
121
140
  };
122
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
+ }
123
161
  //#endregion
124
162
  export { ProteusElement };
@@ -1,5 +1,5 @@
1
1
  import { recipe } from "@optiaxiom/react/css-runtime";
2
- import "./../assets/src/proteus-image-carousel/ProteusImageCarousel.css.ts.vanilla-DXF3wHYt.css";
2
+ import "./../assets/src/proteus-image-carousel/ProteusImageCarousel.css.ts.vanilla-DhXdg25-.css";
3
3
  //#region src/proteus-image-carousel/ProteusImageCarousel.css.ts
4
4
  var carousel = recipe({ base: [{
5
5
  flexDirection: "column",
@@ -1,5 +1,5 @@
1
1
  import { recipe } from "@optiaxiom/react/css-runtime";
2
- import "./../assets/src/proteus-markdown/ProteusMarkdown.css.ts.vanilla-Cjmk3X5z.css";
2
+ import "./../assets/src/proteus-markdown/ProteusMarkdown.css.ts.vanilla-BM9-lPyj.css";
3
3
  //#region src/proteus-markdown/ProteusMarkdown.css.ts
4
4
  var code = recipe({ base: [{
5
5
  bg: "bg.secondary",
@@ -1,5 +1,5 @@
1
1
  import { recipe } from "@optiaxiom/react/css-runtime";
2
- import "./../assets/src/proteus-question/ProteusQuestion.css.ts.vanilla-DVFRsIPp.css";
2
+ import "./../assets/src/proteus-question/ProteusQuestion.css.ts.vanilla-1u353vmb.css";
3
3
  //#region src/proteus-question/ProteusQuestion.css.ts
4
4
  var addon = recipe({
5
5
  base: [{