@pixerate/editor-svelte 0.127.1 → 0.128.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/chart/ChartCanvas.svelte +54 -4
- package/dist/chart/ChartCanvas.svelte.d.ts +6 -1
- package/package.json +23 -5
package/README.md
CHANGED
|
@@ -4,6 +4,9 @@ Svelte 5 bindings for [`@pixerate/editor`](https://www.npmjs.com/package/@pixera
|
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm install @pixerate/editor-svelte @pixerate/editor svelte
|
|
7
|
+
# only if you use the rich-text or prompt editors (the root entry): TipTap, and the rich-text peers
|
|
8
|
+
# listed in the @pixerate/editor README
|
|
9
|
+
npm install @tiptap/extension-bubble-menu @tiptap/core @tiptap/pm @tiptap/starter-kit @tiptap/extension-placeholder
|
|
7
10
|
# only if you use @pixerate/editor-svelte/canvas:
|
|
8
11
|
npm install @xyflow/svelte @dagrejs/dagre
|
|
9
12
|
```
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { onDestroy } from 'svelte';
|
|
2
|
+
import { onDestroy, type Snippet } from 'svelte';
|
|
3
3
|
import {
|
|
4
4
|
CSS_VARIABLE_CHART_THEME,
|
|
5
5
|
chartClientToScene,
|
|
6
|
+
chartTooltipAt,
|
|
7
|
+
sameChartTooltip,
|
|
6
8
|
describeChartSelection,
|
|
7
9
|
handleChartKey,
|
|
8
10
|
layoutChart,
|
|
@@ -12,7 +14,9 @@
|
|
|
12
14
|
type ChartPresence,
|
|
13
15
|
type ChartScene,
|
|
14
16
|
type ChartTextMeasure,
|
|
15
|
-
type ChartTheme
|
|
17
|
+
type ChartTheme,
|
|
18
|
+
type ChartTooltip,
|
|
19
|
+
type ChartTooltipMode
|
|
16
20
|
} from '@pixerate/editor/chart';
|
|
17
21
|
import { chartStateOf } from './createChartEditor.svelte.js';
|
|
18
22
|
import ChartMarks from './ChartMarks.svelte';
|
|
@@ -38,6 +42,10 @@
|
|
|
38
42
|
presence?: ChartPresence;
|
|
39
43
|
/** Receives the scene as drawn (e.g. for `ChartDirector`'s `scene`). */
|
|
40
44
|
sceneRef?: { current: ChartScene | null };
|
|
45
|
+
/** Show a tooltip on hover: `point` (or `true`) for the bar, point or slice under the pointer, `category` for every series in the category under it (default off). */
|
|
46
|
+
tooltip?: boolean | ChartTooltipMode;
|
|
47
|
+
/** Draws the tooltip's content instead of the category label and one row per series. */
|
|
48
|
+
tooltipContent?: Snippet<[ChartTooltip]>;
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
let {
|
|
@@ -51,7 +59,9 @@
|
|
|
51
59
|
emptyMessage,
|
|
52
60
|
class: className = '',
|
|
53
61
|
presence,
|
|
54
|
-
sceneRef
|
|
62
|
+
sceneRef,
|
|
63
|
+
tooltip = false,
|
|
64
|
+
tooltipContent
|
|
55
65
|
}: Props = $props();
|
|
56
66
|
|
|
57
67
|
const view = chartStateOf(() => controller);
|
|
@@ -94,6 +104,10 @@
|
|
|
94
104
|
$effect(() => {
|
|
95
105
|
if (sceneRef) sceneRef.current = scene;
|
|
96
106
|
});
|
|
107
|
+
const tooltipMode = $derived<ChartTooltipMode | null>(tooltip === true ? 'point' : tooltip || null);
|
|
108
|
+
let tip = $state.raw<ChartTooltip | null>(null);
|
|
109
|
+
// In wrapper pixels; `flip` puts the tooltip left of the pointer near the right edge.
|
|
110
|
+
let tipAt = $state({ left: 0, top: 0, flip: false });
|
|
97
111
|
const byKey = $derived(new Map(scene.marks.map((m) => [m.key, m])));
|
|
98
112
|
const label = $derived(view.current.spec.title || 'Chart');
|
|
99
113
|
|
|
@@ -108,12 +122,26 @@
|
|
|
108
122
|
controller.select(target ?? null);
|
|
109
123
|
drag = startChartPointDrag(controller, scene, target, scenePoint(e));
|
|
110
124
|
if (drag) {
|
|
125
|
+
tip = null;
|
|
111
126
|
frozen = { valueDomain: drag.valueDomain, valueDomain2: drag.valueDomain2 ?? null, xDomain: drag.xDomain ?? null, readout: drag.target };
|
|
112
127
|
svg?.setPointerCapture?.(e.pointerId);
|
|
113
128
|
}
|
|
114
129
|
}
|
|
115
130
|
function pointermove(e: PointerEvent) {
|
|
116
131
|
drag?.move(scenePoint(e), { fine: e.altKey, lockAxis: e.shiftKey, noSnap: e.ctrlKey || e.metaKey });
|
|
132
|
+
hover(e);
|
|
133
|
+
}
|
|
134
|
+
function hover(e: PointerEvent) {
|
|
135
|
+
if (!tooltipMode || drag || !wrapper) {
|
|
136
|
+
tip = null;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const next = chartTooltipAt(view.current.spec, scene, scenePoint(e), { mode: tooltipMode, measureText });
|
|
140
|
+
if (!sameChartTooltip(tip, next)) tip = next;
|
|
141
|
+
if (!next) return;
|
|
142
|
+
const box = wrapper.getBoundingClientRect();
|
|
143
|
+
const left = e.clientX - box.left;
|
|
144
|
+
tipAt = { left, top: e.clientY - box.top, flip: left > box.width * 0.6 };
|
|
117
145
|
}
|
|
118
146
|
function endDrag() {
|
|
119
147
|
drag?.end();
|
|
@@ -132,7 +160,7 @@
|
|
|
132
160
|
}
|
|
133
161
|
</script>
|
|
134
162
|
|
|
135
|
-
<div bind:this={wrapper} class="w-full {className}" data-chart-canvas="">
|
|
163
|
+
<div bind:this={wrapper} class="relative w-full {className}" data-chart-canvas="">
|
|
136
164
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex, a11y_no_noninteractive_element_interactions -->
|
|
137
165
|
<svg
|
|
138
166
|
bind:this={svg}
|
|
@@ -147,9 +175,31 @@
|
|
|
147
175
|
onpointermove={pointermove}
|
|
148
176
|
onpointerup={endDrag}
|
|
149
177
|
onpointercancel={endDrag}
|
|
178
|
+
onpointerleave={() => (tip = null)}
|
|
150
179
|
onkeydown={keydown}
|
|
151
180
|
>
|
|
152
181
|
<ChartMarks marks={scene.marks} fontFamily={scene.theme.fontFamily} interactive={editable} />
|
|
153
182
|
{#if presence}<ChartPresenceLayer {presence} />{/if}
|
|
154
183
|
</svg>
|
|
184
|
+
{#if tip}
|
|
185
|
+
<div
|
|
186
|
+
role="tooltip"
|
|
187
|
+
data-chart-tooltip=""
|
|
188
|
+
class="pointer-events-none absolute z-10 min-w-32 rounded-md border px-2.5 py-1.5 text-xs shadow-md"
|
|
189
|
+
style="left: {tipAt.left}px; top: {tipAt.top}px; transform: translate({tipAt.flip ? 'calc(-100% - 12px)' : '12px'}, calc(-100% - 8px)); background: var(--popover, #ffffff); color: var(--popover-foreground, #0f172a); border-color: var(--border, #e2e8f0); font-family: {scene.theme.fontFamily};"
|
|
190
|
+
>
|
|
191
|
+
{#if tooltipContent}
|
|
192
|
+
{@render tooltipContent(tip)}
|
|
193
|
+
{:else}
|
|
194
|
+
{#if tip.title}<div class="mb-1 font-medium">{tip.title}</div>{/if}
|
|
195
|
+
{#each tip.items as item (item.seriesId)}
|
|
196
|
+
<div class="flex items-center gap-2">
|
|
197
|
+
<span class="h-2 w-2 shrink-0 rounded-full" style="background: {item.color}"></span>
|
|
198
|
+
<span style="color: var(--muted-foreground, #64748b)">{item.name}</span>
|
|
199
|
+
<span class="ml-auto pl-3 font-medium tabular-nums">{item.text}</span>
|
|
200
|
+
</div>
|
|
201
|
+
{/each}
|
|
202
|
+
{/if}
|
|
203
|
+
</div>
|
|
204
|
+
{/if}
|
|
155
205
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
import { type ChartController, type ChartPresence, type ChartScene, type ChartTextMeasure, type ChartTheme, type ChartTooltip, type ChartTooltipMode } from '@pixerate/editor/chart';
|
|
2
3
|
interface Props {
|
|
3
4
|
controller: ChartController;
|
|
4
5
|
/** Scene width; with `responsive` this is only the fallback before the container is measured (default 640). */
|
|
@@ -21,6 +22,10 @@ interface Props {
|
|
|
21
22
|
sceneRef?: {
|
|
22
23
|
current: ChartScene | null;
|
|
23
24
|
};
|
|
25
|
+
/** Show a tooltip on hover: `point` (or `true`) for the bar, point or slice under the pointer, `category` for every series in the category under it (default off). */
|
|
26
|
+
tooltip?: boolean | ChartTooltipMode;
|
|
27
|
+
/** Draws the tooltip's content instead of the category label and one row per series. */
|
|
28
|
+
tooltipContent?: Snippet<[ChartTooltip]>;
|
|
24
29
|
}
|
|
25
30
|
declare const ChartCanvas: import("svelte").Component<Props, {}, "">;
|
|
26
31
|
type ChartCanvas = ReturnType<typeof ChartCanvas>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.128.0",
|
|
4
4
|
"description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -165,15 +165,15 @@
|
|
|
165
165
|
"**/*.css"
|
|
166
166
|
],
|
|
167
167
|
"dependencies": {
|
|
168
|
-
"@
|
|
169
|
-
"@tiptap/extension-placeholder": "^2.27.3",
|
|
170
|
-
"@tiptap/starter-kit": "^2.27.3",
|
|
171
|
-
"@pixerate/editor": "0.171.0"
|
|
168
|
+
"@pixerate/editor": "0.172.0"
|
|
172
169
|
},
|
|
173
170
|
"peerDependencies": {
|
|
174
171
|
"@dagrejs/dagre": "^1.1.4",
|
|
175
172
|
"@tiptap/core": "^2.27.3",
|
|
173
|
+
"@tiptap/extension-bubble-menu": "^2.27.3",
|
|
174
|
+
"@tiptap/extension-placeholder": "^2.27.3",
|
|
176
175
|
"@tiptap/pm": "^2.27.3",
|
|
176
|
+
"@tiptap/starter-kit": "^2.27.3",
|
|
177
177
|
"@xyflow/svelte": "^1.6.0",
|
|
178
178
|
"svelte": "^5.57.2"
|
|
179
179
|
},
|
|
@@ -181,6 +181,21 @@
|
|
|
181
181
|
"@dagrejs/dagre": {
|
|
182
182
|
"optional": true
|
|
183
183
|
},
|
|
184
|
+
"@tiptap/core": {
|
|
185
|
+
"optional": true
|
|
186
|
+
},
|
|
187
|
+
"@tiptap/extension-bubble-menu": {
|
|
188
|
+
"optional": true
|
|
189
|
+
},
|
|
190
|
+
"@tiptap/extension-placeholder": {
|
|
191
|
+
"optional": true
|
|
192
|
+
},
|
|
193
|
+
"@tiptap/pm": {
|
|
194
|
+
"optional": true
|
|
195
|
+
},
|
|
196
|
+
"@tiptap/starter-kit": {
|
|
197
|
+
"optional": true
|
|
198
|
+
},
|
|
184
199
|
"@xyflow/svelte": {
|
|
185
200
|
"optional": true
|
|
186
201
|
}
|
|
@@ -190,7 +205,10 @@
|
|
|
190
205
|
"@sveltejs/package": "^3.0.1",
|
|
191
206
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
|
192
207
|
"@tiptap/core": "^2.27.3",
|
|
208
|
+
"@tiptap/extension-bubble-menu": "^2.27.3",
|
|
209
|
+
"@tiptap/extension-placeholder": "^2.27.3",
|
|
193
210
|
"@tiptap/pm": "^2.27.3",
|
|
211
|
+
"@tiptap/starter-kit": "^2.27.3",
|
|
194
212
|
"@types/dagre": "^0.7.52",
|
|
195
213
|
"@xyflow/svelte": "^1.7.0",
|
|
196
214
|
"svelte": "^5.57.2",
|