@pixerate/editor-svelte 0.32.0 → 0.33.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/dist/vector/VectorCanvas.svelte +6 -0
- package/dist/vector/VectorCanvas.svelte.d.ts.map +1 -1
- package/dist/vector/VectorSceneNodes.svelte +33 -0
- package/dist/vector/VectorSceneNodes.svelte.d.ts.map +1 -1
- package/dist/vector/VectorStylePanel.svelte +106 -4
- package/dist/vector/VectorStylePanel.svelte.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -218,6 +218,12 @@
|
|
|
218
218
|
<circle data-vector-anchor={a.ref.index} cx={a.x} cy={a.y} r={size / 2} fill={a.selected ? accentColor : THEME.handleFill} stroke={accentColor} />
|
|
219
219
|
{/if}
|
|
220
220
|
{/each}
|
|
221
|
+
{#each overlay.cornerWidgets as w (`corner:${anchorKey(w)}`)}
|
|
222
|
+
<g data-vector-corner-widget={w.ref.index} data-corner-kind={w.kind}>
|
|
223
|
+
<circle cx={w.x} cy={w.y} r={THEME.cornerWidgetRadius + (w.hovered ? 1 : 0)} fill={THEME.handleFill} stroke={accentColor} />
|
|
224
|
+
<circle cx={w.x} cy={w.y} r={1.5} fill={accentColor} />
|
|
225
|
+
</g>
|
|
226
|
+
{/each}
|
|
221
227
|
{#if closing}
|
|
222
228
|
<circle cx={closing.x} cy={closing.y} r={as} stroke={accentColor} />
|
|
223
229
|
{/if}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VectorCanvas.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/VectorCanvas.svelte.ts"],"names":[],"mappings":"AAQA,OAAO,EAOH,KAAK,sBAAsB,EAC5B,MAAM,yBAAyB,CAAC;AAMjC,UAAU,KAAK;IACb,UAAU,EAAE,sBAAsB,CAAC;IACnC,mFAAmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"VectorCanvas.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/VectorCanvas.svelte.ts"],"names":[],"mappings":"AAQA,OAAO,EAOH,KAAK,sBAAsB,EAC5B,MAAM,yBAAyB,CAAC;AAMjC,UAAU,KAAK;IACb,UAAU,EAAE,sBAAsB,CAAC;IACnC,mFAAmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAqMH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -14,6 +14,39 @@
|
|
|
14
14
|
<g data-vector-id={node.id} transform={node.transform} opacity={node.opacity < 1 ? node.opacity : undefined}>
|
|
15
15
|
<Self nodes={node.children} />
|
|
16
16
|
</g>
|
|
17
|
+
{:else if node.strokeParts}
|
|
18
|
+
{@const sp = node.strokeParts}
|
|
19
|
+
<!-- An aligned stroke (double width, clipped or masked by the shape) or one with arrowheads. -->
|
|
20
|
+
<g data-vector-id={node.id} data-vector-stroke-align={sp.align} transform={node.transform} opacity={node.opacity < 1 ? node.opacity : undefined}>
|
|
21
|
+
{#if sp.clip}
|
|
22
|
+
<defs>
|
|
23
|
+
{#if sp.clip.kind === 'clip'}
|
|
24
|
+
<clipPath id={sp.clip.id}><path d={node.d} clip-rule={node.fillRule} /></clipPath>
|
|
25
|
+
{:else}
|
|
26
|
+
<mask id={sp.clip.id} maskUnits="userSpaceOnUse" x={sp.clip.bounds.x} y={sp.clip.bounds.y} width={sp.clip.bounds.width} height={sp.clip.bounds.height}>
|
|
27
|
+
<rect x={sp.clip.bounds.x} y={sp.clip.bounds.y} width={sp.clip.bounds.width} height={sp.clip.bounds.height} fill="#fff" />
|
|
28
|
+
<path d={node.d} fill="#000" fill-rule={node.fillRule} />
|
|
29
|
+
</mask>
|
|
30
|
+
{/if}
|
|
31
|
+
</defs>
|
|
32
|
+
{/if}
|
|
33
|
+
<path data-vector-part="fill" d={node.d} fill={node.fill} fill-rule={node.fillRule} stroke="none" />
|
|
34
|
+
<path
|
|
35
|
+
data-vector-part="stroke"
|
|
36
|
+
d={sp.d}
|
|
37
|
+
fill="none"
|
|
38
|
+
stroke={node.stroke}
|
|
39
|
+
stroke-width={sp.width}
|
|
40
|
+
stroke-linecap={node.strokeLinecap as any}
|
|
41
|
+
stroke-linejoin={node.strokeLinejoin as any}
|
|
42
|
+
stroke-dasharray={node.strokeDasharray}
|
|
43
|
+
clip-path={sp.clip?.kind === 'clip' ? `url(#${sp.clip.id})` : undefined}
|
|
44
|
+
mask={sp.clip?.kind === 'mask' ? `url(#${sp.clip.id})` : undefined}
|
|
45
|
+
/>
|
|
46
|
+
{#each sp.heads as head, i (i)}
|
|
47
|
+
<path data-vector-part="head" d={head} fill={node.stroke} />
|
|
48
|
+
{/each}
|
|
49
|
+
</g>
|
|
17
50
|
{:else}
|
|
18
51
|
<path
|
|
19
52
|
data-vector-id={node.id}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VectorSceneNodes.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/VectorSceneNodes.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAI9D,UAAU,KAAK;IACb,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACpC;
|
|
1
|
+
{"version":3,"file":"VectorSceneNodes.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/VectorSceneNodes.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAI9D,UAAU,KAAK;IACb,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACpC;AA2CH,QAAA,MAAM,gBAAgB,2CAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
VECTOR_ARROWHEADS,
|
|
4
|
+
VECTOR_ARROWHEAD_LABELS,
|
|
5
|
+
VECTOR_CORNER_KINDS,
|
|
6
|
+
VECTOR_CORNER_KIND_LABELS,
|
|
7
|
+
VECTOR_STROKE_ALIGN_LABELS,
|
|
8
|
+
getVectorSelectionStyle,
|
|
9
|
+
vectorPaintToHex,
|
|
10
|
+
type VectorCornerKind,
|
|
11
|
+
type VectorEditorController,
|
|
12
|
+
type VectorStrokeAlign
|
|
13
|
+
} from '@pixerate/editor/vector';
|
|
3
14
|
import { vectorStateOf } from './subscribe.svelte.js';
|
|
4
15
|
|
|
5
16
|
interface Props {
|
|
@@ -12,9 +23,39 @@
|
|
|
12
23
|
const store = vectorStateOf(() => controller);
|
|
13
24
|
const view = $derived(store.current);
|
|
14
25
|
const style = $derived(getVectorSelectionStyle(view));
|
|
15
|
-
const source = $derived(
|
|
16
|
-
style
|
|
17
|
-
|
|
26
|
+
const source = $derived.by(() => {
|
|
27
|
+
if (style) return style;
|
|
28
|
+
const d = view.defaults;
|
|
29
|
+
return {
|
|
30
|
+
fill: d.fill ?? null,
|
|
31
|
+
stroke: d.stroke ?? null,
|
|
32
|
+
strokeWidth: d.strokeWidth ?? 1,
|
|
33
|
+
opacity: 1,
|
|
34
|
+
strokeAlign: d.strokeAlign ?? 'center',
|
|
35
|
+
startArrow: d.startArrow ?? null,
|
|
36
|
+
endArrow: d.endArrow ?? null,
|
|
37
|
+
arrowAlign: d.arrowAlign ?? 'extend',
|
|
38
|
+
startArrowScale: d.startArrowScale ?? 1,
|
|
39
|
+
endArrowScale: d.endArrowScale ?? 1,
|
|
40
|
+
cornerRadius: d.cornerRadius,
|
|
41
|
+
cornerKind: d.cornerKind ?? 'round',
|
|
42
|
+
corners: 1,
|
|
43
|
+
hasOpenPath: true
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
const aligns = Object.keys(VECTOR_STROKE_ALIGN_LABELS) as VectorStrokeAlign[];
|
|
47
|
+
const ends = [
|
|
48
|
+
{ end: 'start', key: 'startArrow', scaleKey: 'startArrowScale', label: 'Start' },
|
|
49
|
+
{ end: 'end', key: 'endArrow', scaleKey: 'endArrowScale', label: 'End' }
|
|
50
|
+
] as const;
|
|
51
|
+
const selectClass = 'h-7 min-w-0 flex-1 rounded border border-border bg-background px-1 text-xs';
|
|
52
|
+
const numberClass = 'h-7 w-16 rounded border border-border bg-background px-1.5 text-xs';
|
|
53
|
+
|
|
54
|
+
function setCorners(patch: { radius?: number; kind?: VectorCornerKind }) {
|
|
55
|
+
if (!style) controller.setDefaults({ ...(patch.radius !== undefined ? { cornerRadius: patch.radius } : {}), ...(patch.kind ? { cornerKind: patch.kind } : {}) });
|
|
56
|
+
else if (patch.radius !== undefined) controller.setCornerRadius(patch.radius);
|
|
57
|
+
else if (patch.kind) controller.setCornerKind(patch.kind);
|
|
58
|
+
}
|
|
18
59
|
|
|
19
60
|
function apply(patch: Record<string, unknown>) {
|
|
20
61
|
if (style) controller.setStyle(patch);
|
|
@@ -65,6 +106,67 @@
|
|
|
65
106
|
}}
|
|
66
107
|
/>
|
|
67
108
|
</label>
|
|
109
|
+
<label class="flex items-center gap-2 text-xs text-foreground" data-vector-style="strokeAlign">
|
|
110
|
+
<span class="w-16">Align</span>
|
|
111
|
+
<select aria-label="Stroke alignment" class={selectClass} value={source.strokeAlign} onchange={(e) => apply({ strokeAlign: e.currentTarget.value })}>
|
|
112
|
+
{#each aligns as a (a)}<option value={a}>{VECTOR_STROKE_ALIGN_LABELS[a]}</option>{/each}
|
|
113
|
+
</select>
|
|
114
|
+
{#if style?.mixed.strokeAlign}<span class="text-[11px] text-muted-foreground">Mixed</span>{/if}
|
|
115
|
+
</label>
|
|
116
|
+
{#if source.hasOpenPath}
|
|
117
|
+
{#each ends as { key, scaleKey, label } (key)}
|
|
118
|
+
<div class="flex items-center gap-2" data-vector-style={key}>
|
|
119
|
+
<span class="w-16 text-xs text-foreground">{label}</span>
|
|
120
|
+
<select aria-label="{label} arrowhead" class={selectClass} value={source[key] ?? ''} onchange={(e) => apply({ [key]: e.currentTarget.value || null })}>
|
|
121
|
+
<option value="">None</option>
|
|
122
|
+
{#each VECTOR_ARROWHEADS as h (h)}<option value={h}>{VECTOR_ARROWHEAD_LABELS[h]}</option>{/each}
|
|
123
|
+
</select>
|
|
124
|
+
<input
|
|
125
|
+
type="number"
|
|
126
|
+
min="0.1"
|
|
127
|
+
step="0.25"
|
|
128
|
+
aria-label="{label} arrowhead scale"
|
|
129
|
+
title="Scale (× stroke width)"
|
|
130
|
+
class={numberClass}
|
|
131
|
+
value={source[scaleKey]}
|
|
132
|
+
oninput={(e) => {
|
|
133
|
+
const n = parseFloat(e.currentTarget.value);
|
|
134
|
+
if (Number.isFinite(n) && n > 0) apply({ [scaleKey]: n });
|
|
135
|
+
}}
|
|
136
|
+
/>
|
|
137
|
+
</div>
|
|
138
|
+
{/each}
|
|
139
|
+
{#if source.startArrow || source.endArrow}
|
|
140
|
+
<label class="flex items-center gap-2 text-xs text-foreground" data-vector-style="arrowAlign">
|
|
141
|
+
<span class="w-16">Heads</span>
|
|
142
|
+
<select aria-label="Arrowhead alignment" class={selectClass} value={source.arrowAlign} onchange={(e) => apply({ arrowAlign: e.currentTarget.value })}>
|
|
143
|
+
<option value="extend">Tip past end</option>
|
|
144
|
+
<option value="tip">Tip at end</option>
|
|
145
|
+
</select>
|
|
146
|
+
</label>
|
|
147
|
+
{/if}
|
|
148
|
+
{/if}
|
|
149
|
+
{#if source.corners > 0}
|
|
150
|
+
<div class="flex items-center gap-2" data-vector-style="corners">
|
|
151
|
+
<span class="w-16 text-xs text-foreground">Corners</span>
|
|
152
|
+
<input
|
|
153
|
+
type="number"
|
|
154
|
+
min="0"
|
|
155
|
+
step="1"
|
|
156
|
+
aria-label="Corner radius"
|
|
157
|
+
class={numberClass}
|
|
158
|
+
value={Math.round(source.cornerRadius * 100) / 100}
|
|
159
|
+
oninput={(e) => {
|
|
160
|
+
const n = parseFloat(e.currentTarget.value);
|
|
161
|
+
if (Number.isFinite(n) && n >= 0) setCorners({ radius: n });
|
|
162
|
+
}}
|
|
163
|
+
/>
|
|
164
|
+
<select aria-label="Corner kind" class={selectClass} value={source.cornerKind} onchange={(e) => setCorners({ kind: e.currentTarget.value as VectorCornerKind })}>
|
|
165
|
+
{#each VECTOR_CORNER_KINDS as k (k)}<option value={k}>{VECTOR_CORNER_KIND_LABELS[k]}</option>{/each}
|
|
166
|
+
</select>
|
|
167
|
+
{#if style?.mixed.cornerRadius}<span class="text-[11px] text-muted-foreground">Mixed</span>{/if}
|
|
168
|
+
</div>
|
|
169
|
+
{/if}
|
|
68
170
|
{#if style}
|
|
69
171
|
<label class="flex items-center gap-2 text-xs text-foreground">
|
|
70
172
|
<span class="w-16">Opacity</span>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VectorStylePanel.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/VectorStylePanel.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"VectorStylePanel.svelte.d.ts","sourceRoot":"","sources":["../../src/vector/VectorStylePanel.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EASH,KAAK,sBAAsB,EAE5B,MAAM,yBAAyB,CAAC;AAIjC,UAAU,KAAK;IACb,UAAU,EAAE,sBAAsB,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqIH,QAAA,MAAM,gBAAgB,2CAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"@tiptap/extension-bubble-menu": "^2.11.5",
|
|
108
108
|
"@tiptap/extension-placeholder": "^2.11.5",
|
|
109
109
|
"@tiptap/starter-kit": "^2.11.5",
|
|
110
|
-
"@pixerate/editor": "0.
|
|
110
|
+
"@pixerate/editor": "0.36.0"
|
|
111
111
|
},
|
|
112
112
|
"peerDependencies": {
|
|
113
113
|
"@dagrejs/dagre": "^1.1.4",
|