twico-ui 1.37.1 → 1.38.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 +15 -0
- package/dist/index.cjs +107 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.mjs +107 -47
- package/dist/index.mjs.map +1 -1
- package/llms.txt +4 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
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.38.0](https://github.com/EncryptionL/twico-ui/compare/v1.37.2...v1.38.0) (2026-09-22)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **datatable,tooltip:** toolbar/group-bar controls + rich tooltip labels ([#385](https://github.com/EncryptionL/twico-ui/issues/385), [#386](https://github.com/EncryptionL/twico-ui/issues/386), [#387](https://github.com/EncryptionL/twico-ui/issues/387)) ([a89fb1f](https://github.com/EncryptionL/twico-ui/commit/a89fb1f4885bc51f2383b4c3437eb502aa574a37))
|
|
11
|
+
|
|
12
|
+
## [1.37.2](https://github.com/EncryptionL/twico-ui/compare/v1.37.1...v1.37.2) (2026-09-18)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **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)
|
|
18
|
+
* **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))
|
|
19
|
+
|
|
5
20
|
## [1.37.1](https://github.com/EncryptionL/twico-ui/compare/v1.37.0...v1.37.1) (2026-09-14)
|
|
6
21
|
|
|
7
22
|
|
package/dist/index.cjs
CHANGED
|
@@ -7979,7 +7979,11 @@ var TOOLTIP_CSS = `
|
|
|
7979
7979
|
(opacity:0) nor a shown bubble can block neighbouring cells/buttons (matches MUI/Radix tooltips). */
|
|
7980
7980
|
pointer-events: none;
|
|
7981
7981
|
padding: 6px 10px; border-radius: var(--radius-md);
|
|
7982
|
-
|
|
7982
|
+
/* #385: capture the ink as the bubble bg via a private var BEFORE the content wrapper re-scopes
|
|
7983
|
+
--color-text, so a token-driven child (Text/Heading) reads the bubble's fg \u2014 not the page ink,
|
|
7984
|
+
which is this very background \u2014 and the re-scope can't feed back into the bg. */
|
|
7985
|
+
--_tt-bg: var(--color-text); --_tt-fg: var(--color-surface);
|
|
7986
|
+
background: var(--_tt-bg); color: var(--_tt-fg);
|
|
7983
7987
|
font-family: var(--font-sans); font-size: var(--text-xs); font-weight: var(--font-medium);
|
|
7984
7988
|
line-height: 1.3; white-space: normal;
|
|
7985
7989
|
/* Grow horizontally to max-width, then wrap. max-content sizes to the content (capped by
|
|
@@ -7995,7 +7999,13 @@ var TOOLTIP_CSS = `
|
|
|
7995
7999
|
.twc-tooltip[data-place="left"] { transform-origin: right center; translate: 0 -50%; }
|
|
7996
8000
|
.twc-tooltip[data-place="right"] { transform-origin: left center; translate: 0 -50%; }
|
|
7997
8001
|
.twc-tooltip[data-show="true"][data-place="top"], .twc-tooltip[data-show="true"][data-place="bottom"] { transform: scale(1); }
|
|
7998
|
-
.twc-tooltip__arrow { position: absolute; width: 7px; height: 7px; background: var(--
|
|
8002
|
+
.twc-tooltip__arrow { position: absolute; width: 7px; height: 7px; background: var(--_tt-bg); transform: rotate(45deg); }
|
|
8003
|
+
/* #385: re-scope token ink for the label subtree so Text/Heading (which set --color-text as an inline
|
|
8004
|
+
style) render in the bubble's fg instead of the page ink. display:contents adds no box, so the label's
|
|
8005
|
+
own flex/block layout is unchanged; custom properties still inherit through it. */
|
|
8006
|
+
.twc-tooltip__content { display: contents; --color-text: var(--_tt-fg);
|
|
8007
|
+
--color-text-muted: color-mix(in srgb, var(--_tt-fg) 72%, var(--_tt-bg));
|
|
8008
|
+
--color-text-subtle: color-mix(in srgb, var(--_tt-fg) 55%, var(--_tt-bg)); }
|
|
7999
8009
|
/* Arrow tracks the trigger via --_tw-arrow-x/y (px from the tooltip edge) instead of being
|
|
8000
8010
|
locked to the centre, so it still points at the trigger when the bubble is clamped near a
|
|
8001
8011
|
viewport edge. Falls back to 50% before measurement / SSR. */
|
|
@@ -8120,7 +8130,7 @@ function Tooltip({
|
|
|
8120
8130
|
"--_tw-arrow-y": coords.arrowY != null ? `${coords.arrowY}px` : void 0
|
|
8121
8131
|
},
|
|
8122
8132
|
children: [
|
|
8123
|
-
label,
|
|
8133
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-tooltip__content", children: label }),
|
|
8124
8134
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-tooltip__arrow", "aria-hidden": "true" })
|
|
8125
8135
|
]
|
|
8126
8136
|
}
|
|
@@ -9300,6 +9310,8 @@ function Datatable({
|
|
|
9300
9310
|
showExport = false,
|
|
9301
9311
|
showDensity = false,
|
|
9302
9312
|
showPivot = false,
|
|
9313
|
+
showColumns,
|
|
9314
|
+
showFilters,
|
|
9303
9315
|
exportFilename = "export",
|
|
9304
9316
|
aggregationValues = null,
|
|
9305
9317
|
disableColumnReorder = false,
|
|
@@ -9331,6 +9343,8 @@ function Datatable({
|
|
|
9331
9343
|
ariaLabel = "Data table",
|
|
9332
9344
|
"aria-label": ariaLabelAttr,
|
|
9333
9345
|
rowGrouping = [],
|
|
9346
|
+
showGroupBar = true,
|
|
9347
|
+
renderGroupLabel,
|
|
9334
9348
|
rowNumbers = false,
|
|
9335
9349
|
searchFields = null,
|
|
9336
9350
|
searchable = true,
|
|
@@ -10667,8 +10681,10 @@ function Datatable({
|
|
|
10667
10681
|
return;
|
|
10668
10682
|
}
|
|
10669
10683
|
if (k === "v") {
|
|
10670
|
-
|
|
10671
|
-
|
|
10684
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.readText) {
|
|
10685
|
+
e.preventDefault();
|
|
10686
|
+
pasteSelection();
|
|
10687
|
+
}
|
|
10672
10688
|
return;
|
|
10673
10689
|
}
|
|
10674
10690
|
}
|
|
@@ -10888,19 +10904,19 @@ function Datatable({
|
|
|
10888
10904
|
const copyTypeOf = (col) => col && col.copyType != null ? col.copyType : col && col.type === "number" ? "number" : "text";
|
|
10889
10905
|
const writeClipboard = (text) => {
|
|
10890
10906
|
const execFallback = () => {
|
|
10907
|
+
if (typeof document === "undefined") return;
|
|
10908
|
+
const ta = document.createElement("textarea");
|
|
10909
|
+
ta.value = text;
|
|
10910
|
+
ta.style.position = "fixed";
|
|
10911
|
+
ta.style.opacity = "0";
|
|
10912
|
+
document.body.appendChild(ta);
|
|
10913
|
+
ta.focus();
|
|
10914
|
+
ta.select();
|
|
10891
10915
|
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
|
-
}
|
|
10916
|
+
document.execCommand("copy");
|
|
10903
10917
|
} catch {
|
|
10918
|
+
} finally {
|
|
10919
|
+
if (ta.parentNode) ta.parentNode.removeChild(ta);
|
|
10904
10920
|
}
|
|
10905
10921
|
};
|
|
10906
10922
|
try {
|
|
@@ -10971,19 +10987,8 @@ function Datatable({
|
|
|
10971
10987
|
announceClip(`Copied ${n} cell${n === 1 ? "" : "s"}`, cellRect);
|
|
10972
10988
|
}
|
|
10973
10989
|
};
|
|
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
|
-
}
|
|
10990
|
+
const applyPastedText = (text) => {
|
|
10991
|
+
if (text == null || !cellRect) return;
|
|
10987
10992
|
const inApp = clipboardRef.current && clipboardRef.current.tsv === text ? clipboardRef.current : null;
|
|
10988
10993
|
let matrix;
|
|
10989
10994
|
if (inApp) matrix = inApp.matrix;
|
|
@@ -11028,6 +11033,31 @@ function Datatable({
|
|
|
11028
11033
|
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
11034
|
announceClip(`Pasted ${written} cell${written === 1 ? "" : "s"}${skipped ? `, ${skipped} skipped (incompatible column)` : ""}`, pasteRect);
|
|
11030
11035
|
};
|
|
11036
|
+
const pasteSelection = async () => {
|
|
11037
|
+
if (!cellRect) return;
|
|
11038
|
+
let text = null;
|
|
11039
|
+
try {
|
|
11040
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.readText) text = await navigator.clipboard.readText();
|
|
11041
|
+
} catch {
|
|
11042
|
+
setClipboardMsg("Paste unavailable \u2014 clipboard permission denied");
|
|
11043
|
+
return;
|
|
11044
|
+
}
|
|
11045
|
+
if (text == null) {
|
|
11046
|
+
setClipboardMsg("Nothing to paste");
|
|
11047
|
+
return;
|
|
11048
|
+
}
|
|
11049
|
+
applyPastedText(text);
|
|
11050
|
+
};
|
|
11051
|
+
const onGridPaste = (e) => {
|
|
11052
|
+
if (e.target.closest("input, textarea, select, [contenteditable='true']") || editing) return;
|
|
11053
|
+
if (!e.target.closest(".twc-dt__td[data-r]")) return;
|
|
11054
|
+
if (!(enableClipboard && selectionMode === "cell") || !cellRect) return;
|
|
11055
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.readText) return;
|
|
11056
|
+
const text = e.clipboardData ? e.clipboardData.getData("text/plain") : null;
|
|
11057
|
+
if (text == null || text === "") return;
|
|
11058
|
+
e.preventDefault();
|
|
11059
|
+
applyPastedText(text);
|
|
11060
|
+
};
|
|
11031
11061
|
React51__namespace.default.useEffect(() => {
|
|
11032
11062
|
if (!editing) return;
|
|
11033
11063
|
const onDown = (e) => {
|
|
@@ -11094,6 +11124,8 @@ function Datatable({
|
|
|
11094
11124
|
}
|
|
11095
11125
|
const tableMinWidth = leadW + ordered.reduce((a, c) => a + widthOf(c), 0);
|
|
11096
11126
|
const filterableCols = React51__namespace.default.useMemo(() => cols.filter((c) => c.filterable), [cols]);
|
|
11127
|
+
const columnsShown = showColumns !== void 0 ? showColumns : cols.some((c) => c.hideable) || rowNumbers;
|
|
11128
|
+
const filtersShown = showFilters !== void 0 ? showFilters : filterableCols.length > 0;
|
|
11097
11129
|
React51__namespace.default.useEffect(() => {
|
|
11098
11130
|
const el = filterPanelRef.current;
|
|
11099
11131
|
if (panel !== "filters" || !el || typeof document === "undefined") return void 0;
|
|
@@ -11480,6 +11512,7 @@ function Datatable({
|
|
|
11480
11512
|
const totalCols = ordered.length + (checkboxSelection ? 1 : 0) + (showRowNum ? 1 : 0) + (hasExpandCol ? 1 : 0);
|
|
11481
11513
|
function renderGroupRow(item) {
|
|
11482
11514
|
const subs = aggOn ? subtotalText(item.rows) : [];
|
|
11515
|
+
const custom = renderGroupLabel ? renderGroupLabel({ field: item.field, value: item.value, count: item.count, rows: item.rows }) : null;
|
|
11483
11516
|
return /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "twc-dt__group-row", role: "row", children: /* @__PURE__ */ jsxRuntime.jsxs("td", { className: "twc-dt__group-cell", role: "gridcell", colSpan: totalCols, style: { maxWidth: "none" }, children: [
|
|
11484
11517
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11485
11518
|
"button",
|
|
@@ -11491,12 +11524,14 @@ function Datatable({
|
|
|
11491
11524
|
onClick: () => toggleGroup(item.key),
|
|
11492
11525
|
children: [
|
|
11493
11526
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__group-chev", "data-open": !item.collapsed || void 0, children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.chevDown }) }),
|
|
11494
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11499
|
-
|
|
11527
|
+
renderGroupLabel ? custom : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11528
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__group-name", children: [
|
|
11529
|
+
fieldLabel(item.field),
|
|
11530
|
+
":"
|
|
11531
|
+
] }),
|
|
11532
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__group-val", children: String(item.value) }),
|
|
11533
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__group-count", children: item.count })
|
|
11534
|
+
] })
|
|
11500
11535
|
]
|
|
11501
11536
|
}
|
|
11502
11537
|
),
|
|
@@ -11861,11 +11896,12 @@ function Datatable({
|
|
|
11861
11896
|
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: diffOnly, onChange: (e) => setDiffOnly(e.target.checked) }),
|
|
11862
11897
|
diff.toggleLabel != null ? diff.toggleLabel : "Only changed"
|
|
11863
11898
|
] }) : null,
|
|
11864
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11899
|
+
columnsShown ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11865
11900
|
"button",
|
|
11866
11901
|
{
|
|
11867
11902
|
type: "button",
|
|
11868
11903
|
className: "twc-dt__tbtn",
|
|
11904
|
+
"data-tbtn": "columns",
|
|
11869
11905
|
"data-active": panel === "columns" || void 0,
|
|
11870
11906
|
"data-tip": "Show or hide columns",
|
|
11871
11907
|
onClick: (e) => {
|
|
@@ -11885,12 +11921,13 @@ function Datatable({
|
|
|
11885
11921
|
hidden.size ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__tbadge", children: cols.length - hidden.size }) : null
|
|
11886
11922
|
]
|
|
11887
11923
|
}
|
|
11888
|
-
),
|
|
11889
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11924
|
+
) : null,
|
|
11925
|
+
filtersShown ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11890
11926
|
"button",
|
|
11891
11927
|
{
|
|
11892
11928
|
type: "button",
|
|
11893
11929
|
className: "twc-dt__tbtn",
|
|
11930
|
+
"data-tbtn": "filters",
|
|
11894
11931
|
"data-active": panel === "filters" || void 0,
|
|
11895
11932
|
"data-tip": "Filter rows",
|
|
11896
11933
|
onClick: (e) => {
|
|
@@ -11909,7 +11946,7 @@ function Datatable({
|
|
|
11909
11946
|
filters.length ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__tbadge", children: filters.length }) : null
|
|
11910
11947
|
]
|
|
11911
11948
|
}
|
|
11912
|
-
),
|
|
11949
|
+
) : null,
|
|
11913
11950
|
showDensity ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "twc-dt__tbtn", "data-tip": "Change row density", onClick: () => setDensity((d) => d === "compact" ? "standard" : d === "standard" ? "comfortable" : "compact"), children: [
|
|
11914
11951
|
/* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.density }),
|
|
11915
11952
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__tlabel", children: density[0].toUpperCase() + density.slice(1) })
|
|
@@ -12006,7 +12043,7 @@ function Datatable({
|
|
|
12006
12043
|
}, children: /* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.x }) }) : null
|
|
12007
12044
|
] }) : null
|
|
12008
12045
|
] }),
|
|
12009
|
-
!pivotActive && activeGroupBy.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__groupbar", children: [
|
|
12046
|
+
!pivotActive && activeGroupBy.length && showGroupBar ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dt__groupbar", children: [
|
|
12010
12047
|
/* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.group }),
|
|
12011
12048
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dt__groupbar-label", children: "Grouped by" }),
|
|
12012
12049
|
activeGroupBy.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-dt__groupchip", children: [
|
|
@@ -12043,6 +12080,7 @@ function Datatable({
|
|
|
12043
12080
|
"aria-activedescendant": activeCellId,
|
|
12044
12081
|
"aria-busy": loading || void 0,
|
|
12045
12082
|
onKeyDown: onGridKeyDown,
|
|
12083
|
+
onPaste: onGridPaste,
|
|
12046
12084
|
children: [
|
|
12047
12085
|
/* @__PURE__ */ jsxRuntime.jsx("thead", { ref: theadRef, children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
|
|
12048
12086
|
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,
|
|
@@ -12480,13 +12518,13 @@ function Datatable({
|
|
|
12480
12518
|
" Sort descending"
|
|
12481
12519
|
] })
|
|
12482
12520
|
] }) : null,
|
|
12483
|
-
c.filterable ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", onClick: (e) => {
|
|
12521
|
+
c.filterable && filtersShown ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", onClick: (e) => {
|
|
12484
12522
|
addFilter(c.field);
|
|
12485
12523
|
setColMenu(null);
|
|
12486
12524
|
closeMenu();
|
|
12487
12525
|
restoreTriggerFocus();
|
|
12488
12526
|
setPanel("filters");
|
|
12489
|
-
openPanel(document.querySelector(
|
|
12527
|
+
openPanel(document.querySelector('.twc-dt__toolbar .twc-dt__tbtn[data-tbtn="filters"]'), "left", DT_FILTER_PANEL_W);
|
|
12490
12528
|
}, children: [
|
|
12491
12529
|
/* @__PURE__ */ jsxRuntime.jsx(Svg, { d: I.filter }),
|
|
12492
12530
|
" Filter"
|
|
@@ -12559,7 +12597,7 @@ function Datatable({
|
|
|
12559
12597
|
" ",
|
|
12560
12598
|
wrapped.has(c.field) ? "Unwrap text" : "Wrap text"
|
|
12561
12599
|
] }) : null,
|
|
12562
|
-
c.hideable ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", onClick: () => {
|
|
12600
|
+
c.hideable && columnsShown ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", onClick: () => {
|
|
12563
12601
|
setHidden((h) => new Set(h).add(c.field));
|
|
12564
12602
|
close();
|
|
12565
12603
|
}, children: [
|
|
@@ -19117,14 +19155,36 @@ function Code({
|
|
|
19117
19155
|
const timerRef = React51__namespace.default.useRef(null);
|
|
19118
19156
|
React51__namespace.default.useEffect(() => () => clearTimeout(timerRef.current), []);
|
|
19119
19157
|
const doCopy = () => {
|
|
19120
|
-
if (typeof navigator === "undefined" || !navigator.clipboard) return;
|
|
19121
19158
|
const text = typeof children === "string" ? children : rootRef.current?.textContent ?? "";
|
|
19122
|
-
|
|
19159
|
+
const flash = () => {
|
|
19123
19160
|
setCopied(true);
|
|
19124
19161
|
clearTimeout(timerRef.current);
|
|
19125
19162
|
timerRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
19126
|
-
}
|
|
19127
|
-
|
|
19163
|
+
};
|
|
19164
|
+
const execFallback = () => {
|
|
19165
|
+
if (typeof document === "undefined") return;
|
|
19166
|
+
const ta = document.createElement("textarea");
|
|
19167
|
+
ta.value = text;
|
|
19168
|
+
ta.style.position = "fixed";
|
|
19169
|
+
ta.style.opacity = "0";
|
|
19170
|
+
document.body.appendChild(ta);
|
|
19171
|
+
ta.focus();
|
|
19172
|
+
ta.select();
|
|
19173
|
+
try {
|
|
19174
|
+
if (document.execCommand("copy")) flash();
|
|
19175
|
+
} catch {
|
|
19176
|
+
} finally {
|
|
19177
|
+
if (ta.parentNode) ta.parentNode.removeChild(ta);
|
|
19178
|
+
}
|
|
19179
|
+
};
|
|
19180
|
+
try {
|
|
19181
|
+
if (typeof navigator !== "undefined" && navigator.clipboard && navigator.clipboard.writeText) {
|
|
19182
|
+
navigator.clipboard.writeText(text).then(flash).catch(execFallback);
|
|
19183
|
+
return;
|
|
19184
|
+
}
|
|
19185
|
+
} catch {
|
|
19186
|
+
}
|
|
19187
|
+
execFallback();
|
|
19128
19188
|
};
|
|
19129
19189
|
return /* @__PURE__ */ jsxRuntime.jsxs(Tag2, { ref: rootRef, className: `twc-code ${className}`.trim(), "data-block": block || void 0, ...rest, children: [
|
|
19130
19190
|
__twcStyles,
|