@ocelescope/core 0.10.1 → 0.11.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.
Files changed (40) hide show
  1. package/README.md +2 -2
  2. package/dist/ActivityPicker-CtFSu1YR.js +31 -0
  3. package/dist/{AreaChart-DoD3LM50.js → AreaChart-BSwN1fMp.js} +6 -6
  4. package/dist/AttributePicker-Cq7luTEi.js +94 -0
  5. package/dist/{BarChart-Cixo5Okd.js → BarChart-CyMePf1z.js} +6 -6
  6. package/dist/E2ORelationPicker-C8EmrbFx.js +45 -0
  7. package/dist/EventAttributePicker-BgEdydek.js +26 -0
  8. package/dist/EventPicker-D5uNOTw1.js +38 -0
  9. package/dist/HistogramChart-CJwvvDUu.js +86 -0
  10. package/dist/{LineChart-CVz-dkJI.js → LineChart-Cbxnm338.js} +6 -6
  11. package/dist/O2ORelationPicker-CryAxxUo.js +43 -0
  12. package/dist/ObjectAttributePicker-D_I3LQsY.js +26 -0
  13. package/dist/ObjectPicker-D-ksQveT.js +38 -0
  14. package/dist/ObjectTypePicker-Bw8Fsktx.js +45 -0
  15. package/dist/{OcelChart-DvGTjJXo.js → OcelChart-DJNM5peW.js} +3 -4
  16. package/dist/OptionPicker-DQ-WYFQZ.js +344 -0
  17. package/dist/{PieChart-DBiASngC.js → PieChart-BmMoI0TY.js} +6 -6
  18. package/dist/{ScatterChart-jIQOjQes.js → ScatterChart-CASPRlZU.js} +6 -6
  19. package/dist/{SqlChart-bwDArK2l.js → SqlChart-cxKpWkyh.js} +34 -35
  20. package/dist/{SunburstChart-D6FhYBHI.js → SunburstChart-Ddx9EaL-.js} +5 -5
  21. package/dist/attributeOptions-COiWnKUS.js +36 -0
  22. package/dist/{cartesian-5TPNWjl_.js → cartesian-CtdS2iZb.js} +2 -3
  23. package/dist/index.d.ts +228 -209
  24. package/dist/index.js +83 -172
  25. package/dist/relationOptions-hEEsEQrx.js +32 -0
  26. package/dist/{rolldown-runtime-D7D4PA-g.js → rolldown-runtime-D8jQpDG7.js} +1 -2
  27. package/dist/{series-BBXVjHHY.js → series-Bx0HVnSy.js} +2 -3
  28. package/dist/style.css +630 -745
  29. package/dist/{Plot-CxHHyXot.js → useChart-BK4pjGal.js} +29 -5
  30. package/dist/{useCurrentOCEL-BeBa7K0g.js → useCurrentOCEL-BUH5XGje.js} +2 -4
  31. package/dist/useOcelId-BEC6_yRa.js +8 -0
  32. package/dist/{useOcelQuery-D1QM-Zgv.js → useOcelQuery-6vtgZNzz.js} +2 -3
  33. package/dist/useSearch-CdXjjv-a.js +18 -0
  34. package/package.json +25 -26
  35. package/dist/ActivityPicker-DbrGeiC_.js +0 -18
  36. package/dist/EventAttributePicker-Cf2vVKv5.js +0 -27
  37. package/dist/NamePicker-Be-qmr1x.js +0 -43
  38. package/dist/ObjectAttributePicker-CL43EsYt.js +0 -27
  39. package/dist/ObjectTypePicker-CKmszS0y.js +0 -18
  40. package/dist/useOcelId-BSU0-Srk.js +0 -6
@@ -0,0 +1,344 @@
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
+ // 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
+ // src/components/Pickers/internal/ListSelect.module.css
74
+ var ListSelect_module_default = {
75
+ "hideCount": "wENrqW_hideCount",
76
+ "single": "wENrqW_single"
77
+ };
78
+ // src/components/Pickers/internal/options.ts
79
+ const defaultIdOf = (value) => typeof value === "string" ? value : JSON.stringify(value);
80
+ /** The picked values, however the caller holds them. */
81
+ const pickedValues = (selection) => selection.multiple ? [...selection.value] : selection.value == null ? [] : [selection.value];
82
+ /** Report values back as the one value, or the list, the caller asked for. */
83
+ const report = (selection, values) => {
84
+ if (selection.multiple) selection.onChange(values);
85
+ else selection.onChange(values[0]);
86
+ };
87
+ /** Options in groups, in first-seen order. Ungrouped options form one group. */
88
+ const groupOptions = (options) => {
89
+ const groups = /* @__PURE__ */ new Map();
90
+ for (const option of options) {
91
+ const key = option.group?.label ?? "";
92
+ const entry = groups.get(key) ?? {
93
+ group: option.group,
94
+ options: []
95
+ };
96
+ entry.options.push(option);
97
+ groups.set(key, entry);
98
+ }
99
+ return [...groups.values()];
100
+ };
101
+ 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));
102
+ // src/components/Pickers/internal/ListSelect.tsx
103
+ /** Lists at most this long get no search box of their own. */
104
+ const SEARCH_FROM = 8;
105
+ /** One r4pm list scrolls after eight rows; several groups of them share
106
+ * this height, so a grouped picker stays as compact. */
107
+ const GROUPS_HEIGHT = 320;
108
+ /**
109
+ * Every choice at once, one r4pm `FrequencyPicker` per group, so choices
110
+ * keep the colour and frequency bars they have in the viewers.
111
+ */
112
+ const ListSelect = ({ model, counts = true, bars = true, cutoff = false, sort = "count", emptyText, disabled, autoFocus, loading, error, missing, search, onSearch, total }) => {
113
+ const groups = groupOptions(model.options);
114
+ const groupsRef = useRef(null);
115
+ const groupCount = groups.length;
116
+ useEffect(() => {
117
+ if (groupCount < 2) return;
118
+ const frame = requestAnimationFrame(() => groupsRef.current?.scrollTo({ top: 0 }));
119
+ return () => cancelAnimationFrame(frame);
120
+ }, [groupCount]);
121
+ const shownIds = new Set(model.options.map((o) => model.idOf(o.value)));
122
+ const offList = model.picked.filter(({ id }) => !shownIds.has(id));
123
+ const content = () => {
124
+ if (missing) return /* @__PURE__ */ jsx(EmptyState, { title: missing });
125
+ if (error) return /* @__PURE__ */ jsx(ErrorState, {
126
+ error,
127
+ title: "Couldn't load"
128
+ });
129
+ if (loading && model.options.length === 0) return /* @__PURE__ */ jsx(SkeletonList, { rows: 4 });
130
+ if (model.options.length === 0) return /* @__PURE__ */ jsx(EmptyState, { title: emptyText ?? "Nothing to choose from" });
131
+ const lists = groups.map(({ group, options }) => {
132
+ const byLabel = new Map(options.map((option) => [option.label, option]));
133
+ const groupIds = new Set(options.map((o) => model.idOf(o.value)));
134
+ const pickedLabels = options.filter((option) => model.pickedIds.has(model.idOf(option.value))).map((option) => option.label);
135
+ return /* @__PURE__ */ jsxs(Flex, {
136
+ direction: "column",
137
+ gap: "1",
138
+ children: [group && /* @__PURE__ */ jsxs(Flex, {
139
+ gap: "2",
140
+ align: "center",
141
+ children: [/* @__PURE__ */ jsx(Badge, {
142
+ size: "1",
143
+ style: group.color ? softBadgeStyle(group.color) : void 0,
144
+ children: group.label
145
+ }), group.caption && /* @__PURE__ */ jsx(Text, {
146
+ size: "1",
147
+ color: "gray",
148
+ children: group.caption
149
+ })]
150
+ }), /* @__PURE__ */ jsx(FrequencyPicker, {
151
+ items: options.map((option) => ({
152
+ key: option.label,
153
+ count: option.count ?? 0
154
+ })),
155
+ value: new Set(pickedLabels),
156
+ onChange: (next) => {
157
+ if (disabled) return;
158
+ const values = [...next].flatMap((label) => {
159
+ const option = byLabel.get(label);
160
+ return option ? [option.value] : [];
161
+ });
162
+ if (!model.multiple) {
163
+ const fresh = values.find((value) => !model.pickedIds.has(model.idOf(value)));
164
+ return model.set(fresh !== void 0 ? [fresh] : values);
165
+ }
166
+ model.set([...model.picked.filter(({ id }) => !groupIds.has(id)).map(({ value }) => value), ...values]);
167
+ },
168
+ mode: model.multiple ? "multi" : "single",
169
+ searchable: !onSearch && options.length > SEARCH_FROM,
170
+ showBars: bars,
171
+ showCounts: counts,
172
+ showCutoff: cutoff,
173
+ sort,
174
+ colorOf: (_, key) => byLabel.get(key)?.color,
175
+ autoFocus,
176
+ emptyText: "Nothing matches"
177
+ })]
178
+ }, group?.label ?? "");
179
+ });
180
+ return groups.length > 1 ? /* @__PURE__ */ jsx(Flex, {
181
+ direction: "column",
182
+ gap: "3",
183
+ ref: groupsRef,
184
+ style: {
185
+ maxHeight: GROUPS_HEIGHT,
186
+ overflowY: "auto",
187
+ overflowX: "hidden"
188
+ },
189
+ children: lists
190
+ }) : lists;
191
+ };
192
+ return /* @__PURE__ */ jsxs(Flex, {
193
+ direction: "column",
194
+ gap: "2",
195
+ className: [!model.multiple || total !== void 0 ? ListSelect_module_default.hideCount : "", model.multiple ? "" : ListSelect_module_default.single].join(" "),
196
+ children: [
197
+ onSearch && /* @__PURE__ */ jsxs(TextField.Root, {
198
+ size: "2",
199
+ value: search ?? "",
200
+ placeholder: "Search…",
201
+ autoFocus,
202
+ disabled: disabled || !!missing,
203
+ onChange: (event) => onSearch(event.currentTarget.value),
204
+ children: [/* @__PURE__ */ jsx(TextField.Slot, { children: /* @__PURE__ */ jsx(SearchIcon, {
205
+ size: 14,
206
+ "aria-hidden": true
207
+ }) }), loading && /* @__PURE__ */ jsx(TextField.Slot, {
208
+ side: "right",
209
+ children: /* @__PURE__ */ jsx(Spinner, { size: "1" })
210
+ })]
211
+ }),
212
+ model.multiple && total !== void 0 && /* @__PURE__ */ jsxs(Text, {
213
+ size: "1",
214
+ color: "gray",
215
+ children: [
216
+ model.picked.length,
217
+ " of ",
218
+ total.toLocaleString(),
219
+ " selected"
220
+ ]
221
+ }),
222
+ /* @__PURE__ */ jsx(PickedBadges, {
223
+ picked: offList,
224
+ onRemove: model.remove,
225
+ disabled
226
+ }),
227
+ content()
228
+ ]
229
+ });
230
+ };
231
+ // src/components/Pickers/internal/DropdownSelect.tsx
232
+ /**
233
+ * A field that names what is picked and opens the list in a popover, so both
234
+ * variants are the same list.
235
+ */
236
+ const DropdownSelect = (props) => {
237
+ const { model, label, placeholder, disabled, missing, loading } = props;
238
+ const [open, setOpen] = useState(props.autoFocus ?? false);
239
+ const [first, ...more] = model.picked;
240
+ const total = props.total ?? model.options.length;
241
+ const picked = more.length === 0 ? first?.label : `${model.picked.length} of ${total.toLocaleString()} selected`;
242
+ return /* @__PURE__ */ jsxs(Popover.Root, {
243
+ open,
244
+ onOpenChange: setOpen,
245
+ children: [/* @__PURE__ */ jsx(Popover.Trigger, {
246
+ disabled: disabled || !!missing,
247
+ children: /* @__PURE__ */ jsxs(Button, {
248
+ variant: "surface",
249
+ color: "gray",
250
+ "aria-label": label ?? placeholder,
251
+ style: {
252
+ width: "100%",
253
+ justifyContent: "space-between",
254
+ fontWeight: "normal"
255
+ },
256
+ children: [/* @__PURE__ */ jsxs(Flex, {
257
+ gap: "2",
258
+ align: "center",
259
+ minWidth: "0",
260
+ children: [more.length === 0 && /* @__PURE__ */ jsx(Swatch, { color: first?.color }), /* @__PURE__ */ jsx(Text, {
261
+ truncate: true,
262
+ highContrast: !!picked && !missing,
263
+ children: missing ?? (picked || placeholder || "Choose…")
264
+ })]
265
+ }), loading ? /* @__PURE__ */ jsx(Spinner, { size: "1" }) : /* @__PURE__ */ jsx(ChevronsUpDownIcon, {
266
+ size: 14,
267
+ "aria-hidden": true,
268
+ style: { flex: "none" }
269
+ })]
270
+ })
271
+ }), /* @__PURE__ */ jsx(Popover.Content, {
272
+ size: "1",
273
+ align: "start",
274
+ style: {
275
+ width: "var(--radix-popover-trigger-width)",
276
+ minWidth: 260,
277
+ maxHeight: "var(--radix-popover-content-available-height)",
278
+ zIndex: 400
279
+ },
280
+ children: /* @__PURE__ */ jsx(ListSelect, {
281
+ ...props,
282
+ autoFocus: true,
283
+ model: model.multiple ? model : {
284
+ ...model,
285
+ set: (values) => {
286
+ model.set(values);
287
+ setOpen(false);
288
+ }
289
+ }
290
+ })
291
+ })]
292
+ });
293
+ };
294
+ // src/components/Pickers/internal/usePickerModel.ts
295
+ const usePickerModel = (props) => {
296
+ const { options, sort = "count", idOf = defaultIdOf, labelOf } = props;
297
+ const sorted = useMemo(() => groupOptions(options).flatMap((group) => sortOptions(group.options, sort)), [options, sort]);
298
+ const byId = useMemo(() => new Map(sorted.map((option) => [idOf(option.value), option])), [sorted, idOf]);
299
+ const picked = pickedValues(props).map((value) => {
300
+ const id = idOf(value);
301
+ const option = byId.get(id);
302
+ const label = option?.label ?? labelOf?.(value) ?? id;
303
+ return {
304
+ id,
305
+ value,
306
+ label: option?.group ? `${label} (${option.group.label})` : label,
307
+ color: option?.color ?? option?.group?.color
308
+ };
309
+ });
310
+ const pickedIds = new Set(picked.map(({ id }) => id));
311
+ const set = (values) => report(props, values);
312
+ return {
313
+ options: sorted,
314
+ idOf,
315
+ multiple: props.multiple === true,
316
+ picked,
317
+ pickedIds,
318
+ set,
319
+ remove: (id) => set(picked.filter((entry) => entry.id !== id).map((p) => p.value))
320
+ };
321
+ };
322
+ // src/components/Pickers/OptionPicker.tsx
323
+ /**
324
+ * Picking values out of a list of options, as a dropdown or as a list.
325
+ *
326
+ * Presentational: handed the options, it reports what was picked. Every OCEL
327
+ * picker is this, wrapped around an endpoint; use it directly for choices
328
+ * that come from elsewhere.
329
+ */
330
+ const OptionPicker = (props) => {
331
+ const model = usePickerModel(props);
332
+ return /* @__PURE__ */ jsx(Field, {
333
+ label: props.label,
334
+ description: props.description,
335
+ children: props.variant === "list" ? /* @__PURE__ */ jsx(ListSelect, {
336
+ ...props,
337
+ model
338
+ }) : /* @__PURE__ */ jsx(DropdownSelect, {
339
+ ...props,
340
+ model
341
+ })
342
+ });
343
+ };
344
+ export { OptionPicker };
@@ -1,11 +1,12 @@
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";
1
+ import { t as __exportAll } from "./rolldown-runtime-D8jQpDG7.js";
2
+ import { n as Plot, t as useChart } from "./useChart-BK4pjGal.js";
3
+ import { n as toSeries, t as paint } from "./series-Bx0HVnSy.js";
4
4
  import { jsx } from "react/jsx-runtime";
5
- //#region src/components/charts/PieChart.tsx
5
+ // 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);
@@ -58,5 +59,4 @@ const PieChart = ({ hole = .5, ...props }) => {
58
59
  }
59
60
  });
60
61
  };
61
- //#endregion
62
62
  export { PieChart_exports as n, PieChart as t };
@@ -1,11 +1,12 @@
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";
1
+ import { t as __exportAll } from "./rolldown-runtime-D8jQpDG7.js";
2
+ import { a as measureOf, n as Plot, r as axis, t as useChart } from "./useChart-BK4pjGal.js";
3
+ import { n as traceCount, t as cartesian } from "./cartesian-CtdS2iZb.js";
4
4
  import { jsx } from "react/jsx-runtime";
5
- //#region src/components/charts/ScatterChart.tsx
5
+ // 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, {
@@ -32,5 +33,4 @@ const ScatterChart = ({ xRange, ...props }) => {
32
33
  }
33
34
  });
34
35
  };
35
- //#endregion
36
36
  export { ScatterChart_exports as n, ScatterChart as t };
@@ -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-BSwN1fMp.js";
2
+ import { t as BarChart } from "./BarChart-CyMePf1z.js";
3
+ import { t as HistogramChart } from "./HistogramChart-CJwvvDUu.js";
4
+ import { t as LineChart } from "./LineChart-Cbxnm338.js";
5
+ import { t as PieChart } from "./PieChart-BmMoI0TY.js";
6
+ import { t as ScatterChart } from "./ScatterChart-CASPRlZU.js";
7
+ import { t as SunburstChart } from "./SunburstChart-Ddx9EaL-.js";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
- import { EmptyState, useViewSetting, useViewerConfig } from "@r4pm/components";
10
- //#region src/components/charts/SqlChart.tsx
9
+ import { Flex, SegmentedControl, Text } from "@r4pm/components/ui";
10
+ import { EmptyState, useViewSetting } from "@r4pm/components";
11
+ // 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
@@ -97,5 +97,4 @@ const columns = (result, { x, y, series }) => {
97
97
  measures: (named.length > 0 ? named : result.columns.map((column) => column.name).filter((name) => numeric(name) && name !== category)).filter((name) => name !== series)
98
98
  };
99
99
  };
100
- //#endregion
101
100
  export { SqlChart };
@@ -1,10 +1,11 @@
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";
1
+ import { t as __exportAll } from "./rolldown-runtime-D8jQpDG7.js";
2
+ import { a as measureOf, i as label, n as Plot, t as useChart } from "./useChart-BK4pjGal.js";
3
3
  import { jsx } from "react/jsx-runtime";
4
- //#region src/components/charts/SunburstChart.tsx
4
+ // 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)],
@@ -69,5 +70,4 @@ const nest = (rows, path, measure, colorOf) => {
69
70
  };
70
71
  };
71
72
  const named = (column) => Boolean(column);
72
- //#endregion
73
73
  export { SunburstChart_exports as n, SunburstChart as t };
@@ -0,0 +1,36 @@
1
+ // 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
+ export { attributeOptions as n, attributeDefaults as t };
@@ -1,5 +1,5 @@
1
- import { n as toSeries, t as paint } from "./series-BBXVjHHY.js";
2
- //#region src/components/charts/internal/cartesian.ts
1
+ import { n as toSeries, t as paint } from "./series-Bx0HVnSy.js";
2
+ // src/components/charts/internal/cartesian.ts
3
3
  /**
4
4
  * Traces for the charts drawn against two axes.
5
5
  *
@@ -37,5 +37,4 @@ const cartesian = ({ rows, x, y, series, colorOf }, mark, horizontal = false, co
37
37
  };
38
38
  /** How many traces a chart will draw, which decides whether it needs a legend. */
39
39
  const traceCount = (props) => toSeries(props).length;
40
- //#endregion
41
40
  export { traceCount as n, cartesian as t };