twico-ui 1.14.0 → 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 +14 -0
- package/dist/index.cjs +214 -162
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -2
- package/dist/index.d.ts +60 -2
- package/dist/index.mjs +214 -162
- package/dist/index.mjs.map +1 -1
- package/llms.txt +4 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
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
|
+
|
|
12
|
+
## [1.14.1](https://github.com/EncryptionL/twico-ui/compare/v1.14.0...v1.14.1) (2026-07-14)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **styles:** input renders invisibly under React 19 hoist dedup; add Datatable external-search + renderEditCell ([#234](https://github.com/EncryptionL/twico-ui/issues/234), [#235](https://github.com/EncryptionL/twico-ui/issues/235), [#236](https://github.com/EncryptionL/twico-ui/issues/236)) ([f661ea9](https://github.com/EncryptionL/twico-ui/commit/f661ea90dab1bf4b97ee02e8f103fb44ce668f43)), closes [#232](https://github.com/EncryptionL/twico-ui/issues/232)
|
|
18
|
+
|
|
5
19
|
# [1.14.0](https://github.com/EncryptionL/twico-ui/compare/v1.13.0...v1.14.0) (2026-07-13)
|
|
6
20
|
|
|
7
21
|
|
package/dist/index.cjs
CHANGED
|
@@ -7091,7 +7091,8 @@ var FIELD_CSS2 = `
|
|
|
7091
7091
|
.twc-field__req { color: var(--color-danger); }
|
|
7092
7092
|
.twc-field__hint { font-size: var(--text-xs); color: var(--color-text-muted); }
|
|
7093
7093
|
.twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
|
|
7094
|
-
|
|
7094
|
+
`;
|
|
7095
|
+
var INPUT_EXTRA_CSS = `
|
|
7095
7096
|
.twc-input {
|
|
7096
7097
|
--_h: var(--control-h-md);
|
|
7097
7098
|
display: flex; align-items: center; gap: var(--space-2);
|
|
@@ -7100,6 +7101,7 @@ var FIELD_CSS2 = `
|
|
|
7100
7101
|
background: var(--color-surface);
|
|
7101
7102
|
border: var(--border-thin) solid var(--color-border);
|
|
7102
7103
|
border-radius: var(--radius-md);
|
|
7104
|
+
overflow: hidden;
|
|
7103
7105
|
transition: border-color var(--duration-fast) var(--ease-standard),
|
|
7104
7106
|
box-shadow var(--duration-fast) var(--ease-standard),
|
|
7105
7107
|
background-color var(--duration-fast) var(--ease-standard);
|
|
@@ -7133,9 +7135,6 @@ var FIELD_CSS2 = `
|
|
|
7133
7135
|
.twc-input__reveal:hover { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
7134
7136
|
.twc-input__reveal:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
7135
7137
|
.twc-input__reveal svg { width: 17px; height: 17px; }
|
|
7136
|
-
`;
|
|
7137
|
-
var INPUT_EXTRA_CSS = `
|
|
7138
|
-
.twc-input { overflow: hidden; }
|
|
7139
7138
|
.twc-input__addon { align-self: stretch; display: inline-flex; align-items: center; padding-inline: var(--space-3);
|
|
7140
7139
|
background: var(--color-surface-sunken); color: var(--color-text-muted); font-size: var(--text-sm);
|
|
7141
7140
|
font-weight: var(--font-semibold); white-space: nowrap; flex: none; }
|
|
@@ -8035,6 +8034,78 @@ function Tooltip({
|
|
|
8035
8034
|
}
|
|
8036
8035
|
);
|
|
8037
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
|
+
}
|
|
8038
8109
|
var DT_CSS = `
|
|
8039
8110
|
.twc-dt { display: flex; flex-direction: column; font-family: var(--font-sans); color: var(--color-text);
|
|
8040
8111
|
border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-lg);
|
|
@@ -8273,6 +8344,18 @@ var DT_CSS = `
|
|
|
8273
8344
|
/* Row reordering */
|
|
8274
8345
|
.twc-dt__row[data-reorderable] { cursor: grab; }
|
|
8275
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; }
|
|
8276
8359
|
.twc-dt__row[data-row-dropbefore] > .twc-dt__td { box-shadow: inset 0 3px 0 var(--color-primary); }
|
|
8277
8360
|
.twc-dt__row[data-row-dropafter] > .twc-dt__td { box-shadow: inset 0 -3px 0 var(--color-primary); }
|
|
8278
8361
|
/* Keyboard row reorder (grabbed) */
|
|
@@ -8534,6 +8617,38 @@ var NUM_OPS = [
|
|
|
8534
8617
|
var opsFor = (type) => type === "number" ? NUM_OPS : STR_OPS;
|
|
8535
8618
|
var isMultiOp = (op) => op === "isAnyOf";
|
|
8536
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
|
+
};
|
|
8537
8652
|
function testFilter(raw, op, target, type) {
|
|
8538
8653
|
if (op === "isEmpty") return raw == null || raw === "";
|
|
8539
8654
|
if (op === "isNotEmpty") return !(raw == null || raw === "");
|
|
@@ -8852,11 +8967,12 @@ function xlsxPackage(sheetXml) {
|
|
|
8852
8967
|
]);
|
|
8853
8968
|
}
|
|
8854
8969
|
function Datatable({
|
|
8855
|
-
columns,
|
|
8856
|
-
rows,
|
|
8970
|
+
columns: columnsProp,
|
|
8971
|
+
rows: rowsProp = [],
|
|
8857
8972
|
loading = false,
|
|
8858
|
-
rowKey,
|
|
8973
|
+
rowKey: rowKeyProp,
|
|
8859
8974
|
checkboxSelection = false,
|
|
8975
|
+
diff,
|
|
8860
8976
|
density: densityProp = "comfortable",
|
|
8861
8977
|
pageSize = 10,
|
|
8862
8978
|
pageSizeOptions = [5, 10, 25, 50],
|
|
@@ -8893,6 +9009,9 @@ function Datatable({
|
|
|
8893
9009
|
rowGrouping = [],
|
|
8894
9010
|
rowNumbers = false,
|
|
8895
9011
|
searchFields = null,
|
|
9012
|
+
searchable = true,
|
|
9013
|
+
quickFilter,
|
|
9014
|
+
onQuickFilterChange,
|
|
8896
9015
|
rowPinning = false,
|
|
8897
9016
|
rowReorder = false,
|
|
8898
9017
|
rowResize = false,
|
|
@@ -8906,6 +9025,29 @@ function Datatable({
|
|
|
8906
9025
|
...rest
|
|
8907
9026
|
}) {
|
|
8908
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;
|
|
8909
9051
|
const cols = React51__namespace.default.useMemo(() => {
|
|
8910
9052
|
const out = columns.map((c) => {
|
|
8911
9053
|
const isActions = c.type === "actions";
|
|
@@ -8975,7 +9117,13 @@ function Datatable({
|
|
|
8975
9117
|
return { left, right };
|
|
8976
9118
|
});
|
|
8977
9119
|
const [density, setDensity] = React51__namespace.default.useState(densityProp);
|
|
8978
|
-
const [
|
|
9120
|
+
const [internalQuick, setInternalQuick] = React51__namespace.default.useState("");
|
|
9121
|
+
const quick = quickFilter !== void 0 ? quickFilter : internalQuick;
|
|
9122
|
+
const commitQuick = (v) => {
|
|
9123
|
+
onQuickFilterChange?.(v);
|
|
9124
|
+
if (quickFilter === void 0) setInternalQuick(v);
|
|
9125
|
+
commitPage(0);
|
|
9126
|
+
};
|
|
8979
9127
|
const [selected, setSelected] = React51__namespace.default.useState(() => /* @__PURE__ */ new Set());
|
|
8980
9128
|
const [activeRow, setActiveRow] = React51__namespace.default.useState(null);
|
|
8981
9129
|
const [activeCell, setActiveCell] = React51__namespace.default.useState(null);
|
|
@@ -9855,7 +10003,7 @@ function Datatable({
|
|
|
9855
10003
|
setSelected(/* @__PURE__ */ new Set());
|
|
9856
10004
|
}
|
|
9857
10005
|
const [editing, setEditing] = React51__namespace.default.useState(null);
|
|
9858
|
-
const isColEditable = (c) => c.type !== "actions" &&
|
|
10006
|
+
const isColEditable = (c) => c.type !== "actions" && c.editable !== false && (c.editable === true || c.renderEditCell != null || editMode);
|
|
9859
10007
|
function beginEdit(rowK, col, row) {
|
|
9860
10008
|
if (!isColEditable(col)) return;
|
|
9861
10009
|
setEditing({ key: rowK, field: col.field, value: row[col.field] ?? "" });
|
|
@@ -10096,6 +10244,7 @@ function Datatable({
|
|
|
10096
10244
|
role: "row",
|
|
10097
10245
|
"aria-rowindex": (paginated && !serverMode ? pageVal * sizeVal : 0) + ri + 2,
|
|
10098
10246
|
"aria-selected": (checkboxSelection ? sel : rowActive) || void 0,
|
|
10247
|
+
"data-op": row.__diffop || void 0,
|
|
10099
10248
|
"data-selected": sel || void 0,
|
|
10100
10249
|
"data-active": rowActive || void 0,
|
|
10101
10250
|
"data-pinned-row": pinSide || void 0,
|
|
@@ -10186,7 +10335,13 @@ function Datatable({
|
|
|
10186
10335
|
!checkboxSelection && reorderable && ci === 0 && !isEditing ? /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 6, maxWidth: "100%" }, children: [
|
|
10187
10336
|
rowHandle(k, midIdx, row),
|
|
10188
10337
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: isActions ? renderActions(c, row) : c.renderCell ? c.renderCell(val, row) : c.valueFormatter ? c.valueFormatter(val, row) : val })
|
|
10189
|
-
] }) : isEditing ?
|
|
10338
|
+
] }) : isEditing ? c.renderEditCell ? (
|
|
10339
|
+
// #236: full escape hatch — the host drops in its own editor (searchable/creatable/
|
|
10340
|
+
// async Combobox, …) and drives the lifecycle via commit/cancel. Wrapped in
|
|
10341
|
+
// .twc-dt__editor-wrap so inline clicks (and any .twc-pop portal dropdown) don't
|
|
10342
|
+
// trip the outside-click auto-cancel.
|
|
10343
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dt__editor-wrap", children: c.renderEditCell({ value: editing.value, row, field: c.field, commit: (v) => commitEdit(v), cancel: cancelEdit }) })
|
|
10344
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
10190
10345
|
EditCell,
|
|
10191
10346
|
{
|
|
10192
10347
|
col: c,
|
|
@@ -10340,6 +10495,28 @@ function Datatable({
|
|
|
10340
10495
|
))
|
|
10341
10496
|
] })
|
|
10342
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,
|
|
10343
10520
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10344
10521
|
"button",
|
|
10345
10522
|
{
|
|
@@ -10476,13 +10653,10 @@ function Datatable({
|
|
|
10476
10653
|
}
|
|
10477
10654
|
)
|
|
10478
10655
|
] }) : null,
|
|
10479
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__search", children: [
|
|
10656
|
+
searchable ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__search", children: [
|
|
10480
10657
|
/* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.search }),
|
|
10481
|
-
/* @__PURE__ */ jsxRuntime.jsx("input", { placeholder: "Search\u2026", "aria-label": "Search rows", value: quick, onChange: (e) =>
|
|
10482
|
-
|
|
10483
|
-
commitPage(0);
|
|
10484
|
-
} })
|
|
10485
|
-
] })
|
|
10658
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { placeholder: "Search\u2026", "aria-label": "Search rows", value: quick, onChange: (e) => commitQuick(e.target.value) })
|
|
10659
|
+
] }) : null
|
|
10486
10660
|
] }),
|
|
10487
10661
|
!pivotActive && activeGroupBy.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__groupbar", children: [
|
|
10488
10662
|
/* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.group }),
|
|
@@ -11679,55 +11853,13 @@ function CardGrid({
|
|
|
11679
11853
|
] }) : null
|
|
11680
11854
|
] });
|
|
11681
11855
|
}
|
|
11682
|
-
var
|
|
11683
|
-
|
|
11684
|
-
|
|
11685
|
-
|
|
11686
|
-
|
|
11687
|
-
|
|
11688
|
-
|
|
11689
|
-
.twc-difft__table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
|
|
11690
|
-
.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; }
|
|
11691
|
-
.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; }
|
|
11692
|
-
.twc-difft__table tbody tr:last-child td { border-bottom: none; }
|
|
11693
|
-
.twc-difft__table tbody tr[data-op="added"] { background: color-mix(in srgb, var(--color-success) 8%, transparent); }
|
|
11694
|
-
.twc-difft__table tbody tr[data-op="removed"] { background: color-mix(in srgb, var(--color-danger) 8%, transparent); }
|
|
11695
|
-
.twc-difft__table tbody tr[data-op="modified"] { background: color-mix(in srgb, var(--color-warning) 8%, transparent); }
|
|
11696
|
-
.twc-difft__op { white-space: nowrap; }
|
|
11697
|
-
.twc-difft__change { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 2px; }
|
|
11698
|
-
.twc-difft__old { text-decoration: line-through; color: var(--color-text-subtle); }
|
|
11699
|
-
.twc-difft__new { color: var(--color-success-subtle-fg); font-weight: var(--font-medium); }
|
|
11700
|
-
.twc-difft__arrow { margin-inline: 6px; color: var(--color-text-subtle); }
|
|
11701
|
-
.twc-difft__empty { padding: var(--space-8) var(--space-4); text-align: center; color: var(--color-text-muted); }
|
|
11702
|
-
[dir="rtl"] .twc-difft__arrow { transform: scaleX(-1); display: inline-block; }
|
|
11703
|
-
`;
|
|
11704
|
-
var OPS = {
|
|
11705
|
-
added: { label: "Added", tone: "success" },
|
|
11706
|
-
removed: { label: "Removed", tone: "danger" },
|
|
11707
|
-
modified: { label: "Modified", tone: "warning" },
|
|
11708
|
-
moved: { label: "Moved", tone: "info" },
|
|
11709
|
-
unchanged: { label: "Unchanged", tone: "neutral" }
|
|
11710
|
-
};
|
|
11711
|
-
function lisIndexSet(seq) {
|
|
11712
|
-
const n = seq.length;
|
|
11713
|
-
if (n === 0) return /* @__PURE__ */ new Set();
|
|
11714
|
-
const dp = new Array(n).fill(1), prev = new Array(n).fill(-1);
|
|
11715
|
-
let best = 0;
|
|
11716
|
-
for (let i = 0; i < n; i++) {
|
|
11717
|
-
for (let j = 0; j < i; j++) {
|
|
11718
|
-
if (seq[j] < seq[i] && dp[j] + 1 > dp[i]) {
|
|
11719
|
-
dp[i] = dp[j] + 1;
|
|
11720
|
-
prev[i] = j;
|
|
11721
|
-
}
|
|
11722
|
-
}
|
|
11723
|
-
if (dp[i] > dp[best]) best = i;
|
|
11724
|
-
}
|
|
11725
|
-
const set = /* @__PURE__ */ new Set();
|
|
11726
|
-
for (let i = best; i !== -1; i = prev[i]) set.add(i);
|
|
11727
|
-
return set;
|
|
11728
|
-
}
|
|
11729
|
-
var getVal = (col, row) => col.valueGetter ? col.valueGetter(row) : row == null ? void 0 : row[col.field];
|
|
11730
|
-
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
|
+
});
|
|
11731
11863
|
function DiffTable({
|
|
11732
11864
|
from = [],
|
|
11733
11865
|
to = [],
|
|
@@ -11745,104 +11877,24 @@ function DiffTable({
|
|
|
11745
11877
|
className = "",
|
|
11746
11878
|
...rest
|
|
11747
11879
|
}) {
|
|
11748
|
-
const
|
|
11749
|
-
const
|
|
11750
|
-
|
|
11751
|
-
|
|
11752
|
-
|
|
11753
|
-
|
|
11754
|
-
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
|
|
11758
|
-
|
|
11759
|
-
|
|
11760
|
-
const k = rowKey || ((r2) => r2 == null ? r2 : r2.id);
|
|
11761
|
-
const fromMap = /* @__PURE__ */ new Map(), toMap = /* @__PURE__ */ new Map();
|
|
11762
|
-
from.forEach((r2, i) => fromMap.set(k(r2), { row: r2, i }));
|
|
11763
|
-
to.forEach((r2, i) => toMap.set(k(r2), { row: r2, i }));
|
|
11764
|
-
const movedKeys = /* @__PURE__ */ new Set();
|
|
11765
|
-
if (moveDetection) {
|
|
11766
|
-
const commonFrom = from.filter((r2) => toMap.has(k(r2)));
|
|
11767
|
-
const seq = commonFrom.map((r2) => toMap.get(k(r2)).i);
|
|
11768
|
-
const stable = lisIndexSet(seq);
|
|
11769
|
-
commonFrom.forEach((r2, idx) => {
|
|
11770
|
-
if (!stable.has(idx)) movedKeys.add(k(r2));
|
|
11771
|
-
});
|
|
11772
|
-
}
|
|
11773
|
-
const classify = (key) => {
|
|
11774
|
-
const a = fromMap.get(key), b = toMap.get(key);
|
|
11775
|
-
if (a && !b) return { op: "removed", from: a.row, to: null, changed: /* @__PURE__ */ new Set() };
|
|
11776
|
-
if (!a && b) return { op: "added", from: null, to: b.row, changed: /* @__PURE__ */ new Set() };
|
|
11777
|
-
const changed = /* @__PURE__ */ new Set();
|
|
11778
|
-
for (const col of columns) if (!valEq(getVal(col, a.row), getVal(col, b.row), col)) changed.add(col.field);
|
|
11779
|
-
if (changed.size) return { op: "modified", from: a.row, to: b.row, changed };
|
|
11780
|
-
if (movedKeys.has(key)) return { op: "moved", from: a.row, to: b.row, changed };
|
|
11781
|
-
return { op: "unchanged", from: a.row, to: b.row, changed };
|
|
11782
|
-
};
|
|
11783
|
-
const rows = [];
|
|
11784
|
-
to.forEach((r2) => rows.push({ key: k(r2), ...classify(k(r2)) }));
|
|
11785
|
-
from.forEach((r2) => {
|
|
11786
|
-
const key = k(r2);
|
|
11787
|
-
if (!toMap.has(key)) rows.push({ key, ...classify(key) });
|
|
11788
|
-
});
|
|
11789
|
-
const counts = { added: 0, removed: 0, modified: 0, moved: 0, unchanged: 0 };
|
|
11790
|
-
rows.forEach((r2) => {
|
|
11791
|
-
counts[r2.op] += 1;
|
|
11792
|
-
});
|
|
11793
|
-
return { rows, counts };
|
|
11794
|
-
}, [from, to, columns, rowKey, moveDetection, valEq]);
|
|
11795
|
-
const visible = only ? diff.rows.filter((r2) => r2.op !== "unchanged") : diff.rows;
|
|
11796
|
-
const renderCell = (r2, col) => {
|
|
11797
|
-
if (r2.op === "removed") return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__old", children: fmtVal(col, getVal(col, r2.from)) });
|
|
11798
|
-
if (r2.op === "added") return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__new", children: fmtVal(col, getVal(col, r2.to)) });
|
|
11799
|
-
if (r2.op === "modified" && r2.changed.has(col.field)) {
|
|
11800
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-difft__change", children: [
|
|
11801
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__old", children: fmtVal(col, getVal(col, r2.from)) }),
|
|
11802
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__arrow", "aria-hidden": "true", children: "\u2192" }),
|
|
11803
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__new", children: fmtVal(col, getVal(col, r2.to)) })
|
|
11804
|
-
] });
|
|
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 }
|
|
11805
11892
|
}
|
|
11806
|
-
|
|
11807
|
-
|
|
11808
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className:
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
label ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-difft__label", children: label }) : null,
|
|
11812
|
-
showSummary ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-difft__summary", children: [
|
|
11813
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "success", children: [
|
|
11814
|
-
"+",
|
|
11815
|
-
diff.counts.added,
|
|
11816
|
-
" added"
|
|
11817
|
-
] }),
|
|
11818
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "warning", children: [
|
|
11819
|
-
"~",
|
|
11820
|
-
diff.counts.modified,
|
|
11821
|
-
" modified"
|
|
11822
|
-
] }),
|
|
11823
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "danger", children: [
|
|
11824
|
-
"-",
|
|
11825
|
-
diff.counts.removed,
|
|
11826
|
-
" removed"
|
|
11827
|
-
] }),
|
|
11828
|
-
diff.counts.moved ? /* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "info", children: [
|
|
11829
|
-
"\u21C5 ",
|
|
11830
|
-
diff.counts.moved,
|
|
11831
|
-
" moved"
|
|
11832
|
-
] }) : null
|
|
11833
|
-
] }) : null,
|
|
11834
|
-
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
|
|
11835
|
-
] }) : null,
|
|
11836
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-difft__scroll", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "twc-difft__table", children: [
|
|
11837
|
-
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
11838
|
-
/* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Change" }),
|
|
11839
|
-
columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: c.headerName || c.field }, c.field))
|
|
11840
|
-
] }) }),
|
|
11841
|
-
/* @__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: [
|
|
11842
|
-
/* @__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 }) }),
|
|
11843
|
-
columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("td", { children: renderCell(r2, c) }, c.field))
|
|
11844
|
-
] }, r2.key)) })
|
|
11845
|
-
] }) })
|
|
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
|
|
11846
11898
|
] });
|
|
11847
11899
|
}
|
|
11848
11900
|
var FIELD_CSS3 = `
|