@sentropic/dataviz-svelte 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/adapter.d.ts +39 -0
  2. package/dist/adapter.d.ts.map +1 -0
  3. package/dist/adapter.js +39 -0
  4. package/dist/index.d.ts +32 -36
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +21 -38
  7. package/dist/lib/CrossfilteredBarChart.svelte +80 -0
  8. package/dist/lib/CrossfilteredBarChart.svelte.d.ts +32 -0
  9. package/dist/lib/CrossfilteredBarChart.svelte.d.ts.map +1 -0
  10. package/dist/lib/DashboardFilterBar.svelte +51 -0
  11. package/dist/lib/DashboardFilterBar.svelte.d.ts +14 -0
  12. package/dist/lib/DashboardFilterBar.svelte.d.ts.map +1 -0
  13. package/dist/lib/DrillBarChart.svelte +83 -0
  14. package/dist/lib/DrillBarChart.svelte.d.ts +23 -0
  15. package/dist/lib/DrillBarChart.svelte.d.ts.map +1 -0
  16. package/dist/lib/DrillBreadcrumb.svelte +57 -0
  17. package/dist/lib/DrillBreadcrumb.svelte.d.ts +18 -0
  18. package/dist/lib/DrillBreadcrumb.svelte.d.ts.map +1 -0
  19. package/dist/lib/ExportMenu.svelte +74 -0
  20. package/dist/lib/ExportMenu.svelte.d.ts +23 -0
  21. package/dist/lib/ExportMenu.svelte.d.ts.map +1 -0
  22. package/dist/lib/FieldPane.svelte +38 -0
  23. package/dist/lib/FieldPane.svelte.d.ts +14 -0
  24. package/dist/lib/FieldPane.svelte.d.ts.map +1 -0
  25. package/dist/lib/KpiCardGroup.svelte +63 -0
  26. package/dist/lib/KpiCardGroup.svelte.d.ts +17 -0
  27. package/dist/lib/KpiCardGroup.svelte.d.ts.map +1 -0
  28. package/dist/lib/PivotDataTable.svelte +62 -0
  29. package/dist/lib/PivotDataTable.svelte.d.ts +15 -0
  30. package/dist/lib/PivotDataTable.svelte.d.ts.map +1 -0
  31. package/dist/lib/RecordsTable.svelte +53 -0
  32. package/dist/lib/RecordsTable.svelte.d.ts +17 -0
  33. package/dist/lib/RecordsTable.svelte.d.ts.map +1 -0
  34. package/dist/lib/SelectionLegend.svelte +42 -0
  35. package/dist/lib/SelectionLegend.svelte.d.ts +14 -0
  36. package/dist/lib/SelectionLegend.svelte.d.ts.map +1 -0
  37. package/dist/lib/SmallMultiples.svelte +81 -0
  38. package/dist/lib/SmallMultiples.svelte.d.ts +25 -0
  39. package/dist/lib/SmallMultiples.svelte.d.ts.map +1 -0
  40. package/dist/lib/TopNFilter.svelte +51 -0
  41. package/dist/lib/TopNFilter.svelte.d.ts +18 -0
  42. package/dist/lib/TopNFilter.svelte.d.ts.map +1 -0
  43. package/dist/lib/ValueSlicer.svelte +59 -0
  44. package/dist/lib/ValueSlicer.svelte.d.ts +15 -0
  45. package/dist/lib/ValueSlicer.svelte.d.ts.map +1 -0
  46. package/package.json +21 -9
  47. package/dist/index.js.map +0 -1
@@ -0,0 +1,74 @@
1
+ <script lang="ts" module>
2
+ import type { DashboardStore, Row } from '@sentropic/dataviz-core';
3
+
4
+ export type ExportMenuProps = {
5
+ /** The dashboard store to bind to. */
6
+ store: DashboardStore;
7
+ /** View whose cross-filtered rows are exported (omit for global filters). */
8
+ viewId?: string;
9
+ /** Field ids (and order) to export; defaults to all model fields. */
10
+ fields?: string[];
11
+ /** Downloaded file name. */
12
+ filename?: string;
13
+ /** Button label. */
14
+ label?: string;
15
+ class?: string;
16
+ };
17
+
18
+ function escapeCsv(value: unknown): string {
19
+ const s = value == null ? '' : String(value);
20
+ return /[",\n\r]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
21
+ }
22
+
23
+ /** Pure: rows + columns → a CSV string (RFC-4180-ish escaping). */
24
+ export function rowsToCsv(
25
+ rows: readonly Row[],
26
+ columns: { key: string; label: string }[],
27
+ ): string {
28
+ const header = columns.map((c) => escapeCsv(c.label)).join(',');
29
+ const body = rows
30
+ .map((r) => columns.map((c) => escapeCsv(r[c.key] ?? '')).join(','))
31
+ .join('\n');
32
+ return body ? `${header}\n${body}` : header;
33
+ }
34
+ </script>
35
+
36
+ <script lang="ts">
37
+ import { Button } from '@sentropic/design-system-svelte';
38
+ import { findMeasure } from '@sentropic/dataviz-core';
39
+
40
+ let {
41
+ store,
42
+ viewId,
43
+ fields,
44
+ filename = 'export.csv',
45
+ label = 'Exporter (CSV)',
46
+ class: className,
47
+ }: ExportMenuProps = $props();
48
+
49
+ function columns() {
50
+ const ids = fields ?? [
51
+ ...store.model.dimensions.map((d) => d.id),
52
+ ...store.model.measures.map((m) => m.id),
53
+ ];
54
+ return ids.map((id) => {
55
+ const dim = store.model.dimensions.find((d) => d.id === id);
56
+ const meas = findMeasure(store.model, id);
57
+ return { key: id, label: dim?.label ?? meas?.label ?? id };
58
+ });
59
+ }
60
+
61
+ function exportCsv() {
62
+ const csv = rowsToCsv(store.applyCrossfilter(viewId), columns());
63
+ if (typeof URL === 'undefined' || typeof URL.createObjectURL !== 'function') return;
64
+ const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
65
+ const url = URL.createObjectURL(blob);
66
+ const a = document.createElement('a');
67
+ a.href = url;
68
+ a.download = filename;
69
+ a.click();
70
+ URL.revokeObjectURL(url);
71
+ }
72
+ </script>
73
+
74
+ <Button variant="secondary" class={className} onclick={exportCsv}>{label}</Button>
@@ -0,0 +1,23 @@
1
+ import type { DashboardStore, Row } from '@sentropic/dataviz-core';
2
+ export type ExportMenuProps = {
3
+ /** The dashboard store to bind to. */
4
+ store: DashboardStore;
5
+ /** View whose cross-filtered rows are exported (omit for global filters). */
6
+ viewId?: string;
7
+ /** Field ids (and order) to export; defaults to all model fields. */
8
+ fields?: string[];
9
+ /** Downloaded file name. */
10
+ filename?: string;
11
+ /** Button label. */
12
+ label?: string;
13
+ class?: string;
14
+ };
15
+ /** Pure: rows + columns → a CSV string (RFC-4180-ish escaping). */
16
+ export declare function rowsToCsv(rows: readonly Row[], columns: {
17
+ key: string;
18
+ label: string;
19
+ }[]): string;
20
+ declare const ExportMenu: import("svelte").Component<ExportMenuProps, {}, "">;
21
+ type ExportMenu = ReturnType<typeof ExportMenu>;
22
+ export default ExportMenu;
23
+ //# sourceMappingURL=ExportMenu.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExportMenu.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/ExportMenu.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAEnE,MAAM,MAAM,eAAe,GAAG;IAC5B,sCAAsC;IACtC,KAAK,EAAE,cAAc,CAAC;IACtB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAOF,mEAAmE;AACnE,wBAAgB,SAAS,CACvB,IAAI,EAAE,SAAS,GAAG,EAAE,EACpB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,GACxC,MAAM,CAMR;AAkDH,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -0,0 +1,38 @@
1
+ <script lang="ts" module>
2
+ import type { DataModel, FieldId } from '@sentropic/dataviz-core';
3
+
4
+ export type FieldPaneProps = {
5
+ model: DataModel;
6
+ includeDimensions?: boolean;
7
+ includeMeasures?: boolean;
8
+ selectedId?: FieldId | string;
9
+ defaultExpandedIds?: string[];
10
+ label?: string;
11
+ class?: string;
12
+ };
13
+ </script>
14
+
15
+ <script lang="ts">
16
+ import { TreeView } from '@sentropic/design-system-svelte';
17
+ import { buildFieldPaneTree } from '@sentropic/dataviz-core';
18
+
19
+ let {
20
+ model,
21
+ includeDimensions,
22
+ includeMeasures,
23
+ selectedId,
24
+ defaultExpandedIds,
25
+ label = 'Fields',
26
+ class: className,
27
+ }: FieldPaneProps = $props();
28
+
29
+ const tree = $derived(buildFieldPaneTree(model, { includeDimensions, includeMeasures }));
30
+ </script>
31
+
32
+ <TreeView
33
+ nodes={tree.nodes}
34
+ selected={selectedId}
35
+ defaultExpanded={defaultExpandedIds ?? tree.defaultExpandedIds}
36
+ {label}
37
+ class={className}
38
+ />
@@ -0,0 +1,14 @@
1
+ import type { DataModel, FieldId } from '@sentropic/dataviz-core';
2
+ export type FieldPaneProps = {
3
+ model: DataModel;
4
+ includeDimensions?: boolean;
5
+ includeMeasures?: boolean;
6
+ selectedId?: FieldId | string;
7
+ defaultExpandedIds?: string[];
8
+ label?: string;
9
+ class?: string;
10
+ };
11
+ declare const FieldPane: import("svelte").Component<FieldPaneProps, {}, "">;
12
+ type FieldPane = ReturnType<typeof FieldPane>;
13
+ export default FieldPane;
14
+ //# sourceMappingURL=FieldPane.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FieldPane.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/FieldPane.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAElE,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,SAAS,CAAC;IACjB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA6BJ,QAAA,MAAM,SAAS,oDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
@@ -0,0 +1,63 @@
1
+ <script lang="ts" module>
2
+ import type { DashboardStore, KpiCardConfig, Row } from '@sentropic/dataviz-core';
3
+ import type {
4
+ KpiCardDeltaFormat,
5
+ KpiCardFormat,
6
+ KpiCardSize,
7
+ KpiCardTone,
8
+ } from '@sentropic/design-system-svelte';
9
+
10
+ export type KpiCardGroupProps = {
11
+ store: DashboardStore;
12
+ viewId?: string;
13
+ configs: KpiCardConfig[];
14
+ comparisonData?: readonly Row[];
15
+ format?: KpiCardFormat;
16
+ deltaFormat?: KpiCardDeltaFormat;
17
+ size?: KpiCardSize;
18
+ tone?: KpiCardTone;
19
+ class?: string;
20
+ };
21
+ </script>
22
+
23
+ <script lang="ts">
24
+ import { KpiCard } from '@sentropic/design-system-svelte';
25
+ import { buildKpiCards } from '@sentropic/dataviz-core';
26
+ import { useDashboard } from '../adapter.js';
27
+
28
+ let {
29
+ store,
30
+ viewId,
31
+ configs,
32
+ comparisonData,
33
+ format,
34
+ deltaFormat = 'percent',
35
+ size,
36
+ tone,
37
+ class: className,
38
+ }: KpiCardGroupProps = $props();
39
+
40
+ const dash = $derived(useDashboard(store));
41
+ const cards = $derived.by(() => {
42
+ void $dash;
43
+ return buildKpiCards(store.model, store.applyCrossfilter(viewId), configs, { comparisonData });
44
+ });
45
+
46
+ const finite = (value: number | undefined): number | undefined =>
47
+ value === undefined || !Number.isFinite(value) ? undefined : value;
48
+ </script>
49
+
50
+ <div class={className}>
51
+ {#each cards as card (card.id)}
52
+ <KpiCard
53
+ value={card.value}
54
+ label={card.label}
55
+ delta={finite(deltaFormat === 'absolute' ? card.delta : card.deltaPercent)}
56
+ {deltaFormat}
57
+ {format}
58
+ {size}
59
+ {tone}
60
+ sparkline={card.sparkline?.map((point) => point.value)}
61
+ />
62
+ {/each}
63
+ </div>
@@ -0,0 +1,17 @@
1
+ import type { DashboardStore, KpiCardConfig, Row } from '@sentropic/dataviz-core';
2
+ import type { KpiCardDeltaFormat, KpiCardFormat, KpiCardSize, KpiCardTone } from '@sentropic/design-system-svelte';
3
+ export type KpiCardGroupProps = {
4
+ store: DashboardStore;
5
+ viewId?: string;
6
+ configs: KpiCardConfig[];
7
+ comparisonData?: readonly Row[];
8
+ format?: KpiCardFormat;
9
+ deltaFormat?: KpiCardDeltaFormat;
10
+ size?: KpiCardSize;
11
+ tone?: KpiCardTone;
12
+ class?: string;
13
+ };
14
+ declare const KpiCardGroup: import("svelte").Component<KpiCardGroupProps, {}, "">;
15
+ type KpiCardGroup = ReturnType<typeof KpiCardGroup>;
16
+ export default KpiCardGroup;
17
+ //# sourceMappingURL=KpiCardGroup.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KpiCardGroup.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/KpiCardGroup.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,KAAK,EACV,kBAAkB,EAClB,aAAa,EACb,WAAW,EACX,WAAW,EACZ,MAAM,iCAAiC,CAAC;AAEzC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,cAAc,CAAC,EAAE,SAAS,GAAG,EAAE,CAAC;IAChC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA4CJ,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,62 @@
1
+ <script lang="ts" module>
2
+ import type { DashboardStore, PivotConfig } from '@sentropic/dataviz-core';
3
+ import type { DataTableColumn, DataTableRow } from '@sentropic/design-system-svelte';
4
+
5
+ export type PivotDataTableProps = {
6
+ store: DashboardStore;
7
+ viewId?: string;
8
+ rows: PivotConfig['rows'];
9
+ columns?: PivotConfig['columns'];
10
+ measures: PivotConfig['measures'];
11
+ caption?: string;
12
+ size?: 'sm' | 'md' | 'lg';
13
+ class?: string;
14
+ };
15
+
16
+ type TableView = {
17
+ columns: DataTableColumn[];
18
+ rows: DataTableRow[];
19
+ };
20
+ </script>
21
+
22
+ <script lang="ts">
23
+ import { DataTable } from '@sentropic/design-system-svelte';
24
+ import { buildPivotTable } from '@sentropic/dataviz-core';
25
+ import { useDashboard } from '../adapter.js';
26
+
27
+ let {
28
+ store,
29
+ viewId,
30
+ rows,
31
+ columns,
32
+ measures,
33
+ caption,
34
+ size,
35
+ class: className,
36
+ }: PivotDataTableProps = $props();
37
+
38
+ const dash = $derived(useDashboard(store));
39
+ const table = $derived.by((): TableView => {
40
+ void $dash;
41
+ try {
42
+ const pivot = buildPivotTable(store.model, store.applyCrossfilter(viewId), {
43
+ rows,
44
+ columns,
45
+ measures,
46
+ });
47
+ return {
48
+ columns: pivot.columns.map((column) => ({
49
+ key: column.key,
50
+ label: column.label,
51
+ sortable: true,
52
+ align: column.kind === 'value' ? 'end' : 'start',
53
+ })),
54
+ rows: pivot.rows,
55
+ };
56
+ } catch {
57
+ return { columns: [], rows: [] };
58
+ }
59
+ });
60
+ </script>
61
+
62
+ <DataTable columns={table.columns} rows={table.rows} {caption} {size} class={className} />
@@ -0,0 +1,15 @@
1
+ import type { DashboardStore, PivotConfig } from '@sentropic/dataviz-core';
2
+ export type PivotDataTableProps = {
3
+ store: DashboardStore;
4
+ viewId?: string;
5
+ rows: PivotConfig['rows'];
6
+ columns?: PivotConfig['columns'];
7
+ measures: PivotConfig['measures'];
8
+ caption?: string;
9
+ size?: 'sm' | 'md' | 'lg';
10
+ class?: string;
11
+ };
12
+ declare const PivotDataTable: import("svelte").Component<PivotDataTableProps, {}, "">;
13
+ type PivotDataTable = ReturnType<typeof PivotDataTable>;
14
+ export default PivotDataTable;
15
+ //# sourceMappingURL=PivotDataTable.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PivotDataTable.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/PivotDataTable.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG3E,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,OAAO,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACjC,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA0DJ,QAAA,MAAM,cAAc,yDAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -0,0 +1,53 @@
1
+ <script lang="ts" module>
2
+ import type { DashboardStore } from '@sentropic/dataviz-core';
3
+
4
+ export type RecordsTableProps = {
5
+ /** The dashboard store to bind to. */
6
+ store: DashboardStore;
7
+ /** This view's id in the cross-filter graph (rows shown are its visible rows). */
8
+ viewId?: string;
9
+ /** Field ids (and order) to show as columns; defaults to all model fields. */
10
+ fields?: string[];
11
+ caption?: string;
12
+ size?: 'sm' | 'md' | 'lg';
13
+ pageSize?: number;
14
+ class?: string;
15
+ };
16
+ </script>
17
+
18
+ <script lang="ts">
19
+ import { DataTable, type DataTableColumn, type DataTableRow } from '@sentropic/design-system-svelte';
20
+ import { findMeasure } from '@sentropic/dataviz-core';
21
+ import { useDashboard } from '../adapter.js';
22
+
23
+ let { store, viewId, fields, caption, size, pageSize, class: className }: RecordsTableProps = $props();
24
+
25
+ const dash = $derived(useDashboard(store));
26
+ // The underlying ("show records") rows for this view: the cross-filtered data
27
+ // rendered as a design-system DataTable. Columns come from the data model.
28
+ const view = $derived.by((): { columns: DataTableColumn[]; rows: DataTableRow[] } => {
29
+ void $dash;
30
+ const ids = fields ?? [
31
+ ...store.model.dimensions.map((d) => d.id),
32
+ ...store.model.measures.map((m) => m.id),
33
+ ];
34
+ const columns: DataTableColumn[] = ids.map((id) => {
35
+ const dim = store.model.dimensions.find((d) => d.id === id);
36
+ const meas = findMeasure(store.model, id);
37
+ return { key: id, label: dim?.label ?? meas?.label ?? id, sortable: true, align: meas ? 'end' : 'start' };
38
+ });
39
+ const rows: DataTableRow[] = store
40
+ .applyCrossfilter(viewId)
41
+ .map((row, i) => ({ ...row, id: String(i) }));
42
+ return { columns, rows };
43
+ });
44
+ </script>
45
+
46
+ <DataTable
47
+ columns={view.columns}
48
+ rows={view.rows}
49
+ {caption}
50
+ {size}
51
+ {pageSize}
52
+ class={className}
53
+ />
@@ -0,0 +1,17 @@
1
+ import type { DashboardStore } from '@sentropic/dataviz-core';
2
+ export type RecordsTableProps = {
3
+ /** The dashboard store to bind to. */
4
+ store: DashboardStore;
5
+ /** This view's id in the cross-filter graph (rows shown are its visible rows). */
6
+ viewId?: string;
7
+ /** Field ids (and order) to show as columns; defaults to all model fields. */
8
+ fields?: string[];
9
+ caption?: string;
10
+ size?: 'sm' | 'md' | 'lg';
11
+ pageSize?: number;
12
+ class?: string;
13
+ };
14
+ declare const RecordsTable: import("svelte").Component<RecordsTableProps, {}, "">;
15
+ type RecordsTable = ReturnType<typeof RecordsTable>;
16
+ export default RecordsTable;
17
+ //# sourceMappingURL=RecordsTable.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecordsTable.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/RecordsTable.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,sCAAsC;IACtC,KAAK,EAAE,cAAc,CAAC;IACtB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAyCJ,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,42 @@
1
+ <script lang="ts" module>
2
+ import type { DashboardStore } from '@sentropic/dataviz-core';
3
+
4
+ export type SelectionLegendProps = {
5
+ /** The dashboard store to bind to. */
6
+ store: DashboardStore;
7
+ /** Map of viewId -> human label for the legend chips (falls back to the id). */
8
+ labels?: Record<string, string>;
9
+ /** Aria-label of the legend group. */
10
+ label?: string;
11
+ class?: string;
12
+ };
13
+ </script>
14
+
15
+ <script lang="ts">
16
+ import { Inline, SelectionChip } from '@sentropic/design-system-svelte';
17
+ import { useDashboard } from '../adapter.js';
18
+
19
+ let {
20
+ store,
21
+ labels = {},
22
+ label = 'Sélections actives',
23
+ class: className,
24
+ }: SelectionLegendProps = $props();
25
+
26
+ const dash = $derived(useDashboard(store));
27
+ const entries = $derived(
28
+ Object.entries($dash.selections).filter(([, keys]) => keys.length > 0),
29
+ );
30
+ </script>
31
+
32
+ {#if entries.length > 0}
33
+ <Inline role="group" aria-label={label} gap={2} wrap class={className}>
34
+ {#each entries as [viewId, keys] (viewId)}
35
+ <SelectionChip
36
+ label={labels[viewId] ?? viewId}
37
+ count={keys.length}
38
+ onClear={() => store.clearSelection(viewId)}
39
+ />
40
+ {/each}
41
+ </Inline>
42
+ {/if}
@@ -0,0 +1,14 @@
1
+ import type { DashboardStore } from '@sentropic/dataviz-core';
2
+ export type SelectionLegendProps = {
3
+ /** The dashboard store to bind to. */
4
+ store: DashboardStore;
5
+ /** Map of viewId -> human label for the legend chips (falls back to the id). */
6
+ labels?: Record<string, string>;
7
+ /** Aria-label of the legend group. */
8
+ label?: string;
9
+ class?: string;
10
+ };
11
+ declare const SelectionLegend: import("svelte").Component<SelectionLegendProps, {}, "">;
12
+ type SelectionLegend = ReturnType<typeof SelectionLegend>;
13
+ export default SelectionLegend;
14
+ //# sourceMappingURL=SelectionLegend.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectionLegend.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/SelectionLegend.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,MAAM,oBAAoB,GAAG;IACjC,sCAAsC;IACtC,KAAK,EAAE,cAAc,CAAC;IACtB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAmCJ,QAAA,MAAM,eAAe,0DAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
@@ -0,0 +1,81 @@
1
+ <script lang="ts" module>
2
+ import type { DashboardStore } from '@sentropic/dataviz-core';
3
+ import type { BarChartTone } from '@sentropic/design-system-svelte';
4
+
5
+ export type SmallMultiplesProps = {
6
+ /** The dashboard store to bind to. */
7
+ store: DashboardStore;
8
+ /** This view's id in the cross-filter graph. */
9
+ viewId: string;
10
+ /** Dimension whose distinct values each produce one facet (panel). */
11
+ facetBy: string;
12
+ /** Dimension to group rows by inside each facet (bar categories). */
13
+ dimension: string;
14
+ /** Measure id aggregated into each bar's value. */
15
+ measure: string;
16
+ /** Accessible label; each facet chart is "<label> — <facet key>". */
17
+ label: string;
18
+ /** Number of grid columns (design-system Grid). Defaults to 2. */
19
+ columns?: number;
20
+ /** Bar colour tone from the design system. */
21
+ tone?: BarChartTone;
22
+ class?: string;
23
+ };
24
+ </script>
25
+
26
+ <script lang="ts">
27
+ import { Grid, BarChart, type BarChartDatum } from '@sentropic/design-system-svelte';
28
+ import { findDimension, findMeasure, groupAggregate } from '@sentropic/dataviz-core';
29
+ import { useDashboard } from '../adapter.js';
30
+
31
+ let {
32
+ store,
33
+ viewId,
34
+ facetBy,
35
+ dimension,
36
+ measure,
37
+ label,
38
+ columns = 2,
39
+ tone,
40
+ class: className,
41
+ }: SmallMultiplesProps = $props();
42
+
43
+ const key = (v: unknown) => (v == null ? 'null' : String(v));
44
+
45
+ const dash = $derived(useDashboard(store));
46
+ // One panel per distinct `facetBy` value, all sharing a single value domain so
47
+ // the facets are visually comparable (the small-multiples invariant).
48
+ const view = $derived.by((): { panels: { key: string; data: BarChartDatum[] }[]; domain?: [number, number] } => {
49
+ void $dash;
50
+ const fdim = findDimension(store.model, facetBy);
51
+ const dim = findDimension(store.model, dimension);
52
+ const m = findMeasure(store.model, measure);
53
+ if (!fdim || !dim || !m) return { panels: [] };
54
+ const rows = store.applyCrossfilter(viewId);
55
+ const keys: string[] = [];
56
+ const seen = new Set<string>();
57
+ for (const row of rows) {
58
+ const k = key(row[facetBy]);
59
+ if (!seen.has(k)) {
60
+ seen.add(k);
61
+ keys.push(k);
62
+ }
63
+ }
64
+ let max = 0;
65
+ const panels = keys.map((k) => {
66
+ const facetRows = rows.filter((row) => key(row[facetBy]) === k);
67
+ const data = groupAggregate(facetRows, dimension, m).map(({ key: barKey, value }) => {
68
+ if (value > max) max = value;
69
+ return tone ? { label: barKey, value, tone } : { label: barKey, value };
70
+ });
71
+ return { key: k, data };
72
+ });
73
+ return { panels, domain: panels.length ? [0, max] : undefined };
74
+ });
75
+ </script>
76
+
77
+ <Grid {columns} gap={4} class={className} role="group" aria-label={label}>
78
+ {#each view.panels as panel (panel.key)}
79
+ <BarChart data={panel.data} label={`${label} — ${panel.key}`} domain={view.domain} />
80
+ {/each}
81
+ </Grid>
@@ -0,0 +1,25 @@
1
+ import type { DashboardStore } from '@sentropic/dataviz-core';
2
+ import type { BarChartTone } from '@sentropic/design-system-svelte';
3
+ export type SmallMultiplesProps = {
4
+ /** The dashboard store to bind to. */
5
+ store: DashboardStore;
6
+ /** This view's id in the cross-filter graph. */
7
+ viewId: string;
8
+ /** Dimension whose distinct values each produce one facet (panel). */
9
+ facetBy: string;
10
+ /** Dimension to group rows by inside each facet (bar categories). */
11
+ dimension: string;
12
+ /** Measure id aggregated into each bar's value. */
13
+ measure: string;
14
+ /** Accessible label; each facet chart is "<label> — <facet key>". */
15
+ label: string;
16
+ /** Number of grid columns (design-system Grid). Defaults to 2. */
17
+ columns?: number;
18
+ /** Bar colour tone from the design system. */
19
+ tone?: BarChartTone;
20
+ class?: string;
21
+ };
22
+ declare const SmallMultiples: import("svelte").Component<SmallMultiplesProps, {}, "">;
23
+ type SmallMultiples = ReturnType<typeof SmallMultiples>;
24
+ export default SmallMultiples;
25
+ //# sourceMappingURL=SmallMultiples.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmallMultiples.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/SmallMultiples.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAEpE,MAAM,MAAM,mBAAmB,GAAG;IAChC,sCAAsC;IACtC,KAAK,EAAE,cAAc,CAAC;IACtB,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAoEJ,QAAA,MAAM,cAAc,yDAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -0,0 +1,51 @@
1
+ <script lang="ts" module>
2
+ import type { DashboardStore } from '@sentropic/dataviz-core';
3
+
4
+ export type TopNFilterProps = {
5
+ /** The dashboard store to bind to. */
6
+ store: DashboardStore;
7
+ /** Dimension to restrict to its top-N values. */
8
+ dimension: string;
9
+ /** Measure used to rank the dimension's values (descending). */
10
+ measure: string;
11
+ /** Initial N. Defaults to 5. */
12
+ defaultN?: number;
13
+ /** Field label of the number input. */
14
+ label?: string;
15
+ class?: string;
16
+ };
17
+ </script>
18
+
19
+ <script lang="ts">
20
+ import { untrack } from 'svelte';
21
+ import { NumberInput } from '@sentropic/design-system-svelte';
22
+ import { findMeasure, groupAggregate, type Row } from '@sentropic/dataviz-core';
23
+
24
+ let {
25
+ store,
26
+ dimension,
27
+ measure,
28
+ defaultN = 5,
29
+ label = 'Top N',
30
+ class: className,
31
+ }: TopNFilterProps = $props();
32
+
33
+ // Uncontrolled initial value captured intentionally from the prop.
34
+ let n = $state(untrack(() => defaultN));
35
+
36
+ // Apply (and keep in sync) an `include` filter of the dimension's top-N values
37
+ // by the measure, ranked over the full dataset (a stable, predictable Top-N).
38
+ $effect(() => {
39
+ const count = n;
40
+ const m = findMeasure(store.model, measure);
41
+ if (!m || !Number.isFinite(count) || count < 1) return;
42
+ const ranked = groupAggregate([...(store.data as readonly Row[])], dimension, m)
43
+ .slice()
44
+ .sort((a, b) => b.value - a.value)
45
+ .slice(0, count)
46
+ .map((r) => r.key);
47
+ store.setFilter(dimension, { kind: 'include', values: ranked });
48
+ });
49
+ </script>
50
+
51
+ <NumberInput {label} bind:value={n} min={1} step={1} class={className} />
@@ -0,0 +1,18 @@
1
+ import type { DashboardStore } from '@sentropic/dataviz-core';
2
+ export type TopNFilterProps = {
3
+ /** The dashboard store to bind to. */
4
+ store: DashboardStore;
5
+ /** Dimension to restrict to its top-N values. */
6
+ dimension: string;
7
+ /** Measure used to rank the dimension's values (descending). */
8
+ measure: string;
9
+ /** Initial N. Defaults to 5. */
10
+ defaultN?: number;
11
+ /** Field label of the number input. */
12
+ label?: string;
13
+ class?: string;
14
+ };
15
+ declare const TopNFilter: import("svelte").Component<TopNFilterProps, {}, "">;
16
+ type TopNFilter = ReturnType<typeof TopNFilter>;
17
+ export default TopNFilter;
18
+ //# sourceMappingURL=TopNFilter.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TopNFilter.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/TopNFilter.svelte.ts"],"names":[],"mappings":"AAGE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,MAAM,eAAe,GAAG;IAC5B,sCAAsC;IACtC,KAAK,EAAE,cAAc,CAAC;IACtB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AA6CJ,QAAA,MAAM,UAAU,qDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}