@ocelescope/core 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,21 +1,24 @@
1
- import { ActionIcon, Anchor, AppShell, Box, Burger, Button, ColorSchemeScript, Combobox, CopyButton, Divider, Group, Input, InputBase, LoadingOverlay, MantineProvider, Modal, MultiSelect, NavLink, Stack, Table, Text, ThemeIcon, Tooltip, UnstyledButton, createTheme, mantineHtmlProps, useCombobox, useMantineTheme } from "@mantine/core";
2
- import { getDownloadFlatLogQueryKey, getDownloadOCELQueryKey, getDownloadResourceAsPnmlQueryKey, getDownloadResourceQueryKey, getDownloadVariantFlatLogQueryKey, useActivities, useAggregatedAttributes, useAttributeNames, useE2o, useE2oCombinations, useEventAttributes, useGetDefaultOcel, useGetOcels, useImportDefaultOcel, useLogout, useO2o, useO2oCombinations, useObjectAttributes, useObjectTypes, useUpload } from "@ocelescope/api-base";
1
+ import { t as useCurrentOcel } from "./useCurrentOCEL-BeBa7K0g.js";
2
+ import { t as useOcelId } from "./useOcelId-BSU0-Srk.js";
3
+ import { t as useOcelQuery } from "./useOcelQuery-D1QM-Zgv.js";
4
+ import { ActionIcon, Anchor, AppShell, Box, Burger, Button, Center, ColorSchemeScript, CopyButton, Divider, Group, LoadingOverlay, MantineProvider, Modal, MultiSelect, NavLink, Select, Stack, Table, Text, ThemeIcon, Tooltip, UnstyledButton, createTheme, mantineHtmlProps, useMantineTheme } from "@mantine/core";
5
+ import { getDownloadFlatLogQueryKey, getDownloadOCELQueryKey, getDownloadResourceAsPnmlQueryKey, getDownloadResourceQueryKey, getDownloadVariantFlatLogQueryKey, useActivities, useAggregatedAttributes, useAttributeNames, useE2o, useE2oCombinations, useEventAttributes, useEventIds, useGetDefaultOcel, useGetOcels, useImportDefaultOcel, useLogout, useO2o, useO2oCombinations, useObjectAttributes, useObjectIds, useObjectTypes, useUpload } from "@ocelescope/api-base";
3
6
  import { HydrationBoundary, QueryClient, QueryClientProvider, keepPreviousData, useQueryClient } from "@tanstack/react-query";
4
- import { BookOpenIcon, BugIcon, ChevronDownIcon, ChevronRightIcon, ContainerIcon, DownloadIcon, FilterIcon, GlobeIcon, HelpCircleIcon, LightbulbIcon, LogOutIcon, MailIcon, PackageIcon, PackagePlusIcon, PuzzleIcon, TriangleAlertIcon, UploadIcon, XIcon } from "lucide-react";
7
+ import { BookOpenIcon, BugIcon, CheckIcon, ChevronDownIcon, ChevronRightIcon, ContainerIcon, DownloadIcon, FilterIcon, GlobeIcon, HelpCircleIcon, LightbulbIcon, LogOutIcon, MailIcon, PackageIcon, PackagePlusIcon, PuzzleIcon, TriangleAlertIcon, UploadIcon, XIcon } from "lucide-react";
5
8
  import { DataTable } from "mantine-datatable";
6
9
  import { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
7
10
  import dayjs from "dayjs";
8
11
  import isBetween from "dayjs/plugin/isBetween.js";
9
12
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
13
+ import dynamic from "next/dynamic.js";
10
14
  import { Dropzone } from "@mantine/dropzone";
11
15
  import { Readable } from "node:stream";
12
16
  import z from "zod";
13
17
  import { Notifications, showNotification } from "@mantine/notifications";
18
+ import { Theme } from "@r4pm/components/ui";
14
19
  import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
15
- import { useDisclosure } from "@mantine/hooks";
20
+ import { useDebouncedValue, useDisclosure } from "@mantine/hooks";
16
21
  import { env as env$1, useSessionStore } from "@ocelescope/api-client";
17
- import { create } from "zustand";
18
- import { persist } from "zustand/middleware";
19
22
  import Link from "next/link.js";
20
23
  import { useRouter } from "next/router.js";
21
24
  import { Head, Html, Main, NextScript } from "next/document.js";
@@ -106,7 +109,7 @@ const SubAttributeTable = ({ ocelId, entityType = "objects", attributeName, enti
106
109
  }
107
110
  });
108
111
  };
109
- const AttributesTable = ({ ocelId, entityType = "objects", extraColumns = [], hideRange = false, hideValues = false, subTableExtraColumns, ocelVersion, alwaysExpandable = false, visibleAttributes }) => {
112
+ const AttributesTable = ({ ocelId, entityType = "objects", extraColumns = [], hideRange = false, hideValues = false, subTableExtraColumns, ocelVersion, alwaysExpandable = false, visibleAttributes, height, className, style }) => {
110
113
  const isEvent = entityType === "events";
111
114
  const [currentPage, setCurrentPage] = useState(1);
112
115
  const { data: attributeNames } = useAttributeNames(ocelId, {
@@ -233,7 +236,13 @@ const AttributesTable = ({ ocelId, entityType = "objects", extraColumns = [], hi
233
236
  recordsPerPage: PAGE_SIZE$1,
234
237
  onPageChange: setCurrentPage,
235
238
  noRecordsText: "No attributes found",
236
- height: 500,
239
+ height,
240
+ className,
241
+ style: {
242
+ flex: 1,
243
+ minHeight: 0,
244
+ ...style
245
+ },
237
246
  rowExpansion: {
238
247
  allowMultiple: false,
239
248
  expandable: ({ record: { entity_type_names } }) => alwaysExpandable || entity_type_names.length > 1,
@@ -354,6 +363,17 @@ const BarList = ({ data, labelHeader, valueHeader = "Frequency", maxVisibleItems
354
363
  });
355
364
  };
356
365
  //#endregion
366
+ //#region src/components/charts/index.tsx
367
+ const browserOnly = (load) => dynamic(load, { ssr: false });
368
+ const BarChart = browserOnly(() => import("./BarChart-Cixo5Okd.js").then((n) => n.n).then((module) => module.BarChart));
369
+ const LineChart = browserOnly(() => import("./LineChart-CVz-dkJI.js").then((n) => n.n).then((module) => module.LineChart));
370
+ const AreaChart = browserOnly(() => import("./AreaChart-DoD3LM50.js").then((n) => n.n).then((module) => module.AreaChart));
371
+ const ScatterChart = browserOnly(() => import("./ScatterChart-jIQOjQes.js").then((n) => n.n).then((module) => module.ScatterChart));
372
+ const PieChart = browserOnly(() => import("./PieChart-DBiASngC.js").then((n) => n.n).then((module) => module.PieChart));
373
+ const SunburstChart = browserOnly(() => import("./SunburstChart-D6FhYBHI.js").then((n) => n.n).then((module) => module.SunburstChart));
374
+ const SqlChart = browserOnly(() => import("./SqlChart-bwDArK2l.js").then((module) => module.SqlChart));
375
+ const OcelChart = browserOnly(() => import("./OcelChart-DvGTjJXo.js").then((module) => module.OcelChart));
376
+ //#endregion
357
377
  //#region src/components/Dropzone/Dropzone.module.css
358
378
  var Dropzone_module_default = {
359
379
  "control": "IgW5Wa_control",
@@ -686,78 +706,61 @@ const createModulesPage = (config) => {
686
706
  };
687
707
  };
688
708
  //#endregion
689
- //#region src/store/currentOcelStore.ts
690
- const useCurrentOcelStore = create()(persist((set) => ({
691
- ocelId: null,
692
- setOcel: (id) => set({ ocelId: id }),
693
- clearOcel: () => set({ ocelId: null })
694
- }), { name: env$1.current_ocel_id }));
695
- //#endregion
696
- //#region src/hooks/useCurrentOCEL.ts
697
- const useCurrentOcel = () => {
698
- const { data: ocels = [] } = useGetOcels();
699
- const { ocelId, setOcel, clearOcel } = useCurrentOcelStore();
700
- useEffect(() => {
701
- if (ocelId && !ocels?.some(({ id }) => id === ocelId)) clearOcel();
702
- if (!ocelId && ocels[0]) setOcel(ocels[0].id);
703
- }, [
704
- clearOcel,
705
- setOcel,
706
- ocels,
707
- ocelId
708
- ]);
709
- return {
710
- id: ocelId,
711
- setCurrentOcel: setOcel
712
- };
713
- };
714
- //#endregion
715
709
  //#region src/components/OcelSelect/OcelSelect.tsx
716
- const FilteredIndicator = () => /* @__PURE__ */ jsx(Tooltip, {
717
- label: "This log has been filtered",
718
- children: /* @__PURE__ */ jsx(FilterIcon, {
719
- size: 14,
720
- color: "var(--mantine-color-blue-6)"
721
- })
722
- });
723
- const OcelSelect = ({ extension, value, onChange, placeholder = "Select an OCEL", ...inputProps }) => {
724
- const { data } = useGetOcels(extension ? { extension_name: extension } : {});
725
- const ocels = useMemo(() => data ?? [], [data]);
726
- const combobox = useCombobox({ onDropdownClose: () => combobox.resetSelectedOption() });
727
- const selected = useMemo(() => ocels.find((ocel) => ocel.id === value), [ocels, value]);
728
- return /* @__PURE__ */ jsxs(Combobox, {
729
- store: combobox,
730
- onOptionSubmit: (val) => {
731
- onChange?.(val);
732
- combobox.closeDropdown();
733
- },
734
- children: [/* @__PURE__ */ jsx(Combobox.Target, { children: /* @__PURE__ */ jsx(InputBase, {
735
- ...inputProps,
736
- component: "button",
737
- type: "button",
738
- pointer: true,
739
- rightSection: /* @__PURE__ */ jsx(Combobox.Chevron, {}),
740
- rightSectionPointerEvents: "none",
741
- onClick: () => combobox.toggleDropdown(),
742
- children: selected ? /* @__PURE__ */ jsxs(Group, {
743
- gap: 6,
744
- wrap: "nowrap",
745
- style: { overflow: "hidden" },
746
- children: [/* @__PURE__ */ jsx(Text, {
747
- span: true,
748
- size: "sm",
749
- truncate: true,
750
- children: selected.name
751
- }), selected.filter_applied && /* @__PURE__ */ jsx(FilteredIndicator, {})]
752
- }) : /* @__PURE__ */ jsx(Input.Placeholder, { children: placeholder })
753
- }) }), /* @__PURE__ */ jsx(Combobox.Dropdown, { children: /* @__PURE__ */ jsx(Combobox.Options, { children: ocels.map((ocel) => /* @__PURE__ */ jsx(Combobox.Option, {
754
- value: ocel.id,
755
- children: /* @__PURE__ */ jsxs(Group, {
756
- gap: 6,
757
- wrap: "nowrap",
758
- children: [ocel.name, ocel.filter_applied && /* @__PURE__ */ jsx(FilteredIndicator, {})]
710
+ const iconProps = {
711
+ color: "currentColor",
712
+ opacity: .6,
713
+ size: 18
714
+ };
715
+ const OCELFilterIcon = ({ size }) => {
716
+ const theme = useMantineTheme();
717
+ return /* @__PURE__ */ jsx(Tooltip, {
718
+ label: "A filter is applied to this log",
719
+ children: /* @__PURE__ */ jsx(FilterIcon, {
720
+ size,
721
+ color: theme.colors.blue[8]
722
+ })
723
+ });
724
+ };
725
+ const OcelSelect = ({ value, ...props }) => {
726
+ const { data: ocels } = useGetOcels();
727
+ const ocelIds = useMemo(() => (ocels ?? []).map(({ id, name }) => ({
728
+ value: id,
729
+ label: name
730
+ })), [ocels]);
731
+ const filteredOcelIds = useMemo(() => (ocels ?? []).filter(({ filter_applied }) => filter_applied).map(({ id }) => id), [ocels]);
732
+ const renderSelectOption = useCallback(({ option, checked }) => /* @__PURE__ */ jsxs(Group, {
733
+ flex: "1",
734
+ gap: "xs",
735
+ wrap: "nowrap",
736
+ style: { overflow: "hidden" },
737
+ children: [
738
+ filteredOcelIds.includes(option.value) && /* @__PURE__ */ jsx(Center, {
739
+ style: { flexShrink: 0 },
740
+ children: /* @__PURE__ */ jsx(OCELFilterIcon, { size: 14 })
741
+ }),
742
+ /* @__PURE__ */ jsx(Box, {
743
+ flex: "1",
744
+ style: {
745
+ overflow: "hidden",
746
+ textOverflow: "ellipsis",
747
+ whiteSpace: "nowrap"
748
+ },
749
+ children: option.label
750
+ }),
751
+ checked && /* @__PURE__ */ jsx(Center, {
752
+ style: { flexShrink: 0 },
753
+ children: /* @__PURE__ */ jsx(CheckIcon, { ...iconProps })
759
754
  })
760
- }, ocel.id)) }) })]
755
+ ]
756
+ }), [filteredOcelIds]);
757
+ return /* @__PURE__ */ jsx(Select, {
758
+ leftSection: value && filteredOcelIds.includes(value) ? /* @__PURE__ */ jsx(OCELFilterIcon, { size: 14 }) : void 0,
759
+ data: ocelIds,
760
+ value,
761
+ scrollAreaProps: { styles: { content: { minWidth: 0 } } },
762
+ ...props,
763
+ renderOption: renderSelectOption
761
764
  });
762
765
  };
763
766
  const CurrentOcelSelect = () => {
@@ -1095,7 +1098,6 @@ const AppShell$1 = ({ config, children }) => {
1095
1098
  desktop: !desktopOpened
1096
1099
  }
1097
1100
  },
1098
- padding: "md",
1099
1101
  children: [
1100
1102
  /* @__PURE__ */ jsx(AppShell.Header, { children: /* @__PURE__ */ jsxs(Group, {
1101
1103
  h: "100%",
@@ -1294,16 +1296,16 @@ const OcelescopeApp = (config) => ({ Component, pageProps }) => {
1294
1296
  client,
1295
1297
  children: [/* @__PURE__ */ jsx(HydrationBoundary, {
1296
1298
  state: pageProps.dehydratedState,
1297
- children: /* @__PURE__ */ jsxs(MantineProvider, {
1299
+ children: /* @__PURE__ */ jsx(MantineProvider, {
1298
1300
  theme,
1299
- children: [
1301
+ children: /* @__PURE__ */ jsxs(Theme, { children: [
1300
1302
  /* @__PURE__ */ jsx(SSEWrapper, {}),
1301
1303
  /* @__PURE__ */ jsx(Notifications, {}),
1302
1304
  /* @__PURE__ */ jsx(AppShell$1, {
1303
1305
  config,
1304
1306
  children: /* @__PURE__ */ jsx(Component, { ...pageProps })
1305
1307
  })
1306
- ]
1308
+ ] })
1307
1309
  })
1308
1310
  }), /* @__PURE__ */ jsx(ReactQueryDevtools, {})]
1309
1311
  });
@@ -1322,6 +1324,95 @@ const OcelescopeDocument = () => {
1322
1324
  });
1323
1325
  };
1324
1326
  //#endregion
1327
+ //#region src/components/pickers/IdPicker.tsx
1328
+ /**
1329
+ * Picking ids by typing.
1330
+ *
1331
+ * Presentational: a log holds far more events and objects than a list can
1332
+ * show, so the caller decides which ids a search turns up.
1333
+ */
1334
+ const IdPicker = ({ ids, label, placeholder = "Search…", search, onSearch, loading = false, emptyText, disabled, ...selection }) => {
1335
+ const picked = selection.multiple ? [...selection.value] : selection.value ? [selection.value] : [];
1336
+ const shared = {
1337
+ size: "xs",
1338
+ label,
1339
+ placeholder,
1340
+ searchable: true,
1341
+ disabled,
1342
+ data: [.../* @__PURE__ */ new Set([...ids, ...picked])],
1343
+ searchValue: search,
1344
+ onSearchChange: onSearch,
1345
+ nothingFoundMessage: emptyText ?? (loading ? "Searching…" : "Nothing found")
1346
+ };
1347
+ return selection.multiple ? /* @__PURE__ */ jsx(MultiSelect, {
1348
+ ...shared,
1349
+ value: picked,
1350
+ onChange: selection.onChange,
1351
+ clearable: true
1352
+ }) : /* @__PURE__ */ jsx(Select, {
1353
+ ...shared,
1354
+ value: picked[0] ?? null,
1355
+ onChange: (next) => selection.onChange(next ?? void 0)
1356
+ });
1357
+ };
1358
+ //#endregion
1359
+ //#region src/components/pickers/internal/useSearch.ts
1360
+ /** What the reader has typed, slowed to one request per pause in typing. */
1361
+ const useSearch = () => {
1362
+ const [search, setSearch] = useState("");
1363
+ const [debounced] = useDebouncedValue(search, 300);
1364
+ return {
1365
+ search,
1366
+ setSearch,
1367
+ debounced: debounced || void 0
1368
+ };
1369
+ };
1370
+ //#endregion
1371
+ //#region src/components/pickers/EventPicker.tsx
1372
+ /** Events of the log, found by typing part of an id. */
1373
+ const EventPicker = ({ ocelId, ocelVersion = "filtered", limit = 50, ...picker }) => {
1374
+ const id = useOcelId(ocelId);
1375
+ const { search, setSearch, debounced } = useSearch();
1376
+ const { data, isPending } = useEventIds(id, {
1377
+ search: debounced,
1378
+ size: limit,
1379
+ ocel_version: ocelVersion
1380
+ }, { query: { enabled: id != null } });
1381
+ return /* @__PURE__ */ jsx(IdPicker, {
1382
+ ids: data?.response ?? [],
1383
+ search,
1384
+ onSearch: setSearch,
1385
+ loading: isPending,
1386
+ ...picker
1387
+ });
1388
+ };
1389
+ //#endregion
1390
+ //#region src/components/pickers/ObjectPicker.tsx
1391
+ /** Objects of the log, found by typing part of an id. */
1392
+ const ObjectPicker = ({ ocelId, ocelVersion = "filtered", limit = 50, ...picker }) => {
1393
+ const id = useOcelId(ocelId);
1394
+ const { search, setSearch, debounced } = useSearch();
1395
+ const { data, isPending } = useObjectIds(id, {
1396
+ search: debounced,
1397
+ size: limit,
1398
+ ocel_version: ocelVersion
1399
+ }, { query: { enabled: id != null } });
1400
+ return /* @__PURE__ */ jsx(IdPicker, {
1401
+ ids: data?.response ?? [],
1402
+ search,
1403
+ onSearch: setSearch,
1404
+ loading: isPending,
1405
+ ...picker
1406
+ });
1407
+ };
1408
+ //#endregion
1409
+ //#region src/components/pickers/index.tsx
1410
+ const NamePicker = dynamic(() => import("./NamePicker-Be-qmr1x.js").then((module) => module.NamePicker), { ssr: false });
1411
+ const ActivityPicker = dynamic(() => import("./ActivityPicker-DbrGeiC_.js").then((module) => module.ActivityPicker), { ssr: false });
1412
+ const ObjectTypePicker = dynamic(() => import("./ObjectTypePicker-CKmszS0y.js").then((module) => module.ObjectTypePicker), { ssr: false });
1413
+ const EventAttributePicker = dynamic(() => import("./EventAttributePicker-Cf2vVKv5.js").then((module) => module.EventAttributePicker), { ssr: false });
1414
+ const ObjectAttributePicker = dynamic(() => import("./ObjectAttributePicker-CL43EsYt.js").then((module) => module.ObjectAttributePicker), { ssr: false });
1415
+ //#endregion
1325
1416
  //#region src/components/RelationTable.tsx
1326
1417
  const PAGE_SIZE = 10;
1327
1418
  const COLUMN_WIDTHS = {
@@ -1396,7 +1487,7 @@ const SubRelationTable = ({ ocelId, relationType, direction, source, target, hid
1396
1487
  }
1397
1488
  });
1398
1489
  };
1399
- const RelationTable = ({ ocelId, relationType = "o2o", direction = "source", extraColumns = [], subTableExtraColumns, hideRange = false, hideTotal = false, ocelVersion, visibleRelations }) => {
1490
+ const RelationTable = ({ ocelId, relationType = "o2o", direction = "source", extraColumns = [], subTableExtraColumns, hideRange = false, hideTotal = false, ocelVersion, visibleRelations, height, className, style }) => {
1400
1491
  const isE2O = relationType === "e2o";
1401
1492
  const isSource = direction === "source";
1402
1493
  const [currentPage, setCurrentPage] = useState(1);
@@ -1550,7 +1641,13 @@ const RelationTable = ({ ocelId, relationType = "o2o", direction = "source", ext
1550
1641
  recordsPerPage: PAGE_SIZE,
1551
1642
  onPageChange: setCurrentPage,
1552
1643
  noRecordsText: "No relations found",
1553
- height: 500,
1644
+ height,
1645
+ className,
1646
+ style: {
1647
+ flex: 1,
1648
+ minHeight: 0,
1649
+ ...style
1650
+ },
1554
1651
  rowExpansion: {
1555
1652
  allowMultiple: false,
1556
1653
  expandable: ({ record }) => (record.qualifiers?.length ?? 0) > 1,
@@ -1616,4 +1713,4 @@ const useDownloadResourceAsPnml = useDownloadFromServer(getDownloadResourceAsPnm
1616
1713
  const defineModule = (def) => def;
1617
1714
  const defineModuleRoute = (def) => def;
1618
1715
  //#endregion
1619
- export { AttributesTable, BarList, FileDropzone, FullScreenUpload, HelpModal, OcelSelect, OcelescopeApp, OcelescopeDocument, RelationTable, UploadModal, UploadSection, createModulesPage, defineModule, defineModuleRoute, env, formatAttributeValue, getModuleRoute, sseHandler, useCurrentOcel, useDownloadFile, useDownloadFlatOCEL, useDownloadOCEL, useDownloadResource, useDownloadResourceAsPnml, useDownloadVariantFlatLog, useInvalidate };
1716
+ export { ActivityPicker, AreaChart, AttributesTable, BarChart, BarList, EventAttributePicker, EventPicker, FileDropzone, FullScreenUpload, HelpModal, IdPicker, LineChart, NamePicker, ObjectAttributePicker, ObjectPicker, ObjectTypePicker, OcelChart, OcelSelect, OcelescopeApp, OcelescopeDocument, PieChart, RelationTable, ScatterChart, SqlChart, SunburstChart, UploadModal, UploadSection, createModulesPage, defineModule, defineModuleRoute, env, formatAttributeValue, getModuleRoute, sseHandler, useCurrentOcel, useDownloadFile, useDownloadFlatOCEL, useDownloadOCEL, useDownloadResource, useDownloadResourceAsPnml, useDownloadVariantFlatLog, useInvalidate, useOcelQuery };
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll as t };
@@ -0,0 +1,32 @@
1
+ import { a as plotted, i as measureOf, r as label } from "./Plot-CxHHyXot.js";
2
+ //#region src/components/charts/internal/series.ts
3
+ /**
4
+ * The rows as traces: one per value of the `series` column, or one per measure
5
+ * when there is no series column.
6
+ */
7
+ const toSeries = ({ rows, x, y, series }) => {
8
+ const measures = Array.isArray(y) ? y : [y];
9
+ const groups = /* @__PURE__ */ new Map();
10
+ if (series) for (const row of rows) {
11
+ const key = label(row[series]);
12
+ groups.set(key, [...groups.get(key) ?? [], row]);
13
+ }
14
+ else for (const measure of measures) groups.set(measure, rows);
15
+ return [...groups].map(([name, group]) => ({
16
+ name,
17
+ labels: group.map((row) => label(row[x])),
18
+ values: group.map((row) => plotted(row[series ? measureOf(y) : name]))
19
+ }));
20
+ };
21
+ /**
22
+ * What to paint a trace.
23
+ *
24
+ * One trace: the colours tell its categories apart, as in the r4pm activity
25
+ * chart. Several: they tell the traces apart.
26
+ */
27
+ const paint = (series, colorOf, alone) => {
28
+ if (!colorOf) return void 0;
29
+ return alone ? series.labels.map(colorOf) : colorOf(series.name);
30
+ };
31
+ //#endregion
32
+ export { toSeries as n, paint as t };