@pixerate/editor-svelte 0.20.0 → 0.22.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 +4 -3
- package/dist/canvas/CanvasGuidesLayer.svelte +32 -2
- package/dist/canvas/CanvasGuidesLayer.svelte.d.ts +2 -0
- package/dist/canvas/CanvasGuidesLayer.svelte.d.ts.map +1 -1
- package/dist/canvas/ShapeNode.svelte +57 -0
- package/dist/canvas/ShapeNode.svelte.d.ts +21 -0
- package/dist/canvas/ShapeNode.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasArrange.svelte.d.ts +23 -1
- package/dist/canvas/createCanvasArrange.svelte.d.ts.map +1 -1
- package/dist/canvas/createCanvasArrange.svelte.js +19 -2
- package/dist/canvas/createCanvasMeasure.svelte.d.ts +53 -0
- package/dist/canvas/createCanvasMeasure.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasMeasure.svelte.js +80 -0
- package/dist/canvas/index.d.ts +4 -0
- package/dist/canvas/index.d.ts.map +1 -1
- package/dist/canvas/index.js +6 -0
- package/dist/commands/CommandPalette.svelte +129 -0
- package/dist/commands/CommandPalette.svelte.d.ts +13 -0
- package/dist/commands/CommandPalette.svelte.d.ts.map +1 -0
- package/dist/commands/commandShortcuts.svelte.d.ts +30 -0
- package/dist/commands/commandShortcuts.svelte.d.ts.map +1 -0
- package/dist/commands/commandShortcuts.svelte.js +37 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +3 -0
- package/dist/commands/palette.svelte.d.ts +34 -0
- package/dist/commands/palette.svelte.d.ts.map +1 -0
- package/dist/commands/palette.svelte.js +61 -0
- package/dist/history/createHistoryShortcuts.d.ts +1 -1
- package/dist/history/createHistoryShortcuts.d.ts.map +1 -1
- package/dist/history/createHistoryShortcuts.js +10 -32
- package/dist/history/history.svelte.d.ts +13 -4
- package/dist/history/history.svelte.d.ts.map +1 -1
- package/dist/history/history.svelte.js +10 -0
- package/dist/history/historyDirty.svelte.d.ts +31 -0
- package/dist/history/historyDirty.svelte.d.ts.map +1 -0
- package/dist/history/historyDirty.svelte.js +30 -0
- package/dist/history/index.d.ts +1 -0
- package/dist/history/index.d.ts.map +1 -1
- package/dist/history/index.js +1 -0
- package/dist/image-editor/ImageEditor.svelte +39 -0
- package/dist/image-editor/ImageEditor.svelte.d.ts.map +1 -1
- package/dist/image-editor/imageEditorState.svelte.d.ts +2 -0
- package/dist/image-editor/imageEditorState.svelte.d.ts.map +1 -1
- package/dist/image-editor/imageEditorState.svelte.js +4 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/review/ReviewToolbar.svelte +15 -0
- package/dist/review/ReviewToolbar.svelte.d.ts +4 -0
- package/dist/review/ReviewToolbar.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/FormulaBar.svelte +12 -1
- package/dist/spreadsheet/FormulaBar.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/SpreadsheetContextMenu.svelte +21 -2
- package/dist/spreadsheet/SpreadsheetContextMenu.svelte.d.ts +1 -1
- package/dist/spreadsheet/SpreadsheetContextMenu.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/SpreadsheetEditor.svelte +48 -6
- package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/SpreadsheetGroupRow.svelte +1 -1
- package/dist/spreadsheet/spreadsheet.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/tableInteractions.d.ts.map +1 -1
- package/dist/spreadsheet/tableInteractions.js +2 -1
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ Requires **Svelte 5** (the components use runes). Components ship as `.svelte` s
|
|
|
37
37
|
|
|
38
38
|
`content` sets the initial document. Read later changes from the bound `editor` (for example in `onUpdate`), as above. The editor is preloaded with `createRichTextPreset()`. Pass `markdown`, `image`, `uploadImage`, `extensions` or `richTextOptions` to configure it.
|
|
39
39
|
|
|
40
|
-
`fileImport` imports dropped/pasted `.md`, `.html`, `.txt` and `.
|
|
40
|
+
`fileImport` imports dropped/pasted `.md`, `.html`, `.txt`, `.rtf` and `.docx` files (plus any adapter you register, e.g. PDF or zipped exports) at the drop position, and `richClipboard` copies lossless slices between editors (both opt-in). `createFileImport(() => editor)` returns reactive `isImporting` / `error` plus `openFilePicker()` and `importFiles()` for an import button.
|
|
41
41
|
|
|
42
42
|
`useAgentToolProvider(registry, () => editor && createRichTextToolProvider(editor, { id: "doc" }))` registers an agent tool provider (see `ToolRegistry` in `@pixerate/editor/agent`) for the component's lifetime. Call it during component initialisation.
|
|
43
43
|
|
|
@@ -67,15 +67,16 @@ Requires **Svelte 5** (the components use runes). Components ship as `.svelte` s
|
|
|
67
67
|
<CommentsPanel {editor} />
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
Put `<CommentButton {editor} />` inside a `BubbleMenu` to comment on the selection. `createComments(editorOrStore)` and `createTrackChanges(editor)` are rune (and Svelte store) adapters for custom UIs.
|
|
70
|
+
`ReviewToolbar` steps through insertions, deletions, formatting and block changes and shows the current one's author and description (e.g. "Ada: Formatted: Bold"); hide it with `showDescription={false}` or restyle it with `descriptionClass`. Put `<CommentButton {editor} />` inside a `BubbleMenu` to comment on the selection. `createComments(editorOrStore)` and `createTrackChanges(editor)` are rune (and Svelte store) adapters for custom UIs.
|
|
71
71
|
|
|
72
72
|
## More exports
|
|
73
73
|
|
|
74
74
|
| Import | Exports |
|
|
75
75
|
| :--- | :--- |
|
|
76
|
-
| `@pixerate/editor-svelte` | `EditableTextNodeEditor`, `BubbleMenu`, `TemplateRenderer`, `initiateEditor`, `createReactiveEditor`, `createHistory`, `createHistoryShortcuts`, `navigationGuard` (action), `createNavigationGuard`, `SpreadsheetEditor`, `FormulaBar`, `FormulaHints`, `createReactiveSpreadsheet`, `DirtyTracker` |
|
|
76
|
+
| `@pixerate/editor-svelte` | `EditableTextNodeEditor`, `BubbleMenu`, `TemplateRenderer`, `initiateEditor`, `createReactiveEditor`, `createHistory`, `createHistoryDirty`, `createHistoryShortcuts`, `navigationGuard` (action), `createNavigationGuard`, `SpreadsheetEditor`, `FormulaBar`, `FormulaHints`, `createReactiveSpreadsheet`, `DirtyTracker` |
|
|
77
77
|
| `@pixerate/editor-svelte/spreadsheet` | `SpreadsheetEditor`, `FormulaBar`, `FormulaHints`, `SpreadsheetContextMenu`, `SpreadsheetGroupRow`, `createReactiveSpreadsheet` (also re-exported from the root entry) |
|
|
78
78
|
| `@pixerate/editor-svelte/image-editor` | `ImageEditor`, `createReactiveImageEditor`: crop, rotate/flip, adjustments, annotations, depth masks, and `onInpaint` / `onRemoveBackground` AI hooks |
|
|
79
|
+
| `@pixerate/editor-svelte/commands` | `CommandPalette`, `createCommandPalette` (`hotkey: "Mod+K"`; call `destroy()` when done), `createCommandShortcuts`, `useRegisterCommands` over a `CommandRegistry` from `@pixerate/editor/commands` (also re-exported from the root entry) |
|
|
79
80
|
| `@pixerate/editor-svelte/canvas` | Runes for `@xyflow/svelte`: `createCanvasGraph`, `createCanvasClipboard`, `createCanvasDocking`, `createCanvasShortcuts`, `createCanvasInteractions`, `createCanvasExplosion`, `createCanvasNodeSync`, `createCanvasMultiDrag`, `createStreamingCanvas`, `AgentPresenceLayer`, `FloatingHorizontalScrollbar`, plus layout helpers |
|
|
80
81
|
|
|
81
82
|
Prop types are exported alongside each component, for example `EditableTextNodeEditorProps`, `BubbleMenuProps`, `ImageEditorProps` and `SpreadsheetEditorProps`.
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
color?: string;
|
|
11
11
|
/** Colour of equal-spacing guides. */
|
|
12
12
|
spacingColor?: string;
|
|
13
|
+
/** Colour of measuring lines, their labels and extension lines. */
|
|
14
|
+
measureColor?: string;
|
|
13
15
|
class?: string;
|
|
14
16
|
}
|
|
15
17
|
|
|
@@ -18,6 +20,7 @@
|
|
|
18
20
|
viewport = { x: 0, y: 0, zoom: 1 },
|
|
19
21
|
color = '#f59e0b',
|
|
20
22
|
spacingColor = '#ec4899',
|
|
23
|
+
measureColor = '#ef4444',
|
|
21
24
|
class: className = ''
|
|
22
25
|
}: Props = $props();
|
|
23
26
|
|
|
@@ -42,11 +45,38 @@
|
|
|
42
45
|
y1={a.y}
|
|
43
46
|
x2={b.x}
|
|
44
47
|
y2={b.y}
|
|
45
|
-
stroke={guide.kind === '
|
|
48
|
+
stroke={guide.kind === 'measure' || guide.kind === 'extension'
|
|
49
|
+
? measureColor
|
|
50
|
+
: guide.kind === 'spacing'
|
|
51
|
+
? spacingColor
|
|
52
|
+
: color}
|
|
46
53
|
stroke-width="1"
|
|
47
|
-
stroke-dasharray={guide.kind === 'centre' ? '4 3' : undefined}
|
|
54
|
+
stroke-dasharray={guide.kind === 'centre' ? '4 3' : guide.kind === 'extension' ? '3 3' : undefined}
|
|
48
55
|
shape-rendering="crispEdges"
|
|
49
56
|
/>
|
|
50
57
|
{/each}
|
|
58
|
+
{#each guides as guide, i (i)}
|
|
59
|
+
{#if guide.label}
|
|
60
|
+
{@const mid = toScreen((guide.x1 + guide.x2) / 2, (guide.y1 + guide.y2) / 2)}
|
|
61
|
+
{@const vertical = guide.orientation === 'vertical'}
|
|
62
|
+
{@const width = guide.label.length * 6.5 + 8}
|
|
63
|
+
<!-- Labels sit beside vertical lines and below horizontal ones. -->
|
|
64
|
+
<g
|
|
65
|
+
class="pixerate-canvas-guides__label"
|
|
66
|
+
data-label={guide.label}
|
|
67
|
+
transform="translate({vertical ? mid.x + 4 : mid.x - width / 2} {vertical ? mid.y - 8 : mid.y + 4})"
|
|
68
|
+
>
|
|
69
|
+
<rect {width} height="16" rx="3" fill={measureColor} />
|
|
70
|
+
<text
|
|
71
|
+
x={width / 2}
|
|
72
|
+
y="11.5"
|
|
73
|
+
text-anchor="middle"
|
|
74
|
+
font-size="11"
|
|
75
|
+
font-family="system-ui, sans-serif"
|
|
76
|
+
fill="#fff">{guide.label}</text
|
|
77
|
+
>
|
|
78
|
+
</g>
|
|
79
|
+
{/if}
|
|
80
|
+
{/each}
|
|
51
81
|
</svg>
|
|
52
82
|
{/if}
|
|
@@ -8,6 +8,8 @@ interface Props {
|
|
|
8
8
|
color?: string;
|
|
9
9
|
/** Colour of equal-spacing guides. */
|
|
10
10
|
spacingColor?: string;
|
|
11
|
+
/** Colour of measuring lines, their labels and extension lines. */
|
|
12
|
+
measureColor?: string;
|
|
11
13
|
class?: string;
|
|
12
14
|
}
|
|
13
15
|
declare const CanvasGuidesLayer: import("svelte").Component<Props, {}, "">;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CanvasGuidesLayer.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/CanvasGuidesLayer.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGxE,UAAU,KAAK;IACd,kEAAkE;IAClE,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"CanvasGuidesLayer.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/CanvasGuidesLayer.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGxE,UAAU,KAAK;IACd,kEAAkE;IAClE,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,oFAAoF;IACpF,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAgDF,QAAA,MAAM,iBAAiB,2CAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { getShapeRenderData, isShapeDescription, type ShapeDescription } from '@pixerate/editor/canvas';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
/** Node data; `data.shape` holds the shape description. */
|
|
7
|
+
data: { shape?: ShapeDescription; [key: string]: any };
|
|
8
|
+
/** Node width / height (SvelteFlow passes them to custom nodes). */
|
|
9
|
+
width?: number;
|
|
10
|
+
height?: number;
|
|
11
|
+
selected?: boolean;
|
|
12
|
+
class?: string;
|
|
13
|
+
/** Rendered over the shape, e.g. SvelteFlow `<Handle>`s or a label. */
|
|
14
|
+
children?: Snippet;
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let { data, width, height, selected = false, class: className = '', children }: Props = $props();
|
|
19
|
+
|
|
20
|
+
const shape = $derived(isShapeDescription(data?.shape) ? data.shape : null);
|
|
21
|
+
const render = $derived(shape ? getShapeRenderData(shape, { width, height }) : null);
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<!--
|
|
25
|
+
Headless shape node: draws `data.shape` as one SVG path that fills the node box.
|
|
26
|
+
Register it as a SvelteFlow node type (`nodeTypes={{ shape: ShapeNode }}`), or wrap it
|
|
27
|
+
to add handles. Strokes keep their width when the node is resized.
|
|
28
|
+
-->
|
|
29
|
+
{#if shape && render}
|
|
30
|
+
<div
|
|
31
|
+
class="pixerate-shape-node {className}"
|
|
32
|
+
data-shape-kind={shape.kind}
|
|
33
|
+
data-selected={selected ? 'true' : undefined}
|
|
34
|
+
style="position: relative; width: 100%; height: 100%;"
|
|
35
|
+
>
|
|
36
|
+
<svg
|
|
37
|
+
viewBox={render.viewBox}
|
|
38
|
+
preserveAspectRatio="none"
|
|
39
|
+
width="100%"
|
|
40
|
+
height="100%"
|
|
41
|
+
style="display: block; overflow: visible;"
|
|
42
|
+
aria-hidden="true"
|
|
43
|
+
>
|
|
44
|
+
<path
|
|
45
|
+
d={render.d}
|
|
46
|
+
transform={render.transform}
|
|
47
|
+
fill={render.fill}
|
|
48
|
+
fill-rule={render.fillRule}
|
|
49
|
+
stroke={render.stroke}
|
|
50
|
+
stroke-width={render.strokeWidth}
|
|
51
|
+
opacity={render.opacity}
|
|
52
|
+
vector-effect="non-scaling-stroke"
|
|
53
|
+
/>
|
|
54
|
+
</svg>
|
|
55
|
+
{@render children?.()}
|
|
56
|
+
</div>
|
|
57
|
+
{/if}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import { type ShapeDescription } from '@pixerate/editor/canvas';
|
|
3
|
+
interface Props {
|
|
4
|
+
/** Node data; `data.shape` holds the shape description. */
|
|
5
|
+
data: {
|
|
6
|
+
shape?: ShapeDescription;
|
|
7
|
+
[key: string]: any;
|
|
8
|
+
};
|
|
9
|
+
/** Node width / height (SvelteFlow passes them to custom nodes). */
|
|
10
|
+
width?: number;
|
|
11
|
+
height?: number;
|
|
12
|
+
selected?: boolean;
|
|
13
|
+
class?: string;
|
|
14
|
+
/** Rendered over the shape, e.g. SvelteFlow `<Handle>`s or a label. */
|
|
15
|
+
children?: Snippet;
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
}
|
|
18
|
+
declare const ShapeNode: import("svelte").Component<Props, {}, "">;
|
|
19
|
+
type ShapeNode = ReturnType<typeof ShapeNode>;
|
|
20
|
+
export default ShapeNode;
|
|
21
|
+
//# sourceMappingURL=ShapeNode.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShapeNode.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/ShapeNode.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAA0C,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGvG,UAAU,KAAK;IACd,2DAA2D;IAC3D,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,gBAAgB,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IACvD,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACnB;AAwBF,QAAA,MAAM,SAAS,2CAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|
|
@@ -16,10 +16,21 @@ export interface CreateCanvasArrangeOptions<TNode extends CanvasNode = CanvasNod
|
|
|
16
16
|
* Wire snapping to SvelteFlow with `onnodedragstart={() => arrange.beginDrag()}`,
|
|
17
17
|
* `onnodedrag={({ nodes }) => arrange.drag(nodes.map((n) => n.id))}` and
|
|
18
18
|
* `onnodedragstop={() => arrange.endDrag()}`, and render `arrange.guides` with
|
|
19
|
-
* `<CanvasGuidesLayer>`.
|
|
19
|
+
* `<CanvasGuidesLayer>`. Snap resizes with `<NodeResizer {...arrange.resizerHandlers(id)} />`.
|
|
20
20
|
*/
|
|
21
21
|
export declare function createCanvasArrange<TNode extends CanvasNode = CanvasNode>(options: CreateCanvasArrangeOptions<TNode>): {
|
|
22
22
|
guides: GuideLine[];
|
|
23
|
+
/**
|
|
24
|
+
* Resize snapping for SvelteFlow's `<NodeResizer>` / `<NodeResizeControl>`:
|
|
25
|
+
* `<NodeResizer {...arrange.resizerHandlers(id)} />`. The resizer writes the raw size
|
|
26
|
+
* to the nodes after `onResize`, so snapping runs a microtask later and writes the
|
|
27
|
+
* snapped box back. Locked nodes snap back to their starting box.
|
|
28
|
+
*/
|
|
29
|
+
resizerHandlers(id: string): {
|
|
30
|
+
onResizeStart: () => void;
|
|
31
|
+
onResize: () => void;
|
|
32
|
+
onResizeEnd: () => void;
|
|
33
|
+
};
|
|
23
34
|
apply: (name: string, updates: import("@pixerate/editor/canvas").CanvasNodeUpdate[]) => import("@pixerate/editor/canvas").CanvasNodeUpdate[];
|
|
24
35
|
align(edge: import("@pixerate/editor/canvas").AlignEdge, ids?: Iterable<string>, alignOptions?: import("@pixerate/editor/canvas").AlignNodesOptions): import("@pixerate/editor/canvas").CanvasNodeUpdate[];
|
|
25
36
|
distribute(axis: import("@pixerate/editor/canvas").DistributeAxis, mode?: import("@pixerate/editor/canvas").DistributeMode, ids?: Iterable<string>, distributeOptions?: import("@pixerate/editor/canvas").DistributeNodesOptions): import("@pixerate/editor/canvas").CanvasNodeUpdate[];
|
|
@@ -33,10 +44,21 @@ export declare function createCanvasArrange<TNode extends CanvasNode = CanvasNod
|
|
|
33
44
|
unlock: (ids?: Iterable<string>) => string[];
|
|
34
45
|
toggleLock(ids?: Iterable<string>): string[];
|
|
35
46
|
isLocked: (id: string) => boolean;
|
|
47
|
+
combineShapes(operation: import("@pixerate/editor/canvas").ShapeOperation, ids?: Iterable<string>, combineOptions?: import("@pixerate/editor/canvas").CombineShapeNodesOptions): import("@pixerate/editor/canvas").CombineShapeNodesResult<any>;
|
|
48
|
+
unite: (ids?: Iterable<string>, o?: import("@pixerate/editor/canvas").CombineShapeNodesOptions) => import("@pixerate/editor/canvas").CombineShapeNodesResult<any>;
|
|
49
|
+
intersect: (ids?: Iterable<string>, o?: import("@pixerate/editor/canvas").CombineShapeNodesOptions) => import("@pixerate/editor/canvas").CombineShapeNodesResult<any>;
|
|
50
|
+
subtract: (ids?: Iterable<string>, o?: import("@pixerate/editor/canvas").CombineShapeNodesOptions) => import("@pixerate/editor/canvas").CombineShapeNodesResult<any>;
|
|
51
|
+
exclude: (ids?: Iterable<string>, o?: import("@pixerate/editor/canvas").CombineShapeNodesOptions) => import("@pixerate/editor/canvas").CombineShapeNodesResult<any>;
|
|
52
|
+
divide: (ids?: Iterable<string>, o?: import("@pixerate/editor/canvas").CombineShapeNodesOptions) => import("@pixerate/editor/canvas").CombineShapeNodesResult<any>;
|
|
53
|
+
canCombineShapes: (ids?: Iterable<string>) => boolean;
|
|
36
54
|
runAction(action: CanvasArrangeAction): boolean;
|
|
37
55
|
beginDrag(ids?: Iterable<string>): void;
|
|
38
56
|
drag(ids?: Iterable<string>): import("@pixerate/editor/canvas").SnapNodeDragResult | null;
|
|
39
57
|
snapPositionChanges<TChange extends import("@pixerate/editor/canvas").PositionChangeLike>(changes: TChange[]): TChange[];
|
|
58
|
+
beginResize(id: string): void;
|
|
59
|
+
resize(id: string, handle?: import("@pixerate/editor/canvas").ResizeHandle): import("@pixerate/editor/canvas").SnapNodeResizeResult | null;
|
|
60
|
+
endResize(): void;
|
|
61
|
+
snapResizeChanges<TChange extends import("@pixerate/editor/canvas").PositionChangeLike>(changes: TChange[]): TChange[];
|
|
40
62
|
endDrag(): void;
|
|
41
63
|
};
|
|
42
64
|
export type CanvasArrange<TNode extends CanvasNode = CanvasNode> = ReturnType<typeof createCanvasArrange<TNode>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createCanvasArrange.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/createCanvasArrange.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,8BAA8B,EACnC,KAAK,SAAS,EACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C,KAAK,WAAW,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;AAEvD,MAAM,WAAW,0BAA0B,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,CAChF,SAAQ,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,UAAU,GAAG,gBAAgB,CAAC;IACrE,QAAQ,EAAE,MAAM,KAAK,EAAE,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC;IACnC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;CAC/C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,EACxE,OAAO,EAAE,0BAA0B,CAAC,KAAK,CAAC
|
|
1
|
+
{"version":3,"file":"createCanvasArrange.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/createCanvasArrange.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,8BAA8B,EACnC,KAAK,SAAS,EACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAI7C,KAAK,WAAW,GAAG,8BAA8B,CAAC,GAAG,CAAC,CAAC;AAEvD,MAAM,WAAW,0BAA0B,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,CAChF,SAAQ,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,UAAU,GAAG,gBAAgB,CAAC;IACrE,QAAQ,EAAE,MAAM,KAAK,EAAE,CAAC;IACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC;IACnC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,IAAI,CAAC;CAC/C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,EACxE,OAAO,EAAE,0BAA0B,CAAC,KAAK,CAAC;;IAkBzC;;;;;OAKG;wBACiB,MAAM;;;;;;;;;;sBAoD+j/C,CAAC;sBAAiE,CAAC;sBAAiE,CAAC;oBAA+D,CAAC;cAAyD,CAAC;gBAAiD,CAAC;;;;;;;;;0BAA8tC,CAAC;;;;;;;;;;EAxC1miD;AAED,MAAM,MAAM,aAAa,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,IAAI,UAAU,CAAC,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;AAEjH,MAAM,WAAW,6BAA6B;IAC7C,OAAO,EAAE;QAAE,SAAS,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,OAAO,CAAA;KAAE,CAAC;IACjE,uEAAuE;IACvE,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC;IAC1D,aAAa,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IACrC,QAAQ,CAAC,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,6BAA6B,GAAG,MAAM,IAAI,CAqB/F"}
|
|
@@ -9,7 +9,7 @@ import { createCanvasArrangeController, matchArrangeShortcut } from '@pixerate/e
|
|
|
9
9
|
* Wire snapping to SvelteFlow with `onnodedragstart={() => arrange.beginDrag()}`,
|
|
10
10
|
* `onnodedrag={({ nodes }) => arrange.drag(nodes.map((n) => n.id))}` and
|
|
11
11
|
* `onnodedragstop={() => arrange.endDrag()}`, and render `arrange.guides` with
|
|
12
|
-
* `<CanvasGuidesLayer>`.
|
|
12
|
+
* `<CanvasGuidesLayer>`. Snap resizes with `<NodeResizer {...arrange.resizerHandlers(id)} />`.
|
|
13
13
|
*/
|
|
14
14
|
export function createCanvasArrange(options) {
|
|
15
15
|
let guides = $state.raw([]);
|
|
@@ -22,9 +22,26 @@ export function createCanvasArrange(options) {
|
|
|
22
22
|
});
|
|
23
23
|
return {
|
|
24
24
|
...controller,
|
|
25
|
-
/** Guide segments (flow coordinates) for the active drag; empty otherwise. */
|
|
25
|
+
/** Guide segments (flow coordinates) for the active drag or resize; empty otherwise. */
|
|
26
26
|
get guides() {
|
|
27
27
|
return guides;
|
|
28
|
+
},
|
|
29
|
+
/**
|
|
30
|
+
* Resize snapping for SvelteFlow's `<NodeResizer>` / `<NodeResizeControl>`:
|
|
31
|
+
* `<NodeResizer {...arrange.resizerHandlers(id)} />`. The resizer writes the raw size
|
|
32
|
+
* to the nodes after `onResize`, so snapping runs a microtask later and writes the
|
|
33
|
+
* snapped box back. Locked nodes snap back to their starting box.
|
|
34
|
+
*/
|
|
35
|
+
resizerHandlers(id) {
|
|
36
|
+
return {
|
|
37
|
+
onResizeStart: () => controller.beginResize(id),
|
|
38
|
+
onResize: () => {
|
|
39
|
+
queueMicrotask(() => controller.resize(id));
|
|
40
|
+
},
|
|
41
|
+
onResizeEnd: () => {
|
|
42
|
+
queueMicrotask(() => controller.endResize());
|
|
43
|
+
}
|
|
44
|
+
};
|
|
28
45
|
}
|
|
29
46
|
};
|
|
30
47
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type NodeRectOptions } from '@pixerate/editor/canvas';
|
|
2
|
+
import type { CanvasNode } from './types.js';
|
|
3
|
+
export interface CreateCanvasMeasureOptions<TNode extends CanvasNode = CanvasNode> {
|
|
4
|
+
getNodes: () => TNode[];
|
|
5
|
+
/** Ids measured from (default: nodes with `selected: true`). */
|
|
6
|
+
getSelectedIds?: () => string[];
|
|
7
|
+
/** Turns measuring off (default `true`). Read reactively. */
|
|
8
|
+
enabled?: boolean | (() => boolean);
|
|
9
|
+
/** Measure only while Alt / Option is held (default `true`); `false` always measures. */
|
|
10
|
+
requireModifier?: boolean;
|
|
11
|
+
rectOptions?: NodeRectOptions;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Headless Svelte 5 rune for Alt-hover distance measuring: hold Alt / Option and hover a
|
|
15
|
+
* node to see red distance lines with labels from the selection to it (or to the selection's
|
|
16
|
+
* parent when hovering the selection or empty space).
|
|
17
|
+
*
|
|
18
|
+
* Wire it with `$effect(() => measure.listen())`, `onnodepointerenter={measure.onnodepointerenter}`
|
|
19
|
+
* and `onnodepointerleave={measure.onnodepointerleave}` on `<SvelteFlow>`, and render
|
|
20
|
+
* `measure.guides` with `<CanvasGuidesLayer>` (concatenate with `arrange.guides` to share one).
|
|
21
|
+
*/
|
|
22
|
+
export declare function createCanvasMeasure<TNode extends CanvasNode = CanvasNode>(options: CreateCanvasMeasureOptions<TNode>): {
|
|
23
|
+
/** Measuring lines (flow coordinates) for `<CanvasGuidesLayer>`. */
|
|
24
|
+
readonly guides: import("@pixerate/editor/canvas").MeasureGuide[];
|
|
25
|
+
/** The box measured to (outline it), or `null`. */
|
|
26
|
+
readonly target: import("@pixerate/editor/canvas").Rect | null;
|
|
27
|
+
/** Whether measuring is showing. */
|
|
28
|
+
readonly active: boolean;
|
|
29
|
+
readonly hoveredId: string | null;
|
|
30
|
+
setHovered(id: string | null): void;
|
|
31
|
+
/** Sets the modifier state by hand (e.g. from a toolbar toggle). */
|
|
32
|
+
setModifier(held: boolean): void;
|
|
33
|
+
onnodepointerenter: ({ node, event }: {
|
|
34
|
+
node: {
|
|
35
|
+
id: string;
|
|
36
|
+
};
|
|
37
|
+
event?: {
|
|
38
|
+
altKey?: boolean;
|
|
39
|
+
};
|
|
40
|
+
}) => void;
|
|
41
|
+
onnodepointerleave: ({ node }: {
|
|
42
|
+
node: {
|
|
43
|
+
id: string;
|
|
44
|
+
};
|
|
45
|
+
}) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Tracks the Alt key on `target` (default `window`) and resets it when the window
|
|
48
|
+
* loses focus. Returns a cleanup function.
|
|
49
|
+
*/
|
|
50
|
+
listen(target?: HTMLElement | Window | null): () => void;
|
|
51
|
+
};
|
|
52
|
+
export type CanvasMeasure = ReturnType<typeof createCanvasMeasure>;
|
|
53
|
+
//# sourceMappingURL=createCanvasMeasure.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createCanvasMeasure.svelte.d.ts","sourceRoot":"","sources":["../../src/canvas/createCanvasMeasure.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,KAAK,eAAe,EACpB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,0BAA0B,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU;IAChF,QAAQ,EAAE,MAAM,KAAK,EAAE,CAAC;IACxB,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,MAAM,EAAE,CAAC;IAChC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;IACpC,yFAAyF;IACzF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,eAAe,CAAC;CAC9B;AAID;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,SAAS,UAAU,GAAG,UAAU,EAAE,OAAO,EAAE,0BAA0B,CAAC,KAAK,CAAC;IAcnH,oEAAoE;;IAIpE,mDAAmD;;IAInD,oCAAoC;;;mBAOrB,MAAM,GAAG,IAAI;IAG5B,oEAAoE;sBAClD,OAAO;0CAGa;QAAE,IAAI,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,KAAK,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE;mCAI7D;QAAE,IAAI,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE;IAGvD;;;OAGG;oBACY,WAAW,GAAG,MAAM,GAAG,IAAI,GAAmD,MAAM,IAAI;EAmBxG;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { isMeasureModifierHeld, measureSelection } from '@pixerate/editor/canvas';
|
|
2
|
+
const EMPTY = { guides: [], target: null, selection: null };
|
|
3
|
+
/**
|
|
4
|
+
* Headless Svelte 5 rune for Alt-hover distance measuring: hold Alt / Option and hover a
|
|
5
|
+
* node to see red distance lines with labels from the selection to it (or to the selection's
|
|
6
|
+
* parent when hovering the selection or empty space).
|
|
7
|
+
*
|
|
8
|
+
* Wire it with `$effect(() => measure.listen())`, `onnodepointerenter={measure.onnodepointerenter}`
|
|
9
|
+
* and `onnodepointerleave={measure.onnodepointerleave}` on `<SvelteFlow>`, and render
|
|
10
|
+
* `measure.guides` with `<CanvasGuidesLayer>` (concatenate with `arrange.guides` to share one).
|
|
11
|
+
*/
|
|
12
|
+
export function createCanvasMeasure(options) {
|
|
13
|
+
let hoveredId = $state(null);
|
|
14
|
+
let modifier = $state(false);
|
|
15
|
+
const enabled = () => (typeof options.enabled === 'function' ? options.enabled() : options.enabled !== false);
|
|
16
|
+
const active = $derived(enabled() && (options.requireModifier === false || modifier));
|
|
17
|
+
const result = $derived.by(() => {
|
|
18
|
+
if (!active)
|
|
19
|
+
return EMPTY;
|
|
20
|
+
const nodes = options.getNodes();
|
|
21
|
+
const ids = options.getSelectedIds?.() ?? nodes.filter((n) => n.selected).map((n) => n.id);
|
|
22
|
+
return measureSelection(nodes, ids, hoveredId, options.rectOptions);
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
/** Measuring lines (flow coordinates) for `<CanvasGuidesLayer>`. */
|
|
26
|
+
get guides() {
|
|
27
|
+
return result.guides;
|
|
28
|
+
},
|
|
29
|
+
/** The box measured to (outline it), or `null`. */
|
|
30
|
+
get target() {
|
|
31
|
+
return result.target;
|
|
32
|
+
},
|
|
33
|
+
/** Whether measuring is showing. */
|
|
34
|
+
get active() {
|
|
35
|
+
return active;
|
|
36
|
+
},
|
|
37
|
+
get hoveredId() {
|
|
38
|
+
return hoveredId;
|
|
39
|
+
},
|
|
40
|
+
setHovered(id) {
|
|
41
|
+
hoveredId = id;
|
|
42
|
+
},
|
|
43
|
+
/** Sets the modifier state by hand (e.g. from a toolbar toggle). */
|
|
44
|
+
setModifier(held) {
|
|
45
|
+
modifier = held;
|
|
46
|
+
},
|
|
47
|
+
onnodepointerenter: ({ node, event }) => {
|
|
48
|
+
hoveredId = node.id;
|
|
49
|
+
if (event && typeof event.altKey === 'boolean')
|
|
50
|
+
modifier = event.altKey;
|
|
51
|
+
},
|
|
52
|
+
onnodepointerleave: ({ node }) => {
|
|
53
|
+
if (hoveredId === node.id)
|
|
54
|
+
hoveredId = null;
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* Tracks the Alt key on `target` (default `window`) and resets it when the window
|
|
58
|
+
* loses focus. Returns a cleanup function.
|
|
59
|
+
*/
|
|
60
|
+
listen(target = typeof window !== 'undefined' ? window : null) {
|
|
61
|
+
if (!target)
|
|
62
|
+
return () => { };
|
|
63
|
+
const onKey = (event) => {
|
|
64
|
+
modifier = isMeasureModifierHeld(event);
|
|
65
|
+
};
|
|
66
|
+
const onBlur = () => {
|
|
67
|
+
modifier = false;
|
|
68
|
+
};
|
|
69
|
+
target.addEventListener('keydown', onKey);
|
|
70
|
+
target.addEventListener('keyup', onKey);
|
|
71
|
+
const win = typeof window !== 'undefined' ? window : null;
|
|
72
|
+
win?.addEventListener('blur', onBlur);
|
|
73
|
+
return () => {
|
|
74
|
+
target.removeEventListener('keydown', onKey);
|
|
75
|
+
target.removeEventListener('keyup', onKey);
|
|
76
|
+
win?.removeEventListener('blur', onBlur);
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
package/dist/canvas/index.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ export { createStreamingCanvas, type CreateStreamingCanvasOptions } from './crea
|
|
|
17
17
|
export { createCanvasArrange, createCanvasArrangeShortcuts, type CanvasArrange, type CreateCanvasArrangeOptions, type CanvasArrangeShortcutsOptions } from './createCanvasArrange.svelte.js';
|
|
18
18
|
export { createCanvasScenes, type CanvasScenes, type CreateCanvasScenesOptions } from './createCanvasScenes.svelte.js';
|
|
19
19
|
export { default as CanvasGuidesLayer } from './CanvasGuidesLayer.svelte';
|
|
20
|
+
export { createCanvasMeasure, type CanvasMeasure, type CreateCanvasMeasureOptions } from './createCanvasMeasure.svelte.js';
|
|
21
|
+
export { measureBetween, measureToLine, measureSelection, measureLabel, isMeasureModifierHeld, snapToGrid, snapResize, snapNodeResize, inferResizeHandle, resizeHandleAxes, getResizingNodeRect, RESIZE_HANDLES, fitCubics, fitCubicRun, fitPathData, fitFreehandPath, cubicsToPathData, cubicPointAt, isStraightCubic, type MeasureGuide, type MeasureSelectionResult, type MeasureSelectionOptions, type ResizeHandle, type SnapResizeOptions, type SnapResizeResult, type SnapNodeResizeOptions, type SnapNodeResizeResult, type CubicSegment, type FitCubicsOptions, type FitPathDataOptions } from '@pixerate/editor/canvas';
|
|
20
22
|
export { alignNodes, distributeNodes, matchSize, reorderNodes, applyNodeUpdates, invertNodeUpdates, lockNodes, unlockNodes, toggleLockNodes, isLocked, getNodeSize, getNodeRect, getAbsolutePosition, readStyleSize, withStyleSize, computeSnapGuides, createGuideIndex, createNodeGuideIndex, snapNodeDrag, findConnectorSnap, nearestHandlePositions, handlePoint, positionToSide, sideToPosition, oppositePosition, CONNECTION_LINE_TYPES, CanvasScenesStore, createCanvasScenesStore, parseCanvasScenes, fitViewportToRect, fitViewportToNodes, matchArrangeShortcut, DEFAULT_ARRANGE_SHORTCUTS, type AlignEdge, type DistributeAxis, type DistributeMode, type SizeDimension, type ZOrderOperation, type CanvasNodeUpdate, type GuideLine, type GuideIndex, type SnapGuidesOptions, type SnapResult, type ConnectorSnap, type ConnectorSnapTarget, type CanvasConnectionLineType, type CanvasScene, type CanvasScenesState, type CanvasViewport, type CanvasArrangeAction, type ArrangeShortcutBinding } from '@pixerate/editor/canvas';
|
|
23
|
+
export { default as ShapeNode } from './ShapeNode.svelte';
|
|
24
|
+
export { combineShapeNodes, canCombineShapeNodes, applyShapeCombination, revertShapeCombination, shapeNodeToPolygon, isShapeNode, getNodeShape, SHAPE_DATA_KEY, SHAPE_NODE_TYPE, SHAPE_OPERATIONS, SHAPE_KINDS, isShapeDescription, shapeToPolygon, getShapeSvg, getShapeRenderData, parseSvgPath, flattenSvgPath, polygonToSvgPath, simplifyRing, polygonBoolean, unionPolygons, intersectPolygons, subtractPolygons, xorPolygons, dividePolygons, polygonArea, multiPolygonArea, multiPolygonBounds, ringSignedArea, pointInRings, pointInMultiPolygon, type ShapeOperation, type ShapeDescription, type ShapeKind, type ShapePaint, type ShapeSize, type ShapeRenderData, type RectShape, type EllipseShape, type RegularPolygonShape, type StarShape, type PathShape, type PathCommand, type FlattenOptions, type PolygonToPathOptions, type CombineShapeNodesOptions, type CombineShapeNodesResult, type CombineShapeNodesRefusal, type ShapeNodePolygonOptions, type MultiPolygon, type PolygonWithHoles, type PolygonRing, type PolygonFillRule, type PolygonOperand, type PolygonInput, type PolygonPiece, type PolygonBooleanOperation, type PolygonBooleanOptions } from '@pixerate/editor/canvas';
|
|
21
25
|
export { realClock, ManualClock, layoutBounds, canvasHeight, estimateCanvasHeight, blendLayout, connectedOnly, type Clock, type CanvasHeightOptions } from '@pixerate/editor/canvas';
|
|
22
26
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/canvas/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAG3B,OAAO,EACN,iBAAiB,EACjB,yBAAyB,EACzB,kBAAkB,EAClB,KAAK,wBAAwB,EAC7B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EACN,gBAAgB,EAChB,uBAAuB,EACvB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,QAAQ,EACR,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACN,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,UAAU,EACV,KAAK,4BAA4B,EACjC,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EACN,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,KAAK,YAAY,EACjB,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EACN,qBAAqB,EACrB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EACN,wBAAwB,EACxB,uBAAuB,EACvB,oBAAoB,EACpB,yBAAyB,EACzB,KAAK,+BAA+B,EACpC,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EACN,gBAAgB,EAChB,wBAAwB,EACxB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EACN,uBAAuB,EACvB,gCAAgC,EAChC,2BAA2B,EAC3B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EACN,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,4BAA4B,EACjC,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EACN,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,2BAA2B,EAChC,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EACN,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC5B,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EACtB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EACN,yBAAyB,EACzB,sBAAsB,EACtB,KAAK,sBAAsB,EAC3B,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,OAAO,IAAI,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AAG9F,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAG5E,OAAO,EACN,qBAAqB,EACrB,KAAK,4BAA4B,EACjC,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EACN,mBAAmB,EACnB,4BAA4B,EAC5B,KAAK,aAAa,EAClB,KAAK,0BAA0B,EAC/B,KAAK,6BAA6B,EAClC,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACN,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,yBAAyB,EAC9B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/canvas/index.ts"],"names":[],"mappings":"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"}
|
package/dist/canvas/index.js
CHANGED
|
@@ -34,6 +34,12 @@ export { createStreamingCanvas } from './createStreamingCanvas.svelte.js';
|
|
|
34
34
|
export { createCanvasArrange, createCanvasArrangeShortcuts } from './createCanvasArrange.svelte.js';
|
|
35
35
|
export { createCanvasScenes } from './createCanvasScenes.svelte.js';
|
|
36
36
|
export { default as CanvasGuidesLayer } from './CanvasGuidesLayer.svelte';
|
|
37
|
+
// Distance measuring (Alt-hover), resize / grid snapping and curve fitting
|
|
38
|
+
export { createCanvasMeasure } from './createCanvasMeasure.svelte.js';
|
|
39
|
+
export { measureBetween, measureToLine, measureSelection, measureLabel, isMeasureModifierHeld, snapToGrid, snapResize, snapNodeResize, inferResizeHandle, resizeHandleAxes, getResizingNodeRect, RESIZE_HANDLES, fitCubics, fitCubicRun, fitPathData, fitFreehandPath, cubicsToPathData, cubicPointAt, isStraightCubic } from '@pixerate/editor/canvas';
|
|
37
40
|
export { alignNodes, distributeNodes, matchSize, reorderNodes, applyNodeUpdates, invertNodeUpdates, lockNodes, unlockNodes, toggleLockNodes, isLocked, getNodeSize, getNodeRect, getAbsolutePosition, readStyleSize, withStyleSize, computeSnapGuides, createGuideIndex, createNodeGuideIndex, snapNodeDrag, findConnectorSnap, nearestHandlePositions, handlePoint, positionToSide, sideToPosition, oppositePosition, CONNECTION_LINE_TYPES, CanvasScenesStore, createCanvasScenesStore, parseCanvasScenes, fitViewportToRect, fitViewportToNodes, matchArrangeShortcut, DEFAULT_ARRANGE_SHORTCUTS } from '@pixerate/editor/canvas';
|
|
41
|
+
export { default as ShapeNode } from './ShapeNode.svelte';
|
|
42
|
+
// Shape nodes and boolean operations (Unite / Intersect / Subtract / Exclude / Divide)
|
|
43
|
+
export { combineShapeNodes, canCombineShapeNodes, applyShapeCombination, revertShapeCombination, shapeNodeToPolygon, isShapeNode, getNodeShape, SHAPE_DATA_KEY, SHAPE_NODE_TYPE, SHAPE_OPERATIONS, SHAPE_KINDS, isShapeDescription, shapeToPolygon, getShapeSvg, getShapeRenderData, parseSvgPath, flattenSvgPath, polygonToSvgPath, simplifyRing, polygonBoolean, unionPolygons, intersectPolygons, subtractPolygons, xorPolygons, dividePolygons, polygonArea, multiPolygonArea, multiPolygonBounds, ringSignedArea, pointInRings, pointInMultiPolygon } from '@pixerate/editor/canvas';
|
|
38
44
|
// Clock and view helpers from core
|
|
39
45
|
export { realClock, ManualClock, layoutBounds, canvasHeight, estimateCanvasHeight, blendLayout, connectedOnly } from '@pixerate/editor/canvas';
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
// Ids only render while the palette is open (client side), so a counter is enough
|
|
3
|
+
// (`$props.id()` needs Svelte 5.20, newer than our peer range).
|
|
4
|
+
let nextId = 0;
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import type { CommandPaletteItem } from '@pixerate/editor/commands';
|
|
9
|
+
import type { SvelteCommandPalette } from './palette.svelte.js';
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
/** State from `createCommandPalette`. */
|
|
13
|
+
palette: SvelteCommandPalette;
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
emptyMessage?: string;
|
|
16
|
+
/** Extra classes for the dialog panel. */
|
|
17
|
+
class?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let {
|
|
21
|
+
palette,
|
|
22
|
+
placeholder = 'Type a command…',
|
|
23
|
+
emptyMessage = 'No matching commands',
|
|
24
|
+
class: className = ''
|
|
25
|
+
}: Props = $props();
|
|
26
|
+
|
|
27
|
+
const baseId = `command-palette-${++nextId}`;
|
|
28
|
+
const listId = `${baseId}-list`;
|
|
29
|
+
const optionId = (index: number) => `${baseId}-option-${index}`;
|
|
30
|
+
|
|
31
|
+
let inputEl = $state<HTMLInputElement | null>(null);
|
|
32
|
+
let listEl = $state<HTMLUListElement | null>(null);
|
|
33
|
+
|
|
34
|
+
$effect(() => {
|
|
35
|
+
if (palette.open) inputEl?.focus();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
$effect(() => {
|
|
39
|
+
void palette.activeIndex;
|
|
40
|
+
if (!palette.open) return;
|
|
41
|
+
const active = listEl?.querySelector<HTMLElement>('[aria-selected="true"]');
|
|
42
|
+
active?.scrollIntoView?.({ block: 'nearest' });
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const segments = (item: CommandPaletteItem) => {
|
|
46
|
+
const marked = new Set(item.labelIndices);
|
|
47
|
+
return Array.from(item.label).map((ch, i) => ({ ch, match: marked.has(i) }));
|
|
48
|
+
};
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
{#if palette.open}
|
|
52
|
+
<!-- Headless-styled command palette: Arrow keys move, Enter runs, Escape or a backdrop press closes. -->
|
|
53
|
+
<div
|
|
54
|
+
class="fixed inset-0 z-50 flex items-start justify-center bg-black/30 px-4 pt-[15vh]"
|
|
55
|
+
data-command-palette-backdrop=""
|
|
56
|
+
role="presentation"
|
|
57
|
+
onmousedown={(e) => {
|
|
58
|
+
if (e.target === e.currentTarget) palette.setOpen(false);
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
<div
|
|
62
|
+
role="dialog"
|
|
63
|
+
aria-modal="true"
|
|
64
|
+
aria-label="Command palette"
|
|
65
|
+
class="w-full max-w-lg overflow-hidden rounded-lg border border-border bg-popover text-popover-foreground shadow-xl {className}"
|
|
66
|
+
style="background: var(--popover, var(--background, #fff));"
|
|
67
|
+
>
|
|
68
|
+
<input
|
|
69
|
+
bind:this={inputEl}
|
|
70
|
+
type="text"
|
|
71
|
+
role="combobox"
|
|
72
|
+
aria-expanded="true"
|
|
73
|
+
aria-controls={listId}
|
|
74
|
+
aria-autocomplete="list"
|
|
75
|
+
aria-activedescendant={palette.items.length ? optionId(palette.activeIndex) : undefined}
|
|
76
|
+
aria-label="Search commands"
|
|
77
|
+
{placeholder}
|
|
78
|
+
value={palette.query}
|
|
79
|
+
oninput={(e) => palette.setQuery(e.currentTarget.value)}
|
|
80
|
+
onkeydown={(e) => {
|
|
81
|
+
if (palette.handleKeyDown(e)) e.stopPropagation();
|
|
82
|
+
}}
|
|
83
|
+
class="w-full border-b border-border bg-transparent px-3 py-2 text-sm outline-none placeholder:text-muted-foreground"
|
|
84
|
+
/>
|
|
85
|
+
{#if palette.items.length === 0}
|
|
86
|
+
<div class="px-3 py-6 text-center text-sm text-muted-foreground">{emptyMessage}</div>
|
|
87
|
+
{:else}
|
|
88
|
+
<ul bind:this={listEl} id={listId} role="listbox" aria-label="Commands" class="max-h-80 overflow-y-auto py-1">
|
|
89
|
+
{#each palette.items as item, index (item.id)}
|
|
90
|
+
<li
|
|
91
|
+
id={optionId(index)}
|
|
92
|
+
role="option"
|
|
93
|
+
aria-selected={index === palette.activeIndex}
|
|
94
|
+
aria-disabled={!item.enabled || undefined}
|
|
95
|
+
data-command-id={item.id}
|
|
96
|
+
data-recent={item.recent ? '' : undefined}
|
|
97
|
+
title={item.disabledReason}
|
|
98
|
+
onmousemove={() => index !== palette.activeIndex && palette.setActiveIndex(index)}
|
|
99
|
+
onmousedown={(e) => e.preventDefault()}
|
|
100
|
+
onclick={() => palette.run(item.id)}
|
|
101
|
+
onkeydown={() => {}}
|
|
102
|
+
class="flex cursor-pointer items-center gap-2 px-3 py-1.5 text-sm {index === palette.activeIndex
|
|
103
|
+
? 'bg-muted'
|
|
104
|
+
: ''} {item.enabled ? '' : 'cursor-default opacity-50'}"
|
|
105
|
+
>
|
|
106
|
+
<span class="min-w-0 flex-1 truncate">
|
|
107
|
+
{#each segments(item) as segment, i (i)}{#if segment.match}<span
|
|
108
|
+
class="font-semibold text-foreground"
|
|
109
|
+
data-match="">{segment.ch}</span
|
|
110
|
+
>{:else}{segment.ch}{/if}{/each}
|
|
111
|
+
{#if item.disabledReason}
|
|
112
|
+
<span class="ml-2 text-xs text-muted-foreground" data-disabled-reason="">{item.disabledReason}</span>
|
|
113
|
+
{/if}
|
|
114
|
+
</span>
|
|
115
|
+
{#if item.group}
|
|
116
|
+
<span class="shrink-0 text-xs text-muted-foreground">{item.group}</span>
|
|
117
|
+
{/if}
|
|
118
|
+
{#if item.shortcut}
|
|
119
|
+
<kbd class="shrink-0 rounded border border-border px-1.5 font-mono text-[10px] text-muted-foreground"
|
|
120
|
+
>{item.shortcut}</kbd
|
|
121
|
+
>
|
|
122
|
+
{/if}
|
|
123
|
+
</li>
|
|
124
|
+
{/each}
|
|
125
|
+
</ul>
|
|
126
|
+
{/if}
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
{/if}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SvelteCommandPalette } from './palette.svelte.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** State from `createCommandPalette`. */
|
|
4
|
+
palette: SvelteCommandPalette;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
emptyMessage?: string;
|
|
7
|
+
/** Extra classes for the dialog panel. */
|
|
8
|
+
class?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const CommandPalette: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type CommandPalette = ReturnType<typeof CommandPalette>;
|
|
12
|
+
export default CommandPalette;
|
|
13
|
+
//# sourceMappingURL=CommandPalette.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommandPalette.svelte.d.ts","sourceRoot":"","sources":["../../src/commands/CommandPalette.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAG9D,UAAU,KAAK;IACb,yCAAyC;IACzC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA8EH,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|