@ocelescope/core 0.10.0 → 0.10.2

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 (35) hide show
  1. package/dist/ActivityPicker-BfA34hBU.js +29 -0
  2. package/dist/{AreaChart-DoD3LM50.js → AreaChart-q6rVcUIp.js} +4 -3
  3. package/dist/AttributePicker-Dd8eKA_3.js +95 -0
  4. package/dist/{BarChart-Cixo5Okd.js → BarChart-BLZS87ex.js} +4 -3
  5. package/dist/E2ORelationPicker-CcDSJWc0.js +46 -0
  6. package/dist/EventAttributePicker-Ch0rYS1h.js +27 -0
  7. package/dist/EventPicker-DbqFMMr2.js +39 -0
  8. package/dist/HistogramChart-GgiQdlsk.js +87 -0
  9. package/dist/{LineChart-CVz-dkJI.js → LineChart-Cq935Tk2.js} +4 -3
  10. package/dist/O2ORelationPicker-_XU1FfIX.js +44 -0
  11. package/dist/ObjectAttributePicker-Dpt3IfC5.js +27 -0
  12. package/dist/ObjectPicker-Bd68wl9p.js +39 -0
  13. package/dist/ObjectTypePicker-CXCMky34.js +42 -0
  14. package/dist/{OcelChart-DvGTjJXo.js → OcelChart-BnXjHb_r.js} +1 -1
  15. package/dist/OptionPicker-D9rUIwbY.js +351 -0
  16. package/dist/{PieChart-DBiASngC.js → PieChart-DZFHaTXD.js} +4 -3
  17. package/dist/{ScatterChart-jIQOjQes.js → ScatterChart-DJfJmABJ.js} +4 -3
  18. package/dist/{SqlChart-bwDArK2l.js → SqlChart-Bf7D5o5P.js} +33 -33
  19. package/dist/{SunburstChart-D6FhYBHI.js → SunburstChart-CMNYlKon.js} +3 -2
  20. package/dist/attributeOptions-D4slIoZx.js +37 -0
  21. package/dist/{cartesian-5TPNWjl_.js → cartesian-Dt7weMqK.js} +1 -1
  22. package/dist/index.d.ts +240 -143
  23. package/dist/index.js +28 -100
  24. package/dist/relationOptions-DTtIOIr1.js +33 -0
  25. package/dist/{series-BBXVjHHY.js → series-W1jsVape.js} +1 -1
  26. package/dist/style.css +596 -731
  27. package/dist/{Plot-CxHHyXot.js → useChart-jzzXgs0j.js} +28 -1
  28. package/dist/{useOcelId-BSU0-Srk.js → useOcelId-DIu_aGLH.js} +5 -2
  29. package/dist/useSearch-Ad3AtTVj.js +19 -0
  30. package/package.json +17 -18
  31. package/dist/ActivityPicker-DbrGeiC_.js +0 -18
  32. package/dist/EventAttributePicker-Cf2vVKv5.js +0 -27
  33. package/dist/NamePicker-Be-qmr1x.js +0 -43
  34. package/dist/ObjectAttributePicker-CL43EsYt.js +0 -27
  35. package/dist/ObjectTypePicker-CKmszS0y.js +0 -18
@@ -0,0 +1,351 @@
1
+ import { ChevronsUpDownIcon, SearchIcon, XIcon } from "lucide-react";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { Badge, Button, Flex, Popover, Spinner, Text, TextField, Theme } from "@r4pm/components/ui";
5
+ import { EmptyState, ErrorState, FrequencyPicker, SkeletonList, softBadgeStyle } from "@r4pm/components";
6
+ //#region src/components/Pickers/internal/Field.tsx
7
+ /**
8
+ * A picker's label and help text above it.
9
+ *
10
+ * Its own Radix theme, since a Mantine modal is portalled outside the app's:
11
+ * there the Radix parts would lose their styles. Within the app's theme it
12
+ * only inherits it.
13
+ */
14
+ const Field = ({ label, description, children }) => /* @__PURE__ */ jsx(Theme, {
15
+ asChild: true,
16
+ hasBackground: false,
17
+ children: /* @__PURE__ */ jsxs(Flex, {
18
+ direction: "column",
19
+ gap: "1",
20
+ width: "100%",
21
+ children: [
22
+ label && /* @__PURE__ */ jsx(Text, {
23
+ as: "div",
24
+ size: "2",
25
+ weight: "medium",
26
+ children: label
27
+ }),
28
+ description && /* @__PURE__ */ jsx(Text, {
29
+ as: "div",
30
+ size: "1",
31
+ color: "gray",
32
+ children: description
33
+ }),
34
+ children
35
+ ]
36
+ })
37
+ });
38
+ /** A dot in a choice's colour. */
39
+ const Swatch = ({ color }) => color ? /* @__PURE__ */ jsx("span", {
40
+ "aria-hidden": true,
41
+ style: {
42
+ flex: "none",
43
+ width: 8,
44
+ height: 8,
45
+ borderRadius: "50%",
46
+ background: color
47
+ }
48
+ }) : null;
49
+ /** Picked values as badges, each with a button that takes it out. */
50
+ const PickedBadges = ({ picked, onRemove, disabled }) => picked.length === 0 ? null : /* @__PURE__ */ jsx(Flex, {
51
+ gap: "1",
52
+ wrap: "wrap",
53
+ children: picked.map(({ id, label, color }) => /* @__PURE__ */ jsxs(Badge, {
54
+ size: "1",
55
+ style: color ? softBadgeStyle(color) : void 0,
56
+ color: color ? void 0 : "gray",
57
+ children: [label, !disabled && /* @__PURE__ */ jsx(XIcon, {
58
+ size: 12,
59
+ role: "button",
60
+ tabIndex: 0,
61
+ "aria-label": `Remove ${label}`,
62
+ style: { cursor: "pointer" },
63
+ onClick: () => onRemove(id),
64
+ onKeyDown: (event) => {
65
+ if (event.key === "Enter" || event.key === " ") {
66
+ event.preventDefault();
67
+ onRemove(id);
68
+ }
69
+ }
70
+ })]
71
+ }, id))
72
+ });
73
+ //#endregion
74
+ //#region src/components/Pickers/internal/ListSelect.module.css
75
+ var ListSelect_module_default = {
76
+ "hideCount": "wENrqW_hideCount",
77
+ "single": "wENrqW_single"
78
+ };
79
+ //#endregion
80
+ //#region src/components/Pickers/internal/options.ts
81
+ const defaultIdOf = (value) => typeof value === "string" ? value : JSON.stringify(value);
82
+ /** The picked values, however the caller holds them. */
83
+ const pickedValues = (selection) => selection.multiple ? [...selection.value] : selection.value == null ? [] : [selection.value];
84
+ /** Report values back as the one value, or the list, the caller asked for. */
85
+ const report = (selection, values) => {
86
+ if (selection.multiple) selection.onChange(values);
87
+ else selection.onChange(values[0]);
88
+ };
89
+ /** Options in groups, in first-seen order. Ungrouped options form one group. */
90
+ const groupOptions = (options) => {
91
+ const groups = /* @__PURE__ */ new Map();
92
+ for (const option of options) {
93
+ const key = option.group?.label ?? "";
94
+ const entry = groups.get(key) ?? {
95
+ group: option.group,
96
+ options: []
97
+ };
98
+ entry.options.push(option);
99
+ groups.set(key, entry);
100
+ }
101
+ return [...groups.values()];
102
+ };
103
+ const sortOptions = (options, sort) => [...options].sort((a, b) => sort === "name" ? a.label.localeCompare(b.label) : (b.count ?? 0) - (a.count ?? 0) || a.label.localeCompare(b.label));
104
+ //#endregion
105
+ //#region src/components/Pickers/internal/ListSelect.tsx
106
+ /** Lists at most this long get no search box of their own. */
107
+ const SEARCH_FROM = 8;
108
+ /** One r4pm list scrolls after eight rows; several groups of them share
109
+ * this height, so a grouped picker stays as compact. */
110
+ const GROUPS_HEIGHT = 320;
111
+ /**
112
+ * Every choice at once, one r4pm `FrequencyPicker` per group, so choices
113
+ * keep the colour and frequency bars they have in the viewers.
114
+ */
115
+ const ListSelect = ({ model, counts = true, bars = true, cutoff = false, sort = "count", emptyText, disabled, autoFocus, loading, error, missing, search, onSearch, total }) => {
116
+ const groups = groupOptions(model.options);
117
+ const groupsRef = useRef(null);
118
+ const groupCount = groups.length;
119
+ useEffect(() => {
120
+ if (groupCount < 2) return;
121
+ const frame = requestAnimationFrame(() => groupsRef.current?.scrollTo({ top: 0 }));
122
+ return () => cancelAnimationFrame(frame);
123
+ }, [groupCount]);
124
+ const shownIds = new Set(model.options.map((o) => model.idOf(o.value)));
125
+ const offList = model.picked.filter(({ id }) => !shownIds.has(id));
126
+ const content = () => {
127
+ if (missing) return /* @__PURE__ */ jsx(EmptyState, { title: missing });
128
+ if (error) return /* @__PURE__ */ jsx(ErrorState, {
129
+ error,
130
+ title: "Couldn't load"
131
+ });
132
+ if (loading && model.options.length === 0) return /* @__PURE__ */ jsx(SkeletonList, { rows: 4 });
133
+ if (model.options.length === 0) return /* @__PURE__ */ jsx(EmptyState, { title: emptyText ?? "Nothing to choose from" });
134
+ const lists = groups.map(({ group, options }) => {
135
+ const byLabel = new Map(options.map((option) => [option.label, option]));
136
+ const groupIds = new Set(options.map((o) => model.idOf(o.value)));
137
+ const pickedLabels = options.filter((option) => model.pickedIds.has(model.idOf(option.value))).map((option) => option.label);
138
+ return /* @__PURE__ */ jsxs(Flex, {
139
+ direction: "column",
140
+ gap: "1",
141
+ children: [group && /* @__PURE__ */ jsxs(Flex, {
142
+ gap: "2",
143
+ align: "center",
144
+ children: [/* @__PURE__ */ jsx(Badge, {
145
+ size: "1",
146
+ style: group.color ? softBadgeStyle(group.color) : void 0,
147
+ children: group.label
148
+ }), group.caption && /* @__PURE__ */ jsx(Text, {
149
+ size: "1",
150
+ color: "gray",
151
+ children: group.caption
152
+ })]
153
+ }), /* @__PURE__ */ jsx(FrequencyPicker, {
154
+ items: options.map((option) => ({
155
+ key: option.label,
156
+ count: option.count ?? 0
157
+ })),
158
+ value: new Set(pickedLabels),
159
+ onChange: (next) => {
160
+ if (disabled) return;
161
+ const values = [...next].flatMap((label) => {
162
+ const option = byLabel.get(label);
163
+ return option ? [option.value] : [];
164
+ });
165
+ if (!model.multiple) {
166
+ const fresh = values.find((value) => !model.pickedIds.has(model.idOf(value)));
167
+ return model.set(fresh !== void 0 ? [fresh] : values);
168
+ }
169
+ model.set([...model.picked.filter(({ id }) => !groupIds.has(id)).map(({ value }) => value), ...values]);
170
+ },
171
+ mode: model.multiple ? "multi" : "single",
172
+ searchable: !onSearch && options.length > SEARCH_FROM,
173
+ showBars: bars,
174
+ showCounts: counts,
175
+ showCutoff: cutoff,
176
+ sort,
177
+ colorOf: (_, key) => byLabel.get(key)?.color,
178
+ autoFocus,
179
+ emptyText: "Nothing matches"
180
+ })]
181
+ }, group?.label ?? "");
182
+ });
183
+ return groups.length > 1 ? /* @__PURE__ */ jsx(Flex, {
184
+ direction: "column",
185
+ gap: "3",
186
+ ref: groupsRef,
187
+ style: {
188
+ maxHeight: GROUPS_HEIGHT,
189
+ overflowY: "auto",
190
+ overflowX: "hidden"
191
+ },
192
+ children: lists
193
+ }) : lists;
194
+ };
195
+ return /* @__PURE__ */ jsxs(Flex, {
196
+ direction: "column",
197
+ gap: "2",
198
+ className: [!model.multiple || total !== void 0 ? ListSelect_module_default.hideCount : "", model.multiple ? "" : ListSelect_module_default.single].join(" "),
199
+ children: [
200
+ onSearch && /* @__PURE__ */ jsxs(TextField.Root, {
201
+ size: "2",
202
+ value: search ?? "",
203
+ placeholder: "Search…",
204
+ autoFocus,
205
+ disabled: disabled || !!missing,
206
+ onChange: (event) => onSearch(event.currentTarget.value),
207
+ children: [/* @__PURE__ */ jsx(TextField.Slot, { children: /* @__PURE__ */ jsx(SearchIcon, {
208
+ size: 14,
209
+ "aria-hidden": true
210
+ }) }), loading && /* @__PURE__ */ jsx(TextField.Slot, {
211
+ side: "right",
212
+ children: /* @__PURE__ */ jsx(Spinner, { size: "1" })
213
+ })]
214
+ }),
215
+ model.multiple && total !== void 0 && /* @__PURE__ */ jsxs(Text, {
216
+ size: "1",
217
+ color: "gray",
218
+ children: [
219
+ model.picked.length,
220
+ " of ",
221
+ total.toLocaleString(),
222
+ " selected"
223
+ ]
224
+ }),
225
+ /* @__PURE__ */ jsx(PickedBadges, {
226
+ picked: offList,
227
+ onRemove: model.remove,
228
+ disabled
229
+ }),
230
+ content()
231
+ ]
232
+ });
233
+ };
234
+ //#endregion
235
+ //#region src/components/Pickers/internal/DropdownSelect.tsx
236
+ /**
237
+ * A field that names what is picked and opens the list in a popover, so both
238
+ * variants are the same list.
239
+ */
240
+ const DropdownSelect = (props) => {
241
+ const { model, label, placeholder, disabled, missing, loading } = props;
242
+ const [open, setOpen] = useState(props.autoFocus ?? false);
243
+ const [first, ...more] = model.picked;
244
+ const total = props.total ?? model.options.length;
245
+ const picked = more.length === 0 ? first?.label : `${model.picked.length} of ${total.toLocaleString()} selected`;
246
+ return /* @__PURE__ */ jsxs(Popover.Root, {
247
+ open,
248
+ onOpenChange: setOpen,
249
+ children: [/* @__PURE__ */ jsx(Popover.Trigger, {
250
+ disabled: disabled || !!missing,
251
+ children: /* @__PURE__ */ jsxs(Button, {
252
+ variant: "surface",
253
+ color: "gray",
254
+ "aria-label": label ?? placeholder,
255
+ style: {
256
+ width: "100%",
257
+ justifyContent: "space-between",
258
+ fontWeight: "normal"
259
+ },
260
+ children: [/* @__PURE__ */ jsxs(Flex, {
261
+ gap: "2",
262
+ align: "center",
263
+ minWidth: "0",
264
+ children: [more.length === 0 && /* @__PURE__ */ jsx(Swatch, { color: first?.color }), /* @__PURE__ */ jsx(Text, {
265
+ truncate: true,
266
+ highContrast: !!picked && !missing,
267
+ children: missing ?? (picked || placeholder || "Choose…")
268
+ })]
269
+ }), loading ? /* @__PURE__ */ jsx(Spinner, { size: "1" }) : /* @__PURE__ */ jsx(ChevronsUpDownIcon, {
270
+ size: 14,
271
+ "aria-hidden": true,
272
+ style: { flex: "none" }
273
+ })]
274
+ })
275
+ }), /* @__PURE__ */ jsx(Popover.Content, {
276
+ size: "1",
277
+ align: "start",
278
+ style: {
279
+ width: "var(--radix-popover-trigger-width)",
280
+ minWidth: 260,
281
+ maxHeight: "var(--radix-popover-content-available-height)",
282
+ zIndex: 400
283
+ },
284
+ children: /* @__PURE__ */ jsx(ListSelect, {
285
+ ...props,
286
+ autoFocus: true,
287
+ model: model.multiple ? model : {
288
+ ...model,
289
+ set: (values) => {
290
+ model.set(values);
291
+ setOpen(false);
292
+ }
293
+ }
294
+ })
295
+ })]
296
+ });
297
+ };
298
+ //#endregion
299
+ //#region src/components/Pickers/internal/usePickerModel.ts
300
+ const usePickerModel = (props) => {
301
+ const { options, sort = "count", idOf = defaultIdOf, labelOf } = props;
302
+ const sorted = useMemo(() => groupOptions(options).flatMap((group) => sortOptions(group.options, sort)), [options, sort]);
303
+ const byId = useMemo(() => new Map(sorted.map((option) => [idOf(option.value), option])), [sorted, idOf]);
304
+ const picked = pickedValues(props).map((value) => {
305
+ const id = idOf(value);
306
+ const option = byId.get(id);
307
+ const label = option?.label ?? labelOf?.(value) ?? id;
308
+ return {
309
+ id,
310
+ value,
311
+ label: option?.group ? `${label} (${option.group.label})` : label,
312
+ color: option?.color ?? option?.group?.color
313
+ };
314
+ });
315
+ const pickedIds = new Set(picked.map(({ id }) => id));
316
+ const set = (values) => report(props, values);
317
+ return {
318
+ options: sorted,
319
+ idOf,
320
+ multiple: props.multiple === true,
321
+ picked,
322
+ pickedIds,
323
+ set,
324
+ remove: (id) => set(picked.filter((entry) => entry.id !== id).map((p) => p.value))
325
+ };
326
+ };
327
+ //#endregion
328
+ //#region src/components/Pickers/OptionPicker.tsx
329
+ /**
330
+ * Picking values out of a list of options, as a dropdown or as a list.
331
+ *
332
+ * Presentational: handed the options, it reports what was picked. Every OCEL
333
+ * picker is this, wrapped around an endpoint; use it directly for choices
334
+ * that come from elsewhere.
335
+ */
336
+ const OptionPicker = (props) => {
337
+ const model = usePickerModel(props);
338
+ return /* @__PURE__ */ jsx(Field, {
339
+ label: props.label,
340
+ description: props.description,
341
+ children: props.variant === "list" ? /* @__PURE__ */ jsx(ListSelect, {
342
+ ...props,
343
+ model
344
+ }) : /* @__PURE__ */ jsx(DropdownSelect, {
345
+ ...props,
346
+ model
347
+ })
348
+ });
349
+ };
350
+ //#endregion
351
+ export { OptionPicker };
@@ -1,11 +1,12 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { t as Plot } from "./Plot-CxHHyXot.js";
3
- import { n as toSeries, t as paint } from "./series-BBXVjHHY.js";
2
+ import { n as Plot, t as useChart } from "./useChart-jzzXgs0j.js";
3
+ import { n as toSeries, t as paint } from "./series-W1jsVape.js";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  //#region src/components/charts/PieChart.tsx
6
6
  var PieChart_exports = /* @__PURE__ */ __exportAll({ PieChart: () => PieChart });
7
7
  /** Shares of a whole, one slice per category. */
8
- const PieChart = ({ hole = .5, ...props }) => {
8
+ const PieChart = ({ hole = .5, ...given }) => {
9
+ const props = useChart(given);
9
10
  const [slices] = toSeries(props);
10
11
  const colors = slices && paint(slices, props.colorOf, true);
11
12
  const total = slices?.values.reduce((sum, value) => sum + (typeof value === "number" ? value : 0), 0);
@@ -1,11 +1,12 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { i as measureOf, n as axis, t as Plot } from "./Plot-CxHHyXot.js";
3
- import { n as traceCount, t as cartesian } from "./cartesian-5TPNWjl_.js";
2
+ import { a as measureOf, n as Plot, r as axis, t as useChart } from "./useChart-jzzXgs0j.js";
3
+ import { n as traceCount, t as cartesian } from "./cartesian-Dt7weMqK.js";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  //#region src/components/charts/ScatterChart.tsx
6
6
  var ScatterChart_exports = /* @__PURE__ */ __exportAll({ ScatterChart: () => ScatterChart });
7
7
  /** A point per row, for values that have no order to follow. */
8
- const ScatterChart = ({ xRange, ...props }) => {
8
+ const ScatterChart = ({ xRange, ...given }) => {
9
+ const props = useChart(given);
9
10
  const measure = measureOf(props.y);
10
11
  return /* @__PURE__ */ jsx(Plot, {
11
12
  traces: cartesian(props, {
@@ -1,22 +1,22 @@
1
- import { t as AreaChart } from "./AreaChart-DoD3LM50.js";
2
- import { t as BarChart } from "./BarChart-Cixo5Okd.js";
3
- import { t as LineChart } from "./LineChart-CVz-dkJI.js";
4
- import { t as PieChart } from "./PieChart-DBiASngC.js";
5
- import { t as ScatterChart } from "./ScatterChart-jIQOjQes.js";
6
- import { t as SunburstChart } from "./SunburstChart-D6FhYBHI.js";
7
- import { Group, SegmentedControl, Text } from "@mantine/core";
1
+ import { t as AreaChart } from "./AreaChart-q6rVcUIp.js";
2
+ import { t as BarChart } from "./BarChart-BLZS87ex.js";
3
+ import { t as HistogramChart } from "./HistogramChart-GgiQdlsk.js";
4
+ import { t as LineChart } from "./LineChart-Cq935Tk2.js";
5
+ import { t as PieChart } from "./PieChart-DZFHaTXD.js";
6
+ import { t as ScatterChart } from "./ScatterChart-DJfJmABJ.js";
7
+ import { t as SunburstChart } from "./SunburstChart-CMNYlKon.js";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
- import { EmptyState, useViewSetting, useViewerConfig } from "@r4pm/components";
9
+ import { Flex, SegmentedControl, Text } from "@r4pm/components/ui";
10
+ import { EmptyState, useViewSetting } from "@r4pm/components";
10
11
  //#region src/components/charts/SqlChart.tsx
11
12
  /**
12
13
  * A query's result, drawn.
13
14
  *
14
- * This is the r4pm viewer: it reads the result's own column types to decide
15
- * what goes across and what goes up, takes colours and selection from the
16
- * ambient `ViewerConfig`, and hands the rows to one of the charts.
15
+ * It reads the result's own column types to decide what goes across and what
16
+ * goes up, and hands the rows to one of the charts; colours and selection
17
+ * reach them from the ambient `ViewerConfig`, or from the props given here.
17
18
  */
18
- const SqlChart = ({ data, type: initialType = "bar", types = [], x, y, series, path, stacked = false, horizontal = false, yAxes = "shared", colorScope, title, height = "100%", ...config }) => {
19
- const { colorOf, onSelect } = useViewerConfig(config);
19
+ const SqlChart = ({ data, type: initialType = "bar", types = [], x, xEnd, y, series, path, stacked = false, horizontal = false, yAxes = "shared", colorScope, title, height = "100%", colorOf, onSelect }) => {
20
20
  const [type, setType] = useViewSetting(`chartType:${title ?? ""}`, initialType);
21
21
  const { category, measures } = columns(data, {
22
22
  x,
@@ -28,12 +28,9 @@ const SqlChart = ({ data, type: initialType = "bar", types = [], x, y, series, p
28
28
  x: category,
29
29
  y: measures,
30
30
  series,
31
- ...colorScope && { colorOf: (name) => colorOf?.(colorScope, name) ?? "#888888" },
32
- onSelect: (name, point) => onSelect?.({
33
- scope: colorScope ?? category,
34
- key: name,
35
- data: point
36
- })
31
+ colorScope,
32
+ colorOf,
33
+ onSelect
37
34
  };
38
35
  return /* @__PURE__ */ jsxs("div", {
39
36
  style: {
@@ -42,27 +39,27 @@ const SqlChart = ({ data, type: initialType = "bar", types = [], x, y, series, p
42
39
  width: "100%",
43
40
  height
44
41
  },
45
- children: [(title || types.length > 1) && /* @__PURE__ */ jsxs(Group, {
46
- gap: "xs",
47
- mb: "xs",
48
- pr: 48,
49
- justify: "flex-start",
42
+ children: [(title || types.length > 1) && /* @__PURE__ */ jsxs(Flex, {
43
+ gap: "2",
44
+ mb: "2",
45
+ pr: "8",
46
+ align: "center",
50
47
  wrap: "wrap",
51
48
  children: [title && /* @__PURE__ */ jsx(Text, {
52
- size: "sm",
53
- fw: 600,
49
+ size: "2",
50
+ weight: "bold",
54
51
  truncate: true,
55
52
  children: title
56
- }), types.length > 1 && /* @__PURE__ */ jsx(SegmentedControl, {
53
+ }), types.length > 1 && /* @__PURE__ */ jsx(SegmentedControl.Root, {
57
54
  "data-export-ignore": true,
58
- size: "xs",
59
- radius: "xl",
55
+ size: "1",
56
+ radius: "full",
60
57
  value: type,
61
- onChange: (value) => setType(value),
62
- data: types.map((option) => ({
58
+ onValueChange: (value) => setType(value),
59
+ children: types.map((option) => /* @__PURE__ */ jsx(SegmentedControl.Item, {
63
60
  value: option,
64
- label: option[0]?.toUpperCase() + option.slice(1)
65
- }))
61
+ children: option[0]?.toUpperCase() + option.slice(1)
62
+ }, option))
66
63
  })]
67
64
  }), /* @__PURE__ */ jsx("div", {
68
65
  style: {
@@ -76,6 +73,9 @@ const SqlChart = ({ data, type: initialType = "bar", types = [], x, y, series, p
76
73
  ...chart,
77
74
  stacked,
78
75
  horizontal
76
+ }) : type === "histogram" && xEnd ? /* @__PURE__ */ jsx(HistogramChart, {
77
+ ...chart,
78
+ xEnd
79
79
  }) : type === "line" ? /* @__PURE__ */ jsx(LineChart, {
80
80
  ...chart,
81
81
  yAxes
@@ -1,10 +1,11 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { i as measureOf, r as label, t as Plot } from "./Plot-CxHHyXot.js";
2
+ import { a as measureOf, i as label, n as Plot, t as useChart } from "./useChart-jzzXgs0j.js";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  //#region src/components/charts/SunburstChart.tsx
5
5
  var SunburstChart_exports = /* @__PURE__ */ __exportAll({ SunburstChart: () => SunburstChart });
6
6
  /** A hierarchy as rings, each one a column of the path. */
7
- const SunburstChart = ({ path, ...props }) => {
7
+ const SunburstChart = ({ path, ...given }) => {
8
+ const props = useChart(given);
8
9
  const rings = path ?? [props.x, props.series].filter(named);
9
10
  return /* @__PURE__ */ jsx(Plot, {
10
11
  traces: [nest(props.rows, rings, measureOf(props.y), props.colorOf)],
@@ -0,0 +1,37 @@
1
+ //#region src/components/Pickers/internal/attributeOptions.ts
2
+ /**
3
+ * Attributes as options: one per name, with its value types as description
4
+ * and its distinct values as count.
5
+ *
6
+ * Without a type filter the endpoints return an attribute once per event or
7
+ * object type that carries it, so "status" on two object types is merged.
8
+ */
9
+ const attributeOptions = (attributes, valueTypes, toValue, group) => {
10
+ const merged = /* @__PURE__ */ new Map();
11
+ for (const attribute of attributes ?? []) {
12
+ if (valueTypes && !valueTypes.includes(attribute.type)) continue;
13
+ const entry = merged.get(attribute.name) ?? {
14
+ types: /* @__PURE__ */ new Set(),
15
+ count: 0
16
+ };
17
+ entry.types.add(attribute.type);
18
+ entry.count = Math.max(entry.count, attribute.distinct_values);
19
+ merged.set(attribute.name, entry);
20
+ }
21
+ return [...merged].map(([name, { types, count }]) => ({
22
+ value: toValue(name),
23
+ label: name,
24
+ description: [...types].join(", "),
25
+ count,
26
+ group
27
+ }));
28
+ };
29
+ /** Distinct values say how varied an attribute is, not how often it occurs,
30
+ * so by default they neither sort the choices nor draw bars. */
31
+ const attributeDefaults = {
32
+ sort: "name",
33
+ bars: false,
34
+ counts: false
35
+ };
36
+ //#endregion
37
+ export { attributeOptions as n, attributeDefaults as t };
@@ -1,4 +1,4 @@
1
- import { n as toSeries, t as paint } from "./series-BBXVjHHY.js";
1
+ import { n as toSeries, t as paint } from "./series-W1jsVape.js";
2
2
  //#region src/components/charts/internal/cartesian.ts
3
3
  /**
4
4
  * Traces for the charts drawn against two axes.