@pixerate/editor-svelte 0.42.0 → 0.43.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.
@@ -3,19 +3,20 @@
3
3
  import {
4
4
  CSS_VARIABLE_CHART_THEME,
5
5
  chartClientToScene,
6
- chartTextBaseline,
7
- chartTextTransform,
8
6
  describeChartSelection,
9
7
  handleChartKey,
10
8
  layoutChart,
11
9
  startChartPointDrag,
12
10
  type ChartController,
13
- type ChartMark,
14
11
  type ChartPointDrag,
12
+ type ChartPresence,
13
+ type ChartScene,
15
14
  type ChartTextMeasure,
16
15
  type ChartTheme
17
16
  } from '@pixerate/editor/chart';
18
17
  import { chartStateOf } from './createChartEditor.svelte.js';
18
+ import ChartMarks from './ChartMarks.svelte';
19
+ import ChartPresenceLayer from './ChartPresenceLayer.svelte';
19
20
 
20
21
  interface Props {
21
22
  controller: ChartController;
@@ -33,6 +34,10 @@
33
34
  measureText?: ChartTextMeasure;
34
35
  emptyMessage?: string;
35
36
  class?: string;
37
+ /** Agent cursors to draw over the chart (see `ChartDirector`). */
38
+ presence?: ChartPresence;
39
+ /** Receives the scene as drawn (e.g. for `ChartDirector`'s `scene`). */
40
+ sceneRef?: { current: ChartScene | null };
36
41
  }
37
42
 
38
43
  let {
@@ -44,7 +49,9 @@
44
49
  editable = true,
45
50
  measureText,
46
51
  emptyMessage,
47
- class: className = ''
52
+ class: className = '',
53
+ presence,
54
+ sceneRef
48
55
  }: Props = $props();
49
56
 
50
57
  const view = chartStateOf(() => controller);
@@ -64,6 +71,8 @@
64
71
  return () => observer.disconnect();
65
72
  });
66
73
  let drag: ChartPointDrag | null = null;
74
+ // Frozen while a point is dragged so the axes do not rescale under the pointer.
75
+ let frozen = $state.raw<{ valueDomain: ChartPointDrag['valueDomain']; valueDomain2: ChartPointDrag['valueDomain2'] | null; xDomain: ChartPointDrag['xDomain'] | null; readout: ChartPointDrag['target'] } | null>(null);
67
76
 
68
77
  const sceneWidth = $derived((responsive && measured) || width);
69
78
  const fullTheme = $derived({ ...CSS_VARIABLE_CHART_THEME, ...theme });
@@ -74,16 +83,21 @@
74
83
  theme: fullTheme,
75
84
  selection: editable ? view.current.selection : null,
76
85
  measureText,
77
- emptyMessage
86
+ emptyMessage,
87
+ valueDomain: frozen?.valueDomain,
88
+ valueDomain2: frozen?.valueDomain2,
89
+ xDomain: frozen?.xDomain,
90
+ readout: frozen?.readout
78
91
  })
79
92
  );
93
+ $effect(() => {
94
+ if (sceneRef) sceneRef.current = scene;
95
+ });
80
96
  const byKey = $derived(new Map(scene.marks.map((m) => [m.key, m])));
81
97
  const label = $derived(view.current.spec.title || 'Chart');
82
98
 
83
99
  onDestroy(() => drag?.end());
84
100
 
85
- const pointerEvents = (mark: ChartMark) => (mark.role === 'selection' || (!mark.target && mark.role !== 'background') ? 'none' : undefined);
86
- const cursor = (mark: ChartMark) => (editable && mark.target && mark.role !== 'background' ? 'pointer' : undefined);
87
101
  const scenePoint = (e: PointerEvent) => chartClientToScene(scene, svg!.getBoundingClientRect(), e.clientX, e.clientY);
88
102
 
89
103
  function pointerdown(e: PointerEvent) {
@@ -92,16 +106,27 @@
92
106
  const target = key ? byKey.get(key)?.target : undefined;
93
107
  controller.select(target ?? null);
94
108
  drag = startChartPointDrag(controller, scene, target, scenePoint(e));
95
- if (drag) svg?.setPointerCapture?.(e.pointerId);
109
+ if (drag) {
110
+ frozen = { valueDomain: drag.valueDomain, valueDomain2: drag.valueDomain2 ?? null, xDomain: drag.xDomain ?? null, readout: drag.target };
111
+ svg?.setPointerCapture?.(e.pointerId);
112
+ }
96
113
  }
97
114
  function pointermove(e: PointerEvent) {
98
- drag?.move(scenePoint(e));
115
+ drag?.move(scenePoint(e), { fine: e.altKey, lockAxis: e.shiftKey, noSnap: e.ctrlKey || e.metaKey });
99
116
  }
100
117
  function endDrag() {
101
118
  drag?.end();
102
119
  drag = null;
120
+ frozen = null;
103
121
  }
104
122
  function keydown(e: KeyboardEvent) {
123
+ if (drag && e.key === 'Escape') {
124
+ drag.cancel();
125
+ drag = null;
126
+ frozen = null;
127
+ e.preventDefault();
128
+ return;
129
+ }
105
130
  if (editable && handleChartKey(controller, scene, e)) e.preventDefault();
106
131
  }
107
132
  </script>
@@ -123,91 +148,7 @@
123
148
  onpointercancel={endDrag}
124
149
  onkeydown={keydown}
125
150
  >
126
- {#each scene.marks as mark (mark.key)}
127
- {#if mark.kind === 'rect'}
128
- <rect
129
- data-role={mark.role}
130
- data-chart-key={mark.target ? mark.key : undefined}
131
- data-selected={mark.selected ? '' : undefined}
132
- x={mark.x}
133
- y={mark.y}
134
- width={mark.width}
135
- height={mark.height}
136
- rx={mark.radius}
137
- opacity={mark.opacity}
138
- pointer-events={pointerEvents(mark)}
139
- cursor={cursor(mark)}
140
- style:fill={mark.fill}
141
- style:stroke={mark.stroke}
142
- style:stroke-width={mark.strokeWidth}
143
- />
144
- {:else if mark.kind === 'path'}
145
- <path
146
- data-role={mark.role}
147
- data-chart-key={mark.target ? mark.key : undefined}
148
- data-selected={mark.selected ? '' : undefined}
149
- d={mark.d}
150
- stroke-linejoin="round"
151
- stroke-linecap="round"
152
- stroke-dasharray={mark.dash}
153
- opacity={mark.opacity}
154
- pointer-events={pointerEvents(mark)}
155
- cursor={cursor(mark)}
156
- style:fill={mark.fill ?? 'none'}
157
- style:stroke={mark.stroke}
158
- style:stroke-width={mark.strokeWidth}
159
- />
160
- {:else if mark.kind === 'circle'}
161
- <circle
162
- data-role={mark.role}
163
- data-chart-key={mark.target ? mark.key : undefined}
164
- data-selected={mark.selected ? '' : undefined}
165
- cx={mark.cx}
166
- cy={mark.cy}
167
- r={mark.r}
168
- opacity={mark.opacity}
169
- pointer-events={pointerEvents(mark)}
170
- cursor={cursor(mark)}
171
- style:fill={mark.fill}
172
- style:stroke={mark.stroke}
173
- style:stroke-width={mark.strokeWidth}
174
- />
175
- {:else if mark.kind === 'line'}
176
- <line
177
- data-role={mark.role}
178
- data-chart-key={mark.target ? mark.key : undefined}
179
- data-selected={mark.selected ? '' : undefined}
180
- x1={mark.x1}
181
- y1={mark.y1}
182
- x2={mark.x2}
183
- y2={mark.y2}
184
- stroke-dasharray={mark.dash}
185
- opacity={mark.opacity}
186
- pointer-events={pointerEvents(mark)}
187
- cursor={cursor(mark)}
188
- style:stroke={mark.stroke}
189
- style:stroke-width={mark.strokeWidth}
190
- />
191
- {:else}
192
- <text
193
- data-role={mark.role}
194
- data-chart-key={mark.target ? mark.key : undefined}
195
- data-selected={mark.selected ? '' : undefined}
196
- x={mark.x}
197
- y={mark.y}
198
- text-anchor={mark.anchor}
199
- dominant-baseline={chartTextBaseline(mark.baseline)}
200
- transform={chartTextTransform(mark)}
201
- opacity={mark.opacity}
202
- pointer-events={pointerEvents(mark)}
203
- cursor={cursor(mark)}
204
- style:fill={mark.fill}
205
- style:font-size="{mark.size}px"
206
- style:font-weight={mark.weight}
207
- style:font-family={scene.theme.fontFamily}
208
- style:user-select="none">{mark.text}</text
209
- >
210
- {/if}
211
- {/each}
151
+ <ChartMarks marks={scene.marks} fontFamily={scene.theme.fontFamily} interactive={editable} />
152
+ {#if presence}<ChartPresenceLayer {presence} />{/if}
212
153
  </svg>
213
154
  </div>
@@ -1,4 +1,4 @@
1
- import { type ChartController, type ChartTextMeasure, type ChartTheme } from '@pixerate/editor/chart';
1
+ import { type ChartController, type ChartPresence, type ChartScene, type ChartTextMeasure, type ChartTheme } from '@pixerate/editor/chart';
2
2
  interface Props {
3
3
  controller: ChartController;
4
4
  /** Scene width; with `responsive` this is only the fallback before the container is measured (default 640). */
@@ -15,6 +15,12 @@ interface Props {
15
15
  measureText?: ChartTextMeasure;
16
16
  emptyMessage?: string;
17
17
  class?: string;
18
+ /** Agent cursors to draw over the chart (see `ChartDirector`). */
19
+ presence?: ChartPresence;
20
+ /** Receives the scene as drawn (e.g. for `ChartDirector`'s `scene`). */
21
+ sceneRef?: {
22
+ current: ChartScene | null;
23
+ };
18
24
  }
19
25
  declare const ChartCanvas: import("svelte").Component<Props, {}, "">;
20
26
  type ChartCanvas = ReturnType<typeof ChartCanvas>;
@@ -1 +1 @@
1
- {"version":3,"file":"ChartCanvas.svelte.d.ts","sourceRoot":"","sources":["../../src/chart/ChartCanvas.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EASH,KAAK,eAAe,EAGpB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAChB,MAAM,wBAAwB,CAAC;AAIhC,UAAU,KAAK;IACb,UAAU,EAAE,eAAe,CAAC;IAC5B,+GAA+G;IAC/G,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oDAAoD;IACpD,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmGH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"ChartCanvas.svelte.d.ts","sourceRoot":"","sources":["../../src/chart/ChartCanvas.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAOH,KAAK,eAAe,EAEpB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAChB,MAAM,wBAAwB,CAAC;AAMhC,UAAU,KAAK;IACb,UAAU,EAAE,eAAe,CAAC;IAC5B,+GAA+G;IAC/G,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oDAAoD;IACpD,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,wEAAwE;IACxE,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAAA;KAAE,CAAC;CAC3C;AA8GH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -3,26 +3,38 @@
3
3
  // between server and client renders.
4
4
  let nextId = 0;
5
5
 
6
- export type ChartInspectorSection = 'type' | 'titles' | 'options' | 'legend' | 'axes' | 'series';
6
+ export type ChartInspectorSection = 'type' | 'style' | 'titles' | 'options' | 'legend' | 'axes' | 'series';
7
7
  </script>
8
8
 
9
9
  <script lang="ts">
10
10
  import {
11
+ CHART_COLOR_SCHEMES,
11
12
  CHART_CURVES,
13
+ CHART_LABEL_POSITIONS,
14
+ CHART_LAYOUT_PRESETS,
12
15
  CHART_LEGEND_POSITIONS,
16
+ CHART_MARKERS,
13
17
  CHART_NUMBER_STYLES,
14
18
  CHART_SERIES_TYPES,
15
19
  CHART_STACKINGS,
20
+ CHART_TRENDLINE_TYPES,
16
21
  CHART_TYPE_LABELS,
17
22
  CHART_TYPES,
23
+ checkChartColors,
18
24
  chartColorInputValue,
25
+ chartFamily,
19
26
  chartSeriesColor,
20
27
  chartSeriesType,
28
+ chartSupportsTrendlines,
29
+ chartTrendlineName,
21
30
  isCartesianChart,
22
31
  type ChartAxis,
23
32
  type ChartController,
33
+ type ChartLabelPosition,
34
+ type ChartMarker,
24
35
  type ChartNumberFormat,
25
- type ChartSeriesType
36
+ type ChartSeriesType,
37
+ type ChartTrendlineType
26
38
  } from '@pixerate/editor/chart';
27
39
  import ChartCommitInput from './ChartCommitInput.svelte';
28
40
  import { chartStateOf } from './createChartEditor.svelte.js';
@@ -44,23 +56,36 @@
44
56
  const selectedSeries = $derived(view.current.selectedSeries);
45
57
  const show = (section: ChartInspectorSection) => !sections || sections.includes(section);
46
58
  const cartesian = $derived(isCartesianChart(spec.type));
59
+ const family = $derived(chartFamily(spec));
60
+ const hasAxes = $derived(family === 'cartesian' || family === 'xy' || family === 'waterfall' || family === 'histogram' || family === 'box');
47
61
  const types = $derived(spec.series.map((s) => chartSeriesType(spec, s)));
48
62
  const hasBars = $derived(cartesian && types.includes('bar'));
49
63
  const hasLines = $derived(cartesian && types.some((t) => t === 'line' || t === 'area'));
64
+ const usesSecondary = $derived(family === 'cartesian' && spec.series.some((s) => s.axis === 'secondary' && !s.hidden));
65
+ const colorCheck = $derived(checkChartColors(spec.series.filter((s) => !s.hidden).map((s) => chartSeriesColor(spec, spec.series.indexOf(s)))));
66
+ const currentScheme = $derived(CHART_COLOR_SCHEMES.find((c) => c.palette.join() === spec.palette.join())?.id ?? '');
50
67
  const seriesIndex = $derived(selectedSeries ? spec.series.findIndex((s) => s.id === selectedSeries.id) : -1);
51
68
  const horizontal = $derived(spec.orientation === 'horizontal');
52
69
  const cap = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
53
70
  const stackingLabels: Record<string, string> = { none: 'None', stacked: 'Stacked', percent: '100%' };
54
71
 
55
- const setAxis = (axis: 'x' | 'y', patch: Partial<ChartAxis>) => controller.setAxis(axis, patch);
56
- const setFormat = (patch: Partial<ChartNumberFormat>) => setAxis('y', { format: { ...spec.yAxis.format, ...patch } });
57
- const commitBound = (key: 'min' | 'max') => (text: string) => setAxis('y', { [key]: text.trim() === '' ? null : Number(text) }).ok;
58
- function commitDecimals(text: string) {
59
- const format = { ...spec.yAxis.format };
72
+ const keyOf = (axis: 'x' | 'y' | 'y2') => (axis === 'y2' ? 'yAxis2' : `${axis}Axis`);
73
+ const setAxis = (axis: 'x' | 'y' | 'y2', patch: Partial<ChartAxis>) => controller.setAxis(axis, patch);
74
+ const setFormat = (axis: 'x' | 'y' | 'y2', value: ChartAxis, patch: Partial<ChartNumberFormat>) => setAxis(axis, { format: { ...value.format, ...patch } });
75
+ const commitNumber = (axis: 'x' | 'y' | 'y2', key: 'min' | 'max' | 'step') => (text: string) => setAxis(axis, { [key]: text.trim() === '' ? null : Number(text) }).ok;
76
+ function commitDecimals(axis: 'x' | 'y' | 'y2', value: ChartAxis, text: string) {
77
+ const format = { ...value.format };
60
78
  if (text.trim() === '') delete format.decimals;
61
79
  else format.decimals = Number(text);
62
- return setAxis('y', { format }).ok;
80
+ return setAxis(axis, { format }).ok;
63
81
  }
82
+ function commitCode(axis: 'x' | 'y' | 'y2', value: ChartAxis, code: string) {
83
+ const format = { ...value.format };
84
+ if (code.trim()) format.code = code.trim();
85
+ else delete format.code;
86
+ return setAxis(axis, { format }).ok;
87
+ }
88
+ const side = (axis: 'x' | 'y' | 'y2') => (axis === 'x' ? (horizontal ? 'left' : 'bottom') : axis === 'y2' ? (horizontal ? 'top' : 'right') : horizontal ? 'bottom' : 'left');
64
89
  </script>
65
90
 
66
91
  {#snippet toggle(label: string, name: string, checked: boolean, onchange: (checked: boolean) => void)}
@@ -70,39 +95,52 @@
70
95
  </label>
71
96
  {/snippet}
72
97
 
73
- {#snippet axisSection(axis: 'x' | 'y', value: ChartAxis)}
98
+ {#snippet axisSection(axis: 'x' | 'y' | 'y2', value: ChartAxis, numeric: boolean)}
99
+ {@const key = keyOf(axis)}
100
+ {@const valueAxis = axis !== 'x' || numeric}
74
101
  <div class={chartSectionClass} data-section="axis-{axis}">
75
102
  <div class="flex items-center justify-between">
76
103
  <h4 class="text-xs font-semibold text-foreground">
77
- {axis === 'x' ? 'Category axis' : 'Value axis'}
78
- <span class="ml-1 font-normal text-muted-foreground">({axis === 'x' ? (horizontal ? 'left' : 'bottom') : horizontal ? 'bottom' : 'left'})</span>
104
+ {axis === 'x' ? (numeric ? 'X axis' : 'Category axis') : axis === 'y' ? 'Value axis' : 'Secondary axis'}
105
+ <span class="ml-1 font-normal text-muted-foreground">({side(axis)})</span>
79
106
  </h4>
80
- {@render toggle('Show', `${axis}Axis.show`, value.show, (v) => setAxis(axis, { show: v }))}
107
+ {@render toggle('Show', `${key}.show`, value.show, (v) => setAxis(axis, { show: v }))}
81
108
  </div>
82
109
  <div class="flex items-center gap-2">
83
110
  <label for="{idPrefix}-{axis}-title" class="{chartLabelClass} w-20 shrink-0">Title</label>
84
111
  <div class="min-w-0 flex-1">
85
- <ChartCommitInput id="{idPrefix}-{axis}-title" value={value.title} data-option="{axis}Axis.title" oncommit={(title) => void setAxis(axis, { title })} />
112
+ <ChartCommitInput id="{idPrefix}-{axis}-title" value={value.title} data-option="{key}.title" oncommit={(title) => void setAxis(axis, { title })} />
86
113
  </div>
87
114
  </div>
88
- {@render toggle('Grid lines', `${axis}Axis.gridlines`, value.gridlines, (v) => setAxis(axis, { gridlines: v }))}
89
- {#if axis === 'y'}
115
+ <div class="flex flex-wrap gap-x-4 gap-y-1">
116
+ {@render toggle('Grid lines', `${key}.gridlines`, value.gridlines, (v) => setAxis(axis, { gridlines: v }))}
117
+ {#if axis === 'x' && !numeric}
118
+ {@render toggle('Dates', 'xAxis.kind', value.kind === 'date', (dates) => setAxis('x', { kind: dates ? 'date' : undefined } as Partial<ChartAxis>))}
119
+ {/if}
120
+ </div>
121
+ {#if valueAxis}
122
+ <div class="flex items-center gap-2">
123
+ <label for="{idPrefix}-{axis}-step" class="{chartLabelClass} w-20 shrink-0">Step</label>
124
+ <div class="min-w-0 flex-1">
125
+ <ChartCommitInput id="{idPrefix}-{axis}-step" value={value.step === null ? '' : String(value.step)} placeholder="Auto" inputmode="decimal" data-option="{key}.step" oncommit={commitNumber(axis, 'step')} />
126
+ </div>
127
+ </div>
90
128
  <div class="flex items-center gap-2">
91
129
  <span class="{chartLabelClass} w-20 shrink-0">Min / max</span>
92
130
  <div class="flex min-w-0 flex-1 gap-1">
93
- <ChartCommitInput id="{idPrefix}-y-min" value={value.min === null ? '' : String(value.min)} placeholder="Auto" inputmode="decimal" data-option="yAxis.min" oncommit={commitBound('min')} />
94
- <ChartCommitInput id="{idPrefix}-y-max" value={value.max === null ? '' : String(value.max)} placeholder="Auto" inputmode="decimal" data-option="yAxis.max" oncommit={commitBound('max')} />
131
+ <ChartCommitInput id="{idPrefix}-{axis}-min" value={value.min === null ? '' : String(value.min)} placeholder="Auto" inputmode="decimal" data-option="{key}.min" oncommit={commitNumber(axis, 'min')} />
132
+ <ChartCommitInput id="{idPrefix}-{axis}-max" value={value.max === null ? '' : String(value.max)} placeholder="Auto" inputmode="decimal" data-option="{key}.max" oncommit={commitNumber(axis, 'max')} />
95
133
  </div>
96
134
  </div>
97
135
  <div class="flex items-center gap-2">
98
- <label for="{idPrefix}-y-format" class="{chartLabelClass} w-20 shrink-0">Format</label>
136
+ <label for="{idPrefix}-{axis}-format" class="{chartLabelClass} w-20 shrink-0">Format</label>
99
137
  <div class="flex min-w-0 flex-1 gap-1">
100
138
  <select
101
- id="{idPrefix}-y-format"
139
+ id="{idPrefix}-{axis}-format"
102
140
  class={chartInputClass}
103
141
  value={value.format.style ?? 'number'}
104
- data-option="yAxis.format.style"
105
- onchange={(e) => setFormat({ style: e.currentTarget.value as ChartNumberFormat['style'] })}
142
+ data-option="{key}.format.style"
143
+ onchange={(e) => setFormat(axis, value, { style: e.currentTarget.value as ChartNumberFormat['style'] })}
106
144
  >
107
145
  {#each CHART_NUMBER_STYLES as style (style)}
108
146
  <option value={style}>{cap(style)}</option>
@@ -114,20 +152,26 @@
114
152
  aria-label="Decimals"
115
153
  title="Decimals"
116
154
  inputmode="numeric"
117
- data-option="yAxis.format.decimals"
155
+ data-option="{key}.format.decimals"
118
156
  class="{chartInputClass} w-14 shrink-0"
119
- oncommit={commitDecimals}
157
+ oncommit={(text) => commitDecimals(axis, value, text)}
120
158
  />
121
159
  </div>
122
160
  </div>
123
161
  {#if value.format.style === 'currency'}
124
162
  <div class="flex items-center gap-2">
125
- <label for="{idPrefix}-y-currency" class="{chartLabelClass} w-20 shrink-0">Currency</label>
163
+ <label for="{idPrefix}-{axis}-currency" class="{chartLabelClass} w-20 shrink-0">Currency</label>
126
164
  <div class="min-w-0 flex-1">
127
- <ChartCommitInput id="{idPrefix}-y-currency" value={value.format.currency ?? 'USD'} data-option="yAxis.format.currency" oncommit={(c) => void setFormat({ currency: c.toUpperCase() })} />
165
+ <ChartCommitInput id="{idPrefix}-{axis}-currency" value={value.format.currency ?? 'USD'} data-option="{key}.format.currency" oncommit={(c) => void setFormat(axis, value, { currency: c.toUpperCase() })} />
128
166
  </div>
129
167
  </div>
130
168
  {/if}
169
+ <div class="flex items-center gap-2">
170
+ <label for="{idPrefix}-{axis}-code" class="{chartLabelClass} w-20 shrink-0">Code</label>
171
+ <div class="min-w-0 flex-1">
172
+ <ChartCommitInput id="{idPrefix}-{axis}-code" value={value.format.code ?? ''} placeholder={'e.g. #,##0.0,,"M"'} data-option="{key}.format.code" oncommit={(code) => commitCode(axis, value, code)} />
173
+ </div>
174
+ </div>
131
175
  {/if}
132
176
  </div>
133
177
  {/snippet}
@@ -145,6 +189,33 @@
145
189
  </div>
146
190
  {/if}
147
191
 
192
+ {#if show('style')}
193
+ <div class={chartSectionClass} data-section="style">
194
+ <div class="flex items-center gap-2">
195
+ <label for="{idPrefix}-layout" class="{chartLabelClass} w-20 shrink-0">Layout</label>
196
+ <select id="{idPrefix}-layout" class={chartInputClass} value="" data-option="preset.layout" onchange={(e) => e.currentTarget.value && controller.applyPreset({ layout: e.currentTarget.value })}>
197
+ <option value="">Quick layout…</option>
198
+ {#each CHART_LAYOUT_PRESETS as p (p.id)}
199
+ <option value={p.id} title={p.description}>{p.label}</option>
200
+ {/each}
201
+ </select>
202
+ </div>
203
+ <div class="flex items-center gap-2">
204
+ <label for="{idPrefix}-colors" class="{chartLabelClass} w-20 shrink-0">Colours</label>
205
+ <select id="{idPrefix}-colors" class={chartInputClass} value={currentScheme} data-option="preset.colors" onchange={(e) => e.currentTarget.value && controller.applyPreset({ colors: e.currentTarget.value })}>
206
+ <option value="">Custom</option>
207
+ {#each CHART_COLOR_SCHEMES as c (c.id)}
208
+ <option value={c.id} title={c.description}>{c.label}</option>
209
+ {/each}
210
+ </select>
211
+ </div>
212
+ {#if !colorCheck.ok}
213
+ <p class="text-[11px] leading-snug text-amber-600 dark:text-amber-400" data-chart-color-warning="">{colorCheck.issues[0]}</p>
214
+ {/if}
215
+ <button type="button" class={chartButtonClass} data-action="transpose" onclick={() => controller.transpose()}>Switch rows and columns</button>
216
+ </div>
217
+ {/if}
218
+
148
219
  {#if show('titles')}
149
220
  <div class={chartSectionClass} data-section="titles">
150
221
  <div class="flex items-center gap-2">
@@ -191,6 +262,32 @@
191
262
  {/each}
192
263
  </div>
193
264
  </div>
265
+ <div class="flex items-center gap-2">
266
+ <label for="{idPrefix}-gap" class="{chartLabelClass} w-20 shrink-0">Spacing</label>
267
+ <input
268
+ id="{idPrefix}-gap"
269
+ type="range"
270
+ min="0"
271
+ max="0.9"
272
+ step="0.02"
273
+ value={spec.gapWidth}
274
+ data-option="gapWidth"
275
+ class="w-full accent-primary"
276
+ onpointerdown={() => controller.beginGesture('gapWidth')}
277
+ onpointerup={() => controller.endGesture()}
278
+ oninput={(e) => controller.update({ gapWidth: Number(e.currentTarget.value) })}
279
+ />
280
+ </div>
281
+ {/if}
282
+ {#if spec.dataLabels && hasBars}
283
+ <div class="flex items-center gap-2">
284
+ <label for="{idPrefix}-label-position" class="{chartLabelClass} w-20 shrink-0">Labels</label>
285
+ <select id="{idPrefix}-label-position" class={chartInputClass} value={spec.labelPosition} data-option="labelPosition" onchange={(e) => controller.update({ labelPosition: e.currentTarget.value as ChartLabelPosition })}>
286
+ {#each CHART_LABEL_POSITIONS as p (p)}
287
+ <option value={p}>{cap(p)}</option>
288
+ {/each}
289
+ </select>
290
+ </div>
194
291
  {/if}
195
292
  {#if hasLines}
196
293
  <div class="flex items-center gap-2">
@@ -202,6 +299,14 @@
202
299
  </select>
203
300
  </div>
204
301
  {/if}
302
+ {#if spec.type === 'histogram'}
303
+ <div class="flex items-center gap-2">
304
+ <label for="{idPrefix}-bins" class="{chartLabelClass} w-20 shrink-0">Bins</label>
305
+ <div class="min-w-0 flex-1">
306
+ <ChartCommitInput id="{idPrefix}-bins" value={spec.bins === null ? '' : String(spec.bins)} placeholder="Auto" inputmode="numeric" data-option="bins" oncommit={(text) => controller.update({ bins: text.trim() === '' ? null : Number(text) }).ok} />
307
+ </div>
308
+ </div>
309
+ {/if}
205
310
  {#if spec.type === 'donut'}
206
311
  <div class="flex items-center gap-2">
207
312
  <label for="{idPrefix}-hole" class="{chartLabelClass} w-20 shrink-0">Hole</label>
@@ -221,6 +326,9 @@
221
326
  </div>
222
327
  {/if}
223
328
  <div class="flex flex-wrap gap-x-4 gap-y-1">
329
+ {#if spec.type === 'waterfall'}
330
+ {@render toggle('Total bar', 'showTotal', spec.showTotal, (showTotal) => controller.update({ showTotal }))}
331
+ {/if}
224
332
  {#if hasLines}
225
333
  {@render toggle('Points', 'points', spec.points, (points) => controller.update({ points }))}
226
334
  {/if}
@@ -247,13 +355,19 @@
247
355
  </div>
248
356
  {/if}
249
357
 
250
- {#if show('axes') && cartesian}
251
- {@render axisSection('x', spec.xAxis)}
252
- {@render axisSection('y', spec.yAxis)}
358
+ {#if show('axes') && hasAxes}
359
+ {#if family !== 'box' && family !== 'histogram'}
360
+ {@render axisSection('x', spec.xAxis, family === 'xy')}
361
+ {/if}
362
+ {@render axisSection('y', spec.yAxis, false)}
363
+ {#if usesSecondary}
364
+ {@render axisSection('y2', spec.yAxis2, false)}
365
+ {/if}
253
366
  {/if}
254
367
 
255
368
  {#if show('series') && selectedSeries}
256
369
  {@const series = selectedSeries}
370
+ {@const drawnAs = chartSeriesType(spec, series)}
257
371
  <div class={chartSectionClass} data-section="series" data-series-id={series.id}>
258
372
  <h4 class="text-xs font-semibold text-foreground">Series</h4>
259
373
  <div class="flex items-center gap-2">
@@ -297,8 +411,51 @@
297
411
  </select>
298
412
  </div>
299
413
  {/if}
414
+ {#if (cartesian || family === 'xy') && (drawnAs === 'line' || drawnAs === 'area' || drawnAs === 'scatter')}
415
+ <div class="flex items-center gap-2">
416
+ <label for="{idPrefix}-series-marker" class="{chartLabelClass} w-20 shrink-0">Marker</label>
417
+ <select
418
+ id="{idPrefix}-series-marker"
419
+ class={chartInputClass}
420
+ value={series.marker ?? ''}
421
+ data-option="series.marker"
422
+ onchange={(e) => controller.updateSeries(series.id, { marker: (e.currentTarget.value || null) as ChartMarker | null })}
423
+ >
424
+ <option value="">Default</option>
425
+ {#each CHART_MARKERS as m (m)}
426
+ <option value={m}>{cap(m)}</option>
427
+ {/each}
428
+ </select>
429
+ </div>
430
+ {/if}
431
+ {#if chartSupportsTrendlines(spec.type, spec.stacking)}
432
+ <div class="space-y-1" data-section="trendlines">
433
+ {#each series.trendlines ?? [] as t, i (i)}
434
+ <div class="flex items-center gap-1" data-trendline={i}>
435
+ <span class="flex-1 truncate text-muted-foreground">{chartTrendlineName(t, series.name)}</span>
436
+ {@render toggle('R²', `trendline.${i}.showR2`, !!t.showR2, (showR2) => controller.updateTrendline(series.id, i, { showR2 }))}
437
+ <button type="button" class={chartButtonClass} aria-label="Delete trendline" data-action="trendline-delete" onclick={() => controller.removeTrendline(series.id, i)}>×</button>
438
+ </div>
439
+ {/each}
440
+ <select
441
+ class={chartInputClass}
442
+ value=""
443
+ aria-label="Add trendline"
444
+ data-option="trendline.add"
445
+ onchange={(e) => e.currentTarget.value && controller.addTrendline(series.id, { type: e.currentTarget.value as ChartTrendlineType })}
446
+ >
447
+ <option value="">Add trendline…</option>
448
+ {#each CHART_TRENDLINE_TYPES as t (t)}
449
+ <option value={t}>{cap(t.replace('-', ' '))}</option>
450
+ {/each}
451
+ </select>
452
+ </div>
453
+ {/if}
300
454
  <div class="flex flex-wrap items-center gap-1">
301
455
  {@render toggle('Hidden', 'series.hidden', !!series.hidden, (hidden) => controller.updateSeries(series.id, { hidden }))}
456
+ {#if family === 'cartesian'}
457
+ {@render toggle('Secondary axis', 'series.axis', series.axis === 'secondary', (secondary) => controller.updateSeries(series.id, { axis: secondary ? 'secondary' : null }))}
458
+ {/if}
302
459
  <span class="flex-1"></span>
303
460
  <button type="button" class={chartButtonClass} disabled={seriesIndex <= 0} aria-label="Move series earlier" data-action="series-up" onclick={() => controller.moveSeries(series.id, seriesIndex - 1)}>↑</button>
304
461
  <button
@@ -1,4 +1,4 @@
1
- export type ChartInspectorSection = 'type' | 'titles' | 'options' | 'legend' | 'axes' | 'series';
1
+ export type ChartInspectorSection = 'type' | 'style' | 'titles' | 'options' | 'legend' | 'axes' | 'series';
2
2
  import { type ChartController } from '@pixerate/editor/chart';
3
3
  interface Props {
4
4
  controller: ChartController;
@@ -1 +1 @@
1
- {"version":3,"file":"ChartInspector.svelte.d.ts","sourceRoot":"","sources":["../../src/chart/ChartInspector.svelte.ts"],"names":[],"mappings":"AAOE,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAGnG,OAAO,EAaH,KAAK,eAAe,EAGrB,MAAM,wBAAwB,CAAC;AAMhC,UAAU,KAAK;IACb,UAAU,EAAE,eAAe,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC5C,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA2OH,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"ChartInspector.svelte.d.ts","sourceRoot":"","sources":["../../src/chart/ChartInspector.svelte.ts"],"names":[],"mappings":"AAOE,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAG7G,OAAO,EAsBH,KAAK,eAAe,EAMrB,MAAM,wBAAwB,CAAC;AAMhC,UAAU,KAAK;IACb,UAAU,EAAE,eAAe,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC5C,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoWH,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -0,0 +1,102 @@
1
+ <script lang="ts">
2
+ import { chartTextBaseline, chartTextTransform, type ChartMark } from '@pixerate/editor/chart';
3
+
4
+ interface Props {
5
+ marks: readonly ChartMark[];
6
+ fontFamily: string;
7
+ /** Marks with targets get a pointer cursor and receive events. */
8
+ interactive?: boolean;
9
+ }
10
+
11
+ let { marks, fontFamily, interactive = false }: Props = $props();
12
+
13
+ const pointerEvents = (mark: ChartMark) => (mark.role === 'selection' || mark.role === 'drag-readout' || (!mark.target && mark.role !== 'background') ? 'none' : undefined);
14
+ const cursor = (mark: ChartMark) => (interactive && mark.target && mark.role !== 'background' ? 'pointer' : undefined);
15
+ </script>
16
+
17
+ {#each marks as mark (mark.key)}
18
+ {#if mark.kind === 'rect'}
19
+ <rect
20
+ data-role={mark.role}
21
+ data-chart-key={mark.target ? mark.key : undefined}
22
+ data-selected={mark.selected ? '' : undefined}
23
+ x={mark.x}
24
+ y={mark.y}
25
+ width={mark.width}
26
+ height={mark.height}
27
+ rx={mark.radius}
28
+ opacity={mark.opacity}
29
+ pointer-events={pointerEvents(mark)}
30
+ cursor={cursor(mark)}
31
+ style:fill={mark.fill}
32
+ style:stroke={mark.stroke}
33
+ style:stroke-width={mark.strokeWidth}
34
+ />
35
+ {:else if mark.kind === 'path'}
36
+ <path
37
+ data-role={mark.role}
38
+ data-chart-key={mark.target ? mark.key : undefined}
39
+ data-selected={mark.selected ? '' : undefined}
40
+ d={mark.d}
41
+ stroke-linejoin="round"
42
+ stroke-linecap="round"
43
+ stroke-dasharray={mark.dash}
44
+ opacity={mark.opacity}
45
+ pointer-events={pointerEvents(mark)}
46
+ cursor={cursor(mark)}
47
+ style:fill={mark.fill ?? 'none'}
48
+ style:stroke={mark.stroke}
49
+ style:stroke-width={mark.strokeWidth}
50
+ />
51
+ {:else if mark.kind === 'circle'}
52
+ <circle
53
+ data-role={mark.role}
54
+ data-chart-key={mark.target ? mark.key : undefined}
55
+ data-selected={mark.selected ? '' : undefined}
56
+ cx={mark.cx}
57
+ cy={mark.cy}
58
+ r={mark.r}
59
+ opacity={mark.opacity}
60
+ pointer-events={pointerEvents(mark)}
61
+ cursor={cursor(mark)}
62
+ style:fill={mark.fill}
63
+ style:stroke={mark.stroke}
64
+ style:stroke-width={mark.strokeWidth}
65
+ />
66
+ {:else if mark.kind === 'line'}
67
+ <line
68
+ data-role={mark.role}
69
+ data-chart-key={mark.target ? mark.key : undefined}
70
+ data-selected={mark.selected ? '' : undefined}
71
+ x1={mark.x1}
72
+ y1={mark.y1}
73
+ x2={mark.x2}
74
+ y2={mark.y2}
75
+ stroke-dasharray={mark.dash}
76
+ opacity={mark.opacity}
77
+ pointer-events={pointerEvents(mark)}
78
+ cursor={cursor(mark)}
79
+ style:stroke={mark.stroke}
80
+ style:stroke-width={mark.strokeWidth}
81
+ />
82
+ {:else}
83
+ <text
84
+ data-role={mark.role}
85
+ data-chart-key={mark.target ? mark.key : undefined}
86
+ data-selected={mark.selected ? '' : undefined}
87
+ x={mark.x}
88
+ y={mark.y}
89
+ text-anchor={mark.anchor}
90
+ dominant-baseline={chartTextBaseline(mark.baseline)}
91
+ transform={chartTextTransform(mark)}
92
+ opacity={mark.opacity}
93
+ pointer-events={pointerEvents(mark)}
94
+ cursor={cursor(mark)}
95
+ style:fill={mark.fill}
96
+ style:font-size="{mark.size}px"
97
+ style:font-weight={mark.weight}
98
+ style:font-family={fontFamily}
99
+ style:user-select="none">{mark.text}</text
100
+ >
101
+ {/if}
102
+ {/each}
@@ -0,0 +1,11 @@
1
+ import { type ChartMark } from '@pixerate/editor/chart';
2
+ interface Props {
3
+ marks: readonly ChartMark[];
4
+ fontFamily: string;
5
+ /** Marks with targets get a pointer cursor and receive events. */
6
+ interactive?: boolean;
7
+ }
8
+ declare const ChartMarks: import("svelte").Component<Props, {}, "">;
9
+ type ChartMarks = ReturnType<typeof ChartMarks>;
10
+ export default ChartMarks;
11
+ //# sourceMappingURL=ChartMarks.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartMarks.svelte.d.ts","sourceRoot":"","sources":["../../src/chart/ChartMarks.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAyC,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAG7F,UAAU,KAAK;IACb,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AA2BH,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
@@ -0,0 +1,30 @@
1
+ <script lang="ts">
2
+ import type { ChartPresence, ChartPresenceState } from '@pixerate/editor/chart';
3
+
4
+ interface Props {
5
+ /** Agent cursors to draw (see `ChartDirector`). */
6
+ presence: ChartPresence;
7
+ }
8
+
9
+ let { presence }: Props = $props();
10
+
11
+ let current: ChartPresenceState = $state.raw({ actors: [] });
12
+ $effect(() => {
13
+ current = presence.getState();
14
+ return presence.subscribe((next) => {
15
+ current = next;
16
+ });
17
+ });
18
+ </script>
19
+
20
+ <g data-chart-presence="" pointer-events="none">
21
+ {#each current.actors as a (a.id)}
22
+ <g transform="translate({a.x} {a.y})" data-actor={a.id}>
23
+ <path d="M0,0 L0,14 L4,10.5 L7,17 L9.5,16 L6.5,9.5 L11.5,9.5 Z" style:fill={a.color} style:stroke="#ffffff" style:stroke-width="1" transform={a.pressed ? 'scale(0.9)' : undefined} />
24
+ <g transform="translate(13 16)">
25
+ <rect x="0" y="0" rx="4" height="18" width={Math.max(28, (a.message ?? a.name).length * 6.4 + 12)} style:fill={a.color} />
26
+ <text x="6" y="9" dominant-baseline="central" style:fill="#ffffff" style:font-size="11px" style:font-weight="600" style:font-family="inherit">{a.message ?? a.name}</text>
27
+ </g>
28
+ </g>
29
+ {/each}
30
+ </g>
@@ -0,0 +1,9 @@
1
+ import type { ChartPresence } from '@pixerate/editor/chart';
2
+ interface Props {
3
+ /** Agent cursors to draw (see `ChartDirector`). */
4
+ presence: ChartPresence;
5
+ }
6
+ declare const ChartPresenceLayer: import("svelte").Component<Props, {}, "">;
7
+ type ChartPresenceLayer = ReturnType<typeof ChartPresenceLayer>;
8
+ export default ChartPresenceLayer;
9
+ //# sourceMappingURL=ChartPresenceLayer.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartPresenceLayer.svelte.d.ts","sourceRoot":"","sources":["../../src/chart/ChartPresenceLayer.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAsB,MAAM,wBAAwB,CAAC;AAG9E,UAAU,KAAK;IACb,mDAAmD;IACnD,QAAQ,EAAE,aAAa,CAAC;CACzB;AA8BH,QAAA,MAAM,kBAAkB,2CAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import type { ChartScene } from '@pixerate/editor/chart';
3
+ import ChartMarks from './ChartMarks.svelte';
4
+
5
+ interface Props {
6
+ /** A laid-out scene (`layoutChart`, `layoutSparkline`, `blendChartScenes`). */
7
+ scene: ChartScene;
8
+ label?: string;
9
+ class?: string;
10
+ }
11
+
12
+ let { scene, label, class: className = '' }: Props = $props();
13
+ </script>
14
+
15
+ <svg width={scene.width} height={scene.height} viewBox="0 0 {scene.width} {scene.height}" role="img" aria-label={label} class="block max-w-full {className}">
16
+ <ChartMarks marks={scene.marks} fontFamily={scene.theme.fontFamily} />
17
+ </svg>
@@ -0,0 +1,11 @@
1
+ import type { ChartScene } from '@pixerate/editor/chart';
2
+ interface Props {
3
+ /** A laid-out scene (`layoutChart`, `layoutSparkline`, `blendChartScenes`). */
4
+ scene: ChartScene;
5
+ label?: string;
6
+ class?: string;
7
+ }
8
+ declare const ChartSceneSvg: import("svelte").Component<Props, {}, "">;
9
+ type ChartSceneSvg = ReturnType<typeof ChartSceneSvg>;
10
+ export default ChartSceneSvg;
11
+ //# sourceMappingURL=ChartSceneSvg.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartSceneSvg.svelte.d.ts","sourceRoot":"","sources":["../../src/chart/ChartSceneSvg.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAIvD,UAAU,KAAK;IACb,+EAA+E;IAC/E,KAAK,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAeH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -0,0 +1,27 @@
1
+ <script lang="ts">
2
+ import { layoutSparkline, type ChartSparklineKind, type ChartValue } from '@pixerate/editor/chart';
3
+ import ChartSceneSvg from './ChartSceneSvg.svelte';
4
+
5
+ interface Props {
6
+ values: readonly ChartValue[];
7
+ kind?: ChartSparklineKind;
8
+ width?: number;
9
+ height?: number;
10
+ color?: string;
11
+ negativeColor?: string;
12
+ markers?: boolean;
13
+ highLow?: boolean;
14
+ min?: number;
15
+ max?: number;
16
+ /** Accessible label (default: first and last value). */
17
+ label?: string;
18
+ class?: string;
19
+ }
20
+
21
+ let { values, kind = 'line', width = 80, height = 20, color, negativeColor, markers, highLow, min, max, label, class: className = '' }: Props = $props();
22
+
23
+ const scene = $derived(layoutSparkline(values, { kind, width, height, color, negativeColor, markers, highLow, min, max }));
24
+ const present = $derived(values.filter((v): v is number => v !== null));
25
+ </script>
26
+
27
+ <ChartSceneSvg {scene} label={label ?? (present.length ? `Trend from ${present[0]} to ${present[present.length - 1]}` : 'No data')} class="inline-block align-middle {className}" />
@@ -0,0 +1,20 @@
1
+ import { type ChartSparklineKind, type ChartValue } from '@pixerate/editor/chart';
2
+ interface Props {
3
+ values: readonly ChartValue[];
4
+ kind?: ChartSparklineKind;
5
+ width?: number;
6
+ height?: number;
7
+ color?: string;
8
+ negativeColor?: string;
9
+ markers?: boolean;
10
+ highLow?: boolean;
11
+ min?: number;
12
+ max?: number;
13
+ /** Accessible label (default: first and last value). */
14
+ label?: string;
15
+ class?: string;
16
+ }
17
+ declare const ChartSparkline: import("svelte").Component<Props, {}, "">;
18
+ type ChartSparkline = ReturnType<typeof ChartSparkline>;
19
+ export default ChartSparkline;
20
+ //# sourceMappingURL=ChartSparkline.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartSparkline.svelte.d.ts","sourceRoot":"","sources":["../../src/chart/ChartSparkline.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,KAAK,kBAAkB,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAIjG,UAAU,KAAK;IACb,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE,kBAAkB,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgBH,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -0,0 +1,92 @@
1
+ <script lang="ts">
2
+ import { onDestroy, untrack } from 'svelte';
3
+ import {
4
+ CSS_VARIABLE_CHART_THEME,
5
+ ChartStream,
6
+ blendChartScenes,
7
+ easeChartTween,
8
+ layoutChart,
9
+ type ChartIssue,
10
+ type ChartScene,
11
+ type ChartStreamFormat,
12
+ type ChartTheme
13
+ } from '@pixerate/editor/chart';
14
+ import type { Snippet } from 'svelte';
15
+ import ChartSceneSvg from './ChartSceneSvg.svelte';
16
+
17
+ interface Props {
18
+ /** Mermaid (xychart-beta, pie, radar-beta) or a JSON chart spec, as far as it has arrived. */
19
+ source: string;
20
+ /** Nothing more will arrive: the final chart is drawn at once and problems are reported. */
21
+ complete?: boolean;
22
+ format?: ChartStreamFormat;
23
+ width?: number;
24
+ height?: number;
25
+ theme?: Partial<ChartTheme>;
26
+ /** How often a new layout is adopted while streaming (ms, default 300). */
27
+ adoptInterval?: number;
28
+ /** Tween length between layouts (ms, default 450; 0 to switch at once). */
29
+ tween?: number;
30
+ /** Shown before anything can be drawn. */
31
+ placeholder?: Snippet;
32
+ /** Called with the parse problems once `complete`. */
33
+ onissues?: (issues: ChartIssue[]) => void;
34
+ class?: string;
35
+ }
36
+
37
+ let { source, complete = false, format = 'auto', width = 640, height = 360, theme, adoptInterval = 300, tween = 450, placeholder, onissues, class: className = '' }: Props = $props();
38
+
39
+ const stream = $derived(new ChartStream(format));
40
+ const fullTheme = $derived({ ...CSS_VARIABLE_CHART_THEME, ...theme });
41
+ let scene: ChartScene | null = $state.raw(null);
42
+ let lastAdopt = 0;
43
+ let frame: number | null = null;
44
+ let pending: ReturnType<typeof setTimeout> | null = null;
45
+
46
+ function adopt(src: string, done: boolean) {
47
+ const read = stream.update(src, done);
48
+ if (done) onissues?.(read.issues);
49
+ if (!read.spec) return;
50
+ const next = layoutChart(read.spec, { width, height, theme: fullTheme, valueDomain: read.valueDomain });
51
+ const from = untrack(() => scene);
52
+ lastAdopt = Date.now();
53
+ if (frame !== null) cancelAnimationFrame(frame);
54
+ if (!from || tween <= 0 || typeof requestAnimationFrame === 'undefined') {
55
+ scene = next;
56
+ return;
57
+ }
58
+ const start = performance.now();
59
+ const step = () => {
60
+ const t = easeChartTween((performance.now() - start) / tween);
61
+ scene = blendChartScenes(from, next, t);
62
+ frame = t < 1 ? requestAnimationFrame(step) : null;
63
+ };
64
+ frame = requestAnimationFrame(step);
65
+ }
66
+
67
+ $effect(() => {
68
+ const src = source;
69
+ const done = complete;
70
+ if (pending) clearTimeout(pending);
71
+ const wait = done ? 0 : Math.max(0, adoptInterval - (Date.now() - lastAdopt));
72
+ if (wait === 0) adopt(src, done);
73
+ else pending = setTimeout(() => adopt(src, done), wait);
74
+ return () => {
75
+ if (pending) clearTimeout(pending);
76
+ };
77
+ });
78
+
79
+ onDestroy(() => {
80
+ if (frame !== null) cancelAnimationFrame(frame);
81
+ });
82
+ </script>
83
+
84
+ <div class={className} data-chart-streaming={complete ? 'complete' : 'streaming'} aria-busy={!complete}>
85
+ {#if scene}
86
+ <ChartSceneSvg {scene} label={complete ? undefined : 'Chart loading'} />
87
+ {:else if placeholder}
88
+ {@render placeholder()}
89
+ {:else}
90
+ <div style:height="{height}px" class="flex items-center justify-center text-xs text-muted-foreground">Drawing chart…</div>
91
+ {/if}
92
+ </div>
@@ -0,0 +1,25 @@
1
+ import { type ChartIssue, type ChartStreamFormat, type ChartTheme } from '@pixerate/editor/chart';
2
+ import type { Snippet } from 'svelte';
3
+ interface Props {
4
+ /** Mermaid (xychart-beta, pie, radar-beta) or a JSON chart spec, as far as it has arrived. */
5
+ source: string;
6
+ /** Nothing more will arrive: the final chart is drawn at once and problems are reported. */
7
+ complete?: boolean;
8
+ format?: ChartStreamFormat;
9
+ width?: number;
10
+ height?: number;
11
+ theme?: Partial<ChartTheme>;
12
+ /** How often a new layout is adopted while streaming (ms, default 300). */
13
+ adoptInterval?: number;
14
+ /** Tween length between layouts (ms, default 450; 0 to switch at once). */
15
+ tween?: number;
16
+ /** Shown before anything can be drawn. */
17
+ placeholder?: Snippet;
18
+ /** Called with the parse problems once `complete`. */
19
+ onissues?: (issues: ChartIssue[]) => void;
20
+ class?: string;
21
+ }
22
+ declare const ChartStreamingView: import("svelte").Component<Props, {}, "">;
23
+ type ChartStreamingView = ReturnType<typeof ChartStreamingView>;
24
+ export default ChartStreamingView;
25
+ //# sourceMappingURL=ChartStreamingView.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChartStreamingView.svelte.d.ts","sourceRoot":"","sources":["../../src/chart/ChartStreamingView.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAMH,KAAK,UAAU,EAEf,KAAK,iBAAiB,EACtB,KAAK,UAAU,EAChB,MAAM,wBAAwB,CAAC;AAClC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAIpC,UAAU,KAAK;IACb,8FAA8F;IAC9F,MAAM,EAAE,MAAM,CAAC;IACf,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5B,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmEH,QAAA,MAAM,kBAAkB,2CAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
@@ -1,4 +1,5 @@
1
- import { ChartController, type ChartActionResult, type ChartCommandOptions, type ChartControllerOptions, type ChartSelection, type ChartSpecPatch, type ChartState, type ChartType } from "@pixerate/editor/chart";
1
+ import type { ToolRegistry } from "@pixerate/editor/tools";
2
+ import { ChartController, ChartDirector, ChartPresence, type ChartScene, type ChartToolProviderOptions, type ChartActionResult, type ChartCommandOptions, type ChartControllerOptions, type ChartSelection, type ChartSpecPatch, type ChartState, type ChartType } from "@pixerate/editor/chart";
2
3
  export interface SvelteChartEditor {
3
4
  readonly controller: ChartController;
4
5
  /** The controller's state (reactive). */
@@ -35,4 +36,27 @@ export interface ChartCommandTarget {
35
36
  * initialisation). Pass a getter to follow a changing registry.
36
37
  */
37
38
  export declare function useChartCommands(registry: ChartCommandTarget | null | undefined | (() => ChartCommandTarget | null | undefined), controller: ChartController, options?: ChartCommandOptions): void;
39
+ /**
40
+ * Registers the chart's agent tools (`createChartToolProvider`) with a `ToolRegistry` for the
41
+ * lifetime of the calling component. Pass a getter to follow a changing registry.
42
+ */
43
+ export declare function useChartToolProvider(registry: ToolRegistry | null | undefined | (() => ToolRegistry | null | undefined), controller: ChartController, options?: ChartToolProviderOptions): void;
44
+ /**
45
+ * A `ChartPresence` and `ChartDirector` for a chart: pass `presence` and `sceneRef` to
46
+ * `ChartCanvas`, and `director` to `useChartToolProvider` so agent edits are acted out with a
47
+ * cursor.
48
+ */
49
+ export declare function createChartDirector(controller: ChartController, options?: {
50
+ speed?: number;
51
+ size?: {
52
+ width: number;
53
+ height: number;
54
+ };
55
+ }): {
56
+ presence: ChartPresence;
57
+ director: ChartDirector;
58
+ sceneRef: {
59
+ current: ChartScene | null;
60
+ };
61
+ };
38
62
  //# sourceMappingURL=createChartEditor.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createChartEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/chart/createChartEditor.svelte.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EAEf,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAClC,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;IAC1C,MAAM,CAAC,KAAK,EAAE,cAAc,GAAG,iBAAiB,CAAC;IACjD,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,iBAAiB,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAAC;IAC7E,MAAM,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAAC;IAC/C,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,yCAAyC;IACzC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,mBAAmB,GAAE,eAAe,GAAG,sBAA2B,GAAG,iBAAiB,CAyBvH;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,eAAe,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAAE,CAgBnG;AAED,0EAA0E;AAC1E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,IAAI,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,MAAM,kBAAkB,GAAG,IAAI,GAAG,SAAS,CAAC,EAC/F,UAAU,EAAE,eAAe,EAC3B,OAAO,GAAE,mBAAwB,GAChC,IAAI,CAMN"}
1
+ {"version":3,"file":"createChartEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/chart/createChartEditor.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EAIb,KAAK,UAAU,EACf,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;IACrC,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAClC,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;IAC1C,MAAM,CAAC,KAAK,EAAE,cAAc,GAAG,iBAAiB,CAAC;IACjD,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,iBAAiB,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAAC;IAC7E,MAAM,CAAC,SAAS,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAAC;IAC/C,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;IACb,yCAAyC;IACzC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,mBAAmB,GAAE,eAAe,GAAG,sBAA2B,GAAG,iBAAiB,CAyBvH;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,eAAe,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAAE,CAgBnG;AAED,0EAA0E;AAC1E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,IAAI,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,MAAM,kBAAkB,GAAG,IAAI,GAAG,SAAS,CAAC,EAC/F,UAAU,EAAE,eAAe,EAC3B,OAAO,GAAE,mBAAwB,GAChC,IAAI,CAMN;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC,EACnF,UAAU,EAAE,eAAe,EAC3B,OAAO,GAAE,wBAA6B,GACrC,IAAI,CAMN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,eAAe,EAAE,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAO;;;;iBAC9G,UAAU,GAAG,IAAI;;EAK7C"}
@@ -1,5 +1,5 @@
1
1
  import { untrack } from "svelte";
2
- import { ChartController, createChartCommands, } from "@pixerate/editor/chart";
2
+ import { ChartController, ChartDirector, ChartPresence, createChartCommands, createChartToolProvider, layoutChart, } from "@pixerate/editor/chart";
3
3
  /**
4
4
  * Svelte 5 rune: subscribes to a `ChartController` (or creates one from options) and
5
5
  * exposes its state reactively with bound actions.
@@ -59,3 +59,27 @@ export function useChartCommands(registry, controller, options = {}) {
59
59
  return target.register(createChartCommands(controller, options));
60
60
  });
61
61
  }
62
+ /**
63
+ * Registers the chart's agent tools (`createChartToolProvider`) with a `ToolRegistry` for the
64
+ * lifetime of the calling component. Pass a getter to follow a changing registry.
65
+ */
66
+ export function useChartToolProvider(registry, controller, options = {}) {
67
+ $effect(() => {
68
+ const target = typeof registry === "function" ? registry() : registry;
69
+ if (!target)
70
+ return;
71
+ return target.register(createChartToolProvider(controller, options));
72
+ });
73
+ }
74
+ /**
75
+ * A `ChartPresence` and `ChartDirector` for a chart: pass `presence` and `sceneRef` to
76
+ * `ChartCanvas`, and `director` to `useChartToolProvider` so agent edits are acted out with a
77
+ * cursor.
78
+ */
79
+ export function createChartDirector(controller, options = {}) {
80
+ const sceneRef = { current: null };
81
+ const presence = new ChartPresence();
82
+ const size = options.size ?? { width: 640, height: 400 };
83
+ const director = new ChartDirector(controller, presence, { scene: () => sceneRef.current ?? layoutChart(controller.getSpec(), size), speed: options.speed });
84
+ return { presence, director, sceneRef };
85
+ }
@@ -3,11 +3,18 @@ import type ChartCanvasComponent from "./ChartCanvas.svelte";
3
3
  import type ChartDataGridComponent from "./ChartDataGrid.svelte";
4
4
  import type ChartEditorComponent from "./ChartEditor.svelte";
5
5
  import type ChartInspectorComponent from "./ChartInspector.svelte";
6
+ import type ChartStreamingViewComponent from "./ChartStreamingView.svelte";
7
+ import type ChartSparklineComponent from "./ChartSparkline.svelte";
6
8
  export { default as ChartEditor } from "./ChartEditor.svelte";
7
9
  export { default as ChartCanvas } from "./ChartCanvas.svelte";
8
10
  export { default as ChartDataGrid } from "./ChartDataGrid.svelte";
9
11
  export { default as ChartInspector } from "./ChartInspector.svelte";
10
12
  export { default as ChartCommitInput } from "./ChartCommitInput.svelte";
13
+ export { default as ChartMarks } from "./ChartMarks.svelte";
14
+ export { default as ChartSceneSvg } from "./ChartSceneSvg.svelte";
15
+ export { default as ChartPresenceLayer } from "./ChartPresenceLayer.svelte";
16
+ export { default as ChartStreamingView } from "./ChartStreamingView.svelte";
17
+ export { default as ChartSparkline } from "./ChartSparkline.svelte";
11
18
  export type { ChartInspectorSection } from "./ChartInspector.svelte";
12
19
  export * from "./createChartEditor.svelte.js";
13
20
  export * from "./styles.js";
@@ -15,4 +22,6 @@ export type ChartCanvasProps = ComponentProps<typeof ChartCanvasComponent>;
15
22
  export type ChartDataGridProps = ComponentProps<typeof ChartDataGridComponent>;
16
23
  export type ChartEditorProps = ComponentProps<typeof ChartEditorComponent>;
17
24
  export type ChartInspectorProps = ComponentProps<typeof ChartInspectorComponent>;
25
+ export type ChartStreamingViewProps = ComponentProps<typeof ChartStreamingViewComponent>;
26
+ export type ChartSparklineProps = ComponentProps<typeof ChartSparklineComponent>;
18
27
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/chart/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,uBAAuB,MAAM,yBAAyB,CAAC;AAEnE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,YAAY,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACrE,cAAc,+BAA+B,CAAC;AAC9C,cAAc,aAAa,CAAC;AAE5B,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/chart/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,uBAAuB,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,2BAA2B,MAAM,6BAA6B,CAAC;AAC3E,OAAO,KAAK,uBAAuB,MAAM,yBAAyB,CAAC;AAEnE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,YAAY,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACrE,cAAc,+BAA+B,CAAC;AAC9C,cAAc,aAAa,CAAC;AAE5B,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACjF,MAAM,MAAM,uBAAuB,GAAG,cAAc,CAAC,OAAO,2BAA2B,CAAC,CAAC;AACzF,MAAM,MAAM,mBAAmB,GAAG,cAAc,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
@@ -3,5 +3,10 @@ export { default as ChartCanvas } from "./ChartCanvas.svelte";
3
3
  export { default as ChartDataGrid } from "./ChartDataGrid.svelte";
4
4
  export { default as ChartInspector } from "./ChartInspector.svelte";
5
5
  export { default as ChartCommitInput } from "./ChartCommitInput.svelte";
6
+ export { default as ChartMarks } from "./ChartMarks.svelte";
7
+ export { default as ChartSceneSvg } from "./ChartSceneSvg.svelte";
8
+ export { default as ChartPresenceLayer } from "./ChartPresenceLayer.svelte";
9
+ export { default as ChartStreamingView } from "./ChartStreamingView.svelte";
10
+ export { default as ChartSparkline } from "./ChartSparkline.svelte";
6
11
  export * from "./createChartEditor.svelte.js";
7
12
  export * from "./styles.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor-svelte",
3
- "version": "0.42.0",
3
+ "version": "0.43.0",
4
4
  "description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -115,14 +115,14 @@
115
115
  "@tiptap/extension-bubble-menu": "^2.11.5",
116
116
  "@tiptap/extension-placeholder": "^2.11.5",
117
117
  "@tiptap/starter-kit": "^2.11.5",
118
- "@pixerate/editor": "0.46.0"
118
+ "@pixerate/editor": "0.47.0"
119
119
  },
120
120
  "peerDependencies": {
121
121
  "@dagrejs/dagre": "^1.1.4",
122
122
  "@tiptap/core": "^2.11.5",
123
123
  "@tiptap/pm": "^2.11.5",
124
124
  "@xyflow/svelte": "^1.6.0",
125
- "svelte": "^5.0.0"
125
+ "svelte": "^5.57.2"
126
126
  },
127
127
  "peerDependenciesMeta": {
128
128
  "@dagrejs/dagre": {
@@ -139,8 +139,8 @@
139
139
  "@tiptap/core": "^2.11.5",
140
140
  "@tiptap/pm": "^2.11.5",
141
141
  "@types/dagre": "^0.7.52",
142
- "@xyflow/svelte": "^1.6.6",
143
- "svelte": "^5.0.0",
142
+ "@xyflow/svelte": "^1.7.0",
143
+ "svelte": "^5.57.2",
144
144
  "svelte-check": "^4.7.6",
145
145
  "typescript": "^5.7.3",
146
146
  "vitest": "^4.1.11"