@joewinke/jatui 0.26.0 → 0.27.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/CLAUDE.md +106 -1
- package/dist/actions/keyboardScope.d.ts +58 -0
- package/dist/actions/keyboardScope.js +110 -0
- package/dist/actions/listNav.d.ts +48 -3
- package/dist/actions/listNav.js +267 -77
- package/dist/actions/longpress.d.ts +37 -0
- package/dist/actions/longpress.js +105 -0
- package/dist/actions/stickToBottom.d.ts +66 -0
- package/dist/actions/stickToBottom.js +155 -0
- package/dist/actions/swipe.d.ts +64 -0
- package/dist/actions/swipe.js +179 -0
- package/dist/components/BottomSheet.svelte +280 -0
- package/dist/components/BottomSheet.svelte.d.ts +27 -0
- package/dist/components/ConfirmDialog.svelte +21 -0
- package/dist/components/ConfirmDialog.svelte.d.ts +11 -1
- package/dist/components/ConfirmModal.svelte +15 -0
- package/dist/components/ConfirmModal.svelte.d.ts +5 -0
- package/dist/components/Drawer.svelte +18 -1
- package/dist/components/Drawer.svelte.d.ts +9 -1
- package/dist/components/InputDialog.svelte +21 -0
- package/dist/components/InputDialog.svelte.d.ts +11 -1
- package/dist/components/Modal.svelte +18 -1
- package/dist/components/Modal.svelte.d.ts +8 -0
- package/dist/components/basic/Empty.svelte +173 -9
- package/dist/components/basic/Empty.svelte.d.ts +50 -1
- package/dist/components/basic/ErrorState.svelte +128 -0
- package/dist/components/basic/ErrorState.svelte.d.ts +46 -0
- package/dist/components/basic/JumpToLatest.svelte +60 -0
- package/dist/components/basic/JumpToLatest.svelte.d.ts +9 -0
- package/dist/components/basic/PageHeader.svelte +216 -0
- package/dist/components/basic/PageHeader.svelte.d.ts +52 -0
- package/dist/components/basic/ProgressButton.svelte +221 -0
- package/dist/components/basic/ProgressButton.svelte.d.ts +63 -0
- package/dist/components/graph/GraphApiBridge.svelte +36 -0
- package/dist/components/graph/GraphApiBridge.svelte.d.ts +9 -0
- package/dist/components/graph/GraphCanvas.svelte +212 -27
- package/dist/components/graph/GraphCanvas.svelte.d.ts +113 -19
- package/dist/components/graph/api.d.ts +52 -0
- package/dist/components/graph/api.js +66 -0
- package/dist/components/graph/index.d.ts +2 -0
- package/dist/components/graph/index.js +1 -0
- package/dist/components/graph/theme.js +13 -0
- package/dist/components/messaging/MessageItem.svelte +5 -0
- package/dist/components/messaging/MessageItem.svelte.d.ts +7 -0
- package/dist/components/table/DataTable.svelte +452 -78
- package/dist/components/table/DataTable.svelte.d.ts +2 -2
- package/dist/components/table/ManageColumnsDropdown.svelte +466 -0
- package/dist/components/table/ManageColumnsDropdown.svelte.d.ts +26 -0
- package/dist/components/table/columnStorage.d.ts +29 -0
- package/dist/components/table/columnStorage.js +61 -0
- package/dist/components/table/groupRows.d.ts +72 -0
- package/dist/components/table/groupRows.js +118 -0
- package/dist/components/table/index.d.ts +7 -1
- package/dist/components/table/index.js +3 -0
- package/dist/components/table/types.d.ts +121 -20
- package/dist/index.d.ts +25 -2
- package/dist/index.js +32 -1
- package/dist/utils/ansiToHtml.d.ts +83 -0
- package/dist/utils/ansiToHtml.js +543 -0
- package/dist/utils/keyboardShortcutRegistry.d.ts +332 -11
- package/dist/utils/keyboardShortcutRegistry.js +1070 -76
- package/dist/utils/pollBackoff.d.ts +83 -0
- package/dist/utils/pollBackoff.js +151 -0
- package/dist/utils/snapFlick.d.ts +59 -0
- package/dist/utils/snapFlick.js +66 -0
- package/dist/video/advisors/qr.d.ts +1 -1
- package/dist/virtual/createRowWindow.d.ts +75 -0
- package/dist/virtual/createRowWindow.js +129 -0
- package/dist/virtual/index.d.ts +4 -0
- package/dist/virtual/index.js +5 -0
- package/dist/virtual/rowWindowCore.d.ts +202 -0
- package/dist/virtual/rowWindowCore.js +510 -0
- package/package.json +11 -1
|
@@ -1,27 +1,117 @@
|
|
|
1
|
-
<script lang="ts">
|
|
1
|
+
<script lang="ts" generics="N extends Node = Node, E extends Edge = Edge">
|
|
2
2
|
import '@xyflow/svelte/dist/style.css'
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
SvelteFlow,
|
|
6
|
+
Background,
|
|
7
|
+
Controls,
|
|
8
|
+
MiniMap,
|
|
9
|
+
type Node,
|
|
10
|
+
type Edge,
|
|
11
|
+
type NodeTypes,
|
|
12
|
+
type EdgeTypes,
|
|
13
|
+
type DefaultEdgeOptions,
|
|
14
|
+
type Viewport,
|
|
15
|
+
type FitViewOptions,
|
|
16
|
+
type SnapGrid,
|
|
17
|
+
type ConnectionMode,
|
|
18
|
+
type MiniMapProps,
|
|
19
|
+
type BackgroundProps,
|
|
20
|
+
type NodeEventWithPointer,
|
|
21
|
+
type NodeEvents,
|
|
22
|
+
type EdgeEvents,
|
|
23
|
+
type PaneEvents,
|
|
24
|
+
type IsValidConnection,
|
|
25
|
+
type OnConnect,
|
|
26
|
+
type OnDelete,
|
|
27
|
+
type OnBeforeDelete,
|
|
28
|
+
type OnSelectionChange,
|
|
29
|
+
type OnMoveEnd,
|
|
30
|
+
type KeyDefinition,
|
|
31
|
+
} from '@xyflow/svelte'
|
|
32
|
+
import type { Snippet } from 'svelte'
|
|
5
33
|
import JatuiNode from './JatuiNode.svelte'
|
|
34
|
+
import GraphApiBridge from './GraphApiBridge.svelte'
|
|
6
35
|
import { watchAndApplyTheme } from './theme.js'
|
|
36
|
+
import {
|
|
37
|
+
createGraphCanvasApi,
|
|
38
|
+
mergeNodeTypes,
|
|
39
|
+
resolveBackgroundProps,
|
|
40
|
+
resolveMinimapProps,
|
|
41
|
+
viewportsEqual,
|
|
42
|
+
type GraphFlowHelpers,
|
|
43
|
+
} from './api.js'
|
|
7
44
|
|
|
8
|
-
|
|
45
|
+
// Named (exported) xyflow types only — indexed SvelteFlowProps[...] lookups
|
|
46
|
+
// make svelte-package drop the .d.ts as "not portable".
|
|
47
|
+
type Keys = KeyDefinition | KeyDefinition[] | null
|
|
9
48
|
|
|
10
49
|
interface Props {
|
|
11
|
-
|
|
12
|
-
nodes
|
|
13
|
-
|
|
14
|
-
edges
|
|
15
|
-
|
|
50
|
+
// ── data ──────────────────────────────────────────────
|
|
51
|
+
/** Flow nodes — bindable; drags and selection write back. */
|
|
52
|
+
nodes: N[]
|
|
53
|
+
/** Flow edges — bindable; connects and deletes write back. */
|
|
54
|
+
edges: E[]
|
|
55
|
+
/** When true, disables drag/connect/select/pan/zoom interactions. */
|
|
16
56
|
readonly?: boolean
|
|
17
57
|
/** Fit the graph to the viewport on first render. */
|
|
18
58
|
fitView?: boolean
|
|
19
|
-
/** Show the minimap
|
|
20
|
-
minimap?: boolean
|
|
21
|
-
/** Fired when the user clicks a node. */
|
|
22
|
-
onNodeClick?: NodeEventWithPointer<MouseEvent | TouchEvent>
|
|
59
|
+
/** Show the minimap. Object form forwards MiniMap props (nodeColor, pannable, zoomable, …). */
|
|
60
|
+
minimap?: boolean | MiniMapProps
|
|
61
|
+
/** Fired when the user clicks a node (camelCase alias of `onnodeclick`; both fire). */
|
|
62
|
+
onNodeClick?: NodeEventWithPointer<MouseEvent | TouchEvent, N>
|
|
23
63
|
/** Height of the canvas container (CSS value). Defaults to 100%. */
|
|
24
64
|
height?: string
|
|
65
|
+
|
|
66
|
+
// ── types ─────────────────────────────────────────────
|
|
67
|
+
/** Custom node components, merged OVER `{ jatuiNode: JatuiNode }`. Keep the object stable. */
|
|
68
|
+
nodeTypes?: NodeTypes
|
|
69
|
+
/** Custom edge components. Keep the object stable. */
|
|
70
|
+
edgeTypes?: EdgeTypes
|
|
71
|
+
defaultEdgeOptions?: DefaultEdgeOptions
|
|
72
|
+
|
|
73
|
+
// ── viewport ──────────────────────────────────────────
|
|
74
|
+
/** Live viewport `{ x, y, zoom }` — bindable; updates on every pan/zoom. */
|
|
75
|
+
viewport?: Viewport
|
|
76
|
+
/** Default `{ padding: 0.2 }`. */
|
|
77
|
+
fitViewOptions?: FitViewOptions<N>
|
|
78
|
+
minZoom?: number
|
|
79
|
+
maxZoom?: number
|
|
80
|
+
|
|
81
|
+
// ── editing ───────────────────────────────────────────
|
|
82
|
+
snapToGrid?: boolean
|
|
83
|
+
snapGrid?: SnapGrid
|
|
84
|
+
connectionMode?: ConnectionMode
|
|
85
|
+
isValidConnection?: IsValidConnection<E>
|
|
86
|
+
onconnect?: OnConnect
|
|
87
|
+
onbeforedelete?: OnBeforeDelete<N, E>
|
|
88
|
+
ondelete?: OnDelete<N, E>
|
|
89
|
+
deleteKey?: Keys
|
|
90
|
+
panActivationKey?: Keys
|
|
91
|
+
multiSelectionKey?: Keys
|
|
92
|
+
selectionKey?: Keys
|
|
93
|
+
/** Defaults to `!readonly`. */
|
|
94
|
+
panOnDrag?: boolean | number[]
|
|
95
|
+
selectionOnDrag?: boolean
|
|
96
|
+
zoomOnDoubleClick?: boolean
|
|
97
|
+
|
|
98
|
+
// ── events (forwarded verbatim) ───────────────────────
|
|
99
|
+
onnodeclick?: NodeEvents<N>['onnodeclick']
|
|
100
|
+
onnodecontextmenu?: NodeEvents<N>['onnodecontextmenu']
|
|
101
|
+
onnodedragstart?: NodeEvents<N>['onnodedragstart']
|
|
102
|
+
onnodedragstop?: NodeEvents<N>['onnodedragstop']
|
|
103
|
+
onedgeclick?: EdgeEvents<E>['onedgeclick']
|
|
104
|
+
onpaneclick?: PaneEvents['onpaneclick']
|
|
105
|
+
onselectionchange?: OnSelectionChange<N, E>
|
|
106
|
+
onmoveend?: OnMoveEnd
|
|
107
|
+
|
|
108
|
+
// ── chrome ────────────────────────────────────────────
|
|
109
|
+
/** Show zoom controls. Default true. */
|
|
110
|
+
controls?: boolean
|
|
111
|
+
/** `false` hides the dot grid; an object overrides `{ gap: 16, size: 1 }`. */
|
|
112
|
+
background?: false | BackgroundProps
|
|
113
|
+
/** Rendered INSIDE <SvelteFlow> — Panels, overlays, anything that calls useSvelteFlow(). */
|
|
114
|
+
children?: Snippet
|
|
25
115
|
}
|
|
26
116
|
|
|
27
117
|
let {
|
|
@@ -32,9 +122,69 @@
|
|
|
32
122
|
minimap = false,
|
|
33
123
|
onNodeClick,
|
|
34
124
|
height = '100%',
|
|
125
|
+
nodeTypes,
|
|
126
|
+
edgeTypes,
|
|
127
|
+
defaultEdgeOptions,
|
|
128
|
+
viewport = $bindable(),
|
|
129
|
+
fitViewOptions = { padding: 0.2 },
|
|
130
|
+
minZoom,
|
|
131
|
+
maxZoom,
|
|
132
|
+
snapToGrid,
|
|
133
|
+
snapGrid,
|
|
134
|
+
connectionMode,
|
|
135
|
+
isValidConnection,
|
|
136
|
+
onconnect,
|
|
137
|
+
onbeforedelete,
|
|
138
|
+
ondelete,
|
|
139
|
+
deleteKey,
|
|
140
|
+
panActivationKey,
|
|
141
|
+
multiSelectionKey,
|
|
142
|
+
selectionKey,
|
|
143
|
+
panOnDrag,
|
|
144
|
+
selectionOnDrag,
|
|
145
|
+
zoomOnDoubleClick,
|
|
146
|
+
onnodeclick,
|
|
147
|
+
onnodecontextmenu,
|
|
148
|
+
onnodedragstart,
|
|
149
|
+
onnodedragstop,
|
|
150
|
+
onedgeclick,
|
|
151
|
+
onpaneclick,
|
|
152
|
+
onselectionchange,
|
|
153
|
+
onmoveend,
|
|
154
|
+
controls = true,
|
|
155
|
+
background,
|
|
156
|
+
children,
|
|
35
157
|
}: Props = $props()
|
|
36
158
|
|
|
37
|
-
|
|
159
|
+
// Stable identity unless the consumer swaps nodeTypes — xyflow re-mounts
|
|
160
|
+
// every node when this object changes.
|
|
161
|
+
const resolvedNodeTypes = $derived(mergeNodeTypes({ jatuiNode: JatuiNode }, nodeTypes) as NodeTypes)
|
|
162
|
+
const minimapProps = $derived(resolveMinimapProps(minimap))
|
|
163
|
+
const backgroundProps = $derived(resolveBackgroundProps(background))
|
|
164
|
+
|
|
165
|
+
const handleNodeClick: NodeEventWithPointer<MouseEvent | TouchEvent, N> = (e) => {
|
|
166
|
+
onnodeclick?.(e)
|
|
167
|
+
onNodeClick?.(e)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
let helpers: GraphFlowHelpers | null = null
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Imperative handle (`bind:this={canvas}` → `canvas.api.fitView()`). Every
|
|
174
|
+
* method is a safe no-op until the flow initialises. `fitView` lives only on
|
|
175
|
+
* `api` because the `fitView` prop owns the bare name; the rest are also
|
|
176
|
+
* exported directly.
|
|
177
|
+
*/
|
|
178
|
+
export const api = createGraphCanvasApi(() => helpers)
|
|
179
|
+
export const zoomTo = api.zoomTo
|
|
180
|
+
export const getZoom = api.getZoom
|
|
181
|
+
export const setCenter = api.setCenter
|
|
182
|
+
export const screenToFlowPosition = api.screenToFlowPosition
|
|
183
|
+
export const getViewport = api.getViewport
|
|
184
|
+
|
|
185
|
+
function syncViewport(v: Viewport) {
|
|
186
|
+
if (!viewportsEqual(viewport, v)) viewport = v
|
|
187
|
+
}
|
|
38
188
|
|
|
39
189
|
let flowEl: HTMLDivElement | null = $state(null)
|
|
40
190
|
let stopWatch: (() => void) | null = null
|
|
@@ -52,24 +202,54 @@
|
|
|
52
202
|
|
|
53
203
|
<div class="graph-canvas" style:height bind:this={flowEl}>
|
|
54
204
|
<SvelteFlow
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
205
|
+
bind:nodes
|
|
206
|
+
bind:edges
|
|
207
|
+
bind:viewport
|
|
208
|
+
nodeTypes={resolvedNodeTypes}
|
|
209
|
+
{edgeTypes}
|
|
210
|
+
{defaultEdgeOptions}
|
|
58
211
|
{fitView}
|
|
212
|
+
{fitViewOptions}
|
|
213
|
+
{minZoom}
|
|
214
|
+
{maxZoom}
|
|
215
|
+
{connectionMode}
|
|
216
|
+
{isValidConnection}
|
|
217
|
+
{onconnect}
|
|
218
|
+
{onbeforedelete}
|
|
219
|
+
{ondelete}
|
|
220
|
+
{deleteKey}
|
|
221
|
+
{panActivationKey}
|
|
222
|
+
{multiSelectionKey}
|
|
223
|
+
{selectionKey}
|
|
224
|
+
{selectionOnDrag}
|
|
225
|
+
{zoomOnDoubleClick}
|
|
226
|
+
snapGrid={snapToGrid ? (snapGrid ?? [16, 16]) : snapGrid}
|
|
59
227
|
nodesDraggable={!readonly}
|
|
60
228
|
nodesConnectable={!readonly}
|
|
61
229
|
elementsSelectable={!readonly}
|
|
62
|
-
panOnDrag={!readonly}
|
|
230
|
+
panOnDrag={panOnDrag ?? !readonly}
|
|
63
231
|
zoomOnScroll={!readonly}
|
|
64
|
-
onnodeclick={
|
|
65
|
-
|
|
232
|
+
onnodeclick={handleNodeClick}
|
|
233
|
+
{onnodecontextmenu}
|
|
234
|
+
{onnodedragstart}
|
|
235
|
+
{onnodedragstop}
|
|
236
|
+
{onedgeclick}
|
|
237
|
+
{onpaneclick}
|
|
238
|
+
{onselectionchange}
|
|
239
|
+
{onmoveend}
|
|
66
240
|
attributionPosition="bottom-right"
|
|
67
241
|
>
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
242
|
+
<GraphApiBridge onready={(h) => (helpers = h)} onviewport={syncViewport} />
|
|
243
|
+
{#if backgroundProps}
|
|
244
|
+
<Background {...backgroundProps} />
|
|
245
|
+
{/if}
|
|
246
|
+
{#if controls}
|
|
247
|
+
<Controls showLock={false} />
|
|
248
|
+
{/if}
|
|
249
|
+
{#if minimapProps}
|
|
250
|
+
<MiniMap {...minimapProps} />
|
|
72
251
|
{/if}
|
|
252
|
+
{@render children?.()}
|
|
73
253
|
</SvelteFlow>
|
|
74
254
|
</div>
|
|
75
255
|
|
|
@@ -84,19 +264,24 @@
|
|
|
84
264
|
background: var(--color-base-100, oklch(0.98 0 0));
|
|
85
265
|
}
|
|
86
266
|
|
|
87
|
-
/*
|
|
88
|
-
|
|
267
|
+
/*
|
|
268
|
+
* House rule (no at-rest shadows): strip xyflow's built-in shadow on the
|
|
269
|
+
* node WRAPPER — scoped to this canvas so other flows in the app are left
|
|
270
|
+
* alone. A custom node that draws a status glow on an INNER element is
|
|
271
|
+
* unaffected; put glows there, not on the wrapper.
|
|
272
|
+
*/
|
|
273
|
+
.graph-canvas :global(.svelte-flow__node) {
|
|
89
274
|
box-shadow: none !important;
|
|
90
275
|
filter: none !important;
|
|
91
276
|
}
|
|
92
277
|
|
|
93
278
|
/* Edge animation uses opacity+stroke transitions, not layout — allowed */
|
|
94
|
-
:global(.svelte-
|
|
279
|
+
.graph-canvas :global(.svelte-flow__edge path) {
|
|
95
280
|
transition: stroke var(--motion-fast) var(--motion-glide);
|
|
96
281
|
}
|
|
97
282
|
|
|
98
283
|
@media (prefers-reduced-motion: reduce) {
|
|
99
|
-
:global(.svelte-
|
|
284
|
+
.graph-canvas :global(.svelte-flow__edge path) {
|
|
100
285
|
transition: none;
|
|
101
286
|
}
|
|
102
287
|
}
|
|
@@ -1,22 +1,116 @@
|
|
|
1
1
|
import '@xyflow/svelte/dist/style.css';
|
|
2
|
-
import { type Node, type Edge } from '@xyflow/svelte';
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
import { type Node, type Edge, type NodeTypes, type EdgeTypes, type DefaultEdgeOptions, type Viewport, type FitViewOptions, type SnapGrid, type ConnectionMode, type MiniMapProps, type BackgroundProps, type NodeEventWithPointer, type NodeEvents, type EdgeEvents, type PaneEvents, type IsValidConnection, type OnConnect, type OnDelete, type OnBeforeDelete, type OnSelectionChange, type OnMoveEnd, type KeyDefinition } from '@xyflow/svelte';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
declare function $$render<N extends Node = Node, E extends Edge = Edge>(): {
|
|
5
|
+
props: {
|
|
6
|
+
/** Flow nodes — bindable; drags and selection write back. */
|
|
7
|
+
nodes: N[];
|
|
8
|
+
/** Flow edges — bindable; connects and deletes write back. */
|
|
9
|
+
edges: E[];
|
|
10
|
+
/** When true, disables drag/connect/select/pan/zoom interactions. */
|
|
11
|
+
readonly?: boolean;
|
|
12
|
+
/** Fit the graph to the viewport on first render. */
|
|
13
|
+
fitView?: boolean;
|
|
14
|
+
/** Show the minimap. Object form forwards MiniMap props (nodeColor, pannable, zoomable, …). */
|
|
15
|
+
minimap?: boolean | MiniMapProps;
|
|
16
|
+
/** Fired when the user clicks a node (camelCase alias of `onnodeclick`; both fire). */
|
|
17
|
+
onNodeClick?: NodeEventWithPointer<MouseEvent | TouchEvent, N>;
|
|
18
|
+
/** Height of the canvas container (CSS value). Defaults to 100%. */
|
|
19
|
+
height?: string;
|
|
20
|
+
/** Custom node components, merged OVER `{ jatuiNode: JatuiNode }`. Keep the object stable. */
|
|
21
|
+
nodeTypes?: NodeTypes;
|
|
22
|
+
/** Custom edge components. Keep the object stable. */
|
|
23
|
+
edgeTypes?: EdgeTypes;
|
|
24
|
+
defaultEdgeOptions?: DefaultEdgeOptions;
|
|
25
|
+
/** Live viewport `{ x, y, zoom }` — bindable; updates on every pan/zoom. */
|
|
26
|
+
viewport?: Viewport;
|
|
27
|
+
/** Default `{ padding: 0.2 }`. */
|
|
28
|
+
fitViewOptions?: FitViewOptions<N>;
|
|
29
|
+
minZoom?: number;
|
|
30
|
+
maxZoom?: number;
|
|
31
|
+
snapToGrid?: boolean;
|
|
32
|
+
snapGrid?: SnapGrid;
|
|
33
|
+
connectionMode?: ConnectionMode;
|
|
34
|
+
isValidConnection?: IsValidConnection<E>;
|
|
35
|
+
onconnect?: OnConnect;
|
|
36
|
+
onbeforedelete?: OnBeforeDelete<N, E>;
|
|
37
|
+
ondelete?: OnDelete<N, E>;
|
|
38
|
+
deleteKey?: KeyDefinition | KeyDefinition[] | null;
|
|
39
|
+
panActivationKey?: KeyDefinition | KeyDefinition[] | null;
|
|
40
|
+
multiSelectionKey?: KeyDefinition | KeyDefinition[] | null;
|
|
41
|
+
selectionKey?: KeyDefinition | KeyDefinition[] | null;
|
|
42
|
+
/** Defaults to `!readonly`. */
|
|
43
|
+
panOnDrag?: boolean | number[];
|
|
44
|
+
selectionOnDrag?: boolean;
|
|
45
|
+
zoomOnDoubleClick?: boolean;
|
|
46
|
+
onnodeclick?: NodeEvents<N>["onnodeclick"];
|
|
47
|
+
onnodecontextmenu?: NodeEvents<N>["onnodecontextmenu"];
|
|
48
|
+
onnodedragstart?: NodeEvents<N>["onnodedragstart"];
|
|
49
|
+
onnodedragstop?: NodeEvents<N>["onnodedragstop"];
|
|
50
|
+
onedgeclick?: EdgeEvents<E>["onedgeclick"];
|
|
51
|
+
onpaneclick?: PaneEvents["onpaneclick"];
|
|
52
|
+
onselectionchange?: OnSelectionChange<N, E>;
|
|
53
|
+
onmoveend?: OnMoveEnd;
|
|
54
|
+
/** Show zoom controls. Default true. */
|
|
55
|
+
controls?: boolean;
|
|
56
|
+
/** `false` hides the dot grid; an object overrides `{ gap: 16, size: 1 }`. */
|
|
57
|
+
background?: false | BackgroundProps;
|
|
58
|
+
/** Rendered INSIDE <SvelteFlow> — Panels, overlays, anything that calls useSvelteFlow(). */
|
|
59
|
+
children?: Snippet;
|
|
60
|
+
};
|
|
61
|
+
exports: {
|
|
62
|
+
/**
|
|
63
|
+
* Imperative handle (`bind:this={canvas}` → `canvas.api.fitView()`). Every
|
|
64
|
+
* method is a safe no-op until the flow initialises. `fitView` lives only on
|
|
65
|
+
* `api` because the `fitView` prop owns the bare name; the rest are also
|
|
66
|
+
* exported directly.
|
|
67
|
+
*/ api: import("./api.js").GraphCanvasApi;
|
|
68
|
+
zoomTo: (zoom: number, options?: {
|
|
69
|
+
duration?: number;
|
|
70
|
+
}) => Promise<boolean>;
|
|
71
|
+
getZoom: () => number;
|
|
72
|
+
setCenter: (x: number, y: number, options?: {
|
|
73
|
+
zoom?: number;
|
|
74
|
+
duration?: number;
|
|
75
|
+
}) => Promise<boolean>;
|
|
76
|
+
screenToFlowPosition: (p: import("@xyflow/system").XYPosition) => import("@xyflow/system").XYPosition;
|
|
77
|
+
getViewport: () => Viewport;
|
|
78
|
+
};
|
|
79
|
+
bindings: "viewport" | "nodes" | "edges";
|
|
80
|
+
slots: {};
|
|
81
|
+
events: {};
|
|
82
|
+
};
|
|
83
|
+
declare class __sveltets_Render<N extends Node = Node, E extends Edge = Edge> {
|
|
84
|
+
props(): ReturnType<typeof $$render<N, E>>['props'];
|
|
85
|
+
events(): ReturnType<typeof $$render<N, E>>['events'];
|
|
86
|
+
slots(): ReturnType<typeof $$render<N, E>>['slots'];
|
|
87
|
+
bindings(): "viewport" | "nodes" | "edges";
|
|
88
|
+
exports(): {
|
|
89
|
+
/**
|
|
90
|
+
* Imperative handle (`bind:this={canvas}` → `canvas.api.fitView()`). Every
|
|
91
|
+
* method is a safe no-op until the flow initialises. `fitView` lives only on
|
|
92
|
+
* `api` because the `fitView` prop owns the bare name; the rest are also
|
|
93
|
+
* exported directly.
|
|
94
|
+
*/ api: import("./api.js").GraphCanvasApi;
|
|
95
|
+
zoomTo: (zoom: number, options?: {
|
|
96
|
+
duration?: number;
|
|
97
|
+
}) => Promise<boolean>;
|
|
98
|
+
getZoom: () => number;
|
|
99
|
+
setCenter: (x: number, y: number, options?: {
|
|
100
|
+
zoom?: number;
|
|
101
|
+
duration?: number;
|
|
102
|
+
}) => Promise<boolean>;
|
|
103
|
+
screenToFlowPosition: (p: import("@xyflow/system").XYPosition) => import("@xyflow/system").XYPosition;
|
|
104
|
+
getViewport: () => Viewport;
|
|
105
|
+
};
|
|
19
106
|
}
|
|
20
|
-
|
|
21
|
-
|
|
107
|
+
interface $$IsomorphicComponent {
|
|
108
|
+
new <N extends Node = Node, E extends Edge = Edge>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<N, E>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<N, E>['props']>, ReturnType<__sveltets_Render<N, E>['events']>, ReturnType<__sveltets_Render<N, E>['slots']>> & {
|
|
109
|
+
$$bindings?: ReturnType<__sveltets_Render<N, E>['bindings']>;
|
|
110
|
+
} & ReturnType<__sveltets_Render<N, E>['exports']>;
|
|
111
|
+
<N extends Node = Node, E extends Edge = Edge>(internal: unknown, props: ReturnType<__sveltets_Render<N, E>['props']> & {}): ReturnType<__sveltets_Render<N, E>['exports']>;
|
|
112
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any, any>['bindings']>;
|
|
113
|
+
}
|
|
114
|
+
declare const GraphCanvas: $$IsomorphicComponent;
|
|
115
|
+
type GraphCanvas<N extends Node = Node, E extends Edge = Edge> = InstanceType<typeof GraphCanvas<N, E>>;
|
|
22
116
|
export default GraphCanvas;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphCanvas imperative API + pure prop helpers.
|
|
3
|
+
*
|
|
4
|
+
* `useSvelteFlow()` only works inside a CHILD of <SvelteFlow>, so a consumer
|
|
5
|
+
* holding `bind:this` on <GraphCanvas> can't reach it. GraphCanvas mounts a
|
|
6
|
+
* tiny internal child (GraphApiBridge) that calls the hook and hands the
|
|
7
|
+
* helpers up; `createGraphCanvasApi` wraps them so every method is a safe
|
|
8
|
+
* no-op until the flow has initialised.
|
|
9
|
+
*
|
|
10
|
+
* Kept free of Svelte/xyflow runtime imports so it is unit-testable in node.
|
|
11
|
+
*/
|
|
12
|
+
import type { BackgroundProps, FitViewOptions, MiniMapProps, Viewport, XYPosition } from '@xyflow/svelte';
|
|
13
|
+
/** Imperative handle exposed on a GraphCanvas instance (`bind:this`). */
|
|
14
|
+
export interface GraphCanvasApi {
|
|
15
|
+
fitView(options?: FitViewOptions): Promise<boolean>;
|
|
16
|
+
zoomTo(zoom: number, options?: {
|
|
17
|
+
duration?: number;
|
|
18
|
+
}): Promise<boolean>;
|
|
19
|
+
getZoom(): number;
|
|
20
|
+
setCenter(x: number, y: number, options?: {
|
|
21
|
+
zoom?: number;
|
|
22
|
+
duration?: number;
|
|
23
|
+
}): Promise<boolean>;
|
|
24
|
+
screenToFlowPosition(p: XYPosition): XYPosition;
|
|
25
|
+
getViewport(): Viewport;
|
|
26
|
+
}
|
|
27
|
+
/** The subset of `useSvelteFlow()` the bridge hands up. */
|
|
28
|
+
export type GraphFlowHelpers = GraphCanvasApi;
|
|
29
|
+
export declare const DEFAULT_VIEWPORT: Viewport;
|
|
30
|
+
/**
|
|
31
|
+
* Build a GraphCanvasApi over a lazily-resolved helper set. Before the bridge
|
|
32
|
+
* reports in, methods resolve `false` / return identity values instead of
|
|
33
|
+
* throwing.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createGraphCanvasApi(getHelpers: () => GraphFlowHelpers | null): GraphCanvasApi;
|
|
36
|
+
export declare function viewportsEqual(a: Viewport | undefined, b: Viewport | undefined): boolean;
|
|
37
|
+
/** `minimap` prop → MiniMap props, or null when hidden. */
|
|
38
|
+
export declare function resolveMinimapProps(minimap: boolean | MiniMapProps | undefined): MiniMapProps | null;
|
|
39
|
+
export declare const DEFAULT_BACKGROUND: BackgroundProps;
|
|
40
|
+
/** `background` prop → Background props, or null when disabled. */
|
|
41
|
+
export declare function resolveBackgroundProps(background: false | BackgroundProps | undefined): BackgroundProps | null;
|
|
42
|
+
/**
|
|
43
|
+
* Merge consumer nodeTypes OVER the built-ins. Callers must memoise the
|
|
44
|
+
* result — xyflow re-mounts every node when the nodeTypes identity changes.
|
|
45
|
+
*/
|
|
46
|
+
export declare function mergeNodeTypes<T extends Record<string, unknown>>(builtins: T, custom: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
47
|
+
/**
|
|
48
|
+
* Viewport for zooming to `zoom` while keeping the point at the centre of a
|
|
49
|
+
* `width`×`height` pane fixed (xyflow 1.x has no zoomTo helper; setViewport
|
|
50
|
+
* alone would zoom around the top-left corner).
|
|
51
|
+
*/
|
|
52
|
+
export declare function zoomViewportAround(current: Viewport, zoom: number, width: number, height: number): Viewport;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphCanvas imperative API + pure prop helpers.
|
|
3
|
+
*
|
|
4
|
+
* `useSvelteFlow()` only works inside a CHILD of <SvelteFlow>, so a consumer
|
|
5
|
+
* holding `bind:this` on <GraphCanvas> can't reach it. GraphCanvas mounts a
|
|
6
|
+
* tiny internal child (GraphApiBridge) that calls the hook and hands the
|
|
7
|
+
* helpers up; `createGraphCanvasApi` wraps them so every method is a safe
|
|
8
|
+
* no-op until the flow has initialised.
|
|
9
|
+
*
|
|
10
|
+
* Kept free of Svelte/xyflow runtime imports so it is unit-testable in node.
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_VIEWPORT = { x: 0, y: 0, zoom: 1 };
|
|
13
|
+
/**
|
|
14
|
+
* Build a GraphCanvasApi over a lazily-resolved helper set. Before the bridge
|
|
15
|
+
* reports in, methods resolve `false` / return identity values instead of
|
|
16
|
+
* throwing.
|
|
17
|
+
*/
|
|
18
|
+
export function createGraphCanvasApi(getHelpers) {
|
|
19
|
+
return {
|
|
20
|
+
fitView: (options) => getHelpers()?.fitView(options) ?? Promise.resolve(false),
|
|
21
|
+
zoomTo: (zoom, options) => getHelpers()?.zoomTo(zoom, options) ?? Promise.resolve(false),
|
|
22
|
+
getZoom: () => getHelpers()?.getZoom() ?? DEFAULT_VIEWPORT.zoom,
|
|
23
|
+
setCenter: (x, y, options) => getHelpers()?.setCenter(x, y, options) ?? Promise.resolve(false),
|
|
24
|
+
screenToFlowPosition: (p) => getHelpers()?.screenToFlowPosition(p) ?? { x: p.x, y: p.y },
|
|
25
|
+
getViewport: () => getHelpers()?.getViewport() ?? { ...DEFAULT_VIEWPORT },
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function viewportsEqual(a, b) {
|
|
29
|
+
if (a === b)
|
|
30
|
+
return true;
|
|
31
|
+
if (!a || !b)
|
|
32
|
+
return false;
|
|
33
|
+
return a.x === b.x && a.y === b.y && a.zoom === b.zoom;
|
|
34
|
+
}
|
|
35
|
+
/** `minimap` prop → MiniMap props, or null when hidden. */
|
|
36
|
+
export function resolveMinimapProps(minimap) {
|
|
37
|
+
if (!minimap)
|
|
38
|
+
return null;
|
|
39
|
+
return minimap === true ? {} : minimap;
|
|
40
|
+
}
|
|
41
|
+
export const DEFAULT_BACKGROUND = { gap: 16, size: 1 };
|
|
42
|
+
/** `background` prop → Background props, or null when disabled. */
|
|
43
|
+
export function resolveBackgroundProps(background) {
|
|
44
|
+
if (background === false)
|
|
45
|
+
return null;
|
|
46
|
+
return { ...DEFAULT_BACKGROUND, ...(background ?? {}) };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Merge consumer nodeTypes OVER the built-ins. Callers must memoise the
|
|
50
|
+
* result — xyflow re-mounts every node when the nodeTypes identity changes.
|
|
51
|
+
*/
|
|
52
|
+
export function mergeNodeTypes(builtins, custom) {
|
|
53
|
+
return custom ? { ...builtins, ...custom } : builtins;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Viewport for zooming to `zoom` while keeping the point at the centre of a
|
|
57
|
+
* `width`×`height` pane fixed (xyflow 1.x has no zoomTo helper; setViewport
|
|
58
|
+
* alone would zoom around the top-left corner).
|
|
59
|
+
*/
|
|
60
|
+
export function zoomViewportAround(current, zoom, width, height) {
|
|
61
|
+
const cx = width / 2;
|
|
62
|
+
const cy = height / 2;
|
|
63
|
+
const fx = (cx - current.x) / current.zoom;
|
|
64
|
+
const fy = (cy - current.y) / current.zoom;
|
|
65
|
+
return { x: cx - fx * zoom, y: cy - fy * zoom, zoom };
|
|
66
|
+
}
|
|
@@ -2,3 +2,5 @@ export { default as GraphCanvas } from './GraphCanvas.svelte';
|
|
|
2
2
|
export { default as JatuiNode } from './JatuiNode.svelte';
|
|
3
3
|
export { getStatusColor, applyXyflowTheme, watchAndApplyTheme } from './theme';
|
|
4
4
|
export type { NodeStatus } from './theme';
|
|
5
|
+
export { createGraphCanvasApi, DEFAULT_VIEWPORT, DEFAULT_BACKGROUND } from './api';
|
|
6
|
+
export type { GraphCanvasApi } from './api';
|
|
@@ -2,3 +2,4 @@
|
|
|
2
2
|
export { default as GraphCanvas } from './GraphCanvas.svelte';
|
|
3
3
|
export { default as JatuiNode } from './JatuiNode.svelte';
|
|
4
4
|
export { getStatusColor, applyXyflowTheme, watchAndApplyTheme } from './theme';
|
|
5
|
+
export { createGraphCanvasApi, DEFAULT_VIEWPORT, DEFAULT_BACKGROUND } from './api';
|
|
@@ -32,6 +32,13 @@ const THEME_MAP = [
|
|
|
32
32
|
// Selection box
|
|
33
33
|
['--xy-selection-background-color', 'color-mix(in oklch, var(--color-primary, #6366f1) 10%, transparent)'],
|
|
34
34
|
['--xy-selection-border', '1px dotted color-mix(in oklch, var(--color-primary, #6366f1) 50%, transparent)'],
|
|
35
|
+
// Controls (zoom buttons) — otherwise stay light-on-dark in dark themes
|
|
36
|
+
['--xy-controls-button-background-color', 'var(--color-base-100, #fefefe)'],
|
|
37
|
+
['--xy-controls-button-background-color-hover', 'var(--color-base-200, #f4f4f4)'],
|
|
38
|
+
['--xy-controls-button-color', 'var(--color-base-content, inherit)'],
|
|
39
|
+
['--xy-controls-button-color-hover', 'var(--color-base-content, inherit)'],
|
|
40
|
+
['--xy-controls-button-border-color', 'var(--color-base-300, #eee)'],
|
|
41
|
+
['--xy-controls-box-shadow', 'none'],
|
|
35
42
|
// Attribution
|
|
36
43
|
['--xy-attribution-background-color', 'color-mix(in oklch, var(--color-base-100, #fff) 80%, transparent)'],
|
|
37
44
|
];
|
|
@@ -112,6 +119,12 @@ function resolveThemeValue(prop) {
|
|
|
112
119
|
'--xy-minimap-node-background-color': () => getDaisyUIColor('base-200'),
|
|
113
120
|
'--xy-selection-background-color': () => `color-mix(in oklch, ${getDaisyUIColor('primary')} 10%, transparent)`,
|
|
114
121
|
'--xy-selection-border': () => `1px dotted color-mix(in oklch, ${getDaisyUIColor('primary')} 50%, transparent)`,
|
|
122
|
+
'--xy-controls-button-background-color': () => getDaisyUIColor('base-100'),
|
|
123
|
+
'--xy-controls-button-background-color-hover': () => getDaisyUIColor('base-200'),
|
|
124
|
+
'--xy-controls-button-color': () => getDaisyUIColor('base-content'),
|
|
125
|
+
'--xy-controls-button-color-hover': () => getDaisyUIColor('base-content'),
|
|
126
|
+
'--xy-controls-button-border-color': () => getDaisyUIColor('base-300'),
|
|
127
|
+
'--xy-controls-box-shadow': () => 'none',
|
|
115
128
|
'--xy-attribution-background-color': () => `color-mix(in oklch, ${getDaisyUIColor('base-100')} 80%, transparent)`,
|
|
116
129
|
};
|
|
117
130
|
return propToColor[prop]?.() ?? '';
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
AttachmentCallbacks,
|
|
17
17
|
} from '../../types/messaging'
|
|
18
18
|
import { renderMentionsAsHTML, extractPlainText } from '../../utils/mentionParser'
|
|
19
|
+
import { longpress } from '../../actions/longpress'
|
|
19
20
|
import Avatar from './Avatar.svelte'
|
|
20
21
|
import QuotedMessageDisplay from './QuotedMessageDisplay.svelte'
|
|
21
22
|
import MessageAttachment from './MessageAttachment.svelte'
|
|
@@ -49,6 +50,8 @@
|
|
|
49
50
|
swipeActions?: boolean
|
|
50
51
|
/** Snippet rendered in the revealed action zone (right side, behind the item). */
|
|
51
52
|
swipeContent?: Snippet
|
|
53
|
+
/** Long-press (touch) / right-click (mouse) affordance — e.g. open a context sheet. Fires with the message id and gesture coordinates. */
|
|
54
|
+
onlongpress?: (detail: { messageId: string; x: number; y: number; source: 'touch' | 'mouse' }) => void
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
let {
|
|
@@ -72,6 +75,7 @@
|
|
|
72
75
|
onreactionchange,
|
|
73
76
|
swipeActions = false,
|
|
74
77
|
swipeContent,
|
|
78
|
+
onlongpress,
|
|
75
79
|
}: Props = $props()
|
|
76
80
|
|
|
77
81
|
let isEditing = $state(false)
|
|
@@ -276,6 +280,7 @@
|
|
|
276
280
|
class:pt-2={!isConsecutive}
|
|
277
281
|
data-message-id={message.id}
|
|
278
282
|
onclick={handleMessageClick}
|
|
283
|
+
use:longpress={{ enabled: !!onlongpress, onLongPress: (d) => onlongpress?.({ messageId: message.id, x: d.x, y: d.y, source: d.source }) }}
|
|
279
284
|
role="button"
|
|
280
285
|
tabindex="0"
|
|
281
286
|
onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleMessageClick(e as any) } }}
|
|
@@ -40,6 +40,13 @@ interface Props {
|
|
|
40
40
|
swipeActions?: boolean;
|
|
41
41
|
/** Snippet rendered in the revealed action zone (right side, behind the item). */
|
|
42
42
|
swipeContent?: Snippet;
|
|
43
|
+
/** Long-press (touch) / right-click (mouse) affordance — e.g. open a context sheet. Fires with the message id and gesture coordinates. */
|
|
44
|
+
onlongpress?: (detail: {
|
|
45
|
+
messageId: string;
|
|
46
|
+
x: number;
|
|
47
|
+
y: number;
|
|
48
|
+
source: 'touch' | 'mouse';
|
|
49
|
+
}) => void;
|
|
43
50
|
}
|
|
44
51
|
declare const MessageItem: import("svelte").Component<Props, {}, "">;
|
|
45
52
|
type MessageItem = ReturnType<typeof MessageItem>;
|