twico-ui 1.37.1 → 1.37.2
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 +8 -0
- package/dist/index.cjs +69 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +69 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
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.37.2](https://github.com/EncryptionL/twico-ui/compare/v1.37.1...v1.37.2) (2026-09-18)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **datatable,code:** clipboard paste/copy work outside a secure context ([#380](https://github.com/EncryptionL/twico-ui/issues/380)) ([29aa913](https://github.com/EncryptionL/twico-ui/commit/29aa91382df6df40333ec49132b8883ec6f56b9f)), closes [#343](https://github.com/EncryptionL/twico-ui/issues/343)
|
|
11
|
+
* **datatable,code:** harden [#380](https://github.com/EncryptionL/twico-ui/issues/380) clipboard fix (review follow-ups) ([849c9f8](https://github.com/EncryptionL/twico-ui/commit/849c9f88d331e38d5fd1faf41401b8424e904541))
|
|
12
|
+
|
|
5
13
|
## [1.37.1](https://github.com/EncryptionL/twico-ui/compare/v1.37.0...v1.37.1) (2026-09-14)
|
|
6
14
|
|
|
7
15
|
|
package/dist/index.cjs
CHANGED
|
@@ -10667,8 +10667,10 @@ function Datatable({
|
|
|
10667
10667
|
return;
|
|
10668
10668
|
}
|
|
10669
10669
|
if (k === "v") {
|
|
10670
|
-
|
|
10671
|
-
|
|
10670
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.readText) {
|
|
10671
|
+
e.preventDefault();
|
|
10672
|
+
pasteSelection();
|
|
10673
|
+
}
|
|
10672
10674
|
return;
|
|
10673
10675
|
}
|
|
10674
10676
|
}
|
|
@@ -10888,19 +10890,19 @@ function Datatable({
|
|
|
10888
10890
|
const copyTypeOf = (col) => col && col.copyType != null ? col.copyType : col && col.type === "number" ? "number" : "text";
|
|
10889
10891
|
const writeClipboard = (text) => {
|
|
10890
10892
|
const execFallback = () => {
|
|
10893
|
+
if (typeof document === "undefined") return;
|
|
10894
|
+
const ta = document.createElement("textarea");
|
|
10895
|
+
ta.value = text;
|
|
10896
|
+
ta.style.position = "fixed";
|
|
10897
|
+
ta.style.opacity = "0";
|
|
10898
|
+
document.body.appendChild(ta);
|
|
10899
|
+
ta.focus();
|
|
10900
|
+
ta.select();
|
|
10891
10901
|
try {
|
|
10892
|
-
|
|
10893
|
-
const ta = document.createElement("textarea");
|
|
10894
|
-
ta.value = text;
|
|
10895
|
-
ta.style.position = "fixed";
|
|
10896
|
-
ta.style.opacity = "0";
|
|
10897
|
-
document.body.appendChild(ta);
|
|
10898
|
-
ta.focus();
|
|
10899
|
-
ta.select();
|
|
10900
|
-
document.execCommand("copy");
|
|
10901
|
-
document.body.removeChild(ta);
|
|
10902
|
-
}
|
|
10902
|
+
document.execCommand("copy");
|
|
10903
10903
|
} catch {
|
|
10904
|
+
} finally {
|
|
10905
|
+
if (ta.parentNode) ta.parentNode.removeChild(ta);
|
|
10904
10906
|
}
|
|
10905
10907
|
};
|
|
10906
10908
|
try {
|
|
@@ -10971,19 +10973,8 @@ function Datatable({
|
|
|
10971
10973
|
announceClip(`Copied ${n} cell${n === 1 ? "" : "s"}`, cellRect);
|
|
10972
10974
|
}
|
|
10973
10975
|
};
|
|
10974
|
-
const
|
|
10975
|
-
if (!cellRect) return;
|
|
10976
|
-
let text = null;
|
|
10977
|
-
try {
|
|
10978
|
-
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.readText) text = await navigator.clipboard.readText();
|
|
10979
|
-
} catch {
|
|
10980
|
-
setClipboardMsg("Paste unavailable \u2014 clipboard permission denied");
|
|
10981
|
-
return;
|
|
10982
|
-
}
|
|
10983
|
-
if (text == null) {
|
|
10984
|
-
setClipboardMsg("Nothing to paste");
|
|
10985
|
-
return;
|
|
10986
|
-
}
|
|
10976
|
+
const applyPastedText = (text) => {
|
|
10977
|
+
if (text == null || !cellRect) return;
|
|
10987
10978
|
const inApp = clipboardRef.current && clipboardRef.current.tsv === text ? clipboardRef.current : null;
|
|
10988
10979
|
let matrix;
|
|
10989
10980
|
if (inApp) matrix = inApp.matrix;
|
|
@@ -11028,6 +11019,31 @@ function Datatable({
|
|
|
11028
11019
|
const pasteRect = written ? { r0: cellRect.r0, c0: cellRect.c0, r1: Math.min(cellRect.r0 + matrix.length - 1, leafRows.length - 1), c1: Math.min(cellRect.c0 + maxCols - 1, ordered.length - 1) } : null;
|
|
11029
11020
|
announceClip(`Pasted ${written} cell${written === 1 ? "" : "s"}${skipped ? `, ${skipped} skipped (incompatible column)` : ""}`, pasteRect);
|
|
11030
11021
|
};
|
|
11022
|
+
const pasteSelection = async () => {
|
|
11023
|
+
if (!cellRect) return;
|
|
11024
|
+
let text = null;
|
|
11025
|
+
try {
|
|
11026
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.readText) text = await navigator.clipboard.readText();
|
|
11027
|
+
} catch {
|
|
11028
|
+
setClipboardMsg("Paste unavailable \u2014 clipboard permission denied");
|
|
11029
|
+
return;
|
|
11030
|
+
}
|
|
11031
|
+
if (text == null) {
|
|
11032
|
+
setClipboardMsg("Nothing to paste");
|
|
11033
|
+
return;
|
|
11034
|
+
}
|
|
11035
|
+
applyPastedText(text);
|
|
11036
|
+
};
|
|
11037
|
+
const onGridPaste = (e) => {
|
|
11038
|
+
if (e.target.closest("input, textarea, select, [contenteditable='true']") || editing) return;
|
|
11039
|
+
if (!e.target.closest(".twc-dt__td[data-r]")) return;
|
|
11040
|
+
if (!(enableClipboard && selectionMode === "cell") || !cellRect) return;
|
|
11041
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.readText) return;
|
|
11042
|
+
const text = e.clipboardData ? e.clipboardData.getData("text/plain") : null;
|
|
11043
|
+
if (text == null || text === "") return;
|
|
11044
|
+
e.preventDefault();
|
|
11045
|
+
applyPastedText(text);
|
|
11046
|
+
};
|
|
11031
11047
|
React51__namespace.default.useEffect(() => {
|
|
11032
11048
|
if (!editing) return;
|
|
11033
11049
|
const onDown = (e) => {
|
|
@@ -12043,6 +12059,7 @@ function Datatable({
|
|
|
12043
12059
|
"aria-activedescendant": activeCellId,
|
|
12044
12060
|
"aria-busy": loading || void 0,
|
|
12045
12061
|
onKeyDown: onGridKeyDown,
|
|
12062
|
+
onPaste: onGridPaste,
|
|
12046
12063
|
children: [
|
|
12047
12064
|
/* @__PURE__ */ jsxRuntime.jsx("thead", { ref: theadRef, children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
|
|
12048
12065
|
hasExpandCol ? /* @__PURE__ */ jsxRuntime.jsx("th", { className: "twc-dt__th twc-dt__expand-cell", role: "columnheader", "aria-label": "Expand", "data-pin": "left", "data-pin-edge": checkboxSelection || showRowNum || visLeft.length ? void 0 : "left", style: { insetInlineStart: 0, width: EXP_W, minWidth: EXP_W } }) : null,
|
|
@@ -19117,14 +19134,36 @@ function Code({
|
|
|
19117
19134
|
const timerRef = React51__namespace.default.useRef(null);
|
|
19118
19135
|
React51__namespace.default.useEffect(() => () => clearTimeout(timerRef.current), []);
|
|
19119
19136
|
const doCopy = () => {
|
|
19120
|
-
if (typeof navigator === "undefined" || !navigator.clipboard) return;
|
|
19121
19137
|
const text = typeof children === "string" ? children : rootRef.current?.textContent ?? "";
|
|
19122
|
-
|
|
19138
|
+
const flash = () => {
|
|
19123
19139
|
setCopied(true);
|
|
19124
19140
|
clearTimeout(timerRef.current);
|
|
19125
19141
|
timerRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
19126
|
-
}
|
|
19127
|
-
|
|
19142
|
+
};
|
|
19143
|
+
const execFallback = () => {
|
|
19144
|
+
if (typeof document === "undefined") return;
|
|
19145
|
+
const ta = document.createElement("textarea");
|
|
19146
|
+
ta.value = text;
|
|
19147
|
+
ta.style.position = "fixed";
|
|
19148
|
+
ta.style.opacity = "0";
|
|
19149
|
+
document.body.appendChild(ta);
|
|
19150
|
+
ta.focus();
|
|
19151
|
+
ta.select();
|
|
19152
|
+
try {
|
|
19153
|
+
if (document.execCommand("copy")) flash();
|
|
19154
|
+
} catch {
|
|
19155
|
+
} finally {
|
|
19156
|
+
if (ta.parentNode) ta.parentNode.removeChild(ta);
|
|
19157
|
+
}
|
|
19158
|
+
};
|
|
19159
|
+
try {
|
|
19160
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) {
|
|
19161
|
+
navigator.clipboard.writeText(text).then(flash).catch(execFallback);
|
|
19162
|
+
return;
|
|
19163
|
+
}
|
|
19164
|
+
} catch {
|
|
19165
|
+
}
|
|
19166
|
+
execFallback();
|
|
19128
19167
|
};
|
|
19129
19168
|
return /* @__PURE__ */ jsxRuntime.jsxs(Tag2, { ref: rootRef, className: `twc-code ${className}`.trim(), "data-block": block || void 0, ...rest, children: [
|
|
19130
19169
|
__twcStyles,
|