@trackunit/react-table-base-components 2.7.22-alpha-15da733192f.0 → 2.9.1
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/index.cjs.js +35 -82
- package/index.esm.js +37 -83
- package/migrations/utils/jsx-utils.js +201 -0
- package/migrations/v3-0-0/copyablecell-to-copy-pair.js +193 -0
- package/migrations.json +7 -1
- package/package.json +9 -9
- package/src/index.d.ts +0 -2
- package/src/translation.d.ts +2 -2
- package/migrations/entry.js.map +0 -1
- package/src/components/CopyableCell/CopyableCell.d.ts +0 -44
- package/src/components/CopyableCell/CopyableCell.variants.d.ts +0 -6
package/index.cjs.js
CHANGED
|
@@ -12,8 +12,6 @@ var react = require('react');
|
|
|
12
12
|
var sharedUtils = require('@trackunit/shared-utils');
|
|
13
13
|
|
|
14
14
|
var defaultTranslations = {
|
|
15
|
-
"copyableCell.copied": "Copied!",
|
|
16
|
-
"copyableCell.copy": "Copy",
|
|
17
15
|
"rowActions.moreActions": "More actions"
|
|
18
16
|
};
|
|
19
17
|
|
|
@@ -153,85 +151,6 @@ const CheckboxCell = ({ checked, className, "data-testid": dataTestId, style })
|
|
|
153
151
|
return (jsxRuntime.jsx("div", { className: cvaCheckboxCell({ className }), "data-testid": dataTestId, style: style, children: jsxRuntime.jsx(reactFormComponents.Checkbox, { checked: checked, readOnly: true }) }));
|
|
154
152
|
};
|
|
155
153
|
|
|
156
|
-
const cvaMultiRowTableCellSection = cssClassVarianceUtilities.cva({
|
|
157
|
-
base: ["flex", "flex-col", "justify-center", "min-w-0", "max-w-full", "overflow-hidden"],
|
|
158
|
-
});
|
|
159
|
-
const cvaMultiRowTableCell = cssClassVarianceUtilities.cva({ base: ["flex", "justify-start", "min-w-0", "max-w-full"] });
|
|
160
|
-
const cvaMainRowText = cssClassVarianceUtilities.cva({ base: ["overflow-hidden", "text-ellipsis", "text-sm"] });
|
|
161
|
-
const cvaSecondaryRowText = cssClassVarianceUtilities.cva({
|
|
162
|
-
base: ["overflow-hidden", "text-ellipsis", "text-neutral-500", "text-xs"],
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* MultiRowTableCell renders two stacked rows inside a single table cell — a primary `main` row
|
|
167
|
-
* and a secondary row below it. String values are automatically styled with appropriate text sizes.
|
|
168
|
-
*
|
|
169
|
-
* ### When to use
|
|
170
|
-
* Use MultiRowTableCell when a table cell needs to display a primary value with secondary metadata below —
|
|
171
|
-
* for example, an asset name with its serial number, or a user name with their email.
|
|
172
|
-
*
|
|
173
|
-
* ### When not to use
|
|
174
|
-
* Do not use MultiRowTableCell for single-line text — use `TextCell`.
|
|
175
|
-
*
|
|
176
|
-
* @example Name with description in a table cell
|
|
177
|
-
* ```tsx
|
|
178
|
-
* import { MultiRowTableCell } from "@trackunit/react-table-base-components";
|
|
179
|
-
*
|
|
180
|
-
* const cell = ({ row }) => (
|
|
181
|
-
* <MultiRowTableCell main={row.original.name} secondary={row.original.serialNumber} />
|
|
182
|
-
* );
|
|
183
|
-
* ```
|
|
184
|
-
* @param {MultiRowTableCellProps} props - The props for the MultiRowTableCell component
|
|
185
|
-
* @returns {ReactElement} MultiRowTableCell component
|
|
186
|
-
*/
|
|
187
|
-
const MultiRowTableCell = ({ main, secondary, "data-testid": dataTestId, className, style, }) => {
|
|
188
|
-
return (jsxRuntime.jsx("div", { className: cvaMultiRowTableCell({ className }), style: style, children: jsxRuntime.jsxs("section", { className: cvaMultiRowTableCellSection(), "data-testid": dataTestId, children: [typeof main === "string" ? jsxRuntime.jsx("div", { className: cvaMainRowText(), children: main }) : main, typeof secondary === "string" && secondary !== "" ? (jsxRuntime.jsx("div", { className: cvaSecondaryRowText(), children: secondary })) : (secondary)] }) }));
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
const cvaCopyableCell = cssClassVarianceUtilities.cva({ base: ["overflow-hidden", "w-fit"] });
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* CopyableCell renders a table cell with click-to-copy functionality.
|
|
195
|
-
* Supports single-line and multi-line layouts.
|
|
196
|
-
*
|
|
197
|
-
* ### When to use
|
|
198
|
-
* Use CopyableCell inside table column definitions when a cell value (ID, name, reference) should be copyable.
|
|
199
|
-
*
|
|
200
|
-
* ### When not to use
|
|
201
|
-
* For standalone copyable text outside of tables, use `CopyableText` from `@trackunit/react-components`.
|
|
202
|
-
*
|
|
203
|
-
* @example Single-line copyable cell
|
|
204
|
-
* ```tsx
|
|
205
|
-
* import { CopyableCell } from "@trackunit/react-table-base-components";
|
|
206
|
-
*
|
|
207
|
-
* const cell = ({ getValue }) => (
|
|
208
|
-
* <CopyableCell text={getValue()} />
|
|
209
|
-
* );
|
|
210
|
-
* ```
|
|
211
|
-
* @example Multi-line copyable cell
|
|
212
|
-
* ```tsx
|
|
213
|
-
* import { CopyableCell } from "@trackunit/react-table-base-components";
|
|
214
|
-
*
|
|
215
|
-
* const cell = ({ row }) => (
|
|
216
|
-
* <CopyableCell
|
|
217
|
-
* text={String(row.original.customerId)}
|
|
218
|
-
* secondary={{ text: row.original.name }}
|
|
219
|
-
* />
|
|
220
|
-
* );
|
|
221
|
-
* ```
|
|
222
|
-
* @param {CopyableCellProps} props - The props for the CopyableCell component
|
|
223
|
-
* @returns {ReactElement} CopyableCell component
|
|
224
|
-
*/
|
|
225
|
-
const CopyableCell = ({ text, secondary, "data-testid": dataTestId, className, style, }) => {
|
|
226
|
-
const [t] = useTranslation();
|
|
227
|
-
const copyLabel = t("copyableCell.copy");
|
|
228
|
-
const copiedLabel = t("copyableCell.copied");
|
|
229
|
-
if (secondary !== undefined) {
|
|
230
|
-
return (jsxRuntime.jsx(MultiRowTableCell, { className: cvaCopyableCell({ className }), "data-testid": dataTestId, main: jsxRuntime.jsx(reactComponents.CopyableText, { className: "self-start", copiedLabel: copiedLabel, copyLabel: copyLabel, text: text }), secondary: jsxRuntime.jsx(reactComponents.CopyableText, { className: "self-start", copiedLabel: copiedLabel, copyLabel: copyLabel, size: "xs", text: secondary.text }), style: style }));
|
|
231
|
-
}
|
|
232
|
-
return (jsxRuntime.jsx(reactComponents.CopyableText, { className: cvaCopyableCell({ className }), copiedLabel: copiedLabel, copyLabel: copyLabel, "data-testid": dataTestId, style: style, text: text }));
|
|
233
|
-
};
|
|
234
|
-
|
|
235
154
|
const cvaDateTimeCell = cssClassVarianceUtilities.cva({ base: [""] });
|
|
236
155
|
const cvaDateTime$1 = cssClassVarianceUtilities.cva({ base: ["slashed-zero", "text-sm", "text-ellipsis"] });
|
|
237
156
|
const cvaDateTimeSince$1 = cssClassVarianceUtilities.cva({ base: ["slashed-zero", "text-neutral-500", "text-xs", "text-ellipsis"] });
|
|
@@ -578,6 +497,41 @@ const LinkCell = ({ link, type, className, ref, ...rest }) => {
|
|
|
578
497
|
return (jsxRuntime.jsx(reactComponents.ExternalLink, { className: cvaLinkCell({ className }), href: `${linkPrefix}${link}`, ref: ref, ...rest, color: "neutral", onClick: handleClick, children: link }));
|
|
579
498
|
};
|
|
580
499
|
|
|
500
|
+
const cvaMultiRowTableCellSection = cssClassVarianceUtilities.cva({
|
|
501
|
+
base: ["flex", "flex-col", "justify-center", "min-w-0", "max-w-full", "overflow-hidden"],
|
|
502
|
+
});
|
|
503
|
+
const cvaMultiRowTableCell = cssClassVarianceUtilities.cva({ base: ["flex", "justify-start", "min-w-0", "max-w-full"] });
|
|
504
|
+
const cvaMainRowText = cssClassVarianceUtilities.cva({ base: ["overflow-hidden", "text-ellipsis", "text-sm"] });
|
|
505
|
+
const cvaSecondaryRowText = cssClassVarianceUtilities.cva({
|
|
506
|
+
base: ["overflow-hidden", "text-ellipsis", "text-neutral-500", "text-xs"],
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* MultiRowTableCell renders two stacked rows inside a single table cell — a primary `main` row
|
|
511
|
+
* and a secondary row below it. String values are automatically styled with appropriate text sizes.
|
|
512
|
+
*
|
|
513
|
+
* ### When to use
|
|
514
|
+
* Use MultiRowTableCell when a table cell needs to display a primary value with secondary metadata below —
|
|
515
|
+
* for example, an asset name with its serial number, or a user name with their email.
|
|
516
|
+
*
|
|
517
|
+
* ### When not to use
|
|
518
|
+
* Do not use MultiRowTableCell for single-line text — use `TextCell`.
|
|
519
|
+
*
|
|
520
|
+
* @example Name with description in a table cell
|
|
521
|
+
* ```tsx
|
|
522
|
+
* import { MultiRowTableCell } from "@trackunit/react-table-base-components";
|
|
523
|
+
*
|
|
524
|
+
* const cell = ({ row }) => (
|
|
525
|
+
* <MultiRowTableCell main={row.original.name} secondary={row.original.serialNumber} />
|
|
526
|
+
* );
|
|
527
|
+
* ```
|
|
528
|
+
* @param {MultiRowTableCellProps} props - The props for the MultiRowTableCell component
|
|
529
|
+
* @returns {ReactElement} MultiRowTableCell component
|
|
530
|
+
*/
|
|
531
|
+
const MultiRowTableCell = ({ main, secondary, "data-testid": dataTestId, className, style, }) => {
|
|
532
|
+
return (jsxRuntime.jsx("div", { className: cvaMultiRowTableCell({ className }), style: style, children: jsxRuntime.jsxs("section", { className: cvaMultiRowTableCellSection(), "data-testid": dataTestId, children: [typeof main === "string" ? jsxRuntime.jsx("div", { className: cvaMainRowText(), children: main }) : main, typeof secondary === "string" && secondary !== "" ? (jsxRuntime.jsx("div", { className: cvaSecondaryRowText(), children: secondary })) : (secondary)] }) }));
|
|
533
|
+
};
|
|
534
|
+
|
|
581
535
|
/**
|
|
582
536
|
* Generic list to be used as tooltip content.
|
|
583
537
|
* The component is data-shape agnostic. It supports primitives, React elements,
|
|
@@ -1367,7 +1321,6 @@ setupLibraryTranslations();
|
|
|
1367
1321
|
|
|
1368
1322
|
exports.ButtonCell = ButtonCell;
|
|
1369
1323
|
exports.CheckboxCell = CheckboxCell;
|
|
1370
|
-
exports.CopyableCell = CopyableCell;
|
|
1371
1324
|
exports.DateTimeCell = DateTimeCell;
|
|
1372
1325
|
exports.HighlightCell = HighlightCell;
|
|
1373
1326
|
exports.IdentityCell = IdentityCell;
|
package/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { registerTranslations, useNamespaceTranslation } from '@trackunit/i18n-library-translation';
|
|
3
|
-
import { Button, Icon,
|
|
3
|
+
import { Button, Icon, Highlight, Heading, ExternalLink, DetailsList, Indicator, Spinner, Tooltip, Text, Tag, Notice, IconButton, MoreMenu, MenuContent, MenuItem, MenuDivider, useMeasure, useMergeRefs } from '@trackunit/react-components';
|
|
4
4
|
import { twMerge } from 'tailwind-merge';
|
|
5
5
|
import { Checkbox } from '@trackunit/react-form-components';
|
|
6
6
|
import { cva } from '@trackunit/css-class-variance-utilities';
|
|
@@ -10,8 +10,6 @@ import { useMemo, useState, useEffect, isValidElement, cloneElement } from 'reac
|
|
|
10
10
|
import { DateTimeFormat } from '@trackunit/shared-utils';
|
|
11
11
|
|
|
12
12
|
var defaultTranslations = {
|
|
13
|
-
"copyableCell.copied": "Copied!",
|
|
14
|
-
"copyableCell.copy": "Copy",
|
|
15
13
|
"rowActions.moreActions": "More actions"
|
|
16
14
|
};
|
|
17
15
|
|
|
@@ -151,85 +149,6 @@ const CheckboxCell = ({ checked, className, "data-testid": dataTestId, style })
|
|
|
151
149
|
return (jsx("div", { className: cvaCheckboxCell({ className }), "data-testid": dataTestId, style: style, children: jsx(Checkbox, { checked: checked, readOnly: true }) }));
|
|
152
150
|
};
|
|
153
151
|
|
|
154
|
-
const cvaMultiRowTableCellSection = cva({
|
|
155
|
-
base: ["flex", "flex-col", "justify-center", "min-w-0", "max-w-full", "overflow-hidden"],
|
|
156
|
-
});
|
|
157
|
-
const cvaMultiRowTableCell = cva({ base: ["flex", "justify-start", "min-w-0", "max-w-full"] });
|
|
158
|
-
const cvaMainRowText = cva({ base: ["overflow-hidden", "text-ellipsis", "text-sm"] });
|
|
159
|
-
const cvaSecondaryRowText = cva({
|
|
160
|
-
base: ["overflow-hidden", "text-ellipsis", "text-neutral-500", "text-xs"],
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* MultiRowTableCell renders two stacked rows inside a single table cell — a primary `main` row
|
|
165
|
-
* and a secondary row below it. String values are automatically styled with appropriate text sizes.
|
|
166
|
-
*
|
|
167
|
-
* ### When to use
|
|
168
|
-
* Use MultiRowTableCell when a table cell needs to display a primary value with secondary metadata below —
|
|
169
|
-
* for example, an asset name with its serial number, or a user name with their email.
|
|
170
|
-
*
|
|
171
|
-
* ### When not to use
|
|
172
|
-
* Do not use MultiRowTableCell for single-line text — use `TextCell`.
|
|
173
|
-
*
|
|
174
|
-
* @example Name with description in a table cell
|
|
175
|
-
* ```tsx
|
|
176
|
-
* import { MultiRowTableCell } from "@trackunit/react-table-base-components";
|
|
177
|
-
*
|
|
178
|
-
* const cell = ({ row }) => (
|
|
179
|
-
* <MultiRowTableCell main={row.original.name} secondary={row.original.serialNumber} />
|
|
180
|
-
* );
|
|
181
|
-
* ```
|
|
182
|
-
* @param {MultiRowTableCellProps} props - The props for the MultiRowTableCell component
|
|
183
|
-
* @returns {ReactElement} MultiRowTableCell component
|
|
184
|
-
*/
|
|
185
|
-
const MultiRowTableCell = ({ main, secondary, "data-testid": dataTestId, className, style, }) => {
|
|
186
|
-
return (jsx("div", { className: cvaMultiRowTableCell({ className }), style: style, children: jsxs("section", { className: cvaMultiRowTableCellSection(), "data-testid": dataTestId, children: [typeof main === "string" ? jsx("div", { className: cvaMainRowText(), children: main }) : main, typeof secondary === "string" && secondary !== "" ? (jsx("div", { className: cvaSecondaryRowText(), children: secondary })) : (secondary)] }) }));
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
const cvaCopyableCell = cva({ base: ["overflow-hidden", "w-fit"] });
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* CopyableCell renders a table cell with click-to-copy functionality.
|
|
193
|
-
* Supports single-line and multi-line layouts.
|
|
194
|
-
*
|
|
195
|
-
* ### When to use
|
|
196
|
-
* Use CopyableCell inside table column definitions when a cell value (ID, name, reference) should be copyable.
|
|
197
|
-
*
|
|
198
|
-
* ### When not to use
|
|
199
|
-
* For standalone copyable text outside of tables, use `CopyableText` from `@trackunit/react-components`.
|
|
200
|
-
*
|
|
201
|
-
* @example Single-line copyable cell
|
|
202
|
-
* ```tsx
|
|
203
|
-
* import { CopyableCell } from "@trackunit/react-table-base-components";
|
|
204
|
-
*
|
|
205
|
-
* const cell = ({ getValue }) => (
|
|
206
|
-
* <CopyableCell text={getValue()} />
|
|
207
|
-
* );
|
|
208
|
-
* ```
|
|
209
|
-
* @example Multi-line copyable cell
|
|
210
|
-
* ```tsx
|
|
211
|
-
* import { CopyableCell } from "@trackunit/react-table-base-components";
|
|
212
|
-
*
|
|
213
|
-
* const cell = ({ row }) => (
|
|
214
|
-
* <CopyableCell
|
|
215
|
-
* text={String(row.original.customerId)}
|
|
216
|
-
* secondary={{ text: row.original.name }}
|
|
217
|
-
* />
|
|
218
|
-
* );
|
|
219
|
-
* ```
|
|
220
|
-
* @param {CopyableCellProps} props - The props for the CopyableCell component
|
|
221
|
-
* @returns {ReactElement} CopyableCell component
|
|
222
|
-
*/
|
|
223
|
-
const CopyableCell = ({ text, secondary, "data-testid": dataTestId, className, style, }) => {
|
|
224
|
-
const [t] = useTranslation();
|
|
225
|
-
const copyLabel = t("copyableCell.copy");
|
|
226
|
-
const copiedLabel = t("copyableCell.copied");
|
|
227
|
-
if (secondary !== undefined) {
|
|
228
|
-
return (jsx(MultiRowTableCell, { className: cvaCopyableCell({ className }), "data-testid": dataTestId, main: jsx(CopyableText, { className: "self-start", copiedLabel: copiedLabel, copyLabel: copyLabel, text: text }), secondary: jsx(CopyableText, { className: "self-start", copiedLabel: copiedLabel, copyLabel: copyLabel, size: "xs", text: secondary.text }), style: style }));
|
|
229
|
-
}
|
|
230
|
-
return (jsx(CopyableText, { className: cvaCopyableCell({ className }), copiedLabel: copiedLabel, copyLabel: copyLabel, "data-testid": dataTestId, style: style, text: text }));
|
|
231
|
-
};
|
|
232
|
-
|
|
233
152
|
const cvaDateTimeCell = cva({ base: [""] });
|
|
234
153
|
const cvaDateTime$1 = cva({ base: ["slashed-zero", "text-sm", "text-ellipsis"] });
|
|
235
154
|
const cvaDateTimeSince$1 = cva({ base: ["slashed-zero", "text-neutral-500", "text-xs", "text-ellipsis"] });
|
|
@@ -576,6 +495,41 @@ const LinkCell = ({ link, type, className, ref, ...rest }) => {
|
|
|
576
495
|
return (jsx(ExternalLink, { className: cvaLinkCell({ className }), href: `${linkPrefix}${link}`, ref: ref, ...rest, color: "neutral", onClick: handleClick, children: link }));
|
|
577
496
|
};
|
|
578
497
|
|
|
498
|
+
const cvaMultiRowTableCellSection = cva({
|
|
499
|
+
base: ["flex", "flex-col", "justify-center", "min-w-0", "max-w-full", "overflow-hidden"],
|
|
500
|
+
});
|
|
501
|
+
const cvaMultiRowTableCell = cva({ base: ["flex", "justify-start", "min-w-0", "max-w-full"] });
|
|
502
|
+
const cvaMainRowText = cva({ base: ["overflow-hidden", "text-ellipsis", "text-sm"] });
|
|
503
|
+
const cvaSecondaryRowText = cva({
|
|
504
|
+
base: ["overflow-hidden", "text-ellipsis", "text-neutral-500", "text-xs"],
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* MultiRowTableCell renders two stacked rows inside a single table cell — a primary `main` row
|
|
509
|
+
* and a secondary row below it. String values are automatically styled with appropriate text sizes.
|
|
510
|
+
*
|
|
511
|
+
* ### When to use
|
|
512
|
+
* Use MultiRowTableCell when a table cell needs to display a primary value with secondary metadata below —
|
|
513
|
+
* for example, an asset name with its serial number, or a user name with their email.
|
|
514
|
+
*
|
|
515
|
+
* ### When not to use
|
|
516
|
+
* Do not use MultiRowTableCell for single-line text — use `TextCell`.
|
|
517
|
+
*
|
|
518
|
+
* @example Name with description in a table cell
|
|
519
|
+
* ```tsx
|
|
520
|
+
* import { MultiRowTableCell } from "@trackunit/react-table-base-components";
|
|
521
|
+
*
|
|
522
|
+
* const cell = ({ row }) => (
|
|
523
|
+
* <MultiRowTableCell main={row.original.name} secondary={row.original.serialNumber} />
|
|
524
|
+
* );
|
|
525
|
+
* ```
|
|
526
|
+
* @param {MultiRowTableCellProps} props - The props for the MultiRowTableCell component
|
|
527
|
+
* @returns {ReactElement} MultiRowTableCell component
|
|
528
|
+
*/
|
|
529
|
+
const MultiRowTableCell = ({ main, secondary, "data-testid": dataTestId, className, style, }) => {
|
|
530
|
+
return (jsx("div", { className: cvaMultiRowTableCell({ className }), style: style, children: jsxs("section", { className: cvaMultiRowTableCellSection(), "data-testid": dataTestId, children: [typeof main === "string" ? jsx("div", { className: cvaMainRowText(), children: main }) : main, typeof secondary === "string" && secondary !== "" ? (jsx("div", { className: cvaSecondaryRowText(), children: secondary })) : (secondary)] }) }));
|
|
531
|
+
};
|
|
532
|
+
|
|
579
533
|
/**
|
|
580
534
|
* Generic list to be used as tooltip content.
|
|
581
535
|
* The component is data-shape agnostic. It supports primitives, React elements,
|
|
@@ -1363,4 +1317,4 @@ const cvaTr = cva({
|
|
|
1363
1317
|
*/
|
|
1364
1318
|
setupLibraryTranslations();
|
|
1365
1319
|
|
|
1366
|
-
export { ButtonCell, CheckboxCell,
|
|
1320
|
+
export { ButtonCell, CheckboxCell, DateTimeCell, HighlightCell, IdentityCell, ImageCell, IndicatorCell, LinkCell, ListTooltip, MultiRowTableCell, MultiValueTextCell, NoticeCell, NumberCell, PlainDateCell, ResizeHandle, RowActions, SortIndicator, TableRoot, TagsCell, Tbody, Td, TextCell, Tfoot, Th, Thead, Tr };
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.insertAttributeIntoOpeningTag = exports.logSummary = exports.parseTsx = exports.hasSpreadAttribute = exports.findJsxAttribute = exports.findJsxElements = exports.getLocalAliasFor = exports.getImportedAliases = exports.visitTsFiles = exports.visitTsxFiles = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const devkit_1 = require("@nx/devkit");
|
|
6
|
+
const ts = tslib_1.__importStar(require("typescript"));
|
|
7
|
+
const TSX_EXTENSIONS = [".tsx", ".jsx"];
|
|
8
|
+
const TS_EXTENSIONS = [".ts", ".tsx", ".jsx"];
|
|
9
|
+
const isTsxFile = (filePath) => TSX_EXTENSIONS.some(ext => filePath.endsWith(ext));
|
|
10
|
+
const isTsFile = (filePath) => TS_EXTENSIONS.some(ext => filePath.endsWith(ext));
|
|
11
|
+
const isUnderNodeModules = (filePath) => filePath.includes("/node_modules/") || filePath.startsWith("node_modules/");
|
|
12
|
+
const isUnderDist = (filePath) => filePath.includes("/dist/") || filePath.startsWith("dist/") || filePath.includes("/.nx/");
|
|
13
|
+
/**
|
|
14
|
+
* Visits every `.tsx`/`.jsx` file under the workspace root and invokes the
|
|
15
|
+
* callback with the file path and its current contents. Files that don't
|
|
16
|
+
* include the marker substring are skipped, which makes large workspaces
|
|
17
|
+
* cheap to scan.
|
|
18
|
+
*/
|
|
19
|
+
const visitTsxFiles = (tree, marker, callback) => {
|
|
20
|
+
let touched = 0;
|
|
21
|
+
(0, devkit_1.visitNotIgnoredFiles)(tree, "/", filePath => {
|
|
22
|
+
if (!isTsxFile(filePath))
|
|
23
|
+
return;
|
|
24
|
+
if (isUnderNodeModules(filePath) || isUnderDist(filePath))
|
|
25
|
+
return;
|
|
26
|
+
const content = tree.read(filePath, "utf-8");
|
|
27
|
+
if (content === null)
|
|
28
|
+
return;
|
|
29
|
+
if (!content.includes(marker))
|
|
30
|
+
return;
|
|
31
|
+
const updated = callback(filePath, content);
|
|
32
|
+
if (updated !== null && updated !== undefined && updated !== content) {
|
|
33
|
+
tree.write(filePath, updated);
|
|
34
|
+
touched += 1;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return touched;
|
|
38
|
+
};
|
|
39
|
+
exports.visitTsxFiles = visitTsxFiles;
|
|
40
|
+
/**
|
|
41
|
+
* Same as {@link visitTsxFiles} but also includes plain `.ts` files. Use this
|
|
42
|
+
* when the codemod also rewrites non-JSX files such as helpers or hooks.
|
|
43
|
+
*/
|
|
44
|
+
const visitTsFiles = (tree, marker, callback) => {
|
|
45
|
+
let touched = 0;
|
|
46
|
+
(0, devkit_1.visitNotIgnoredFiles)(tree, "/", filePath => {
|
|
47
|
+
if (!isTsFile(filePath))
|
|
48
|
+
return;
|
|
49
|
+
if (isUnderNodeModules(filePath) || isUnderDist(filePath))
|
|
50
|
+
return;
|
|
51
|
+
const content = tree.read(filePath, "utf-8");
|
|
52
|
+
if (content === null)
|
|
53
|
+
return;
|
|
54
|
+
if (!content.includes(marker))
|
|
55
|
+
return;
|
|
56
|
+
const updated = callback(filePath, content);
|
|
57
|
+
if (updated !== null && updated !== undefined && updated !== content) {
|
|
58
|
+
tree.write(filePath, updated);
|
|
59
|
+
touched += 1;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return touched;
|
|
63
|
+
};
|
|
64
|
+
exports.visitTsFiles = visitTsFiles;
|
|
65
|
+
/**
|
|
66
|
+
* Mapping of imported component aliases to their original names for a given
|
|
67
|
+
* package. For `import { IconButton as Btn } from "@trackunit/react-components"`
|
|
68
|
+
* this returns `{ Btn: "IconButton" }`.
|
|
69
|
+
*
|
|
70
|
+
* Returns `null` when the file imports nothing from the package, which lets
|
|
71
|
+
* callers short-circuit before parsing JSX.
|
|
72
|
+
*/
|
|
73
|
+
const getImportedAliases = (sourceFile, packageName) => {
|
|
74
|
+
const result = {};
|
|
75
|
+
let found = false;
|
|
76
|
+
for (const stmt of sourceFile.statements) {
|
|
77
|
+
if (!ts.isImportDeclaration(stmt))
|
|
78
|
+
continue;
|
|
79
|
+
const moduleSpecifier = stmt.moduleSpecifier;
|
|
80
|
+
if (!ts.isStringLiteral(moduleSpecifier))
|
|
81
|
+
continue;
|
|
82
|
+
if (moduleSpecifier.text !== packageName)
|
|
83
|
+
continue;
|
|
84
|
+
const namedBindings = stmt.importClause?.namedBindings;
|
|
85
|
+
if (namedBindings === undefined || !ts.isNamedImports(namedBindings))
|
|
86
|
+
continue;
|
|
87
|
+
for (const element of namedBindings.elements) {
|
|
88
|
+
const localName = element.name.text;
|
|
89
|
+
const importedName = element.propertyName?.text ?? localName;
|
|
90
|
+
result[localName] = importedName;
|
|
91
|
+
found = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return found ? result : null;
|
|
95
|
+
};
|
|
96
|
+
exports.getImportedAliases = getImportedAliases;
|
|
97
|
+
/**
|
|
98
|
+
* Returns the local alias used in this file for `originalName` when imported
|
|
99
|
+
* from `packageName`, or `null` if the component is not imported.
|
|
100
|
+
*/
|
|
101
|
+
const getLocalAliasFor = (sourceFile, packageName, originalName) => {
|
|
102
|
+
const aliases = (0, exports.getImportedAliases)(sourceFile, packageName);
|
|
103
|
+
if (aliases === null)
|
|
104
|
+
return null;
|
|
105
|
+
for (const [local, original] of Object.entries(aliases)) {
|
|
106
|
+
if (original === originalName)
|
|
107
|
+
return local;
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
};
|
|
111
|
+
exports.getLocalAliasFor = getLocalAliasFor;
|
|
112
|
+
/**
|
|
113
|
+
* Finds every JSX element whose tag name resolves to one of `tagNames`
|
|
114
|
+
* (typically the local aliases returned by {@link getImportedAliases}).
|
|
115
|
+
*
|
|
116
|
+
* The result intentionally includes both opening and full elements so callers
|
|
117
|
+
* can manipulate attributes (via `openingElement`) or wrap/replace the whole
|
|
118
|
+
* element (via `element`).
|
|
119
|
+
*/
|
|
120
|
+
const findJsxElements = (sourceFile, tagNames) => {
|
|
121
|
+
const matches = [];
|
|
122
|
+
const tagSet = new Set(tagNames);
|
|
123
|
+
const visit = (node) => {
|
|
124
|
+
if (ts.isJsxSelfClosingElement(node)) {
|
|
125
|
+
if (ts.isIdentifier(node.tagName) && tagSet.has(node.tagName.text)) {
|
|
126
|
+
matches.push({ openingElement: node, element: node });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else if (ts.isJsxElement(node)) {
|
|
130
|
+
const opening = node.openingElement;
|
|
131
|
+
if (ts.isIdentifier(opening.tagName) && tagSet.has(opening.tagName.text)) {
|
|
132
|
+
matches.push({ openingElement: opening, element: node });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
ts.forEachChild(node, visit);
|
|
136
|
+
};
|
|
137
|
+
visit(sourceFile);
|
|
138
|
+
return matches;
|
|
139
|
+
};
|
|
140
|
+
exports.findJsxElements = findJsxElements;
|
|
141
|
+
/**
|
|
142
|
+
* Looks up a named JSX attribute on the opening element. Returns `null` when
|
|
143
|
+
* the attribute is missing or part of a spread attribute (which we cannot
|
|
144
|
+
* statically inspect).
|
|
145
|
+
*/
|
|
146
|
+
const findJsxAttribute = (openingElement, attributeName) => {
|
|
147
|
+
for (const attr of openingElement.attributes.properties) {
|
|
148
|
+
if (!ts.isJsxAttribute(attr))
|
|
149
|
+
continue;
|
|
150
|
+
if (!ts.isIdentifier(attr.name))
|
|
151
|
+
continue;
|
|
152
|
+
if (attr.name.text === attributeName)
|
|
153
|
+
return attr;
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
};
|
|
157
|
+
exports.findJsxAttribute = findJsxAttribute;
|
|
158
|
+
/**
|
|
159
|
+
* `true` when the element forwards a spread expression such as `{...rest}`,
|
|
160
|
+
* which means we can't be sure which attributes are actually set.
|
|
161
|
+
*/
|
|
162
|
+
const hasSpreadAttribute = (openingElement) => {
|
|
163
|
+
return openingElement.attributes.properties.some(prop => ts.isJsxSpreadAttribute(prop));
|
|
164
|
+
};
|
|
165
|
+
exports.hasSpreadAttribute = hasSpreadAttribute;
|
|
166
|
+
/**
|
|
167
|
+
* Parses the file as TSX so JSX is recognised. We do not need a full program
|
|
168
|
+
* here; tsquery's `ast` helper produces a script-kind source file which loses
|
|
169
|
+
* JSX context, so we go through `createSourceFile` directly.
|
|
170
|
+
*/
|
|
171
|
+
const parseTsx = (content, fileName = "file.tsx") => ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
172
|
+
exports.parseTsx = parseTsx;
|
|
173
|
+
/**
|
|
174
|
+
* Helper for codemods to log a one-line summary at the end of a run. Migration
|
|
175
|
+
* runners aggregate logs per migration, so this keeps output focused.
|
|
176
|
+
*/
|
|
177
|
+
const logSummary = (migrationName, touched, manualReviewNeeded) => {
|
|
178
|
+
if (touched === 0) {
|
|
179
|
+
devkit_1.logger.info(` ${migrationName}: no files changed`);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const reviewSuffix = manualReviewNeeded !== undefined && manualReviewNeeded > 0
|
|
183
|
+
? ` (${manualReviewNeeded} location(s) need manual review)`
|
|
184
|
+
: "";
|
|
185
|
+
devkit_1.logger.info(` ${migrationName}: updated ${touched} file(s)${reviewSuffix}`);
|
|
186
|
+
};
|
|
187
|
+
exports.logSummary = logSummary;
|
|
188
|
+
/**
|
|
189
|
+
* Inserts an attribute string immediately after the tag name (so the new
|
|
190
|
+
* attribute appears first). Returns the resulting source content.
|
|
191
|
+
*
|
|
192
|
+
* The added attribute is rendered verbatim, so callers are responsible for
|
|
193
|
+
* including the leading space (e.g. ` title="Close"`).
|
|
194
|
+
*/
|
|
195
|
+
const insertAttributeIntoOpeningTag = (content, openingElement, attributeText) => {
|
|
196
|
+
const tagName = openingElement.tagName;
|
|
197
|
+
const insertPos = tagName.getEnd();
|
|
198
|
+
return `${content.slice(0, insertPos)} ${attributeText}${content.slice(insertPos)}`;
|
|
199
|
+
};
|
|
200
|
+
exports.insertAttributeIntoOpeningTag = insertAttributeIntoOpeningTag;
|
|
201
|
+
//# sourceMappingURL=jsx-utils.js.map
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.copyableCellToCopyPair = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const ts = tslib_1.__importStar(require("typescript"));
|
|
6
|
+
const jsx_utils_1 = require("../utils/jsx-utils");
|
|
7
|
+
const TABLE_PACKAGE = "@trackunit/react-table-base-components";
|
|
8
|
+
const COMPONENTS_PACKAGE = "@trackunit/react-components";
|
|
9
|
+
const COMPONENT_NAME = "CopyableCell";
|
|
10
|
+
/**
|
|
11
|
+
* The expression a `text`-like attribute resolves to: `text="abc"` yields
|
|
12
|
+
* `"abc"`, `text={value}` yields `value`.
|
|
13
|
+
*/
|
|
14
|
+
const textExpression = (attr) => {
|
|
15
|
+
const initializer = attr.initializer;
|
|
16
|
+
if (initializer === undefined)
|
|
17
|
+
return null;
|
|
18
|
+
if (ts.isStringLiteral(initializer))
|
|
19
|
+
return initializer.getText();
|
|
20
|
+
if (ts.isJsxExpression(initializer) && initializer.expression !== undefined) {
|
|
21
|
+
return initializer.expression.getText();
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
};
|
|
25
|
+
/** For `secondary={{ text: X }}` returns the text of `X`; anything else is null. */
|
|
26
|
+
const secondaryTextExpression = (attr) => {
|
|
27
|
+
const initializer = attr.initializer;
|
|
28
|
+
if (initializer === undefined || !ts.isJsxExpression(initializer) || initializer.expression === undefined) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const expression = initializer.expression;
|
|
32
|
+
if (!ts.isObjectLiteralExpression(expression))
|
|
33
|
+
return null;
|
|
34
|
+
for (const prop of expression.properties) {
|
|
35
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "text") {
|
|
36
|
+
return prop.initializer.getText();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
};
|
|
41
|
+
const renderPair = (textExpr, secondaryRow) => {
|
|
42
|
+
const textProps = [
|
|
43
|
+
`className="min-w-0 truncate${secondaryRow ? " text-neutral-500" : ""}"`,
|
|
44
|
+
secondaryRow ? `size="small"` : null,
|
|
45
|
+
`type="span"`,
|
|
46
|
+
]
|
|
47
|
+
.filter(Boolean)
|
|
48
|
+
.join(" ");
|
|
49
|
+
return `<div className="flex min-w-0 max-w-full items-center overflow-hidden"><Text ${textProps}>{${textExpr}}</Text><CopyButton className="shrink-0" size="extraSmall" value={${textExpr}} /></div>`;
|
|
50
|
+
};
|
|
51
|
+
const attributeSourceText = (attr) => attr !== null && attr.initializer !== undefined ? attr.initializer.getText() : null;
|
|
52
|
+
const removeNamedImport = (content, packageName, name) => {
|
|
53
|
+
const sourceFile = (0, jsx_utils_1.parseTsx)(content, "source.tsx");
|
|
54
|
+
for (const stmt of sourceFile.statements) {
|
|
55
|
+
if (!ts.isImportDeclaration(stmt))
|
|
56
|
+
continue;
|
|
57
|
+
const moduleSpecifier = stmt.moduleSpecifier;
|
|
58
|
+
if (!ts.isStringLiteral(moduleSpecifier) || moduleSpecifier.text !== packageName)
|
|
59
|
+
continue;
|
|
60
|
+
const namedBindings = stmt.importClause?.namedBindings;
|
|
61
|
+
if (namedBindings === undefined || !ts.isNamedImports(namedBindings))
|
|
62
|
+
continue;
|
|
63
|
+
const remaining = namedBindings.elements.filter(el => (el.propertyName?.text ?? el.name.text) !== name);
|
|
64
|
+
if (remaining.length === namedBindings.elements.length)
|
|
65
|
+
continue;
|
|
66
|
+
if (remaining.length === 0) {
|
|
67
|
+
const start = stmt.getFullStart();
|
|
68
|
+
const end = stmt.getEnd();
|
|
69
|
+
const trailing = content.slice(end).startsWith("\n") ? end + 1 : end;
|
|
70
|
+
return `${content.slice(0, start)}${content.slice(trailing)}`;
|
|
71
|
+
}
|
|
72
|
+
const elementsText = remaining.map(el => el.getText()).join(", ");
|
|
73
|
+
return `${content.slice(0, namedBindings.getStart())}{ ${elementsText} }${content.slice(namedBindings.getEnd())}`;
|
|
74
|
+
}
|
|
75
|
+
return content;
|
|
76
|
+
};
|
|
77
|
+
const ensureNamedImport = (content, packageName, namesToAdd) => {
|
|
78
|
+
const sourceFile = (0, jsx_utils_1.parseTsx)(content, "source.tsx");
|
|
79
|
+
const aliases = (0, jsx_utils_1.getImportedAliases)(sourceFile, packageName) ?? {};
|
|
80
|
+
const missing = namesToAdd.filter(name => !Object.values(aliases).includes(name));
|
|
81
|
+
if (missing.length === 0)
|
|
82
|
+
return content;
|
|
83
|
+
for (const stmt of sourceFile.statements) {
|
|
84
|
+
if (!ts.isImportDeclaration(stmt))
|
|
85
|
+
continue;
|
|
86
|
+
const moduleSpecifier = stmt.moduleSpecifier;
|
|
87
|
+
if (!ts.isStringLiteral(moduleSpecifier) || moduleSpecifier.text !== packageName)
|
|
88
|
+
continue;
|
|
89
|
+
const namedBindings = stmt.importClause?.namedBindings;
|
|
90
|
+
if (namedBindings === undefined || !ts.isNamedImports(namedBindings))
|
|
91
|
+
continue;
|
|
92
|
+
const elementsText = namedBindings.elements.map(el => el.getText()).join(", ");
|
|
93
|
+
const merged = [elementsText, ...missing].join(", ");
|
|
94
|
+
return `${content.slice(0, namedBindings.getStart())}{ ${merged} }${content.slice(namedBindings.getEnd())}`;
|
|
95
|
+
}
|
|
96
|
+
const importLine = `import { ${missing.join(", ")} } from "${packageName}";\n`;
|
|
97
|
+
return `${importLine}${content}`;
|
|
98
|
+
};
|
|
99
|
+
let manualReviewCount = 0;
|
|
100
|
+
const transformCopyableCellUsage = (filePath, content) => {
|
|
101
|
+
const sourceFile = (0, jsx_utils_1.parseTsx)(content, filePath);
|
|
102
|
+
const aliases = (0, jsx_utils_1.getImportedAliases)(sourceFile, TABLE_PACKAGE);
|
|
103
|
+
if (aliases === null)
|
|
104
|
+
return null;
|
|
105
|
+
const cellAlias = Object.entries(aliases).find(([, name]) => name === COMPONENT_NAME)?.[0];
|
|
106
|
+
if (cellAlias === undefined)
|
|
107
|
+
return null;
|
|
108
|
+
if (Object.values(aliases).includes("CopyableCellProps")) {
|
|
109
|
+
manualReviewCount += 1;
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const matches = (0, jsx_utils_1.findJsxElements)(sourceFile, [cellAlias]);
|
|
113
|
+
if (matches.length === 0)
|
|
114
|
+
return null;
|
|
115
|
+
const edits = [];
|
|
116
|
+
let needsMultiRow = false;
|
|
117
|
+
for (const { openingElement, element } of matches) {
|
|
118
|
+
if ((0, jsx_utils_1.hasSpreadAttribute)(openingElement)) {
|
|
119
|
+
manualReviewCount += 1;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const textAttr = (0, jsx_utils_1.findJsxAttribute)(openingElement, "text");
|
|
123
|
+
const textExpr = textAttr !== null ? textExpression(textAttr) : null;
|
|
124
|
+
if (textExpr === null) {
|
|
125
|
+
manualReviewCount += 1;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const classNameAttr = (0, jsx_utils_1.findJsxAttribute)(openingElement, "className");
|
|
129
|
+
if (classNameAttr !== null) {
|
|
130
|
+
// The old cell forwarded className to its own cva root; there is no
|
|
131
|
+
// 1:1 slot for it on the pair, so leave these for a human.
|
|
132
|
+
manualReviewCount += 1;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const secondaryAttr = (0, jsx_utils_1.findJsxAttribute)(openingElement, "secondary");
|
|
136
|
+
const testIdText = attributeSourceText((0, jsx_utils_1.findJsxAttribute)(openingElement, "data-testid"));
|
|
137
|
+
let replacement;
|
|
138
|
+
if (secondaryAttr === null) {
|
|
139
|
+
replacement = renderPair(textExpr, false);
|
|
140
|
+
if (testIdText !== null) {
|
|
141
|
+
replacement = replacement.replace(`<div className="flex min-w-0 max-w-full items-center overflow-hidden">`, `<div className="flex min-w-0 max-w-full items-center overflow-hidden" data-testid=${testIdText}>`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
const secondaryExpr = secondaryTextExpression(secondaryAttr);
|
|
146
|
+
if (secondaryExpr === null) {
|
|
147
|
+
// `secondary` was something other than an inline `{{ text: … }}`.
|
|
148
|
+
manualReviewCount += 1;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
needsMultiRow = true;
|
|
152
|
+
const testIdProp = testIdText !== null ? ` data-testid=${testIdText}` : "";
|
|
153
|
+
replacement = `<MultiRowTableCell className="w-fit overflow-hidden"${testIdProp} main={${renderPair(textExpr, false)}} secondary={${renderPair(secondaryExpr, true)}} />`;
|
|
154
|
+
}
|
|
155
|
+
edits.push({ start: element.getStart(), end: element.getEnd(), replacement });
|
|
156
|
+
}
|
|
157
|
+
if (edits.length === 0)
|
|
158
|
+
return null;
|
|
159
|
+
edits.sort((a, b) => b.start - a.start);
|
|
160
|
+
let updated = content;
|
|
161
|
+
for (const { start, end, replacement } of edits) {
|
|
162
|
+
updated = `${updated.slice(0, start)}${replacement}${updated.slice(end)}`;
|
|
163
|
+
}
|
|
164
|
+
const remaining = (0, jsx_utils_1.findJsxElements)((0, jsx_utils_1.parseTsx)(updated, filePath), [cellAlias]);
|
|
165
|
+
if (remaining.length === 0) {
|
|
166
|
+
updated = removeNamedImport(updated, TABLE_PACKAGE, COMPONENT_NAME);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
manualReviewCount += 1;
|
|
170
|
+
}
|
|
171
|
+
if (needsMultiRow) {
|
|
172
|
+
updated = ensureNamedImport(updated, TABLE_PACKAGE, ["MultiRowTableCell"]);
|
|
173
|
+
}
|
|
174
|
+
updated = ensureNamedImport(updated, COMPONENTS_PACKAGE, ["Text", "CopyButton"]);
|
|
175
|
+
return updated;
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Rewrites `<CopyableCell text={x} secondary={{ text: y }} …/>` (removed in
|
|
179
|
+
* v3) into the value/copy pair used by table cells: a truncating `Text` next
|
|
180
|
+
* to an `extraSmall` `CopyButton`, wrapped for two-row cells in
|
|
181
|
+
* `MultiRowTableCell` with the `w-fit overflow-hidden` guard that keeps the
|
|
182
|
+
* pair inside the cell's grid track. Usages with spreads, dynamic
|
|
183
|
+
* `secondary` values, forwarded classNames, or a referenced
|
|
184
|
+
* `CopyableCellProps` type are left for manual review.
|
|
185
|
+
*/
|
|
186
|
+
const copyableCellToCopyPair = (tree) => {
|
|
187
|
+
manualReviewCount = 0;
|
|
188
|
+
const touched = (0, jsx_utils_1.visitTsxFiles)(tree, COMPONENT_NAME, transformCopyableCellUsage);
|
|
189
|
+
(0, jsx_utils_1.logSummary)("copyablecell-to-copy-pair", touched, manualReviewCount);
|
|
190
|
+
};
|
|
191
|
+
exports.copyableCellToCopyPair = copyableCellToCopyPair;
|
|
192
|
+
exports.default = exports.copyableCellToCopyPair;
|
|
193
|
+
//# sourceMappingURL=copyablecell-to-copy-pair.js.map
|
package/migrations.json
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generators": {
|
|
2
|
+
"generators": {
|
|
3
|
+
"v3-0-0-copyablecell-to-copy-pair": {
|
|
4
|
+
"version": "3.0.0",
|
|
5
|
+
"description": "Replace the removed CopyableCell with the Text + CopyButton pair, wrapped in MultiRowTableCell for two-row cells.",
|
|
6
|
+
"implementation": "./migrations/v3-0-0/copyablecell-to-copy-pair"
|
|
7
|
+
}
|
|
8
|
+
}
|
|
3
9
|
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-table-base-components",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.1",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=24.x"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@trackunit/react-components": "
|
|
11
|
-
"@trackunit/ui-icons": "1.14.45
|
|
12
|
-
"@trackunit/react-form-components": "2.
|
|
13
|
-
"@trackunit/css-class-variance-utilities": "2.0.16
|
|
14
|
-
"@trackunit/date-and-time-utils": "1.14.47
|
|
15
|
-
"@trackunit/react-date-and-time-hooks": "2.
|
|
16
|
-
"@trackunit/shared-utils": "1.16.51
|
|
17
|
-
"@trackunit/i18n-library-translation": "2.
|
|
10
|
+
"@trackunit/react-components": "3.1.1",
|
|
11
|
+
"@trackunit/ui-icons": "1.14.45",
|
|
12
|
+
"@trackunit/react-form-components": "2.7.1",
|
|
13
|
+
"@trackunit/css-class-variance-utilities": "2.0.16",
|
|
14
|
+
"@trackunit/date-and-time-utils": "1.14.47",
|
|
15
|
+
"@trackunit/react-date-and-time-hooks": "2.7.1",
|
|
16
|
+
"@trackunit/shared-utils": "1.16.51",
|
|
17
|
+
"@trackunit/i18n-library-translation": "2.5.1",
|
|
18
18
|
"tailwind-merge": "^2.0.0"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
package/src/index.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export * from "./components/ButtonCell/ButtonCell";
|
|
2
2
|
export * from "./components/CheckboxCell/CheckboxCell";
|
|
3
|
-
export { CopyableCell } from "./components/CopyableCell/CopyableCell";
|
|
4
|
-
export type { CopyableCellProps } from "./components/CopyableCell/CopyableCell";
|
|
5
3
|
export * from "./components/DateTimeCell/DateTimeCell";
|
|
6
4
|
export { HighlightCell } from "./components/HighlightCell/HighlightCell";
|
|
7
5
|
export type { HighlightCellProps } from "./components/HighlightCell/HighlightCell";
|
package/src/translation.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ export declare const translations: TranslationResource<TranslationKeys>;
|
|
|
6
6
|
/**
|
|
7
7
|
* Local useTranslation for this specific library
|
|
8
8
|
*/
|
|
9
|
-
export declare const useTranslation: () => [TransForLibs<"
|
|
10
|
-
t: TransForLibs<"
|
|
9
|
+
export declare const useTranslation: () => [TransForLibs<"rowActions.moreActions">, import("i18next").i18n, boolean] & {
|
|
10
|
+
t: TransForLibs<"rowActions.moreActions">;
|
|
11
11
|
i18n: import("i18next").i18n;
|
|
12
12
|
ready: boolean;
|
|
13
13
|
};
|
package/migrations/entry.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"entry.js","sourceRoot":"","sources":["../../../../../libs/react/table-base-components/migrations/entry.ts"],"names":[],"mappings":"","sourcesContent":["export {};\n"]}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { CommonProps, type CopyableTextProps, type Styleable } from "@trackunit/react-components";
|
|
2
|
-
import type { ReactElement } from "react";
|
|
3
|
-
type CopyableCellSecondary = Pick<CopyableTextProps, "text">;
|
|
4
|
-
export interface CopyableCellProps extends CommonProps, Pick<CopyableTextProps, "text">, Styleable {
|
|
5
|
-
/**
|
|
6
|
-
* When provided, renders a multi-line cell with a secondary row below the primary.
|
|
7
|
-
* The secondary row is independently copyable.
|
|
8
|
-
*/
|
|
9
|
-
readonly secondary?: CopyableCellSecondary;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* CopyableCell renders a table cell with click-to-copy functionality.
|
|
13
|
-
* Supports single-line and multi-line layouts.
|
|
14
|
-
*
|
|
15
|
-
* ### When to use
|
|
16
|
-
* Use CopyableCell inside table column definitions when a cell value (ID, name, reference) should be copyable.
|
|
17
|
-
*
|
|
18
|
-
* ### When not to use
|
|
19
|
-
* For standalone copyable text outside of tables, use `CopyableText` from `@trackunit/react-components`.
|
|
20
|
-
*
|
|
21
|
-
* @example Single-line copyable cell
|
|
22
|
-
* ```tsx
|
|
23
|
-
* import { CopyableCell } from "@trackunit/react-table-base-components";
|
|
24
|
-
*
|
|
25
|
-
* const cell = ({ getValue }) => (
|
|
26
|
-
* <CopyableCell text={getValue()} />
|
|
27
|
-
* );
|
|
28
|
-
* ```
|
|
29
|
-
* @example Multi-line copyable cell
|
|
30
|
-
* ```tsx
|
|
31
|
-
* import { CopyableCell } from "@trackunit/react-table-base-components";
|
|
32
|
-
*
|
|
33
|
-
* const cell = ({ row }) => (
|
|
34
|
-
* <CopyableCell
|
|
35
|
-
* text={String(row.original.customerId)}
|
|
36
|
-
* secondary={{ text: row.original.name }}
|
|
37
|
-
* />
|
|
38
|
-
* );
|
|
39
|
-
* ```
|
|
40
|
-
* @param {CopyableCellProps} props - The props for the CopyableCell component
|
|
41
|
-
* @returns {ReactElement} CopyableCell component
|
|
42
|
-
*/
|
|
43
|
-
export declare const CopyableCell: ({ text, secondary, "data-testid": dataTestId, className, style, }: CopyableCellProps) => ReactElement;
|
|
44
|
-
export {};
|