@internetarchive/ads-table 0.0.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.
Files changed (34) hide show
  1. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/ads-table-storybook.d.ts +6 -0
  2. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/ads-table-storybook.js +88 -0
  3. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/ads-table-storybook.js.map +1 -0
  4. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/ads-table.d.ts +53 -0
  5. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/ads-table.js +425 -0
  6. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/ads-table.js.map +1 -0
  7. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/index.d.ts +2 -0
  8. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/index.js +3 -0
  9. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/index.js.map +1 -0
  10. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/types.d.ts +27 -0
  11. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/types.js +88 -0
  12. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/dist/types.js.map +1 -0
  13. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/ads-table/tsconfig.tsbuildinfo +1 -0
  14. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/sample-package/dist/index.d.ts +1 -0
  15. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/sample-package/dist/index.js +2 -0
  16. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/sample-package/dist/index.js.map +1 -0
  17. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/sample-package/dist/sample-component.d.ts +7 -0
  18. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/sample-package/dist/sample-component.js +43 -0
  19. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/sample-package/dist/sample-component.js.map +1 -0
  20. package/.rollup.cache/Users/jeffwklein/work/archive/ads-common/packages/sample-package/tsconfig.tsbuildinfo +1 -0
  21. package/dist/ads-table-storybook.d.ts +6 -0
  22. package/dist/ads-table.d.ts +53 -0
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.js +659 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/types.d.ts +27 -0
  27. package/package.json +38 -0
  28. package/rollup.config.cjs +17 -0
  29. package/src/ads-table-storybook.ts +104 -0
  30. package/src/ads-table.ts +473 -0
  31. package/src/index.ts +14 -0
  32. package/src/types.ts +129 -0
  33. package/tsconfig.json +31 -0
  34. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,6 @@
1
+ import { LitElement } from "lit";
2
+ import "./ads-table";
3
+ export declare class AdsTableStorybook extends LitElement {
4
+ render(): import("lit-html").TemplateResult<1>;
5
+ static styles: import("lit").CSSResult;
6
+ }
@@ -0,0 +1,88 @@
1
+ import { __decorate } from "tslib";
2
+ import { html, css, LitElement } from "lit";
3
+ import { customElement } from "lit/decorators.js";
4
+ import "./ads-table";
5
+ import { BooleanDataType, FromKey, NumberDataType, StringDataType, UndefinedHelpers, } from "./types";
6
+ // corresponding columns for each field in PersonData
7
+ const columns = [
8
+ {
9
+ key: "firstName",
10
+ label: "First Name",
11
+ dataType: FromKey(StringDataType, "firstName"),
12
+ },
13
+ {
14
+ key: "lastName",
15
+ label: "Last Name",
16
+ dataType: FromKey(StringDataType, "lastName"),
17
+ },
18
+ {
19
+ key: "age",
20
+ label: "Age",
21
+ dataType: FromKey(NumberDataType, "age"),
22
+ },
23
+ {
24
+ key: "hasRegistered",
25
+ label: "Registered?",
26
+ dataType: FromKey(BooleanDataType, "hasRegistered"),
27
+ },
28
+ {
29
+ key: "catsName",
30
+ label: "Cat's Name",
31
+ dataType: FromKey(UndefinedHelpers(StringDataType), "catsName"),
32
+ },
33
+ ];
34
+ // sample data, a list of PersonData instances with IDs
35
+ const rows = [
36
+ {
37
+ id: "a",
38
+ data: {
39
+ firstName: "Tyler",
40
+ lastName: "Allgeier",
41
+ age: 22,
42
+ hasRegistered: true,
43
+ catsName: "Cookie",
44
+ },
45
+ },
46
+ {
47
+ id: "b",
48
+ data: {
49
+ firstName: "Drake",
50
+ lastName: "London",
51
+ age: 23,
52
+ hasRegistered: true,
53
+ catsName: "Garbanzo",
54
+ },
55
+ },
56
+ {
57
+ id: "c",
58
+ data: {
59
+ firstName: "Matt",
60
+ lastName: "Bryant",
61
+ age: 50,
62
+ hasRegistered: true,
63
+ catsName: "Boots",
64
+ },
65
+ },
66
+ {
67
+ id: "d",
68
+ data: {
69
+ firstName: "Jeff",
70
+ lastName: "Klein",
71
+ age: 30,
72
+ hasRegistered: false,
73
+ },
74
+ },
75
+ ];
76
+ let AdsTableStorybook = class AdsTableStorybook extends LitElement {
77
+ render() {
78
+ return html `
79
+ <ads-simple-table .columns=${columns} .rows=${rows}> </ads-simple-table>
80
+ `;
81
+ }
82
+ };
83
+ AdsTableStorybook.styles = css ``;
84
+ AdsTableStorybook = __decorate([
85
+ customElement("ads-table-storybook")
86
+ ], AdsTableStorybook);
87
+ export { AdsTableStorybook };
88
+ //# sourceMappingURL=ads-table-storybook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ads-table-storybook.js","sourceRoot":"","sources":["../src/ads-table-storybook.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,aAAa,CAAC;AACrB,OAAO,EACL,eAAe,EACf,OAAO,EACP,cAAc,EACd,cAAc,EAGd,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAWjB,qDAAqD;AACrD,MAAM,OAAO,GAA8B;IACzC;QACE,GAAG,EAAE,WAAW;QAChB,KAAK,EAAE,YAAY;QACnB,QAAQ,EAAE,OAAO,CAAC,cAAc,EAAE,WAAW,CAAC;KAC/C;IACD;QACE,GAAG,EAAE,UAAU;QACf,KAAK,EAAE,WAAW;QAClB,QAAQ,EAAE,OAAO,CAAC,cAAc,EAAE,UAAU,CAAC;KAC9C;IACD;QACE,GAAG,EAAE,KAAK;QACV,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,OAAO,CAAC,cAAc,EAAE,KAAK,CAAC;KACzC;IACD;QACE,GAAG,EAAE,eAAe;QACpB,KAAK,EAAE,aAAa;QACpB,QAAQ,EAAE,OAAO,CAAC,eAAe,EAAE,eAAe,CAAC;KACpD;IACD;QACE,GAAG,EAAE,UAAU;QACf,KAAK,EAAE,YAAY;QACnB,QAAQ,EAAE,OAAO,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;KAChE;CACF,CAAC;AAEF,uDAAuD;AACvD,MAAM,IAAI,GAA2B;IACnC;QACE,EAAE,EAAE,GAAG;QACP,IAAI,EAAE;YACJ,SAAS,EAAE,OAAO;YAClB,QAAQ,EAAE,UAAU;YACpB,GAAG,EAAE,EAAE;YACP,aAAa,EAAE,IAAI;YACnB,QAAQ,EAAE,QAAQ;SACnB;KACF;IACD;QACE,EAAE,EAAE,GAAG;QACP,IAAI,EAAE;YACJ,SAAS,EAAE,OAAO;YAClB,QAAQ,EAAE,QAAQ;YAClB,GAAG,EAAE,EAAE;YACP,aAAa,EAAE,IAAI;YACnB,QAAQ,EAAE,UAAU;SACrB;KACF;IACD;QACE,EAAE,EAAE,GAAG;QACP,IAAI,EAAE;YACJ,SAAS,EAAE,MAAM;YACjB,QAAQ,EAAE,QAAQ;YAClB,GAAG,EAAE,EAAE;YACP,aAAa,EAAE,IAAI;YACnB,QAAQ,EAAE,OAAO;SAClB;KACF;IACD;QACE,EAAE,EAAE,GAAG;QACP,IAAI,EAAE;YACJ,SAAS,EAAE,MAAM;YACjB,QAAQ,EAAE,OAAO;YACjB,GAAG,EAAE,EAAE;YACP,aAAa,EAAE,KAAK;SACrB;KACF;CACF,CAAC;AAGK,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,UAAU;IAC/C,MAAM;QACJ,OAAO,IAAI,CAAA;mCACoB,OAAO,UAAU,IAAI;KACnD,CAAC;IACJ,CAAC;;AAEM,wBAAM,GAAG,GAAG,CAAA,EAAE,AAAR,CAAS;AAPX,iBAAiB;IAD7B,aAAa,CAAC,qBAAqB,CAAC;GACxB,iBAAiB,CAQ7B","sourcesContent":["import { html, css, LitElement } from \"lit\";\nimport { customElement } from \"lit/decorators.js\";\nimport \"./ads-table\";\nimport {\n BooleanDataType,\n FromKey,\n NumberDataType,\n StringDataType,\n TableColumn,\n TableRow,\n UndefinedHelpers,\n} from \"./types\";\n\n// a simple interface for a sample table\ninterface PersonData {\n firstName: string;\n lastName: string;\n age: number;\n hasRegistered: boolean;\n catsName?: string;\n}\n\n// corresponding columns for each field in PersonData\nconst columns: TableColumn<PersonData>[] = [\n {\n key: \"firstName\",\n label: \"First Name\",\n dataType: FromKey(StringDataType, \"firstName\"),\n },\n {\n key: \"lastName\",\n label: \"Last Name\",\n dataType: FromKey(StringDataType, \"lastName\"),\n },\n {\n key: \"age\",\n label: \"Age\",\n dataType: FromKey(NumberDataType, \"age\"),\n },\n {\n key: \"hasRegistered\",\n label: \"Registered?\",\n dataType: FromKey(BooleanDataType, \"hasRegistered\"),\n },\n {\n key: \"catsName\",\n label: \"Cat's Name\",\n dataType: FromKey(UndefinedHelpers(StringDataType), \"catsName\"),\n },\n];\n\n// sample data, a list of PersonData instances with IDs\nconst rows: TableRow<PersonData>[] = [\n {\n id: \"a\",\n data: {\n firstName: \"Tyler\",\n lastName: \"Allgeier\",\n age: 22,\n hasRegistered: true,\n catsName: \"Cookie\",\n },\n },\n {\n id: \"b\",\n data: {\n firstName: \"Drake\",\n lastName: \"London\",\n age: 23,\n hasRegistered: true,\n catsName: \"Garbanzo\",\n },\n },\n {\n id: \"c\",\n data: {\n firstName: \"Matt\",\n lastName: \"Bryant\",\n age: 50,\n hasRegistered: true,\n catsName: \"Boots\",\n },\n },\n {\n id: \"d\",\n data: {\n firstName: \"Jeff\",\n lastName: \"Klein\",\n age: 30,\n hasRegistered: false,\n },\n },\n];\n\n@customElement(\"ads-table-storybook\")\nexport class AdsTableStorybook extends LitElement {\n render() {\n return html`\n <ads-simple-table .columns=${columns} .rows=${rows}> </ads-simple-table>\n `;\n }\n\n static styles = css``;\n}\n"]}
@@ -0,0 +1,53 @@
1
+ import { LitElement, PropertyValues, TemplateResult } from "lit";
2
+ import { SortComparisonFunction, TableColumn, TableDataType, TableRow } from "./types";
3
+ export declare abstract class AdsTable<T> extends LitElement {
4
+ tableElement: HTMLTableElement | undefined;
5
+ rows: TableRow<T>[];
6
+ protected abstract columns: TableColumn<T>[];
7
+ protected abstract sortKey: keyof T | undefined;
8
+ protected abstract secondarySortKey: keyof T | undefined;
9
+ protected noDataText: string;
10
+ protected readonly defaultSortDirection: "ascending" | "descending";
11
+ protected sortDirection: "ascending" | "descending";
12
+ protected selectedRowIds: string[];
13
+ isLoading: boolean;
14
+ protected updated(changedProperties: PropertyValues): void;
15
+ protected rowsDidUpdate(changedProperties: PropertyValues): boolean;
16
+ protected emitEvent(eventName: string, detail?: {}): void;
17
+ protected get visibleColumns(): TableColumn<T>[];
18
+ protected get rowsById(): {
19
+ [key: string]: TableRow<T>;
20
+ };
21
+ protected get sortedRows(): TableRow<T>[];
22
+ protected get selectedRows(): TableRow<T>[];
23
+ protected onColumnClick(column: TableColumn<T>, defaultSortDirection?: "ascending" | "descending"): void;
24
+ protected get columnKeyToDataType(): {
25
+ [columnKey: string]: TableDataType<T>;
26
+ };
27
+ protected get sortColumnDataType(): TableDataType<T> | undefined;
28
+ protected get secondarySortDataType(): TableDataType<T> | undefined;
29
+ protected getSortFunction(dataType: TableDataType<T> | undefined, sortDirection: "ascending" | "descending"): SortComparisonFunction<T> | undefined;
30
+ protected renderArrowIcon(columnKey: keyof T): TemplateResult;
31
+ protected get selectedRowIdsSet(): Set<string>;
32
+ protected get rowIdsSet(): Set<string>;
33
+ protected isSelected(row: TableRow<T>): boolean;
34
+ protected toggleRowSelected(rowId: string): void;
35
+ protected get lastSelectedRowId(): string;
36
+ protected get indexOfLastSelectedRow(): number;
37
+ protected groupRowSelect(rowIndex: number): void;
38
+ protected onRowClick(event: MouseEvent, clickedRow: TableRow<T>, rowIndex: number): void;
39
+ protected filterSelectedRowsToExistingRows(): void;
40
+ protected onRowDoubleClick(clickedRow: TableRow<T>): void;
41
+ protected onKeyDown(event: KeyboardEvent): void;
42
+ protected onUpDownArrowKey(key: "ArrowUp" | "ArrowDown"): void;
43
+ protected constrainIndex(index: number): number;
44
+ connectedCallback(): void;
45
+ render(): TemplateResult<1>;
46
+ static styles: import("lit").CSSResult;
47
+ }
48
+ export declare class AdsSimpleTable<T> extends AdsTable<T> {
49
+ columns: TableColumn<T>[];
50
+ secondarySortKey: keyof T | undefined;
51
+ sortKey: keyof T | undefined;
52
+ protected updated(changedProperties: PropertyValues): void;
53
+ }
@@ -0,0 +1,425 @@
1
+ import { __decorate } from "tslib";
2
+ // interface class for a Lit component class that contains table data
3
+ import { css, html, LitElement } from "lit";
4
+ import { property, state, query, customElement } from "lit/decorators.js";
5
+ import { EventHelpers } from "@jeffklein/ads-library";
6
+ import { getUserOS, UserOperatingSystem } from "@jeffklein/ads-library";
7
+ export class AdsTable extends LitElement {
8
+ constructor() {
9
+ super(...arguments);
10
+ // base list of data that this class sorts
11
+ this.rows = [];
12
+ this.noDataText = "No items found";
13
+ this.defaultSortDirection = "ascending";
14
+ this.sortDirection = this.defaultSortDirection;
15
+ // list of selected rows in order of least to most recently added
16
+ this.selectedRowIds = [];
17
+ this.isLoading = false;
18
+ }
19
+ updated(changedProperties) {
20
+ super.updated(changedProperties);
21
+ if (changedProperties.has("selectedRowIds")) {
22
+ // report selected rows to parent via an event
23
+ this.emitEvent("row-select", { selectedRows: this.selectedRows });
24
+ }
25
+ // if rows change, re-ensure selected rows exist in table
26
+ if (this.rowsDidUpdate(changedProperties)) {
27
+ this.filterSelectedRowsToExistingRows();
28
+ }
29
+ }
30
+ // rather than compare references, determine if 'this.rows' has updated. an update occurs if:
31
+ // - row list is a different size
32
+ // - any elements in the sorted list may have changed place
33
+ rowsDidUpdate(changedProperties) {
34
+ // if the sort properties change, assume the elements have rearranged
35
+ if (changedProperties.has("sortKey") ||
36
+ changedProperties.has("sortDirection")) {
37
+ return true;
38
+ }
39
+ if (!changedProperties.has("rows") || !changedProperties.get("rows")) {
40
+ return false;
41
+ }
42
+ const oldRowIds = changedProperties.get("rows").map((row) => row.id);
43
+ // first check length. if list length changes, rows have changed.
44
+ if (oldRowIds.length !== this.rows.length) {
45
+ return true;
46
+ }
47
+ // otherwise, if they're the same size, compare individual items and ensure they're the same set of items
48
+ const newRowsIdsSet = new Set(this.rows.map((row) => row.id));
49
+ return !oldRowIds.every((id) => newRowsIdsSet.has(id));
50
+ }
51
+ emitEvent(eventName, detail = {}) {
52
+ this.dispatchEvent(EventHelpers.createEvent(eventName, detail ? { detail } : {}));
53
+ }
54
+ get visibleColumns() {
55
+ return this.columns.filter(({ isHidden }) => !isHidden);
56
+ }
57
+ get rowsById() {
58
+ return Object.fromEntries(this.rows.map((row) => [row.id, row]));
59
+ }
60
+ get sortedRows() {
61
+ var _a;
62
+ const sortByPrimaryKey = this.getSortFunction(this.sortColumnDataType, this.sortDirection);
63
+ const sortBySecondaryKey = this.getSortFunction(this.secondarySortDataType, ((_a = this.secondarySortDataType) === null || _a === void 0 ? void 0 : _a.defaultSortDirection) || this.sortDirection);
64
+ return this.rows.sort((rowA, rowB) => {
65
+ // sort by primary key: the selected column and direction
66
+ const sortResult = (sortByPrimaryKey === null || sortByPrimaryKey === void 0 ? void 0 : sortByPrimaryKey(rowA.data, rowB.data)) || 0;
67
+ // if sort result on primary sort key is inconclusive, use secondary sort data type
68
+ if (sortResult === 0) {
69
+ return (sortBySecondaryKey === null || sortBySecondaryKey === void 0 ? void 0 : sortBySecondaryKey(rowA.data, rowB.data)) || 0;
70
+ }
71
+ else {
72
+ return sortResult;
73
+ }
74
+ });
75
+ }
76
+ get selectedRows() {
77
+ return this.selectedRowIds.map((id) => this.rowsById[id]).filter((x) => x);
78
+ }
79
+ // handler for when a user clicks on a column header
80
+ onColumnClick(column, defaultSortDirection = this
81
+ .defaultSortDirection) {
82
+ if (this.sortKey === column.key) {
83
+ // toggle the sort direction if the column you are clicking is already sorted
84
+ this.sortDirection =
85
+ this.sortDirection === "ascending" ? "descending" : "ascending";
86
+ }
87
+ else {
88
+ // otherwise, sort by the column you clicked on, and in the default sort direction
89
+ this.sortKey = column.key;
90
+ this.sortDirection =
91
+ column.dataType.defaultSortDirection || defaultSortDirection;
92
+ }
93
+ }
94
+ // a map of column keys to their respective data types so we don't have to call .find everywhere
95
+ get columnKeyToDataType() {
96
+ return Object.fromEntries(this.columns.map((col) => [col.key, col.dataType]));
97
+ }
98
+ // data type of the currently sorted column
99
+ get sortColumnDataType() {
100
+ if (this.sortKey) {
101
+ return this.columnKeyToDataType[this.sortKey];
102
+ }
103
+ else {
104
+ return undefined;
105
+ }
106
+ }
107
+ // data type of the secondary sort column
108
+ get secondarySortDataType() {
109
+ if (this.secondarySortKey) {
110
+ return this.columnKeyToDataType[this.secondarySortKey];
111
+ }
112
+ else {
113
+ return undefined;
114
+ }
115
+ }
116
+ // swaps the parameters of the sort function to reverse the sort direction
117
+ getSortFunction(dataType, sortDirection) {
118
+ if (!dataType) {
119
+ return undefined;
120
+ }
121
+ if (sortDirection === "ascending") {
122
+ // return the original comparison function
123
+ return dataType.compare;
124
+ }
125
+ else if (dataType.compare !== undefined) {
126
+ // swap compare function parameters for descending
127
+ return (a, b) => { var _a; return ((_a = dataType.compare) === null || _a === void 0 ? void 0 : _a.call(dataType, b, a)) || 0; };
128
+ }
129
+ else {
130
+ return undefined;
131
+ }
132
+ }
133
+ renderArrowIcon(columnKey) {
134
+ if (columnKey !== this.sortKey) {
135
+ return html ``;
136
+ }
137
+ else if (this.sortDirection === "ascending") {
138
+ return html `▲`;
139
+ }
140
+ else {
141
+ return html `▼`;
142
+ }
143
+ }
144
+ get selectedRowIdsSet() {
145
+ return new Set(this.selectedRowIds);
146
+ }
147
+ get rowIdsSet() {
148
+ return new Set(this.rows.map((row) => row.id));
149
+ }
150
+ isSelected(row) {
151
+ return this.selectedRowIdsSet.has(row.id);
152
+ }
153
+ toggleRowSelected(rowId) {
154
+ if (this.selectedRowIdsSet.has(rowId)) {
155
+ // row is already selected: filter out clicked id
156
+ this.selectedRowIds = this.selectedRowIds.filter((id) => id !== rowId);
157
+ }
158
+ else {
159
+ // row is not yet selected: append clicked id
160
+ this.selectedRowIds = [...this.selectedRowIds, rowId];
161
+ }
162
+ }
163
+ get lastSelectedRowId() {
164
+ return this.selectedRowIds[this.selectedRowIds.length - 1];
165
+ }
166
+ get indexOfLastSelectedRow() {
167
+ return this.rows.findIndex((row) => row.id === this.lastSelectedRowId);
168
+ }
169
+ // select rows in order from the last selected element up til the given index
170
+ groupRowSelect(rowIndex) {
171
+ const getRowsToAdd = () => {
172
+ // get rows between index of last selected until index of selected row
173
+ if (rowIndex > this.indexOfLastSelectedRow) {
174
+ return this.rows.filter((_, i) => rowIndex >= i && i >= this.indexOfLastSelectedRow);
175
+ }
176
+ else {
177
+ // reverse order of adding rows since clicked index is lower than last selected
178
+ return this.rows
179
+ .filter((_, i) => this.indexOfLastSelectedRow >= i && i >= rowIndex)
180
+ .reverse();
181
+ }
182
+ };
183
+ const rowIdsToAdd = getRowsToAdd().map((row) => row.id);
184
+ const rowIdsSet = new Set(rowIdsToAdd);
185
+ // first remove ids you are about to re-add, so they'll be in renewed order
186
+ this.selectedRowIds = this.selectedRowIds.filter((id) => !rowIdsSet.has(id));
187
+ // finally, add the new rows
188
+ this.selectedRowIds = [...this.selectedRowIds, ...rowIdsToAdd];
189
+ }
190
+ onRowClick(event, clickedRow, rowIndex) {
191
+ const userOs = getUserOS();
192
+ // meta (cmd) key for mac, control key for non-mac
193
+ const macHoldingHotKey = userOs === UserOperatingSystem.MAC && event.metaKey;
194
+ const nonMacHoldingHotKey = userOs !== UserOperatingSystem.MAC && event.ctrlKey;
195
+ // if holding meta on mac or ctrl on windows/linux, toggle individual row selection
196
+ if (macHoldingHotKey || nonMacHoldingHotKey) {
197
+ this.toggleRowSelected(clickedRow.id);
198
+ }
199
+ else if (event.shiftKey) {
200
+ // if holding shift, select rows between this selection and the last selection
201
+ this.groupRowSelect(rowIndex);
202
+ }
203
+ else {
204
+ // clicking a row will select just that row.
205
+ this.selectedRowIds = [clickedRow.id];
206
+ }
207
+ this.filterSelectedRowsToExistingRows();
208
+ // emit event so users can hook into this action
209
+ this.emitEvent("row-click", { row: clickedRow });
210
+ }
211
+ // filter selected down to rows that actually exist in the table
212
+ filterSelectedRowsToExistingRows() {
213
+ this.selectedRowIds = this.selectedRowIds.filter((id) => this.rowIdsSet.has(id));
214
+ }
215
+ onRowDoubleClick(clickedRow) {
216
+ // emit event so users can hook into this event
217
+ this.emitEvent("row-double-click", { row: clickedRow });
218
+ }
219
+ // All keyboard events implemented through this method.
220
+ onKeyDown(event) {
221
+ var _a;
222
+ switch (event.key) {
223
+ case "ArrowUp":
224
+ case "ArrowDown":
225
+ event.preventDefault();
226
+ // shift focus to table element when navigating with arrow keys
227
+ (_a = this.tableElement) === null || _a === void 0 ? void 0 : _a.focus();
228
+ return this.onUpDownArrowKey(event.key);
229
+ }
230
+ }
231
+ onUpDownArrowKey(key) {
232
+ if (this.selectedRowIds.length === 0) {
233
+ // select the first row if none are selected
234
+ this.selectedRowIds = [this.rows[0].id];
235
+ return;
236
+ }
237
+ // offset in the proper direction of the arrow
238
+ const indexOffset = key === "ArrowUp" ? -1 : 1;
239
+ const newSelectedRowIndex = this.constrainIndex(this.indexOfLastSelectedRow + indexOffset);
240
+ const newSelectedRowId = this.rows[newSelectedRowIndex].id;
241
+ this.selectedRowIds = [newSelectedRowId];
242
+ }
243
+ // ensures index values are kept to the closest in-bounds index
244
+ constrainIndex(index) {
245
+ return Math.max(Math.min(index, this.rows.length - 1), 0);
246
+ }
247
+ connectedCallback() {
248
+ super.connectedCallback();
249
+ // attach keyboard listener
250
+ window.addEventListener("keydown", (e) => this.onKeyDown(e));
251
+ }
252
+ render() {
253
+ return html `
254
+ <table id="main-table" tabindex="0">
255
+ <thead>
256
+ <tr>
257
+ ${this.visibleColumns.map((column) => html `
258
+ <th
259
+ @click=${() => this.onColumnClick(column)}
260
+ class=${column.dataType.compare ? "sortable" : ""}
261
+ style=${`flex: ${column.flexRatio}`}
262
+ >
263
+ ${column.label}
264
+ ${column.dataType.compare
265
+ ? html `<span>${this.renderArrowIcon(column.key)}</span>`
266
+ : ""}
267
+ </th>
268
+ `)}
269
+ </tr>
270
+ </thead>
271
+ <tbody>
272
+ ${!this.isLoading
273
+ ? this.sortedRows.map((row, index) => html `
274
+ <tr
275
+ @click=${(e) => this.onRowClick(e, row, index)}
276
+ @dblclick=${() => this.onRowDoubleClick(row)}
277
+ class=${this.isSelected(row) ? "row-selected" : ""}
278
+ data-row-selected=${this.isSelected(row)}
279
+ data-id=${row.id}
280
+ >
281
+ ${this.visibleColumns.map((column) => html `
282
+ <td style=${`flex: ${column.flexRatio}`}>
283
+ ${column.dataType.format(row.data)}
284
+ </td>
285
+ `)}
286
+ </tr>
287
+ `)
288
+ : html `
289
+ <tr>
290
+ <td class="no-data">Loading...</td>
291
+ </tr>
292
+ `}
293
+ ${!this.isLoading && this.sortedRows.length === 0
294
+ ? html `
295
+ <tr>
296
+ <td class="no-data">${this.noDataText}</td>
297
+ </tr>
298
+ `
299
+ : null}
300
+ </tbody>
301
+ </table>
302
+ `;
303
+ }
304
+ }
305
+ AdsTable.styles = css `
306
+ table {
307
+ display: flex;
308
+ flex-direction: column;
309
+ user-select: none;
310
+ border-collapse: collapse;
311
+ }
312
+
313
+ thead,
314
+ tbody {
315
+ display: flex;
316
+ flex-direction: column;
317
+ }
318
+
319
+ thead {
320
+ background: #2a282c;
321
+ }
322
+
323
+ tbody {
324
+ scrollbar-gutter: stable;
325
+ }
326
+
327
+ tr {
328
+ display: flex;
329
+ width: 100%;
330
+ min-height: 40px;
331
+ flex-shrink: 0;
332
+ }
333
+
334
+ tr.row-selected {
335
+ background: #ccddf2;
336
+ }
337
+
338
+ td.no-data {
339
+ font-style: italic;
340
+ justify-content: center;
341
+ }
342
+
343
+ td,
344
+ th {
345
+ display: flex;
346
+ flex: 1;
347
+ justify-content: flex-start;
348
+ align-items: center;
349
+ padding: 0 12px;
350
+ height: 40px;
351
+
352
+ overflow: hidden;
353
+ text-overflow: ellipsis;
354
+ white-space: nowrap;
355
+ min-width: 0;
356
+ }
357
+
358
+ th {
359
+ color: white;
360
+ }
361
+
362
+ th.sortable {
363
+ cursor: pointer;
364
+ }
365
+
366
+ th.sortable:hover {
367
+ background: #525252;
368
+ }
369
+
370
+ th span {
371
+ padding-left: 5px;
372
+ }
373
+
374
+ td {
375
+ border-bottom: 1px solid #bbbbbb;
376
+ }
377
+ `;
378
+ __decorate([
379
+ query("#main-table")
380
+ ], AdsTable.prototype, "tableElement", void 0);
381
+ __decorate([
382
+ property({ type: Array })
383
+ ], AdsTable.prototype, "rows", void 0);
384
+ __decorate([
385
+ state()
386
+ ], AdsTable.prototype, "sortDirection", void 0);
387
+ __decorate([
388
+ state()
389
+ ], AdsTable.prototype, "selectedRowIds", void 0);
390
+ __decorate([
391
+ state()
392
+ ], AdsTable.prototype, "isLoading", void 0);
393
+ // a simple, generic, out-of-the box implementation of AdsTable
394
+ let AdsSimpleTable = class AdsSimpleTable extends AdsTable {
395
+ constructor() {
396
+ var _a;
397
+ super(...arguments);
398
+ // columns are exposed as a parameter like rows, not a class member to implement
399
+ this.columns = [];
400
+ this.secondarySortKey = undefined;
401
+ // sort key is automatically held in state
402
+ this.sortKey = (_a = this.columns[0]) === null || _a === void 0 ? void 0 : _a.key;
403
+ }
404
+ updated(changedProperties) {
405
+ var _a;
406
+ super.updated(changedProperties);
407
+ if (changedProperties.has("columns")) {
408
+ this.sortKey = (_a = this.columns[0]) === null || _a === void 0 ? void 0 : _a.key;
409
+ }
410
+ }
411
+ };
412
+ __decorate([
413
+ property({ type: Array })
414
+ ], AdsSimpleTable.prototype, "columns", void 0);
415
+ __decorate([
416
+ property({ type: String })
417
+ ], AdsSimpleTable.prototype, "secondarySortKey", void 0);
418
+ __decorate([
419
+ state()
420
+ ], AdsSimpleTable.prototype, "sortKey", void 0);
421
+ AdsSimpleTable = __decorate([
422
+ customElement("ads-simple-table")
423
+ ], AdsSimpleTable);
424
+ export { AdsSimpleTable };
425
+ //# sourceMappingURL=ads-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ads-table.js","sourceRoot":"","sources":["../src/ads-table.ts"],"names":[],"mappings":"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","sourcesContent":["// interface class for a Lit component class that contains table data\nimport { css, html, LitElement, PropertyValues, TemplateResult } from \"lit\";\nimport {\n SortComparisonFunction,\n TableColumn,\n TableDataType,\n TableRow,\n} from \"./types\";\nimport { property, state, query, customElement } from \"lit/decorators.js\";\nimport { EventHelpers } from \"@jeffklein/ads-library\";\nimport { getUserOS, UserOperatingSystem } from \"@jeffklein/ads-library\";\n\nexport abstract class AdsTable<T> extends LitElement {\n @query(\"#main-table\") tableElement: HTMLTableElement | undefined;\n\n // base list of data that this class sorts\n @property({ type: Array }) rows: TableRow<T>[] = [];\n\n // abstract members to override\n protected abstract columns: TableColumn<T>[];\n protected abstract sortKey: keyof T | undefined;\n protected abstract secondarySortKey: keyof T | undefined;\n\n protected noDataText: string = \"No items found\";\n\n protected readonly defaultSortDirection: \"ascending\" | \"descending\" =\n \"ascending\";\n\n @state() protected sortDirection: \"ascending\" | \"descending\" =\n this.defaultSortDirection;\n\n // list of selected rows in order of least to most recently added\n @state() protected selectedRowIds: string[] = [];\n\n @state() isLoading: boolean = false;\n\n protected override updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has(\"selectedRowIds\")) {\n // report selected rows to parent via an event\n this.emitEvent(\"row-select\", { selectedRows: this.selectedRows });\n }\n\n // if rows change, re-ensure selected rows exist in table\n if (this.rowsDidUpdate(changedProperties)) {\n this.filterSelectedRowsToExistingRows();\n }\n }\n\n // rather than compare references, determine if 'this.rows' has updated. an update occurs if:\n // - row list is a different size\n // - any elements in the sorted list may have changed place\n protected rowsDidUpdate(changedProperties: PropertyValues): boolean {\n // if the sort properties change, assume the elements have rearranged\n if (\n changedProperties.has(\"sortKey\") ||\n changedProperties.has(\"sortDirection\")\n ) {\n return true;\n }\n if (!changedProperties.has(\"rows\") || !changedProperties.get(\"rows\")) {\n return false;\n }\n const oldRowIds: string[] = (\n changedProperties.get(\"rows\") as TableRow<T>[]\n ).map((row: TableRow<T>) => row.id);\n // first check length. if list length changes, rows have changed.\n if (oldRowIds.length !== this.rows.length) {\n return true;\n }\n // otherwise, if they're the same size, compare individual items and ensure they're the same set of items\n const newRowsIdsSet: Set<string> = new Set(this.rows.map((row) => row.id));\n return !oldRowIds.every((id) => newRowsIdsSet.has(id));\n }\n\n protected emitEvent(eventName: string, detail = {}) {\n this.dispatchEvent(\n EventHelpers.createEvent(eventName, detail ? { detail } : {}),\n );\n }\n\n protected get visibleColumns(): TableColumn<T>[] {\n return this.columns.filter(({ isHidden }) => !isHidden);\n }\n\n protected get rowsById(): { [key: string]: TableRow<T> } {\n return Object.fromEntries<TableRow<T>>(\n this.rows.map((row) => [row.id, row]),\n );\n }\n\n protected get sortedRows(): TableRow<T>[] {\n const sortByPrimaryKey = this.getSortFunction(\n this.sortColumnDataType,\n this.sortDirection,\n );\n const sortBySecondaryKey = this.getSortFunction(\n this.secondarySortDataType,\n this.secondarySortDataType?.defaultSortDirection || this.sortDirection,\n );\n return this.rows.sort((rowA, rowB) => {\n // sort by primary key: the selected column and direction\n const sortResult = sortByPrimaryKey?.(rowA.data, rowB.data) || 0;\n // if sort result on primary sort key is inconclusive, use secondary sort data type\n if (sortResult === 0) {\n return sortBySecondaryKey?.(rowA.data, rowB.data) || 0;\n } else {\n return sortResult;\n }\n });\n }\n\n protected get selectedRows(): TableRow<T>[] {\n return this.selectedRowIds.map((id) => this.rowsById[id]).filter((x) => x);\n }\n\n // handler for when a user clicks on a column header\n protected onColumnClick(\n column: TableColumn<T>,\n defaultSortDirection: \"ascending\" | \"descending\" = this\n .defaultSortDirection,\n ): void {\n if (this.sortKey === column.key) {\n // toggle the sort direction if the column you are clicking is already sorted\n this.sortDirection =\n this.sortDirection === \"ascending\" ? \"descending\" : \"ascending\";\n } else {\n // otherwise, sort by the column you clicked on, and in the default sort direction\n this.sortKey = column.key;\n this.sortDirection =\n column.dataType.defaultSortDirection || defaultSortDirection;\n }\n }\n\n // a map of column keys to their respective data types so we don't have to call .find everywhere\n protected get columnKeyToDataType(): {\n [columnKey: string]: TableDataType<T>;\n } {\n return Object.fromEntries<TableDataType<T>>(\n this.columns.map((col) => [col.key, col.dataType]),\n );\n }\n\n // data type of the currently sorted column\n protected get sortColumnDataType(): TableDataType<T> | undefined {\n if (this.sortKey) {\n return this.columnKeyToDataType[this.sortKey as string];\n } else {\n return undefined;\n }\n }\n\n // data type of the secondary sort column\n protected get secondarySortDataType(): TableDataType<T> | undefined {\n if (this.secondarySortKey) {\n return this.columnKeyToDataType[this.secondarySortKey as string];\n } else {\n return undefined;\n }\n }\n\n // swaps the parameters of the sort function to reverse the sort direction\n protected getSortFunction(\n dataType: TableDataType<T> | undefined,\n sortDirection: \"ascending\" | \"descending\",\n ): SortComparisonFunction<T> | undefined {\n if (!dataType) {\n return undefined;\n }\n if (sortDirection === \"ascending\") {\n // return the original comparison function\n return dataType.compare;\n } else if (dataType.compare !== undefined) {\n // swap compare function parameters for descending\n return (a, b) => dataType.compare?.(b, a) || 0;\n } else {\n return undefined;\n }\n }\n\n protected renderArrowIcon(columnKey: keyof T): TemplateResult {\n if (columnKey !== this.sortKey) {\n return html``;\n } else if (this.sortDirection === \"ascending\") {\n return html`▲`;\n } else {\n return html`▼`;\n }\n }\n\n protected get selectedRowIdsSet(): Set<string> {\n return new Set(this.selectedRowIds);\n }\n\n protected get rowIdsSet(): Set<string> {\n return new Set(this.rows.map((row) => row.id));\n }\n\n protected isSelected(row: TableRow<T>): boolean {\n return this.selectedRowIdsSet.has(row.id);\n }\n\n protected toggleRowSelected(rowId: string): void {\n if (this.selectedRowIdsSet.has(rowId)) {\n // row is already selected: filter out clicked id\n this.selectedRowIds = this.selectedRowIds.filter((id) => id !== rowId);\n } else {\n // row is not yet selected: append clicked id\n this.selectedRowIds = [...this.selectedRowIds, rowId];\n }\n }\n\n protected get lastSelectedRowId(): string {\n return this.selectedRowIds[this.selectedRowIds.length - 1];\n }\n\n protected get indexOfLastSelectedRow(): number {\n return this.rows.findIndex((row) => row.id === this.lastSelectedRowId);\n }\n\n // select rows in order from the last selected element up til the given index\n protected groupRowSelect(rowIndex: number): void {\n const getRowsToAdd = (): TableRow<T>[] => {\n // get rows between index of last selected until index of selected row\n if (rowIndex > this.indexOfLastSelectedRow) {\n return this.rows.filter(\n (_, i) => rowIndex >= i && i >= this.indexOfLastSelectedRow,\n );\n } else {\n // reverse order of adding rows since clicked index is lower than last selected\n return this.rows\n .filter((_, i) => this.indexOfLastSelectedRow >= i && i >= rowIndex)\n .reverse();\n }\n };\n const rowIdsToAdd: string[] = getRowsToAdd().map((row) => row.id);\n const rowIdsSet: Set<string> = new Set(rowIdsToAdd);\n // first remove ids you are about to re-add, so they'll be in renewed order\n this.selectedRowIds = this.selectedRowIds.filter(\n (id) => !rowIdsSet.has(id),\n );\n // finally, add the new rows\n this.selectedRowIds = [...this.selectedRowIds, ...rowIdsToAdd];\n }\n\n protected onRowClick(\n event: MouseEvent,\n clickedRow: TableRow<T>,\n rowIndex: number,\n ): void {\n const userOs = getUserOS();\n // meta (cmd) key for mac, control key for non-mac\n const macHoldingHotKey =\n userOs === UserOperatingSystem.MAC && event.metaKey;\n const nonMacHoldingHotKey =\n userOs !== UserOperatingSystem.MAC && event.ctrlKey;\n // if holding meta on mac or ctrl on windows/linux, toggle individual row selection\n if (macHoldingHotKey || nonMacHoldingHotKey) {\n this.toggleRowSelected(clickedRow.id);\n } else if (event.shiftKey) {\n // if holding shift, select rows between this selection and the last selection\n this.groupRowSelect(rowIndex);\n } else {\n // clicking a row will select just that row.\n this.selectedRowIds = [clickedRow.id];\n }\n this.filterSelectedRowsToExistingRows();\n // emit event so users can hook into this action\n this.emitEvent(\"row-click\", { row: clickedRow });\n }\n\n // filter selected down to rows that actually exist in the table\n protected filterSelectedRowsToExistingRows() {\n this.selectedRowIds = this.selectedRowIds.filter((id) =>\n this.rowIdsSet.has(id),\n );\n }\n\n protected onRowDoubleClick(clickedRow: TableRow<T>): void {\n // emit event so users can hook into this event\n this.emitEvent(\"row-double-click\", { row: clickedRow });\n }\n\n // All keyboard events implemented through this method.\n protected onKeyDown(event: KeyboardEvent): void {\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowDown\":\n event.preventDefault();\n // shift focus to table element when navigating with arrow keys\n this.tableElement?.focus();\n return this.onUpDownArrowKey(event.key);\n }\n }\n\n protected onUpDownArrowKey(key: \"ArrowUp\" | \"ArrowDown\"): void {\n if (this.selectedRowIds.length === 0) {\n // select the first row if none are selected\n this.selectedRowIds = [this.rows[0].id];\n return;\n }\n // offset in the proper direction of the arrow\n const indexOffset = key === \"ArrowUp\" ? -1 : 1;\n const newSelectedRowIndex = this.constrainIndex(\n this.indexOfLastSelectedRow + indexOffset,\n );\n const newSelectedRowId = this.rows[newSelectedRowIndex].id;\n this.selectedRowIds = [newSelectedRowId];\n }\n\n // ensures index values are kept to the closest in-bounds index\n protected constrainIndex(index: number): number {\n return Math.max(Math.min(index, this.rows.length - 1), 0);\n }\n\n connectedCallback() {\n super.connectedCallback();\n // attach keyboard listener\n window.addEventListener(\"keydown\", (e: KeyboardEvent) => this.onKeyDown(e));\n }\n\n render() {\n return html`\n <table id=\"main-table\" tabindex=\"0\">\n <thead>\n <tr>\n ${this.visibleColumns.map(\n (column) => html`\n <th\n @click=${() => this.onColumnClick(column)}\n class=${column.dataType.compare ? \"sortable\" : \"\"}\n style=${`flex: ${column.flexRatio}`}\n >\n ${column.label}\n ${column.dataType.compare\n ? html`<span>${this.renderArrowIcon(column.key)}</span>`\n : \"\"}\n </th>\n `,\n )}\n </tr>\n </thead>\n <tbody>\n ${!this.isLoading\n ? this.sortedRows.map(\n (row, index) => html`\n <tr\n @click=${(e: MouseEvent) => this.onRowClick(e, row, index)}\n @dblclick=${() => this.onRowDoubleClick(row)}\n class=${this.isSelected(row) ? \"row-selected\" : \"\"}\n data-row-selected=${this.isSelected(row)}\n data-id=${row.id}\n >\n ${this.visibleColumns.map(\n (column) => html`\n <td style=${`flex: ${column.flexRatio}`}>\n ${column.dataType.format(row.data)}\n </td>\n `,\n )}\n </tr>\n `,\n )\n : html`\n <tr>\n <td class=\"no-data\">Loading...</td>\n </tr>\n `}\n ${!this.isLoading && this.sortedRows.length === 0\n ? html`\n <tr>\n <td class=\"no-data\">${this.noDataText}</td>\n </tr>\n `\n : null}\n </tbody>\n </table>\n `;\n }\n\n static styles = css`\n table {\n display: flex;\n flex-direction: column;\n user-select: none;\n border-collapse: collapse;\n }\n\n thead,\n tbody {\n display: flex;\n flex-direction: column;\n }\n\n thead {\n background: #2a282c;\n }\n\n tbody {\n scrollbar-gutter: stable;\n }\n\n tr {\n display: flex;\n width: 100%;\n min-height: 40px;\n flex-shrink: 0;\n }\n\n tr.row-selected {\n background: #ccddf2;\n }\n\n td.no-data {\n font-style: italic;\n justify-content: center;\n }\n\n td,\n th {\n display: flex;\n flex: 1;\n justify-content: flex-start;\n align-items: center;\n padding: 0 12px;\n height: 40px;\n\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n }\n\n th {\n color: white;\n }\n\n th.sortable {\n cursor: pointer;\n }\n\n th.sortable:hover {\n background: #525252;\n }\n\n th span {\n padding-left: 5px;\n }\n\n td {\n border-bottom: 1px solid #bbbbbb;\n }\n `;\n}\n\n// a simple, generic, out-of-the box implementation of AdsTable\n@customElement(\"ads-simple-table\")\nexport class AdsSimpleTable<T> extends AdsTable<T> {\n // columns are exposed as a parameter like rows, not a class member to implement\n @property({ type: Array }) columns: TableColumn<T>[] = [];\n\n @property({ type: String }) secondarySortKey: keyof T | undefined = undefined;\n\n // sort key is automatically held in state\n @state() sortKey: keyof T | undefined = this.columns[0]?.key;\n\n protected override updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n if (changedProperties.has(\"columns\")) {\n this.sortKey = this.columns[0]?.key;\n }\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export { AdsTable, AdsSimpleTable } from "./ads-table";
2
+ export { TableDataType, TableColumn, TableRow, StringDataType, DateDataType, BytesDataType, NumberDataType, SortComparisonFunction, SortComparisonResult, NonSortable, UndefinedHelpers, } from "./types";
@@ -0,0 +1,3 @@
1
+ export { AdsTable, AdsSimpleTable } from "./ads-table";
2
+ export { StringDataType, DateDataType, BytesDataType, NumberDataType, NonSortable, UndefinedHelpers, } from "./types";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAIL,cAAc,EACd,YAAY,EACZ,aAAa,EACb,cAAc,EAGd,WAAW,EACX,gBAAgB,GACjB,MAAM,SAAS,CAAC","sourcesContent":["export { AdsTable, AdsSimpleTable } from \"./ads-table\";\nexport {\n TableDataType,\n TableColumn,\n TableRow,\n StringDataType,\n DateDataType,\n BytesDataType,\n NumberDataType,\n SortComparisonFunction,\n SortComparisonResult,\n NonSortable,\n UndefinedHelpers,\n} from \"./types\";\n"]}