@equinor/apollo-components 1.0.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.
@@ -0,0 +1,35 @@
1
+ import { IconData } from '@equinor/eds-icons';
2
+ import { ReactNode } from 'react';
3
+ import { ColumnDef } from '@tanstack/react-table';
4
+
5
+ interface AppShellProps {
6
+ children?: ReactNode;
7
+ sidebar?: ReactNode;
8
+ icon?: IconData;
9
+ title?: string;
10
+ }
11
+ declare const AppShell: ({ children, icon, title, sidebar }: AppShellProps) => JSX.Element;
12
+
13
+ declare function AppSidebar(): JSX.Element;
14
+
15
+ declare const ChipsCell: (props: {
16
+ values?: string[];
17
+ }) => JSX.Element;
18
+
19
+ interface DataTableProps<T> {
20
+ className?: string;
21
+ columns: ColumnDef<T, any>[];
22
+ data: T[];
23
+ tableCaption?: string;
24
+ captionPadding?: string;
25
+ globalFilter?: boolean;
26
+ globalFilterPlaceholder?: string;
27
+ stickyHeader?: boolean;
28
+ tableWidth?: string;
29
+ sortable?: boolean;
30
+ virtual?: boolean;
31
+ height?: string;
32
+ }
33
+ declare function DataTable<T>({ columns, data, ...props }: DataTableProps<T>): JSX.Element;
34
+
35
+ export { AppShell, AppSidebar, ChipsCell, DataTable };
package/dist/index.js ADDED
@@ -0,0 +1,471 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
25
+
26
+ // src/index.tsx
27
+ var src_exports = {};
28
+ __export(src_exports, {
29
+ AppShell: () => AppShell,
30
+ AppSidebar: () => AppSidebar,
31
+ ChipsCell: () => ChipsCell,
32
+ DataTable: () => DataTable
33
+ });
34
+ module.exports = __toCommonJS(src_exports);
35
+
36
+ // src/AppShell/AppShell.tsx
37
+ var import_eds_core_react = require("@equinor/eds-core-react");
38
+ var import_eds_icons = require("@equinor/eds-icons");
39
+ var import_styled_components = __toESM(require("styled-components"));
40
+ var import_jsx_runtime = require("react/jsx-runtime");
41
+ var Wrapper = import_styled_components.default.div`
42
+ display: flex;
43
+ flex-direction: column;
44
+ margin: 0;
45
+ height: 100vh;
46
+ .--content-wrapper {
47
+ display: flex;
48
+ flex: 1;
49
+ }
50
+ .--content-outlet {
51
+ flex: 1;
52
+ }
53
+ `;
54
+ var AppShell = ({ children, icon, title, sidebar }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrapper, {
55
+ children: [
56
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_eds_core_react.TopBar, {
57
+ sticky: false,
58
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_eds_core_react.TopBar.Header, {
59
+ children: [
60
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_eds_core_react.Icon, {
61
+ data: icon ?? import_eds_icons.apps
62
+ }),
63
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
64
+ children: title ?? "App Title"
65
+ })
66
+ ]
67
+ })
68
+ }),
69
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
70
+ className: "--content-wrapper",
71
+ children: [
72
+ sidebar,
73
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
74
+ className: "--content-outlet",
75
+ children
76
+ })
77
+ ]
78
+ })
79
+ ]
80
+ });
81
+
82
+ // src/AppShell/AppSidebar.tsx
83
+ var import_eds_core_react2 = require("@equinor/eds-core-react");
84
+ var import_eds_icons2 = require("@equinor/eds-icons");
85
+ var import_eds_tokens = require("@equinor/eds-tokens");
86
+ var import_react = require("react");
87
+ var import_styled_components2 = __toESM(require("styled-components"));
88
+ var import_jsx_runtime2 = require("react/jsx-runtime");
89
+ var Wrapper2 = import_styled_components2.default.div`
90
+ display: flex;
91
+ flex-direction: column;
92
+ justify-content: space-between;
93
+ width: ${(props) => props.collapsed ? "64px" : "192px"};
94
+ height: 100%;
95
+ background-color: ${import_eds_tokens.tokens.colors.ui.background__default.hex};
96
+ border-right: 2px solid ${import_eds_tokens.tokens.colors.ui.background__medium.hex};
97
+
98
+ .collapse-button-wrapper {
99
+ display: flex;
100
+ align-items: center;
101
+ height: 64px;
102
+ border-bottom: 1px solid ${import_eds_tokens.tokens.colors.ui.background__medium.hex};
103
+ ${(props) => props.collapsed && "justify-content: center;"}
104
+ }
105
+ .collapse-button {
106
+ ${(props) => !props.collapsed && import_styled_components2.css`
107
+ display: flex;
108
+ justify-content: space-between;
109
+ width: 100%;
110
+ margin: 0 12px;
111
+ border-radius: 50px;
112
+ `}
113
+ }
114
+ `;
115
+ function AppSidebar() {
116
+ const [collapsed, setCollapsed] = (0, import_react.useState)(false);
117
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Wrapper2, {
118
+ collapsed,
119
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
120
+ className: "collapse-button-wrapper",
121
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_eds_core_react2.Button, {
122
+ className: "collapse-button",
123
+ variant: collapsed ? "ghost_icon" : "ghost",
124
+ onClick: () => setCollapsed(!collapsed),
125
+ children: [
126
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_eds_core_react2.Icon, {
127
+ data: collapsed ? import_eds_icons2.last_page : import_eds_icons2.first_page
128
+ }),
129
+ !collapsed && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
130
+ children: "Collapse"
131
+ })
132
+ ]
133
+ })
134
+ })
135
+ });
136
+ }
137
+
138
+ // src/cells/ChipsCell.tsx
139
+ var import_eds_tokens2 = require("@equinor/eds-tokens");
140
+ var import_styled_components3 = __toESM(require("styled-components"));
141
+
142
+ // src/cells/utils.ts
143
+ function stringToHslColor(str, s = 80, l = 85) {
144
+ let hash = 0;
145
+ for (let i = 0; i < str.length; i++) {
146
+ hash = str.charCodeAt(i) + ((hash << 5) - hash);
147
+ }
148
+ const h = hash % 360;
149
+ return "hsl(" + h + ", " + s + "%, " + l + "%)";
150
+ }
151
+
152
+ // src/cells/ChipsCell.tsx
153
+ var import_jsx_runtime3 = require("react/jsx-runtime");
154
+ var ChipsWrapper = import_styled_components3.default.div`
155
+ display: flex;
156
+ align-items: center;
157
+ gap: 0.25rem;
158
+ `;
159
+ var Chip = import_styled_components3.default.div`
160
+ border-radius: 25px;
161
+ line-height: 22px;
162
+ height: 22px;
163
+ padding: 0 6px;
164
+ background-color: ${(props) => props.backgroundColor ?? import_eds_tokens2.tokens.colors.ui.background__medium.hex};
165
+ color: darkslategrey;
166
+ `;
167
+ var ChipsCell = (props) => {
168
+ var _a;
169
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChipsWrapper, {
170
+ children: (_a = props.values) == null ? void 0 : _a.map((value) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Chip, {
171
+ backgroundColor: stringToHslColor(value),
172
+ children: value
173
+ }, value))
174
+ });
175
+ };
176
+
177
+ // src/DataTable/DataTable.tsx
178
+ var import_react_table4 = require("@tanstack/react-table");
179
+ var import_react3 = require("react");
180
+ var import_styled_components7 = __toESM(require("styled-components"));
181
+
182
+ // src/DataTable/components/BasicTable.tsx
183
+ var import_eds_core_react5 = require("@equinor/eds-core-react");
184
+ var import_react_table2 = require("@tanstack/react-table");
185
+
186
+ // src/DataTable/components/TableHeader.tsx
187
+ var import_eds_core_react4 = require("@equinor/eds-core-react");
188
+
189
+ // src/DataTable/components/HeaderCell.tsx
190
+ var import_eds_core_react3 = require("@equinor/eds-core-react");
191
+ var import_eds_icons3 = require("@equinor/eds-icons");
192
+ var import_react_table = require("@tanstack/react-table");
193
+ var import_styled_components4 = __toESM(require("styled-components"));
194
+ var import_jsx_runtime4 = require("react/jsx-runtime");
195
+ var HeaderDiv = import_styled_components4.default.div`
196
+ display: flex;
197
+ align-items: center;
198
+ gap: 0.25rem;
199
+ `;
200
+ var HeaderCell = ({ header }) => {
201
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_eds_core_react3.Table.Cell, {
202
+ colSpan: header.colSpan,
203
+ children: header.isPlaceholder ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(HeaderDiv, {
204
+ onClick: header.column.getToggleSortingHandler(),
205
+ children: [
206
+ (0, import_react_table.flexRender)(header.column.columnDef.header, header.getContext()),
207
+ {
208
+ asc: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_eds_core_react3.Icon, {
209
+ data: import_eds_icons3.arrow_down
210
+ }),
211
+ desc: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_eds_core_react3.Icon, {
212
+ data: import_eds_icons3.arrow_up
213
+ })
214
+ }[header.column.getIsSorted()] ?? null
215
+ ]
216
+ })
217
+ }, header.id);
218
+ };
219
+
220
+ // src/DataTable/components/TableHeader.tsx
221
+ var import_jsx_runtime5 = require("react/jsx-runtime");
222
+ var TableHeader = ({ table, sticky }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_eds_core_react4.Table.Head, {
223
+ sticky,
224
+ children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_eds_core_react4.Table.Row, {
225
+ children: headerGroup.headers.map((header) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(HeaderCell, {
226
+ header
227
+ }, header.id))
228
+ }, headerGroup.id))
229
+ });
230
+
231
+ // src/DataTable/components/BasicTable.tsx
232
+ var import_jsx_runtime6 = require("react/jsx-runtime");
233
+ function BasicTable({ table, stickyHeader }) {
234
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_eds_core_react5.Table, {
235
+ children: [
236
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TableHeader, {
237
+ sticky: stickyHeader,
238
+ table
239
+ }),
240
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_eds_core_react5.Table.Body, {
241
+ children: table.getRowModel().rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_eds_core_react5.Table.Row, {
242
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_eds_core_react5.Table.Cell, {
243
+ children: (0, import_react_table2.flexRender)(cell.column.columnDef.cell, cell.getContext())
244
+ }, cell.id))
245
+ }, row.id))
246
+ })
247
+ ]
248
+ });
249
+ }
250
+
251
+ // src/DataTable/components/DataTableHeader.tsx
252
+ var import_eds_core_react7 = require("@equinor/eds-core-react");
253
+ var import_styled_components6 = __toESM(require("styled-components"));
254
+
255
+ // src/DataTable/filters/DebouncedInput.tsx
256
+ var import_eds_core_react6 = require("@equinor/eds-core-react");
257
+ var import_react2 = require("react");
258
+ var import_styled_components5 = __toESM(require("styled-components"));
259
+ var import_jsx_runtime7 = require("react/jsx-runtime");
260
+ var Wrapper3 = import_styled_components5.default.div`
261
+ width: 300px;
262
+ `;
263
+ function DebouncedInput({
264
+ value: initialValue,
265
+ onChange,
266
+ debounce = 500,
267
+ ...props
268
+ }) {
269
+ const [value, setValue] = (0, import_react2.useState)(initialValue);
270
+ (0, import_react2.useEffect)(() => {
271
+ setValue(initialValue);
272
+ }, [initialValue]);
273
+ (0, import_react2.useEffect)(() => {
274
+ const timeout = setTimeout(() => {
275
+ onChange(value);
276
+ }, debounce);
277
+ return () => clearTimeout(timeout);
278
+ }, [value]);
279
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Wrapper3, {
280
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_eds_core_react6.Input, {
281
+ ...props,
282
+ value,
283
+ onChange: (event) => setValue(event.target.value)
284
+ })
285
+ });
286
+ }
287
+
288
+ // src/DataTable/filters/functions.ts
289
+ var import_match_sorter_utils = require("@tanstack/match-sorter-utils");
290
+ var fuzzyFilter = (row, columnId, value, addMeta) => {
291
+ const itemRank = (0, import_match_sorter_utils.rankItem)(row.getValue(columnId), value);
292
+ addMeta({
293
+ itemRank
294
+ });
295
+ return itemRank.passed;
296
+ };
297
+
298
+ // src/DataTable/components/DataTableHeader.tsx
299
+ var import_jsx_runtime8 = require("react/jsx-runtime");
300
+ var DataTableHeaderWrapper = import_styled_components6.default.div`
301
+ & > * + * {
302
+ margin-top: 0.5rem;
303
+ }
304
+ gap: 0.5rem;
305
+ padding: ${(props) => props.captionPadding ?? "1rem"};
306
+ `;
307
+ var FilterContainer = import_styled_components6.default.div`
308
+ display: flex;
309
+ align-items: center;
310
+ gap: 0.5rem;
311
+ `;
312
+ var DataTableHeader = (props) => {
313
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DataTableHeaderWrapper, {
314
+ className: "--table-caption",
315
+ captionPadding: props.captionPadding,
316
+ children: [
317
+ (props == null ? void 0 : props.tableCaption) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_eds_core_react7.Typography, {
318
+ variant: "h2",
319
+ children: props == null ? void 0 : props.tableCaption
320
+ }),
321
+ (props == null ? void 0 : props.enableGlobalFilter) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FilterContainer, {
322
+ className: "--filter-container",
323
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DebouncedInput, {
324
+ value: props.globalFilter ?? "",
325
+ placeholder: (props == null ? void 0 : props.globalFilterPlaceholder) ?? "Search all columns",
326
+ onChange: (value) => {
327
+ var _a;
328
+ return (_a = props.setGlobalFilter) == null ? void 0 : _a.call(props, String(value));
329
+ }
330
+ })
331
+ })
332
+ ]
333
+ });
334
+ };
335
+
336
+ // src/DataTable/components/VirtualTable.tsx
337
+ var import_eds_core_react9 = require("@equinor/eds-core-react");
338
+ var import_react_table3 = require("@tanstack/react-table");
339
+ var import_react_virtual = require("@tanstack/react-virtual");
340
+
341
+ // src/DataTable/components/PaddingRow.tsx
342
+ var import_eds_core_react8 = require("@equinor/eds-core-react");
343
+ var import_jsx_runtime9 = require("react/jsx-runtime");
344
+ var PaddingRow = (props) => {
345
+ if (!props.height)
346
+ return null;
347
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_eds_core_react8.Table.Row, {
348
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_eds_core_react8.Table.Cell, {
349
+ style: { height: `${props.height}px` }
350
+ })
351
+ });
352
+ };
353
+
354
+ // src/DataTable/components/VirtualTable.tsx
355
+ var import_jsx_runtime10 = require("react/jsx-runtime");
356
+ function VirtualTable({ table, containerRef, ...props }) {
357
+ var _a, _b;
358
+ const { rows } = table.getRowModel();
359
+ const rowVirtualizer = (0, import_react_virtual.useVirtual)({
360
+ overscan: 10,
361
+ size: rows.length,
362
+ parentRef: containerRef
363
+ });
364
+ const { virtualItems: virtualRows, totalSize } = rowVirtualizer;
365
+ const paddingTop = virtualRows.length > 0 ? ((_a = virtualRows == null ? void 0 : virtualRows[0]) == null ? void 0 : _a.start) || 0 : 0;
366
+ const paddingBottom = virtualRows.length > 0 ? totalSize - (((_b = virtualRows == null ? void 0 : virtualRows[virtualRows.length - 1]) == null ? void 0 : _b.end) || 0) : 0;
367
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_eds_core_react9.Table, {
368
+ children: [
369
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TableHeader, {
370
+ sticky: props.stickyHeader,
371
+ table
372
+ }),
373
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_eds_core_react9.Table.Body, {
374
+ children: [
375
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PaddingRow, {
376
+ height: paddingTop
377
+ }),
378
+ virtualRows.map((virtualRow) => {
379
+ const row = rows[virtualRow.index];
380
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_eds_core_react9.Table.Row, {
381
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_eds_core_react9.Table.Cell, {
382
+ children: (0, import_react_table3.flexRender)(cell.column.columnDef.cell, cell.getContext())
383
+ }, cell.id))
384
+ }, row.id);
385
+ }),
386
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PaddingRow, {
387
+ height: paddingBottom
388
+ })
389
+ ]
390
+ })
391
+ ]
392
+ });
393
+ }
394
+
395
+ // src/DataTable/utils.ts
396
+ function enableOrUndefined(enabled, value) {
397
+ return Boolean(enabled) ? value : void 0;
398
+ }
399
+
400
+ // src/DataTable/DataTable.tsx
401
+ var import_jsx_runtime11 = require("react/jsx-runtime");
402
+ var DataTableWrapper = import_styled_components7.default.div`
403
+ width: ${(props) => props.width ?? "100%"};
404
+
405
+ .--table-container {
406
+ height: ${(props) => props.height ?? "100%"};
407
+ width: ${(props) => props.width ?? "100%"};
408
+ overflow: auto;
409
+
410
+ table {
411
+ width: 100%;
412
+ }
413
+ }
414
+ `;
415
+ function DataTable({ columns, data, ...props }) {
416
+ const [globalFilter, setGlobalFilter] = (0, import_react3.useState)("");
417
+ function enableGlobalFilter(value) {
418
+ return enableOrUndefined(props.globalFilter, value);
419
+ }
420
+ const [sorting, setSorting] = (0, import_react3.useState)([]);
421
+ const table = (0, import_react_table4.useReactTable)({
422
+ columns,
423
+ data,
424
+ getCoreRowModel: (0, import_react_table4.getCoreRowModel)(),
425
+ getFilteredRowModel: enableGlobalFilter((0, import_react_table4.getFilteredRowModel)()),
426
+ globalFilterFn: enableGlobalFilter(fuzzyFilter),
427
+ state: {
428
+ globalFilter: enableGlobalFilter(globalFilter),
429
+ sorting
430
+ },
431
+ enableSorting: props.sortable,
432
+ onSortingChange: setSorting,
433
+ getSortedRowModel: (0, import_react_table4.getSortedRowModel)(),
434
+ onGlobalFilterChange: enableGlobalFilter(setGlobalFilter)
435
+ });
436
+ const tableContainerRef = (0, import_react3.useRef)(null);
437
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(DataTableWrapper, {
438
+ captionPadding: props.captionPadding,
439
+ height: props.height,
440
+ width: props.tableWidth,
441
+ children: [
442
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DataTableHeader, {
443
+ tableCaption: props.tableCaption,
444
+ enableGlobalFilter: props.globalFilter,
445
+ globalFilter,
446
+ setGlobalFilter,
447
+ globalFilterPlaceholder: props.globalFilterPlaceholder,
448
+ captionPadding: props.captionPadding
449
+ }),
450
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", {
451
+ ref: tableContainerRef,
452
+ className: "--table-container",
453
+ children: props.virtual ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(VirtualTable, {
454
+ containerRef: tableContainerRef,
455
+ table,
456
+ stickyHeader: props.stickyHeader
457
+ }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(BasicTable, {
458
+ table,
459
+ stickyHeader: props.stickyHeader
460
+ })
461
+ })
462
+ ]
463
+ });
464
+ }
465
+ // Annotate the CommonJS export names for ESM import in node:
466
+ 0 && (module.exports = {
467
+ AppShell,
468
+ AppSidebar,
469
+ ChipsCell,
470
+ DataTable
471
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,440 @@
1
+ // src/AppShell/AppShell.tsx
2
+ import { Icon, TopBar } from "@equinor/eds-core-react";
3
+ import { apps } from "@equinor/eds-icons";
4
+ import styled from "styled-components";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ var Wrapper = styled.div`
7
+ display: flex;
8
+ flex-direction: column;
9
+ margin: 0;
10
+ height: 100vh;
11
+ .--content-wrapper {
12
+ display: flex;
13
+ flex: 1;
14
+ }
15
+ .--content-outlet {
16
+ flex: 1;
17
+ }
18
+ `;
19
+ var AppShell = ({ children, icon, title, sidebar }) => /* @__PURE__ */ jsxs(Wrapper, {
20
+ children: [
21
+ /* @__PURE__ */ jsx(TopBar, {
22
+ sticky: false,
23
+ children: /* @__PURE__ */ jsxs(TopBar.Header, {
24
+ children: [
25
+ /* @__PURE__ */ jsx(Icon, {
26
+ data: icon ?? apps
27
+ }),
28
+ /* @__PURE__ */ jsx("span", {
29
+ children: title ?? "App Title"
30
+ })
31
+ ]
32
+ })
33
+ }),
34
+ /* @__PURE__ */ jsxs("div", {
35
+ className: "--content-wrapper",
36
+ children: [
37
+ sidebar,
38
+ /* @__PURE__ */ jsx("div", {
39
+ className: "--content-outlet",
40
+ children
41
+ })
42
+ ]
43
+ })
44
+ ]
45
+ });
46
+
47
+ // src/AppShell/AppSidebar.tsx
48
+ import { Button, Icon as Icon2 } from "@equinor/eds-core-react";
49
+ import { first_page, last_page } from "@equinor/eds-icons";
50
+ import { tokens } from "@equinor/eds-tokens";
51
+ import { useState } from "react";
52
+ import styled2, { css } from "styled-components";
53
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
54
+ var Wrapper2 = styled2.div`
55
+ display: flex;
56
+ flex-direction: column;
57
+ justify-content: space-between;
58
+ width: ${(props) => props.collapsed ? "64px" : "192px"};
59
+ height: 100%;
60
+ background-color: ${tokens.colors.ui.background__default.hex};
61
+ border-right: 2px solid ${tokens.colors.ui.background__medium.hex};
62
+
63
+ .collapse-button-wrapper {
64
+ display: flex;
65
+ align-items: center;
66
+ height: 64px;
67
+ border-bottom: 1px solid ${tokens.colors.ui.background__medium.hex};
68
+ ${(props) => props.collapsed && "justify-content: center;"}
69
+ }
70
+ .collapse-button {
71
+ ${(props) => !props.collapsed && css`
72
+ display: flex;
73
+ justify-content: space-between;
74
+ width: 100%;
75
+ margin: 0 12px;
76
+ border-radius: 50px;
77
+ `}
78
+ }
79
+ `;
80
+ function AppSidebar() {
81
+ const [collapsed, setCollapsed] = useState(false);
82
+ return /* @__PURE__ */ jsx2(Wrapper2, {
83
+ collapsed,
84
+ children: /* @__PURE__ */ jsx2("div", {
85
+ className: "collapse-button-wrapper",
86
+ children: /* @__PURE__ */ jsxs2(Button, {
87
+ className: "collapse-button",
88
+ variant: collapsed ? "ghost_icon" : "ghost",
89
+ onClick: () => setCollapsed(!collapsed),
90
+ children: [
91
+ /* @__PURE__ */ jsx2(Icon2, {
92
+ data: collapsed ? last_page : first_page
93
+ }),
94
+ !collapsed && /* @__PURE__ */ jsx2("div", {
95
+ children: "Collapse"
96
+ })
97
+ ]
98
+ })
99
+ })
100
+ });
101
+ }
102
+
103
+ // src/cells/ChipsCell.tsx
104
+ import { tokens as tokens2 } from "@equinor/eds-tokens";
105
+ import styled3 from "styled-components";
106
+
107
+ // src/cells/utils.ts
108
+ function stringToHslColor(str, s = 80, l = 85) {
109
+ let hash = 0;
110
+ for (let i = 0; i < str.length; i++) {
111
+ hash = str.charCodeAt(i) + ((hash << 5) - hash);
112
+ }
113
+ const h = hash % 360;
114
+ return "hsl(" + h + ", " + s + "%, " + l + "%)";
115
+ }
116
+
117
+ // src/cells/ChipsCell.tsx
118
+ import { jsx as jsx3 } from "react/jsx-runtime";
119
+ var ChipsWrapper = styled3.div`
120
+ display: flex;
121
+ align-items: center;
122
+ gap: 0.25rem;
123
+ `;
124
+ var Chip = styled3.div`
125
+ border-radius: 25px;
126
+ line-height: 22px;
127
+ height: 22px;
128
+ padding: 0 6px;
129
+ background-color: ${(props) => props.backgroundColor ?? tokens2.colors.ui.background__medium.hex};
130
+ color: darkslategrey;
131
+ `;
132
+ var ChipsCell = (props) => {
133
+ var _a;
134
+ return /* @__PURE__ */ jsx3(ChipsWrapper, {
135
+ children: (_a = props.values) == null ? void 0 : _a.map((value) => /* @__PURE__ */ jsx3(Chip, {
136
+ backgroundColor: stringToHslColor(value),
137
+ children: value
138
+ }, value))
139
+ });
140
+ };
141
+
142
+ // src/DataTable/DataTable.tsx
143
+ import {
144
+ getCoreRowModel,
145
+ getFilteredRowModel,
146
+ getSortedRowModel,
147
+ useReactTable
148
+ } from "@tanstack/react-table";
149
+ import { useRef, useState as useState3 } from "react";
150
+ import styled7 from "styled-components";
151
+
152
+ // src/DataTable/components/BasicTable.tsx
153
+ import { Table as EdsTable } from "@equinor/eds-core-react";
154
+ import { flexRender as flexRender2 } from "@tanstack/react-table";
155
+
156
+ // src/DataTable/components/TableHeader.tsx
157
+ import { Table as Table2 } from "@equinor/eds-core-react";
158
+
159
+ // src/DataTable/components/HeaderCell.tsx
160
+ import { Icon as Icon3, Table } from "@equinor/eds-core-react";
161
+ import { arrow_down, arrow_up } from "@equinor/eds-icons";
162
+ import { flexRender } from "@tanstack/react-table";
163
+ import styled4 from "styled-components";
164
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
165
+ var HeaderDiv = styled4.div`
166
+ display: flex;
167
+ align-items: center;
168
+ gap: 0.25rem;
169
+ `;
170
+ var HeaderCell = ({ header }) => {
171
+ return /* @__PURE__ */ jsx4(Table.Cell, {
172
+ colSpan: header.colSpan,
173
+ children: header.isPlaceholder ? null : /* @__PURE__ */ jsxs3(HeaderDiv, {
174
+ onClick: header.column.getToggleSortingHandler(),
175
+ children: [
176
+ flexRender(header.column.columnDef.header, header.getContext()),
177
+ {
178
+ asc: /* @__PURE__ */ jsx4(Icon3, {
179
+ data: arrow_down
180
+ }),
181
+ desc: /* @__PURE__ */ jsx4(Icon3, {
182
+ data: arrow_up
183
+ })
184
+ }[header.column.getIsSorted()] ?? null
185
+ ]
186
+ })
187
+ }, header.id);
188
+ };
189
+
190
+ // src/DataTable/components/TableHeader.tsx
191
+ import { jsx as jsx5 } from "react/jsx-runtime";
192
+ var TableHeader = ({ table, sticky }) => /* @__PURE__ */ jsx5(Table2.Head, {
193
+ sticky,
194
+ children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx5(Table2.Row, {
195
+ children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx5(HeaderCell, {
196
+ header
197
+ }, header.id))
198
+ }, headerGroup.id))
199
+ });
200
+
201
+ // src/DataTable/components/BasicTable.tsx
202
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
203
+ function BasicTable({ table, stickyHeader }) {
204
+ return /* @__PURE__ */ jsxs4(EdsTable, {
205
+ children: [
206
+ /* @__PURE__ */ jsx6(TableHeader, {
207
+ sticky: stickyHeader,
208
+ table
209
+ }),
210
+ /* @__PURE__ */ jsx6(EdsTable.Body, {
211
+ children: table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx6(EdsTable.Row, {
212
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx6(EdsTable.Cell, {
213
+ children: flexRender2(cell.column.columnDef.cell, cell.getContext())
214
+ }, cell.id))
215
+ }, row.id))
216
+ })
217
+ ]
218
+ });
219
+ }
220
+
221
+ // src/DataTable/components/DataTableHeader.tsx
222
+ import { Typography } from "@equinor/eds-core-react";
223
+ import styled6 from "styled-components";
224
+
225
+ // src/DataTable/filters/DebouncedInput.tsx
226
+ import { Input } from "@equinor/eds-core-react";
227
+ import { useEffect, useState as useState2 } from "react";
228
+ import styled5 from "styled-components";
229
+ import { jsx as jsx7 } from "react/jsx-runtime";
230
+ var Wrapper3 = styled5.div`
231
+ width: 300px;
232
+ `;
233
+ function DebouncedInput({
234
+ value: initialValue,
235
+ onChange,
236
+ debounce = 500,
237
+ ...props
238
+ }) {
239
+ const [value, setValue] = useState2(initialValue);
240
+ useEffect(() => {
241
+ setValue(initialValue);
242
+ }, [initialValue]);
243
+ useEffect(() => {
244
+ const timeout = setTimeout(() => {
245
+ onChange(value);
246
+ }, debounce);
247
+ return () => clearTimeout(timeout);
248
+ }, [value]);
249
+ return /* @__PURE__ */ jsx7(Wrapper3, {
250
+ children: /* @__PURE__ */ jsx7(Input, {
251
+ ...props,
252
+ value,
253
+ onChange: (event) => setValue(event.target.value)
254
+ })
255
+ });
256
+ }
257
+
258
+ // src/DataTable/filters/functions.ts
259
+ import { rankItem } from "@tanstack/match-sorter-utils";
260
+ var fuzzyFilter = (row, columnId, value, addMeta) => {
261
+ const itemRank = rankItem(row.getValue(columnId), value);
262
+ addMeta({
263
+ itemRank
264
+ });
265
+ return itemRank.passed;
266
+ };
267
+
268
+ // src/DataTable/components/DataTableHeader.tsx
269
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
270
+ var DataTableHeaderWrapper = styled6.div`
271
+ & > * + * {
272
+ margin-top: 0.5rem;
273
+ }
274
+ gap: 0.5rem;
275
+ padding: ${(props) => props.captionPadding ?? "1rem"};
276
+ `;
277
+ var FilterContainer = styled6.div`
278
+ display: flex;
279
+ align-items: center;
280
+ gap: 0.5rem;
281
+ `;
282
+ var DataTableHeader = (props) => {
283
+ return /* @__PURE__ */ jsxs5(DataTableHeaderWrapper, {
284
+ className: "--table-caption",
285
+ captionPadding: props.captionPadding,
286
+ children: [
287
+ (props == null ? void 0 : props.tableCaption) && /* @__PURE__ */ jsx8(Typography, {
288
+ variant: "h2",
289
+ children: props == null ? void 0 : props.tableCaption
290
+ }),
291
+ (props == null ? void 0 : props.enableGlobalFilter) && /* @__PURE__ */ jsx8(FilterContainer, {
292
+ className: "--filter-container",
293
+ children: /* @__PURE__ */ jsx8(DebouncedInput, {
294
+ value: props.globalFilter ?? "",
295
+ placeholder: (props == null ? void 0 : props.globalFilterPlaceholder) ?? "Search all columns",
296
+ onChange: (value) => {
297
+ var _a;
298
+ return (_a = props.setGlobalFilter) == null ? void 0 : _a.call(props, String(value));
299
+ }
300
+ })
301
+ })
302
+ ]
303
+ });
304
+ };
305
+
306
+ // src/DataTable/components/VirtualTable.tsx
307
+ import { Table as Table5 } from "@equinor/eds-core-react";
308
+ import { flexRender as flexRender3 } from "@tanstack/react-table";
309
+ import { useVirtual } from "@tanstack/react-virtual";
310
+
311
+ // src/DataTable/components/PaddingRow.tsx
312
+ import { Table as Table4 } from "@equinor/eds-core-react";
313
+ import { jsx as jsx9 } from "react/jsx-runtime";
314
+ var PaddingRow = (props) => {
315
+ if (!props.height)
316
+ return null;
317
+ return /* @__PURE__ */ jsx9(Table4.Row, {
318
+ children: /* @__PURE__ */ jsx9(Table4.Cell, {
319
+ style: { height: `${props.height}px` }
320
+ })
321
+ });
322
+ };
323
+
324
+ // src/DataTable/components/VirtualTable.tsx
325
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
326
+ function VirtualTable({ table, containerRef, ...props }) {
327
+ var _a, _b;
328
+ const { rows } = table.getRowModel();
329
+ const rowVirtualizer = useVirtual({
330
+ overscan: 10,
331
+ size: rows.length,
332
+ parentRef: containerRef
333
+ });
334
+ const { virtualItems: virtualRows, totalSize } = rowVirtualizer;
335
+ const paddingTop = virtualRows.length > 0 ? ((_a = virtualRows == null ? void 0 : virtualRows[0]) == null ? void 0 : _a.start) || 0 : 0;
336
+ const paddingBottom = virtualRows.length > 0 ? totalSize - (((_b = virtualRows == null ? void 0 : virtualRows[virtualRows.length - 1]) == null ? void 0 : _b.end) || 0) : 0;
337
+ return /* @__PURE__ */ jsxs6(Table5, {
338
+ children: [
339
+ /* @__PURE__ */ jsx10(TableHeader, {
340
+ sticky: props.stickyHeader,
341
+ table
342
+ }),
343
+ /* @__PURE__ */ jsxs6(Table5.Body, {
344
+ children: [
345
+ /* @__PURE__ */ jsx10(PaddingRow, {
346
+ height: paddingTop
347
+ }),
348
+ virtualRows.map((virtualRow) => {
349
+ const row = rows[virtualRow.index];
350
+ return /* @__PURE__ */ jsx10(Table5.Row, {
351
+ children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx10(Table5.Cell, {
352
+ children: flexRender3(cell.column.columnDef.cell, cell.getContext())
353
+ }, cell.id))
354
+ }, row.id);
355
+ }),
356
+ /* @__PURE__ */ jsx10(PaddingRow, {
357
+ height: paddingBottom
358
+ })
359
+ ]
360
+ })
361
+ ]
362
+ });
363
+ }
364
+
365
+ // src/DataTable/utils.ts
366
+ function enableOrUndefined(enabled, value) {
367
+ return Boolean(enabled) ? value : void 0;
368
+ }
369
+
370
+ // src/DataTable/DataTable.tsx
371
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
372
+ var DataTableWrapper = styled7.div`
373
+ width: ${(props) => props.width ?? "100%"};
374
+
375
+ .--table-container {
376
+ height: ${(props) => props.height ?? "100%"};
377
+ width: ${(props) => props.width ?? "100%"};
378
+ overflow: auto;
379
+
380
+ table {
381
+ width: 100%;
382
+ }
383
+ }
384
+ `;
385
+ function DataTable({ columns, data, ...props }) {
386
+ const [globalFilter, setGlobalFilter] = useState3("");
387
+ function enableGlobalFilter(value) {
388
+ return enableOrUndefined(props.globalFilter, value);
389
+ }
390
+ const [sorting, setSorting] = useState3([]);
391
+ const table = useReactTable({
392
+ columns,
393
+ data,
394
+ getCoreRowModel: getCoreRowModel(),
395
+ getFilteredRowModel: enableGlobalFilter(getFilteredRowModel()),
396
+ globalFilterFn: enableGlobalFilter(fuzzyFilter),
397
+ state: {
398
+ globalFilter: enableGlobalFilter(globalFilter),
399
+ sorting
400
+ },
401
+ enableSorting: props.sortable,
402
+ onSortingChange: setSorting,
403
+ getSortedRowModel: getSortedRowModel(),
404
+ onGlobalFilterChange: enableGlobalFilter(setGlobalFilter)
405
+ });
406
+ const tableContainerRef = useRef(null);
407
+ return /* @__PURE__ */ jsxs7(DataTableWrapper, {
408
+ captionPadding: props.captionPadding,
409
+ height: props.height,
410
+ width: props.tableWidth,
411
+ children: [
412
+ /* @__PURE__ */ jsx11(DataTableHeader, {
413
+ tableCaption: props.tableCaption,
414
+ enableGlobalFilter: props.globalFilter,
415
+ globalFilter,
416
+ setGlobalFilter,
417
+ globalFilterPlaceholder: props.globalFilterPlaceholder,
418
+ captionPadding: props.captionPadding
419
+ }),
420
+ /* @__PURE__ */ jsx11("div", {
421
+ ref: tableContainerRef,
422
+ className: "--table-container",
423
+ children: props.virtual ? /* @__PURE__ */ jsx11(VirtualTable, {
424
+ containerRef: tableContainerRef,
425
+ table,
426
+ stickyHeader: props.stickyHeader
427
+ }) : /* @__PURE__ */ jsx11(BasicTable, {
428
+ table,
429
+ stickyHeader: props.stickyHeader
430
+ })
431
+ })
432
+ ]
433
+ });
434
+ }
435
+ export {
436
+ AppShell,
437
+ AppSidebar,
438
+ ChipsCell,
439
+ DataTable
440
+ };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@equinor/apollo-components",
3
+ "version": "1.0.0",
4
+ "license": "MIT",
5
+ "main": "./src/index.tsx",
6
+ "types": "./src/index.tsx",
7
+ "files": [
8
+ "dist/**"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsup src/index.tsx --format esm,cjs --dts --external react",
12
+ "build-storybook": "storybook build",
13
+ "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
14
+ "dev": "tsup src/index.tsx --format esm,cjs --watch --dts --external react",
15
+ "lint": "TIMING=1 eslint . --fix",
16
+ "storybook": "storybook dev"
17
+ },
18
+ "dependencies": {
19
+ "@equinor/eds-core-react": "^0.24.0",
20
+ "@equinor/eds-icons": "^0.15.0",
21
+ "@equinor/eds-tokens": "^0.9.0",
22
+ "@tanstack/match-sorter-utils": "^8.5.14",
23
+ "@tanstack/react-table": "^8.5.15",
24
+ "@tanstack/react-virtual": "^3.0.0-alpha.0",
25
+ "styled-components": "^5.3.6",
26
+ "tsup": "^6.3.0"
27
+ },
28
+ "devDependencies": {
29
+ "@storybook/addon-essentials": "^7.0.0-alpha.38",
30
+ "@storybook/addon-interactions": "^7.0.0-alpha.38",
31
+ "@storybook/addon-links": "^7.0.0-alpha.38",
32
+ "@storybook/react": "^7.0.0-alpha.38",
33
+ "@storybook/react-vite": "^7.0.0-alpha.38",
34
+ "@storybook/testing-library": "^0.0.13",
35
+ "@types/react": "^18.0.1",
36
+ "@types/react-dom": "^18.0.1",
37
+ "@types/styled-components": "^5.1.26",
38
+ "eslint": "^7.32.0",
39
+ "eslint-config-custom": "*",
40
+ "react": "^18.2.0",
41
+ "react-dom": "^18.2.0",
42
+ "storybook": "^7.0.0-alpha.38",
43
+ "tsconfig": "*",
44
+ "typescript": "^4.5.2"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ }
49
+ }