twico-ui 1.14.1 → 1.15.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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to Twico UI are documented here (newest first). This file is generated automatically on each release by [semantic-release](https://semantic-release.gitbook.io/) from [Conventional Commits](https://www.conventionalcommits.org/) — do not edit it by hand. The same notes appear on each [GitHub Release](https://github.com/EncryptionL/twico-ui/releases).
4
4
 
5
+ # [1.15.0](https://github.com/EncryptionL/twico-ui/compare/v1.14.1...v1.15.0) (2026-07-14)
6
+
7
+
8
+ ### Features
9
+
10
+ * **datatable:** add `diff` mode — re-home DiffTable on the Datatable engine ([#239](https://github.com/EncryptionL/twico-ui/issues/239)) ([d7cf524](https://github.com/EncryptionL/twico-ui/commit/d7cf524e44e579318b36ead62aa13b832142cd89)), closes [#205](https://github.com/EncryptionL/twico-ui/issues/205)
11
+
5
12
  ## [1.14.1](https://github.com/EncryptionL/twico-ui/compare/v1.14.0...v1.14.1) (2026-07-14)
6
13
 
7
14
 
package/dist/index.cjs CHANGED
@@ -8034,6 +8034,78 @@ function Tooltip({
8034
8034
  }
8035
8035
  );
8036
8036
  }
8037
+
8038
+ // components/_diff.js
8039
+ var DIFF_OPS = {
8040
+ added: { label: "Added", tone: "success" },
8041
+ removed: { label: "Removed", tone: "danger" },
8042
+ modified: { label: "Modified", tone: "warning" },
8043
+ moved: { label: "Moved", tone: "info" },
8044
+ unchanged: { label: "Unchanged", tone: "neutral" }
8045
+ };
8046
+ function lisIndexSet(seq) {
8047
+ const n = seq.length;
8048
+ if (n === 0) return /* @__PURE__ */ new Set();
8049
+ const dp = new Array(n).fill(1), prev = new Array(n).fill(-1);
8050
+ let best = 0;
8051
+ for (let i = 0; i < n; i++) {
8052
+ for (let j = 0; j < i; j++) {
8053
+ if (seq[j] < seq[i] && dp[j] + 1 > dp[i]) {
8054
+ dp[i] = dp[j] + 1;
8055
+ prev[i] = j;
8056
+ }
8057
+ }
8058
+ if (dp[i] > dp[best]) best = i;
8059
+ }
8060
+ const set = /* @__PURE__ */ new Set();
8061
+ for (let i = best; i !== -1; i = prev[i]) set.add(i);
8062
+ return set;
8063
+ }
8064
+ var cellVal = (col, row) => col.valueGetter ? col.valueGetter(row) : row == null ? void 0 : row[col.field];
8065
+ function classifyDiff(from = [], to = [], columns = [], rowKey, opts = {}) {
8066
+ const { moveDetection = true, compare } = opts;
8067
+ const k = rowKey || ((r2) => r2 == null ? r2 : r2.id);
8068
+ const valEq = (a, b, col) => {
8069
+ if (col.compare) return col.compare(a, b);
8070
+ if (compare) return compare(a, b, col.field);
8071
+ if (a === b) return true;
8072
+ if (a == null || b == null) return a === b;
8073
+ return JSON.stringify(a) === JSON.stringify(b);
8074
+ };
8075
+ const fromMap = /* @__PURE__ */ new Map(), toMap = /* @__PURE__ */ new Map();
8076
+ from.forEach((r2, i) => fromMap.set(k(r2), { row: r2, i }));
8077
+ to.forEach((r2, i) => toMap.set(k(r2), { row: r2, i }));
8078
+ const movedKeys = /* @__PURE__ */ new Set();
8079
+ if (moveDetection) {
8080
+ const commonFrom = from.filter((r2) => toMap.has(k(r2)));
8081
+ const seq = commonFrom.map((r2) => toMap.get(k(r2)).i);
8082
+ const stable = lisIndexSet(seq);
8083
+ commonFrom.forEach((r2, idx) => {
8084
+ if (!stable.has(idx)) movedKeys.add(k(r2));
8085
+ });
8086
+ }
8087
+ const classify = (key) => {
8088
+ const a = fromMap.get(key), b = toMap.get(key);
8089
+ if (a && !b) return { op: "removed", from: a.row, to: null, changed: /* @__PURE__ */ new Set() };
8090
+ if (!a && b) return { op: "added", from: null, to: b.row, changed: /* @__PURE__ */ new Set() };
8091
+ const changed = /* @__PURE__ */ new Set();
8092
+ for (const col of columns) if (col.field && !valEq(cellVal(col, a.row), cellVal(col, b.row), col)) changed.add(col.field);
8093
+ if (changed.size) return { op: "modified", from: a.row, to: b.row, changed };
8094
+ if (movedKeys.has(key)) return { op: "moved", from: a.row, to: b.row, changed };
8095
+ return { op: "unchanged", from: a.row, to: b.row, changed };
8096
+ };
8097
+ const rows = [];
8098
+ to.forEach((r2) => rows.push({ key: k(r2), ...classify(k(r2)) }));
8099
+ from.forEach((r2) => {
8100
+ const key = k(r2);
8101
+ if (!toMap.has(key)) rows.push({ key, ...classify(key) });
8102
+ });
8103
+ const counts = { added: 0, removed: 0, modified: 0, moved: 0, unchanged: 0 };
8104
+ rows.forEach((r2) => {
8105
+ counts[r2.op] += 1;
8106
+ });
8107
+ return { rows, counts };
8108
+ }
8037
8109
  var DT_CSS = `
8038
8110
  .twc-dt { display: flex; flex-direction: column; font-family: var(--font-sans); color: var(--color-text);
8039
8111
  border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-lg);
@@ -8272,6 +8344,18 @@ var DT_CSS = `
8272
8344
  /* Row reordering */
8273
8345
  .twc-dt__row[data-reorderable] { cursor: grab; }
8274
8346
  .twc-dt__row[data-row-dragging] { opacity: 0.4; }
8347
+ /* #239 diff mode: row op tint + before\u2192after cells (single-line, clipped by the td's own overflow). */
8348
+ .twc-dt__row[data-op="added"] > .twc-dt__td { background: color-mix(in srgb, var(--color-success) 7%, transparent); }
8349
+ .twc-dt__row[data-op="removed"] > .twc-dt__td { background: color-mix(in srgb, var(--color-danger) 7%, transparent); }
8350
+ .twc-dt__row[data-op="modified"] > .twc-dt__td { background: color-mix(in srgb, var(--color-warning) 6%, transparent); }
8351
+ .twc-dt__diff-change { display: inline-flex; align-items: center; gap: 4px; min-width: 0; max-width: 100%; }
8352
+ .twc-dt__diff-old { text-decoration: line-through; color: var(--color-text-subtle); }
8353
+ .twc-dt__diff-new { color: var(--color-success-subtle-fg); font-weight: var(--font-medium); }
8354
+ .twc-dt__diff-arrow { color: var(--color-text-subtle); flex: none; }
8355
+ [dir="rtl"] .twc-dt__diff-arrow { transform: scaleX(-1); display: inline-block; }
8356
+ .twc-dt__diff-summary { display: inline-flex; align-items: center; gap: 4px; flex: none; }
8357
+ .twc-dt__diff-toggle { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-sm); color: var(--color-text-muted); cursor: pointer; white-space: nowrap; flex: none; }
8358
+ .twc-dt__diff-toggle input { width: 15px; height: 15px; accent-color: var(--color-primary); cursor: pointer; margin: 0; }
8275
8359
  .twc-dt__row[data-row-dropbefore] > .twc-dt__td { box-shadow: inset 0 3px 0 var(--color-primary); }
8276
8360
  .twc-dt__row[data-row-dropafter] > .twc-dt__td { box-shadow: inset 0 -3px 0 var(--color-primary); }
8277
8361
  /* Keyboard row reorder (grabbed) */
@@ -8533,6 +8617,38 @@ var NUM_OPS = [
8533
8617
  var opsFor = (type) => type === "number" ? NUM_OPS : STR_OPS;
8534
8618
  var isMultiOp = (op) => op === "isAnyOf";
8535
8619
  var getColVal = (col, row) => col && col.valueGetter ? col.valueGetter(row) : row == null ? void 0 : row[col && col.field];
8620
+ var diffValueNode = (col, v, row) => col.renderCell ? col.renderCell(v, row) : col.valueFormatter ? col.valueFormatter(v, row) : v == null ? "" : v;
8621
+ function renderDiffCell(col, val, row) {
8622
+ const meta = row && row.__diffMeta;
8623
+ if (!meta) return diffValueNode(col, val, row);
8624
+ if (meta.op === "removed") return React51__namespace.default.createElement("span", { className: "twc-dt__diff-old" }, diffValueNode(col, getColVal(col, meta.from), meta.from));
8625
+ if (meta.op === "added") return React51__namespace.default.createElement("span", { className: "twc-dt__diff-new" }, diffValueNode(col, getColVal(col, meta.to), meta.to));
8626
+ if (meta.op === "modified" && meta.changed.has(col.field)) {
8627
+ return React51__namespace.default.createElement(
8628
+ "span",
8629
+ { className: "twc-dt__diff-change" },
8630
+ React51__namespace.default.createElement("span", { className: "twc-dt__diff-old" }, diffValueNode(col, getColVal(col, meta.from), meta.from)),
8631
+ React51__namespace.default.createElement("span", { className: "twc-dt__diff-arrow", "aria-hidden": "true" }, "\u2192"),
8632
+ React51__namespace.default.createElement("span", { className: "twc-dt__diff-new" }, diffValueNode(col, getColVal(col, meta.to), meta.to))
8633
+ );
8634
+ }
8635
+ return diffValueNode(col, val, row);
8636
+ }
8637
+ var DIFF_OP_COLUMN = {
8638
+ field: "__diffop",
8639
+ headerName: "Change",
8640
+ width: 122,
8641
+ pinned: "left",
8642
+ sortable: true,
8643
+ filterable: false,
8644
+ groupable: true,
8645
+ reorderable: false,
8646
+ resizable: true,
8647
+ wrappable: false,
8648
+ hideable: false,
8649
+ renderCell: (v) => v && DIFF_OPS[v] ? React51__namespace.default.createElement(Badge, { size: "sm", variant: "soft", tone: DIFF_OPS[v].tone }, DIFF_OPS[v].label) : null,
8650
+ exportValue: (v) => v && DIFF_OPS[v] ? DIFF_OPS[v].label : ""
8651
+ };
8536
8652
  function testFilter(raw, op, target, type) {
8537
8653
  if (op === "isEmpty") return raw == null || raw === "";
8538
8654
  if (op === "isNotEmpty") return !(raw == null || raw === "");
@@ -8851,11 +8967,12 @@ function xlsxPackage(sheetXml) {
8851
8967
  ]);
8852
8968
  }
8853
8969
  function Datatable({
8854
- columns,
8855
- rows,
8970
+ columns: columnsProp,
8971
+ rows: rowsProp = [],
8856
8972
  loading = false,
8857
- rowKey,
8973
+ rowKey: rowKeyProp,
8858
8974
  checkboxSelection = false,
8975
+ diff,
8859
8976
  density: densityProp = "comfortable",
8860
8977
  pageSize = 10,
8861
8978
  pageSizeOptions = [5, 10, 25, 50],
@@ -8908,6 +9025,29 @@ function Datatable({
8908
9025
  ...rest
8909
9026
  }) {
8910
9027
  const __twcStyles = useScopedStyles("twc-dt-styles", DT_CSS);
9028
+ const isDiff = !!diff;
9029
+ const [diffOnly, setDiffOnly] = React51__namespace.default.useState(diff && diff.onlyChanged !== void 0 ? diff.onlyChanged : true);
9030
+ const diffRowKey = diff && diff.rowKey || rowKeyProp || ((r2) => r2 == null ? r2 : r2.id);
9031
+ const diffData = React51__namespace.default.useMemo(
9032
+ () => isDiff ? classifyDiff(diff.from || [], diff.to || [], columnsProp, diffRowKey, { moveDetection: diff.moveDetection, compare: diff.compare }) : null,
9033
+ [isDiff, diff, columnsProp]
9034
+ // eslint-disable-line react-hooks/exhaustive-deps
9035
+ );
9036
+ const onClassifiedRef = React51__namespace.default.useRef(diff && diff.onClassified);
9037
+ onClassifiedRef.current = diff && diff.onClassified;
9038
+ React51__namespace.default.useEffect(() => {
9039
+ if (diffData && onClassifiedRef.current) onClassifiedRef.current(diffData.counts);
9040
+ }, [diffData]);
9041
+ const diffRowKeyFn = React51__namespace.default.useCallback((r2) => r2.__diffKey, []);
9042
+ const columns = React51__namespace.default.useMemo(
9043
+ () => isDiff ? [DIFF_OP_COLUMN, ...columnsProp.map((c) => ({ ...c, renderCell: (val, row) => renderDiffCell(c, val, row) }))] : columnsProp,
9044
+ [isDiff, columnsProp]
9045
+ );
9046
+ const rows = React51__namespace.default.useMemo(
9047
+ () => isDiff ? diffData.rows.filter((r2) => !diffOnly || r2.op !== "unchanged").map((r2) => ({ ...r2.to || r2.from, __diffop: r2.op, __diffMeta: r2, __diffKey: r2.key })) : rowsProp,
9048
+ [isDiff, diffData, diffOnly, rowsProp]
9049
+ );
9050
+ const rowKey = isDiff ? diffRowKeyFn : rowKeyProp;
8911
9051
  const cols = React51__namespace.default.useMemo(() => {
8912
9052
  const out = columns.map((c) => {
8913
9053
  const isActions = c.type === "actions";
@@ -10104,6 +10244,7 @@ function Datatable({
10104
10244
  role: "row",
10105
10245
  "aria-rowindex": (paginated && !serverMode ? pageVal * sizeVal : 0) + ri + 2,
10106
10246
  "aria-selected": (checkboxSelection ? sel : rowActive) || void 0,
10247
+ "data-op": row.__diffop || void 0,
10107
10248
  "data-selected": sel || void 0,
10108
10249
  "data-active": rowActive || void 0,
10109
10250
  "data-pinned-row": pinSide || void 0,
@@ -10354,6 +10495,28 @@ function Datatable({
10354
10495
  ))
10355
10496
  ] })
10356
10497
  ] }) : null,
10498
+ isDiff && diff.showSummary !== false ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__diff-summary", "aria-label": "Diff summary", children: [
10499
+ /* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "success", children: [
10500
+ "+",
10501
+ diffData.counts.added
10502
+ ] }),
10503
+ /* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "warning", children: [
10504
+ "~",
10505
+ diffData.counts.modified
10506
+ ] }),
10507
+ /* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "danger", children: [
10508
+ "\u2212",
10509
+ diffData.counts.removed
10510
+ ] }),
10511
+ diffData.counts.moved ? /* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "info", children: [
10512
+ "\u21C5",
10513
+ diffData.counts.moved
10514
+ ] }) : null
10515
+ ] }) : null,
10516
+ isDiff && diff.showToggle !== false ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "twc-dt__diff-toggle", children: [
10517
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: diffOnly, onChange: (e) => setDiffOnly(e.target.checked) }),
10518
+ diff.toggleLabel != null ? diff.toggleLabel : "Only changed"
10519
+ ] }) : null,
10357
10520
  /* @__PURE__ */ jsxRuntime.jsxs(
10358
10521
  "button",
10359
10522
  {
@@ -11690,55 +11853,13 @@ function CardGrid({
11690
11853
  ] }) : null
11691
11854
  ] });
11692
11855
  }
11693
- var DIFFTABLE_CSS = `
11694
- .twc-difft { font-family: var(--font-sans); display: flex; flex-direction: column; gap: var(--space-3); color: var(--color-text); }
11695
- .twc-difft__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
11696
- .twc-difft__label { font-size: var(--text-sm); font-weight: var(--font-semibold); }
11697
- .twc-difft__summary { display: inline-flex; flex-wrap: wrap; gap: var(--space-1-5); }
11698
- .twc-difft__toggle { margin-inline-start: auto; }
11699
- .twc-difft__scroll { overflow-x: auto; border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-lg); }
11700
- .twc-difft__table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
11701
- .twc-difft__table th, .twc-difft__table td { text-align: start; padding: var(--space-2) var(--space-3); border-bottom: var(--border-thin) solid var(--color-divider); vertical-align: top; }
11702
- .twc-difft__table thead th { position: sticky; top: 0; background: var(--color-surface-sunken); font-weight: var(--font-semibold); color: var(--color-text-muted); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.02em; white-space: nowrap; z-index: 1; }
11703
- .twc-difft__table tbody tr:last-child td { border-bottom: none; }
11704
- .twc-difft__table tbody tr[data-op="added"] { background: color-mix(in srgb, var(--color-success) 8%, transparent); }
11705
- .twc-difft__table tbody tr[data-op="removed"] { background: color-mix(in srgb, var(--color-danger) 8%, transparent); }
11706
- .twc-difft__table tbody tr[data-op="modified"] { background: color-mix(in srgb, var(--color-warning) 8%, transparent); }
11707
- .twc-difft__op { white-space: nowrap; }
11708
- .twc-difft__change { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 2px; }
11709
- .twc-difft__old { text-decoration: line-through; color: var(--color-text-subtle); }
11710
- .twc-difft__new { color: var(--color-success-subtle-fg); font-weight: var(--font-medium); }
11711
- .twc-difft__arrow { margin-inline: 6px; color: var(--color-text-subtle); }
11712
- .twc-difft__empty { padding: var(--space-8) var(--space-4); text-align: center; color: var(--color-text-muted); }
11713
- [dir="rtl"] .twc-difft__arrow { transform: scaleX(-1); display: inline-block; }
11714
- `;
11715
- var OPS = {
11716
- added: { label: "Added", tone: "success" },
11717
- removed: { label: "Removed", tone: "danger" },
11718
- modified: { label: "Modified", tone: "warning" },
11719
- moved: { label: "Moved", tone: "info" },
11720
- unchanged: { label: "Unchanged", tone: "neutral" }
11721
- };
11722
- function lisIndexSet(seq) {
11723
- const n = seq.length;
11724
- if (n === 0) return /* @__PURE__ */ new Set();
11725
- const dp = new Array(n).fill(1), prev = new Array(n).fill(-1);
11726
- let best = 0;
11727
- for (let i = 0; i < n; i++) {
11728
- for (let j = 0; j < i; j++) {
11729
- if (seq[j] < seq[i] && dp[j] + 1 > dp[i]) {
11730
- dp[i] = dp[j] + 1;
11731
- prev[i] = j;
11732
- }
11733
- }
11734
- if (dp[i] > dp[best]) best = i;
11735
- }
11736
- const set = /* @__PURE__ */ new Set();
11737
- for (let i = best; i !== -1; i = prev[i]) set.add(i);
11738
- return set;
11739
- }
11740
- var getVal = (col, row) => col.valueGetter ? col.valueGetter(row) : row == null ? void 0 : row[col.field];
11741
- var fmtVal = (col, v) => col.valueFormatter ? col.valueFormatter(v) : v == null ? "" : String(v);
11856
+ var toDatatableColumn = (c) => ({
11857
+ field: c.field,
11858
+ headerName: typeof c.headerName === "string" ? c.headerName : c.field,
11859
+ valueGetter: c.valueGetter,
11860
+ valueFormatter: c.valueFormatter,
11861
+ compare: c.compare
11862
+ });
11742
11863
  function DiffTable({
11743
11864
  from = [],
11744
11865
  to = [],
@@ -11756,104 +11877,24 @@ function DiffTable({
11756
11877
  className = "",
11757
11878
  ...rest
11758
11879
  }) {
11759
- const styles = useScopedStyles("twc-difftable-styles", DIFFTABLE_CSS);
11760
- const autoId = React51__namespace.default.useId();
11761
- const fieldId = id || autoId;
11762
- const [only, setOnly] = React51__namespace.default.useState(onlyChanged);
11763
- const valEq = React51__namespace.default.useCallback((a, b, col) => {
11764
- if (col.compare) return col.compare(a, b);
11765
- if (compare) return compare(a, b, col.field);
11766
- if (a === b) return true;
11767
- if (a == null || b == null) return a === b;
11768
- return JSON.stringify(a) === JSON.stringify(b);
11769
- }, [compare]);
11770
- const diff = React51__namespace.default.useMemo(() => {
11771
- const k = rowKey || ((r2) => r2 == null ? r2 : r2.id);
11772
- const fromMap = /* @__PURE__ */ new Map(), toMap = /* @__PURE__ */ new Map();
11773
- from.forEach((r2, i) => fromMap.set(k(r2), { row: r2, i }));
11774
- to.forEach((r2, i) => toMap.set(k(r2), { row: r2, i }));
11775
- const movedKeys = /* @__PURE__ */ new Set();
11776
- if (moveDetection) {
11777
- const commonFrom = from.filter((r2) => toMap.has(k(r2)));
11778
- const seq = commonFrom.map((r2) => toMap.get(k(r2)).i);
11779
- const stable = lisIndexSet(seq);
11780
- commonFrom.forEach((r2, idx) => {
11781
- if (!stable.has(idx)) movedKeys.add(k(r2));
11782
- });
11783
- }
11784
- const classify = (key) => {
11785
- const a = fromMap.get(key), b = toMap.get(key);
11786
- if (a && !b) return { op: "removed", from: a.row, to: null, changed: /* @__PURE__ */ new Set() };
11787
- if (!a && b) return { op: "added", from: null, to: b.row, changed: /* @__PURE__ */ new Set() };
11788
- const changed = /* @__PURE__ */ new Set();
11789
- for (const col of columns) if (!valEq(getVal(col, a.row), getVal(col, b.row), col)) changed.add(col.field);
11790
- if (changed.size) return { op: "modified", from: a.row, to: b.row, changed };
11791
- if (movedKeys.has(key)) return { op: "moved", from: a.row, to: b.row, changed };
11792
- return { op: "unchanged", from: a.row, to: b.row, changed };
11793
- };
11794
- const rows = [];
11795
- to.forEach((r2) => rows.push({ key: k(r2), ...classify(k(r2)) }));
11796
- from.forEach((r2) => {
11797
- const key = k(r2);
11798
- if (!toMap.has(key)) rows.push({ key, ...classify(key) });
11799
- });
11800
- const counts = { added: 0, removed: 0, modified: 0, moved: 0, unchanged: 0 };
11801
- rows.forEach((r2) => {
11802
- counts[r2.op] += 1;
11803
- });
11804
- return { rows, counts };
11805
- }, [from, to, columns, rowKey, moveDetection, valEq]);
11806
- const visible = only ? diff.rows.filter((r2) => r2.op !== "unchanged") : diff.rows;
11807
- const renderCell = (r2, col) => {
11808
- if (r2.op === "removed") return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__old", children: fmtVal(col, getVal(col, r2.from)) });
11809
- if (r2.op === "added") return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__new", children: fmtVal(col, getVal(col, r2.to)) });
11810
- if (r2.op === "modified" && r2.changed.has(col.field)) {
11811
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-difft__change", children: [
11812
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__old", children: fmtVal(col, getVal(col, r2.from)) }),
11813
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__arrow", "aria-hidden": "true", children: "\u2192" }),
11814
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__new", children: fmtVal(col, getVal(col, r2.to)) })
11815
- ] });
11880
+ const dtColumns = React51__namespace.default.useMemo(() => columns.map(toDatatableColumn), [columns]);
11881
+ const diff = React51__namespace.default.useMemo(
11882
+ () => ({ from, to, rowKey, onlyChanged, showToggle, showSummary, moveDetection, compare, toggleLabel }),
11883
+ [from, to, rowKey, onlyChanged, showToggle, showSummary, moveDetection, compare, toggleLabel]
11884
+ );
11885
+ const table = /* @__PURE__ */ jsxRuntime.jsx(
11886
+ Datatable,
11887
+ {
11888
+ columns: dtColumns,
11889
+ diff,
11890
+ emptyMessage: emptyState,
11891
+ ...label ? {} : { id, className, ...rest }
11816
11892
  }
11817
- return /* @__PURE__ */ jsxRuntime.jsx("span", { children: fmtVal(col, getVal(col, r2.to ?? r2.from)) });
11818
- };
11819
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-difft ${className}`, id: fieldId, ...rest, children: [
11820
- styles,
11821
- label || showSummary || showToggle ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-difft__head", children: [
11822
- label ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-difft__label", children: label }) : null,
11823
- showSummary ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-difft__summary", children: [
11824
- /* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "success", children: [
11825
- "+",
11826
- diff.counts.added,
11827
- " added"
11828
- ] }),
11829
- /* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "warning", children: [
11830
- "~",
11831
- diff.counts.modified,
11832
- " modified"
11833
- ] }),
11834
- /* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "danger", children: [
11835
- "-",
11836
- diff.counts.removed,
11837
- " removed"
11838
- ] }),
11839
- diff.counts.moved ? /* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "info", children: [
11840
- "\u21C5 ",
11841
- diff.counts.moved,
11842
- " moved"
11843
- ] }) : null
11844
- ] }) : null,
11845
- showToggle ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-difft__toggle", children: /* @__PURE__ */ jsxRuntime.jsx(Checkbox, { label: toggleLabel, checked: only, onChange: (e) => setOnly(e.target.checked) }) }) : null
11846
- ] }) : null,
11847
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-difft__scroll", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "twc-difft__table", children: [
11848
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
11849
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Change" }),
11850
- columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: c.headerName || c.field }, c.field))
11851
- ] }) }),
11852
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-difft__empty", colSpan: columns.length + 1, children: emptyState }) }) : visible.map((r2) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { "data-op": r2.op, children: [
11853
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-difft__op", children: /* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "sm", variant: "soft", tone: OPS[r2.op].tone, children: OPS[r2.op].label }) }),
11854
- columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("td", { children: renderCell(r2, c) }, c.field))
11855
- ] }, r2.key)) })
11856
- ] }) })
11893
+ );
11894
+ if (!label) return table;
11895
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id, className, ...rest, style: { display: "flex", flexDirection: "column", gap: "var(--space-2)", fontFamily: "var(--font-sans)" }, children: [
11896
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "var(--text-sm)", fontWeight: "var(--font-semibold)", color: "var(--color-text)" }, children: label }),
11897
+ table
11857
11898
  ] });
11858
11899
  }
11859
11900
  var FIELD_CSS3 = `