@dou-ui/flow 0.0.0-stage → 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +10 -2
- package/dist/collaboration/index.js +360 -0
- package/dist/collaboration/index.js.map +1 -0
- package/dist/collaboration/peers.js +76 -0
- package/dist/collaboration/peers.js.map +1 -0
- package/dist/components/default-node.js +6 -0
- package/dist/components/default-node.js.map +1 -0
- package/dist/components/default-node.vue_vue_type_script_setup_true_lang.js +87 -0
- package/dist/components/default-node.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/default-node2.js +116 -0
- package/dist/components/default-node2.js.map +1 -0
- package/dist/components/flow-controls.js +6 -0
- package/dist/components/flow-controls.js.map +1 -0
- package/dist/components/flow-controls.vue_vue_type_script_setup_true_lang.js +148 -0
- package/dist/components/flow-controls.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/flow-menu.js +6 -0
- package/dist/components/flow-menu.js.map +1 -0
- package/dist/components/flow-menu.vue_vue_type_script_setup_true_lang.js +52 -0
- package/dist/components/flow-menu.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/flow-minimap.js +6 -0
- package/dist/components/flow-minimap.js.map +1 -0
- package/dist/components/flow-minimap.vue_vue_type_script_setup_true_lang.js +238 -0
- package/dist/components/flow-minimap.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/flow-port.js +6 -0
- package/dist/components/flow-port.js.map +1 -0
- package/dist/components/flow-port.vue_vue_type_script_setup_true_lang.js +57 -0
- package/dist/components/flow-port.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/flow-quick-add.js +6 -0
- package/dist/components/flow-quick-add.js.map +1 -0
- package/dist/components/flow-quick-add.vue_vue_type_script_setup_true_lang.js +126 -0
- package/dist/components/flow-quick-add.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/flow-toolbar.js +6 -0
- package/dist/components/flow-toolbar.js.map +1 -0
- package/dist/components/flow-toolbar.vue_vue_type_script_setup_true_lang.js +161 -0
- package/dist/components/flow-toolbar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/group-node.js +6 -0
- package/dist/components/group-node.js.map +1 -0
- package/dist/components/group-node.vue_vue_type_script_setup_true_lang.js +84 -0
- package/dist/components/group-node.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/group-node2.js +42 -0
- package/dist/components/group-node2.js.map +1 -0
- package/dist/components/node-view.js +6 -0
- package/dist/components/node-view.js.map +1 -0
- package/dist/components/node-view.vue_vue_type_script_setup_true_lang.js +179 -0
- package/dist/components/node-view.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/context.js +13 -0
- package/dist/context.js.map +1 -0
- package/dist/core/clipboard.js +37 -0
- package/dist/core/clipboard.js.map +1 -0
- package/dist/core/connect.js +74 -0
- package/dist/core/connect.js.map +1 -0
- package/dist/core/edge-types.js +240 -0
- package/dist/core/edge-types.js.map +1 -0
- package/dist/core/extension.js +63 -0
- package/dist/core/extension.js.map +1 -0
- package/dist/core/geometry.js +232 -0
- package/dist/core/geometry.js.map +1 -0
- package/dist/core/groups.js +76 -0
- package/dist/core/groups.js.map +1 -0
- package/dist/core/history.js +79 -0
- package/dist/core/history.js.map +1 -0
- package/dist/core/model.js +21 -0
- package/dist/core/model.js.map +1 -0
- package/dist/core/node-types.js +32 -0
- package/dist/core/node-types.js.map +1 -0
- package/dist/core/order.js +42 -0
- package/dist/core/order.js.map +1 -0
- package/dist/core/transaction.js +288 -0
- package/dist/core/transaction.js.map +1 -0
- package/dist/document.js +220 -0
- package/dist/document.js.map +1 -0
- package/dist/export/color.js +38 -0
- package/dist/export/color.js.map +1 -0
- package/dist/export/context.js +223 -0
- package/dist/export/context.js.map +1 -0
- package/dist/export/draw.js +249 -0
- package/dist/export/draw.js.map +1 -0
- package/dist/flow-editor.js +6 -0
- package/dist/flow-editor.js.map +1 -0
- package/dist/flow-editor.vue_vue_type_script_setup_true_lang.js +3721 -0
- package/dist/flow-editor.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/kit.js +234 -0
- package/dist/kit.js.map +1 -0
- package/dist/layers.js +150 -0
- package/dist/layers.js.map +1 -0
- package/dist/locale.js +426 -0
- package/dist/locale.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/style.d.ts +1 -0
- package/dist/style.js +8 -0
- package/dist/types/collaboration/index.d.ts +42 -0
- package/dist/types/collaboration/peers.d.ts +27 -0
- package/dist/types/components/default-node.d.ts +18 -0
- package/dist/types/components/default-node.vue.d.ts +6 -0
- package/dist/types/components/flow-controls.vue.d.ts +8 -0
- package/dist/types/components/flow-menu.vue.d.ts +29 -0
- package/dist/types/components/flow-minimap.vue.d.ts +8 -0
- package/dist/types/components/flow-port.vue.d.ts +9 -0
- package/dist/types/components/flow-quick-add.vue.d.ts +31 -0
- package/dist/types/components/flow-toolbar.vue.d.ts +25 -0
- package/dist/types/components/group-node.d.ts +13 -0
- package/dist/types/components/group-node.vue.d.ts +6 -0
- package/dist/types/components/node-view.vue.d.ts +28 -0
- package/dist/types/context.d.ts +362 -0
- package/dist/types/core/clipboard.d.ts +9 -0
- package/dist/types/core/connect.d.ts +63 -0
- package/dist/types/core/edge-types.d.ts +50 -0
- package/dist/types/core/extension.d.ts +141 -0
- package/dist/types/core/geometry.d.ts +63 -0
- package/dist/types/core/groups.d.ts +23 -0
- package/dist/types/core/history.d.ts +24 -0
- package/dist/types/core/menu.d.ts +40 -0
- package/dist/types/core/model.d.ts +87 -0
- package/dist/types/core/node-types.d.ts +103 -0
- package/dist/types/core/order.d.ts +7 -0
- package/dist/types/core/transaction.d.ts +97 -0
- package/dist/types/document.d.ts +57 -0
- package/dist/types/export/color.d.ts +7 -0
- package/dist/types/export/context.d.ts +90 -0
- package/dist/types/export/draw.d.ts +72 -0
- package/dist/types/flow-editor.vue.d.ts +63 -0
- package/dist/types/index.d.ts +202 -0
- package/dist/types/kit.d.ts +22 -0
- package/dist/types/layers.d.ts +24 -0
- package/dist/types/locale.d.ts +172 -0
- package/dist/types/whiteboard/board-draft.vue.d.ts +3 -0
- package/dist/types/whiteboard/board-node.vue.d.ts +19 -0
- package/dist/types/whiteboard/connector.d.ts +12 -0
- package/dist/types/whiteboard/draw.d.ts +5 -0
- package/dist/types/whiteboard/image.d.ts +27 -0
- package/dist/types/whiteboard/index.d.ts +6 -0
- package/dist/types/whiteboard/ink.d.ts +30 -0
- package/dist/types/whiteboard/kit.d.ts +36 -0
- package/dist/types/whiteboard/model.d.ts +79 -0
- package/dist/types/whiteboard/pen.d.ts +7 -0
- package/dist/types/whiteboard/state.d.ts +37 -0
- package/dist/types/whiteboard/transform.d.ts +67 -0
- package/dist/types/whiteboard/whiteboard-toolbar.vue.d.ts +3 -0
- package/dist/whiteboard/board-draft.js +6 -0
- package/dist/whiteboard/board-draft.js.map +1 -0
- package/dist/whiteboard/board-draft.vue_vue_type_script_setup_true_lang.js +58 -0
- package/dist/whiteboard/board-draft.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/whiteboard/board-node.js +6 -0
- package/dist/whiteboard/board-node.js.map +1 -0
- package/dist/whiteboard/board-node.vue_vue_type_script_setup_true_lang.js +332 -0
- package/dist/whiteboard/board-node.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/whiteboard/connector.js +180 -0
- package/dist/whiteboard/connector.js.map +1 -0
- package/dist/whiteboard/draw.js +68 -0
- package/dist/whiteboard/draw.js.map +1 -0
- package/dist/whiteboard/image.js +104 -0
- package/dist/whiteboard/image.js.map +1 -0
- package/dist/whiteboard/index.js +5 -0
- package/dist/whiteboard/ink.js +168 -0
- package/dist/whiteboard/ink.js.map +1 -0
- package/dist/whiteboard/kit.js +406 -0
- package/dist/whiteboard/kit.js.map +1 -0
- package/dist/whiteboard/model.js +52 -0
- package/dist/whiteboard/model.js.map +1 -0
- package/dist/whiteboard/pen.js +88 -0
- package/dist/whiteboard/pen.js.map +1 -0
- package/dist/whiteboard/state.js +26 -0
- package/dist/whiteboard/state.js.map +1 -0
- package/dist/whiteboard/transform.js +256 -0
- package/dist/whiteboard/transform.js.map +1 -0
- package/dist/whiteboard/whiteboard-toolbar.js +6 -0
- package/dist/whiteboard/whiteboard-toolbar.js.map +1 -0
- package/dist/whiteboard/whiteboard-toolbar.vue_vue_type_script_setup_true_lang.js +171 -0
- package/dist/whiteboard/whiteboard-toolbar.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/package.json +74 -4
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { turn } from "../core/geometry.js";
|
|
2
|
+
import { format } from "../locale.js";
|
|
3
|
+
import { onBeforeUnmount, ref } from "vue";
|
|
4
|
+
// src/whiteboard/transform.ts
|
|
5
|
+
/** Degrees in `[0, 360)`, rounded to a whole degree. */
|
|
6
|
+
var normalizeAngle = (degrees) => (Math.round(degrees) % 360 + 360) % 360;
|
|
7
|
+
/** Where a turn lands: a multiple of 15° with Shift; near a right angle, the right angle. */
|
|
8
|
+
function snapAngle(degrees, shift) {
|
|
9
|
+
if (shift) return normalizeAngle(Math.round(degrees / 15) * 15);
|
|
10
|
+
const right = Math.round(degrees / 90) * 90;
|
|
11
|
+
return normalizeAngle(Math.abs(degrees - right) < 4 ? right : degrees);
|
|
12
|
+
}
|
|
13
|
+
/** The eight handles, corners first. */
|
|
14
|
+
var RESIZE_HANDLES = [
|
|
15
|
+
{
|
|
16
|
+
x: -1,
|
|
17
|
+
y: -1
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
x: 1,
|
|
21
|
+
y: -1
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
x: 1,
|
|
25
|
+
y: 1
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
x: -1,
|
|
29
|
+
y: 1
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
x: 0,
|
|
33
|
+
y: -1
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
x: 1,
|
|
37
|
+
y: 0
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
x: 0,
|
|
41
|
+
y: 1
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
x: -1,
|
|
45
|
+
y: 0
|
|
46
|
+
}
|
|
47
|
+
];
|
|
48
|
+
/**
|
|
49
|
+
* The box a node gets when `handle` is dragged by `delta` (canvas units),
|
|
50
|
+
* turned by `rotation` or not: it grows along the node's own axes, and the
|
|
51
|
+
* corner or side across from the handle stays where it is. With `keepRatio`
|
|
52
|
+
* a corner keeps the box's proportions.
|
|
53
|
+
*/
|
|
54
|
+
function resizeBox(start, rotation, handle, delta, min, keepRatio = false) {
|
|
55
|
+
const local = turn(delta, {
|
|
56
|
+
x: 0,
|
|
57
|
+
y: 0
|
|
58
|
+
}, -rotation);
|
|
59
|
+
let width = handle.x ? Math.max(min.width, start.width + handle.x * local.x) : start.width;
|
|
60
|
+
let height = handle.y ? Math.max(min.height, start.height + handle.y * local.y) : start.height;
|
|
61
|
+
if (keepRatio && handle.x && handle.y && start.width && start.height) {
|
|
62
|
+
const w = start.width + handle.x * local.x;
|
|
63
|
+
const h = start.height + handle.y * local.y;
|
|
64
|
+
const along = (w * start.width + h * start.height) / (start.width ** 2 + start.height ** 2);
|
|
65
|
+
const scale = Math.max(along, min.width / start.width, min.height / start.height);
|
|
66
|
+
width = start.width * scale;
|
|
67
|
+
height = start.height * scale;
|
|
68
|
+
}
|
|
69
|
+
const centre = {
|
|
70
|
+
x: start.x + start.width / 2,
|
|
71
|
+
y: start.y + start.height / 2
|
|
72
|
+
};
|
|
73
|
+
const across = (w, h) => turn({
|
|
74
|
+
x: -handle.x * w / 2,
|
|
75
|
+
y: -handle.y * h / 2
|
|
76
|
+
}, {
|
|
77
|
+
x: 0,
|
|
78
|
+
y: 0
|
|
79
|
+
}, rotation);
|
|
80
|
+
const from = across(start.width, start.height);
|
|
81
|
+
const to = across(width, height);
|
|
82
|
+
const next = {
|
|
83
|
+
x: centre.x + from.x - to.x,
|
|
84
|
+
y: centre.y + from.y - to.y
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
x: next.x - width / 2,
|
|
88
|
+
y: next.y - height / 2,
|
|
89
|
+
width,
|
|
90
|
+
height
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Follows a pointer from a handle until it lets go: `move` on each step,
|
|
95
|
+
* `end` when let go, `cancel` on Escape or when the pointer is lost.
|
|
96
|
+
* Returns a function that cancels it.
|
|
97
|
+
*/
|
|
98
|
+
function follow(event, move, end, cancel) {
|
|
99
|
+
const el = event.currentTarget;
|
|
100
|
+
el.setPointerCapture?.(event.pointerId);
|
|
101
|
+
const id = event.pointerId;
|
|
102
|
+
const stop = () => {
|
|
103
|
+
el.removeEventListener("pointermove", onMove);
|
|
104
|
+
el.removeEventListener("pointerup", onUp);
|
|
105
|
+
el.removeEventListener("pointercancel", onCancel);
|
|
106
|
+
window.removeEventListener("keydown", onKey, true);
|
|
107
|
+
};
|
|
108
|
+
const onMove = (e) => e.pointerId === id && move(e);
|
|
109
|
+
const onUp = (e) => {
|
|
110
|
+
if (e.pointerId !== id) return;
|
|
111
|
+
stop();
|
|
112
|
+
end(e);
|
|
113
|
+
};
|
|
114
|
+
const onCancel = (e) => {
|
|
115
|
+
if (e.pointerId !== id) return;
|
|
116
|
+
stop();
|
|
117
|
+
cancel();
|
|
118
|
+
};
|
|
119
|
+
const onKey = (e) => {
|
|
120
|
+
if (e.key !== "Escape") return;
|
|
121
|
+
e.preventDefault();
|
|
122
|
+
e.stopPropagation();
|
|
123
|
+
stop();
|
|
124
|
+
cancel();
|
|
125
|
+
};
|
|
126
|
+
el.addEventListener("pointermove", onMove);
|
|
127
|
+
el.addEventListener("pointerup", onUp);
|
|
128
|
+
el.addEventListener("pointercancel", onCancel);
|
|
129
|
+
window.addEventListener("keydown", onKey, true);
|
|
130
|
+
return () => {
|
|
131
|
+
stop();
|
|
132
|
+
cancel();
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The turn and corner handles of a board node. While a handle is dragged
|
|
137
|
+
* the node is only shown changed, through `previewNode`, so its frame,
|
|
138
|
+
* handles, ports and edges all follow; the document changes once, when it
|
|
139
|
+
* is let go. `turning` and `sizing` say what is being dragged to.
|
|
140
|
+
*/
|
|
141
|
+
function useTransformHandles(ctx, node, rotation, min) {
|
|
142
|
+
const turning = ref(null);
|
|
143
|
+
const sizing = ref(null);
|
|
144
|
+
let abort = null;
|
|
145
|
+
onBeforeUnmount(() => abort?.());
|
|
146
|
+
let held = null;
|
|
147
|
+
const show = (patch) => {
|
|
148
|
+
if (held) ctx.previewNode(held, patch);
|
|
149
|
+
if (!patch) held = null;
|
|
150
|
+
};
|
|
151
|
+
const rectOf = () => {
|
|
152
|
+
return ctx.getNodeRect(node.value.id) ?? {
|
|
153
|
+
x: node.value.x,
|
|
154
|
+
y: node.value.y,
|
|
155
|
+
width: 0,
|
|
156
|
+
height: 0
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
function startTurn(event) {
|
|
160
|
+
if (ctx.readonly.value || node.value.locked || event.button !== 0) return;
|
|
161
|
+
event.preventDefault();
|
|
162
|
+
event.stopPropagation();
|
|
163
|
+
const rect = rectOf();
|
|
164
|
+
const centre = {
|
|
165
|
+
x: rect.x + rect.width / 2,
|
|
166
|
+
y: rect.y + rect.height / 2
|
|
167
|
+
};
|
|
168
|
+
const data = node.value.data;
|
|
169
|
+
const before = rotation.value;
|
|
170
|
+
held = node.value.id;
|
|
171
|
+
abort = follow(event, (e) => {
|
|
172
|
+
const p = ctx.toCanvas({
|
|
173
|
+
x: e.clientX,
|
|
174
|
+
y: e.clientY
|
|
175
|
+
});
|
|
176
|
+
const degrees = Math.atan2(p.y - centre.y, p.x - centre.x) * 180 / Math.PI - 90;
|
|
177
|
+
turning.value = snapAngle(degrees, e.shiftKey);
|
|
178
|
+
show({ data: {
|
|
179
|
+
...data,
|
|
180
|
+
rotation: turning.value || void 0
|
|
181
|
+
} });
|
|
182
|
+
}, () => {
|
|
183
|
+
const next = turning.value;
|
|
184
|
+
turning.value = null;
|
|
185
|
+
show(null);
|
|
186
|
+
if (next === null || next === before) return;
|
|
187
|
+
ctx.transact((tr) => tr.updateData(node.value.id, { rotation: next || void 0 }));
|
|
188
|
+
ctx.announce(format(ctx.messages.value.board.turned, { degrees: next }));
|
|
189
|
+
}, () => {
|
|
190
|
+
turning.value = null;
|
|
191
|
+
show(null);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Drags `handle`. `options.keepRatio` says whether a corner keeps the
|
|
196
|
+
* proportions: Shift turns it the other way. `options.widthOnly` changes
|
|
197
|
+
* only the width, for text whose height follows its lines.
|
|
198
|
+
*/
|
|
199
|
+
function startResize(event, handle, options = {}) {
|
|
200
|
+
if (ctx.readonly.value || node.value.locked || event.button !== 0) return;
|
|
201
|
+
event.preventDefault();
|
|
202
|
+
event.stopPropagation();
|
|
203
|
+
const start = { ...rectOf() };
|
|
204
|
+
const turned = rotation.value;
|
|
205
|
+
const from = ctx.toCanvas({
|
|
206
|
+
x: event.clientX,
|
|
207
|
+
y: event.clientY
|
|
208
|
+
});
|
|
209
|
+
held = node.value.id;
|
|
210
|
+
abort = follow(event, (e) => {
|
|
211
|
+
const p = ctx.toCanvas({
|
|
212
|
+
x: e.clientX,
|
|
213
|
+
y: e.clientY
|
|
214
|
+
});
|
|
215
|
+
const delta = {
|
|
216
|
+
x: p.x - from.x,
|
|
217
|
+
y: p.y - from.y
|
|
218
|
+
};
|
|
219
|
+
const keep = !!options.keepRatio !== e.shiftKey;
|
|
220
|
+
const along = options.widthOnly ? {
|
|
221
|
+
x: handle.x,
|
|
222
|
+
y: 0
|
|
223
|
+
} : handle;
|
|
224
|
+
const next = resizeBox(start, turned, along, delta, min, keep);
|
|
225
|
+
sizing.value = next;
|
|
226
|
+
show(options.widthOnly ? {
|
|
227
|
+
...next,
|
|
228
|
+
height: void 0
|
|
229
|
+
} : next);
|
|
230
|
+
}, () => {
|
|
231
|
+
const next = sizing.value;
|
|
232
|
+
sizing.value = null;
|
|
233
|
+
show(null);
|
|
234
|
+
if (!next) return;
|
|
235
|
+
const patch = {
|
|
236
|
+
x: Math.round(next.x),
|
|
237
|
+
y: Math.round(next.y),
|
|
238
|
+
width: Math.round(next.width)
|
|
239
|
+
};
|
|
240
|
+
patch.height = options.widthOnly ? void 0 : Math.round(next.height);
|
|
241
|
+
ctx.transact((tr) => tr.updateNode(node.value.id, patch));
|
|
242
|
+
}, () => {
|
|
243
|
+
sizing.value = null;
|
|
244
|
+
show(null);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
turning,
|
|
249
|
+
sizing,
|
|
250
|
+
startTurn,
|
|
251
|
+
startResize
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
export { RESIZE_HANDLES, normalizeAngle, resizeBox, snapAngle, useTransformHandles };
|
|
255
|
+
|
|
256
|
+
//# sourceMappingURL=transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.js","names":[],"sources":["../../src/whiteboard/transform.ts"],"sourcesContent":["import { onBeforeUnmount, ref, type Ref } from 'vue'\nimport type { FlowEditorContext, FlowNodePreview } from '../context'\nimport type { FlowNode, Point } from '../core/model'\nimport { format } from '../locale'\nimport { turn } from '../core/geometry'\n\n/** Degrees in `[0, 360)`, rounded to a whole degree. */\nexport const normalizeAngle = (degrees: number) => ((Math.round(degrees) % 360) + 360) % 360\n\n/** Where a turn lands: a multiple of 15° with Shift; near a right angle, the right angle. */\nexport function snapAngle(degrees: number, shift: boolean) {\n if (shift) return normalizeAngle(Math.round(degrees / 15) * 15)\n const right = Math.round(degrees / 90) * 90\n return normalizeAngle(Math.abs(degrees - right) < 4 ? right : degrees)\n}\n\n/** A resize handle: the side or corner it sits on, `-1`, `0` or `1` along each axis. */\nexport interface ResizeHandle {\n x: -1 | 0 | 1\n y: -1 | 0 | 1\n}\n\n/** The eight handles, corners first. */\nexport const RESIZE_HANDLES: readonly ResizeHandle[] = [\n { x: -1, y: -1 },\n { x: 1, y: -1 },\n { x: 1, y: 1 },\n { x: -1, y: 1 },\n { x: 0, y: -1 },\n { x: 1, y: 0 },\n { x: 0, y: 1 },\n { x: -1, y: 0 },\n]\n\n/**\n * The box a node gets when `handle` is dragged by `delta` (canvas units),\n * turned by `rotation` or not: it grows along the node's own axes, and the\n * corner or side across from the handle stays where it is. With `keepRatio`\n * a corner keeps the box's proportions.\n */\nexport function resizeBox(\n start: { x: number; y: number; width: number; height: number },\n rotation: number,\n handle: ResizeHandle,\n delta: Point,\n min: { width: number; height: number },\n keepRatio = false,\n) {\n const local = turn(delta, { x: 0, y: 0 }, -rotation)\n let width = handle.x ? Math.max(min.width, start.width + handle.x * local.x) : start.width\n let height = handle.y ? Math.max(min.height, start.height + handle.y * local.y) : start.height\n if (keepRatio && handle.x && handle.y && start.width && start.height) {\n // the pointer taken onto the box's diagonal, so the corner stays under\n // it; no smaller than the least size\n const w = start.width + handle.x * local.x\n const h = start.height + handle.y * local.y\n const along = (w * start.width + h * start.height) / (start.width ** 2 + start.height ** 2)\n const scale = Math.max(along, min.width / start.width, min.height / start.height)\n width = start.width * scale\n height = start.height * scale\n }\n const centre = { x: start.x + start.width / 2, y: start.y + start.height / 2 }\n // the point across from the handle, on screen, stays put\n const across = (w: number, h: number) =>\n turn({ x: (-handle.x * w) / 2, y: (-handle.y * h) / 2 }, { x: 0, y: 0 }, rotation)\n const from = across(start.width, start.height)\n const to = across(width, height)\n const next = { x: centre.x + from.x - to.x, y: centre.y + from.y - to.y }\n return { x: next.x - width / 2, y: next.y - height / 2, width, height }\n}\n\ntype Drag = (event: PointerEvent) => void\n\n/**\n * Follows a pointer from a handle until it lets go: `move` on each step,\n * `end` when let go, `cancel` on Escape or when the pointer is lost.\n * Returns a function that cancels it.\n */\nfunction follow(event: PointerEvent, move: Drag, end: Drag, cancel: () => void) {\n const el = event.currentTarget as HTMLElement\n el.setPointerCapture?.(event.pointerId)\n const id = event.pointerId\n const stop = () => {\n el.removeEventListener('pointermove', onMove)\n el.removeEventListener('pointerup', onUp)\n el.removeEventListener('pointercancel', onCancel)\n window.removeEventListener('keydown', onKey, true)\n }\n const onMove = (e: PointerEvent) => e.pointerId === id && move(e)\n const onUp = (e: PointerEvent) => {\n if (e.pointerId !== id) return\n stop()\n end(e)\n }\n const onCancel = (e: PointerEvent) => {\n if (e.pointerId !== id) return\n stop()\n cancel()\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return\n e.preventDefault()\n e.stopPropagation()\n stop()\n cancel()\n }\n el.addEventListener('pointermove', onMove)\n el.addEventListener('pointerup', onUp)\n el.addEventListener('pointercancel', onCancel)\n window.addEventListener('keydown', onKey, true)\n return () => {\n stop()\n cancel()\n }\n}\n\n/**\n * The turn and corner handles of a board node. While a handle is dragged\n * the node is only shown changed, through `previewNode`, so its frame,\n * handles, ports and edges all follow; the document changes once, when it\n * is let go. `turning` and `sizing` say what is being dragged to.\n */\nexport function useTransformHandles(\n ctx: FlowEditorContext,\n node: Ref<FlowNode>,\n rotation: Ref<number>,\n min: { width: number; height: number },\n) {\n const turning = ref<number | null>(null)\n const sizing = ref<{ x: number; y: number; width: number; height: number } | null>(null)\n let abort: (() => void) | null = null\n onBeforeUnmount(() => abort?.())\n // the id held when the drag began, in case the node is swapped meanwhile\n let held: string | null = null\n const show = (patch: FlowNodePreview | null) => {\n if (held) ctx.previewNode(held, patch)\n if (!patch) held = null\n }\n\n const rectOf = () => {\n const rect = ctx.getNodeRect(node.value.id)\n return rect ?? { x: node.value.x, y: node.value.y, width: 0, height: 0 }\n }\n\n function startTurn(event: PointerEvent) {\n if (ctx.readonly.value || node.value.locked || event.button !== 0) return\n event.preventDefault()\n event.stopPropagation()\n const rect = rectOf()\n const centre = { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 }\n // what it is turned to now: once dragging, the node shows the new turn\n const data = node.value.data\n const before = rotation.value\n held = node.value.id\n abort = follow(\n event,\n (e) => {\n const p = ctx.toCanvas({ x: e.clientX, y: e.clientY })\n // the handle sits below the centre: straight down is 0°\n const degrees = (Math.atan2(p.y - centre.y, p.x - centre.x) * 180) / Math.PI - 90\n turning.value = snapAngle(degrees, e.shiftKey)\n show({ data: { ...data, rotation: turning.value || undefined } })\n },\n () => {\n const next = turning.value\n turning.value = null\n show(null)\n if (next === null || next === before) return\n ctx.transact((tr) => tr.updateData(node.value.id, { rotation: next || undefined }))\n ctx.announce(format(ctx.messages.value.board.turned, { degrees: next }))\n },\n () => {\n turning.value = null\n show(null)\n },\n )\n }\n\n /**\n * Drags `handle`. `options.keepRatio` says whether a corner keeps the\n * proportions: Shift turns it the other way. `options.widthOnly` changes\n * only the width, for text whose height follows its lines.\n */\n function startResize(\n event: PointerEvent,\n handle: ResizeHandle,\n options: { keepRatio?: boolean; widthOnly?: boolean } = {},\n ) {\n if (ctx.readonly.value || node.value.locked || event.button !== 0) return\n event.preventDefault()\n event.stopPropagation()\n const start = { ...rectOf() }\n const turned = rotation.value\n const from = ctx.toCanvas({ x: event.clientX, y: event.clientY })\n held = node.value.id\n abort = follow(\n event,\n (e) => {\n const p = ctx.toCanvas({ x: e.clientX, y: e.clientY })\n const delta = { x: p.x - from.x, y: p.y - from.y }\n const keep = !!options.keepRatio !== e.shiftKey\n // only the width: a corner works as its side\n const along = options.widthOnly ? { x: handle.x, y: 0 as const } : handle\n const next = resizeBox(start, turned, along, delta, min, keep)\n sizing.value = next\n // text keeps no height: it follows its lines as it widens\n show(options.widthOnly ? { ...next, height: undefined } : next)\n },\n () => {\n const next = sizing.value\n sizing.value = null\n show(null)\n if (!next) return\n const patch: Partial<FlowNode> = {\n x: Math.round(next.x),\n y: Math.round(next.y),\n width: Math.round(next.width),\n }\n // text keeps no height: it follows its lines\n patch.height = options.widthOnly ? undefined : Math.round(next.height)\n ctx.transact((tr) => tr.updateNode(node.value.id, patch))\n },\n () => {\n sizing.value = null\n show(null)\n },\n )\n }\n\n return { turning, sizing, startTurn, startResize }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import whiteboard_toolbar_vue_vue_type_script_setup_true_lang_default from "./whiteboard-toolbar.vue_vue_type_script_setup_true_lang.js";
|
|
2
|
+
// src/whiteboard/whiteboard-toolbar.vue
|
|
3
|
+
var whiteboard_toolbar_default = whiteboard_toolbar_vue_vue_type_script_setup_true_lang_default;
|
|
4
|
+
export { whiteboard_toolbar_default as default };
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=whiteboard-toolbar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whiteboard-toolbar.js","names":["_sfc_main"],"sources":["../../src/whiteboard/whiteboard-toolbar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n CircleIcon,\n CursorIcon,\n DiamondIcon,\n EraserIcon,\n HandGrabIcon,\n HandIcon,\n ImageIcon,\n PencilIcon,\n SquareIcon,\n StickyNoteIcon,\n TypeIcon,\n} from '@dou-ui/icons'\nimport { DouTooltip, scrollPositionOf } from 'dou-ui'\nimport { computed, onBeforeUnmount, ref, useTemplateRef, watch, type Component } from 'vue'\nimport { useFlowEditor } from '../context'\nimport { pickImages } from './image'\nimport { imageKey, whiteboardKeys, type WhiteboardTool } from './model'\nimport { boardState } from './state'\n\ndefineOptions({ name: 'DouWhiteboardToolbar' })\n\nconst ctx = useFlowEditor()\nconst state = boardState(ctx)\nconst t = computed(() => ctx.messages.value.board)\n\nconst groups: { tool: WhiteboardTool; icon: Component }[][] = [\n [\n { tool: 'select', icon: CursorIcon },\n { tool: 'hand', icon: HandIcon },\n ],\n [\n { tool: 'rect', icon: SquareIcon },\n { tool: 'ellipse', icon: CircleIcon },\n { tool: 'diamond', icon: DiamondIcon },\n ],\n [\n { tool: 'sticky', icon: StickyNoteIcon },\n { tool: 'text', icon: TypeIcon },\n ],\n [\n { tool: 'pen', icon: PencilIcon },\n { tool: 'eraser', icon: EraserIcon },\n ],\n]\n\n/** Tools that go back to select after one use, unless kept with a double click. */\nconst once = new Set<WhiteboardTool>(['rect', 'ellipse', 'diamond', 'sticky', 'text'])\n\n// A click picks the tool for one use; a double click keeps it. Focus goes\n// back to the canvas, where the tool is used and its keys work.\nfunction pick(tool: WhiteboardTool, keep: boolean) {\n state.tool.value = tool\n state.locked.value = keep && once.has(tool)\n ctx.root.value?.focus({ preventScroll: true })\n}\n\nfunction insertImage() {\n pickImages(ctx)\n}\n\n// Too narrow for every tool: one row that scrolls sideways, faded at the\n// side with more, and the tool in hand kept in view.\nconst el = useTemplateRef<HTMLElement>('el')\nconst more = ref({ start: false, end: false })\n/** Right to left; read when the row is laid out, not on every scroll. */\nlet rtl = false\nfunction measure() {\n const box = el.value\n if (!box) return\n // from the start, also right to left, and kept in range while the row bounces\n const left = Math.abs(scrollPositionOf(box, rtl).left)\n const rest = box.scrollWidth - box.clientWidth - left\n more.value = { start: left > 1, end: rest > 1 }\n}\nlet observer: ResizeObserver | undefined\nwatch(\n el,\n (box) => {\n observer?.disconnect()\n if (!box || typeof ResizeObserver === 'undefined') return\n observer = new ResizeObserver(() => {\n rtl = getComputedStyle(box).direction === 'rtl'\n measure()\n })\n observer.observe(box)\n },\n { flush: 'post' },\n)\nonBeforeUnmount(() => observer?.disconnect())\nwatch(\n () => state.tool.value,\n () => {\n const box = el.value\n const button = box?.querySelector<HTMLElement>('[aria-pressed=\"true\"]')\n if (!box || !button || box.scrollWidth <= box.clientWidth) return\n const start = button.offsetLeft - 24\n const end = button.offsetLeft + button.offsetWidth + 24 - box.clientWidth\n if (box.scrollLeft > start) box.scrollLeft = start\n else if (box.scrollLeft < end) box.scrollLeft = end\n },\n { flush: 'post' },\n)\n</script>\n\n<template>\n <div\n v-if=\"!ctx.readonly.value\"\n class=\"dou-whiteboard-toolbar\"\n data-flow-overlay\n role=\"toolbar\"\n :aria-label=\"t.tools\"\n >\n <div\n ref=\"el\"\n class=\"dou-whiteboard-toolbar__scroll\"\n :class=\"{ 'has-more-start': more.start, 'has-more-end': more.end }\"\n @scroll.passive=\"measure\"\n >\n <template v-for=\"(group, i) in groups\" :key=\"i\">\n <span v-if=\"i\" class=\"dou-whiteboard-toolbar__divider\" />\n <DouTooltip\n v-for=\"item in group\"\n :key=\"item.tool\"\n :content=\"t[item.tool]\"\n :shortcut=\"whiteboardKeys[item.tool]\"\n placement=\"bottom\"\n >\n <button\n type=\"button\"\n class=\"dou-whiteboard-toolbar__button\"\n :class=\"{ 'is-locked': state.tool.value === item.tool && state.locked.value }\"\n :aria-pressed=\"state.tool.value === item.tool\"\n :aria-label=\"t[item.tool]\"\n @click=\"pick(item.tool, false)\"\n @dblclick=\"pick(item.tool, true)\"\n >\n <component\n :is=\"item.tool === 'hand' && state.panning.value ? HandGrabIcon : item.icon\"\n />\n </button>\n </DouTooltip>\n </template>\n <DouTooltip :content=\"t.image\" :shortcut=\"imageKey\" placement=\"bottom\">\n <button\n type=\"button\"\n class=\"dou-whiteboard-toolbar__button\"\n :class=\"{ 'is-busy': state.uploading.value > 0 }\"\n :aria-label=\"t.image\"\n :aria-busy=\"state.uploading.value > 0 || undefined\"\n @click=\"insertImage\"\n >\n <ImageIcon />\n </button>\n </DouTooltip>\n </div>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { useFlowEditor } from "../context.js";
|
|
2
|
+
import { whiteboardKeys } from "./model.js";
|
|
3
|
+
import { boardState } from "./state.js";
|
|
4
|
+
import { pickImages } from "./image.js";
|
|
5
|
+
import { DouTooltip, scrollPositionOf } from "dou-ui";
|
|
6
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, onBeforeUnmount, openBlock, ref, renderList, resolveDynamicComponent, unref, useTemplateRef, watch, withCtx } from "vue";
|
|
7
|
+
import { CircleIcon, CursorIcon, DiamondIcon, EraserIcon, HandGrabIcon, HandIcon, ImageIcon, PencilIcon, SquareIcon, StickyNoteIcon, TypeIcon } from "@dou-ui/icons";
|
|
8
|
+
// src/whiteboard/whiteboard-toolbar.vue?vue&type=script&setup=true&lang.ts
|
|
9
|
+
var _hoisted_1 = ["aria-label"];
|
|
10
|
+
var _hoisted_2 = {
|
|
11
|
+
key: 0,
|
|
12
|
+
class: "dou-whiteboard-toolbar__divider"
|
|
13
|
+
};
|
|
14
|
+
var _hoisted_3 = [
|
|
15
|
+
"aria-pressed",
|
|
16
|
+
"aria-label",
|
|
17
|
+
"onClick",
|
|
18
|
+
"onDblclick"
|
|
19
|
+
];
|
|
20
|
+
var _hoisted_4 = ["aria-label", "aria-busy"];
|
|
21
|
+
var whiteboard_toolbar_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
22
|
+
name: "DouWhiteboardToolbar",
|
|
23
|
+
__name: "whiteboard-toolbar",
|
|
24
|
+
setup(__props) {
|
|
25
|
+
const ctx = useFlowEditor();
|
|
26
|
+
const state = boardState(ctx);
|
|
27
|
+
const t = computed(() => ctx.messages.value.board);
|
|
28
|
+
const groups = [
|
|
29
|
+
[{
|
|
30
|
+
tool: "select",
|
|
31
|
+
icon: CursorIcon
|
|
32
|
+
}, {
|
|
33
|
+
tool: "hand",
|
|
34
|
+
icon: HandIcon
|
|
35
|
+
}],
|
|
36
|
+
[
|
|
37
|
+
{
|
|
38
|
+
tool: "rect",
|
|
39
|
+
icon: SquareIcon
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
tool: "ellipse",
|
|
43
|
+
icon: CircleIcon
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
tool: "diamond",
|
|
47
|
+
icon: DiamondIcon
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
[{
|
|
51
|
+
tool: "sticky",
|
|
52
|
+
icon: StickyNoteIcon
|
|
53
|
+
}, {
|
|
54
|
+
tool: "text",
|
|
55
|
+
icon: TypeIcon
|
|
56
|
+
}],
|
|
57
|
+
[{
|
|
58
|
+
tool: "pen",
|
|
59
|
+
icon: PencilIcon
|
|
60
|
+
}, {
|
|
61
|
+
tool: "eraser",
|
|
62
|
+
icon: EraserIcon
|
|
63
|
+
}]
|
|
64
|
+
];
|
|
65
|
+
/** Tools that go back to select after one use, unless kept with a double click. */
|
|
66
|
+
const once = /* @__PURE__ */ new Set([
|
|
67
|
+
"rect",
|
|
68
|
+
"ellipse",
|
|
69
|
+
"diamond",
|
|
70
|
+
"sticky",
|
|
71
|
+
"text"
|
|
72
|
+
]);
|
|
73
|
+
function pick(tool, keep) {
|
|
74
|
+
state.tool.value = tool;
|
|
75
|
+
state.locked.value = keep && once.has(tool);
|
|
76
|
+
ctx.root.value?.focus({ preventScroll: true });
|
|
77
|
+
}
|
|
78
|
+
function insertImage() {
|
|
79
|
+
pickImages(ctx);
|
|
80
|
+
}
|
|
81
|
+
const el = useTemplateRef("el");
|
|
82
|
+
const more = ref({
|
|
83
|
+
start: false,
|
|
84
|
+
end: false
|
|
85
|
+
});
|
|
86
|
+
/** Right to left; read when the row is laid out, not on every scroll. */
|
|
87
|
+
let rtl = false;
|
|
88
|
+
function measure() {
|
|
89
|
+
const box = el.value;
|
|
90
|
+
if (!box) return;
|
|
91
|
+
const left = Math.abs(scrollPositionOf(box, rtl).left);
|
|
92
|
+
const rest = box.scrollWidth - box.clientWidth - left;
|
|
93
|
+
more.value = {
|
|
94
|
+
start: left > 1,
|
|
95
|
+
end: rest > 1
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
let observer;
|
|
99
|
+
watch(el, (box) => {
|
|
100
|
+
observer?.disconnect();
|
|
101
|
+
if (!box || typeof ResizeObserver === "undefined") return;
|
|
102
|
+
observer = new ResizeObserver(() => {
|
|
103
|
+
rtl = getComputedStyle(box).direction === "rtl";
|
|
104
|
+
measure();
|
|
105
|
+
});
|
|
106
|
+
observer.observe(box);
|
|
107
|
+
}, { flush: "post" });
|
|
108
|
+
onBeforeUnmount(() => observer?.disconnect());
|
|
109
|
+
watch(() => state.tool.value, () => {
|
|
110
|
+
const box = el.value;
|
|
111
|
+
const button = box?.querySelector("[aria-pressed=\"true\"]");
|
|
112
|
+
if (!box || !button || box.scrollWidth <= box.clientWidth) return;
|
|
113
|
+
const start = button.offsetLeft - 24;
|
|
114
|
+
const end = button.offsetLeft + button.offsetWidth + 24 - box.clientWidth;
|
|
115
|
+
if (box.scrollLeft > start) box.scrollLeft = start;
|
|
116
|
+
else if (box.scrollLeft < end) box.scrollLeft = end;
|
|
117
|
+
}, { flush: "post" });
|
|
118
|
+
return (_ctx, _cache) => {
|
|
119
|
+
return !unref(ctx).readonly.value ? (openBlock(), createElementBlock("div", {
|
|
120
|
+
key: 0,
|
|
121
|
+
class: "dou-whiteboard-toolbar",
|
|
122
|
+
"data-flow-overlay": "",
|
|
123
|
+
role: "toolbar",
|
|
124
|
+
"aria-label": t.value.tools
|
|
125
|
+
}, [createElementVNode("div", {
|
|
126
|
+
ref_key: "el",
|
|
127
|
+
ref: el,
|
|
128
|
+
class: normalizeClass(["dou-whiteboard-toolbar__scroll", {
|
|
129
|
+
"has-more-start": more.value.start,
|
|
130
|
+
"has-more-end": more.value.end
|
|
131
|
+
}]),
|
|
132
|
+
onScrollPassive: measure
|
|
133
|
+
}, [(openBlock(), createElementBlock(Fragment, null, renderList(groups, (group, i) => {
|
|
134
|
+
return openBlock(), createElementBlock(Fragment, { key: i }, [i ? (openBlock(), createElementBlock("span", _hoisted_2)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(group, (item) => {
|
|
135
|
+
return openBlock(), createBlock(unref(DouTooltip), {
|
|
136
|
+
key: item.tool,
|
|
137
|
+
content: t.value[item.tool],
|
|
138
|
+
shortcut: unref(whiteboardKeys)[item.tool],
|
|
139
|
+
placement: "bottom"
|
|
140
|
+
}, {
|
|
141
|
+
default: withCtx(() => [createElementVNode("button", {
|
|
142
|
+
type: "button",
|
|
143
|
+
class: normalizeClass(["dou-whiteboard-toolbar__button", { "is-locked": unref(state).tool.value === item.tool && unref(state).locked.value }]),
|
|
144
|
+
"aria-pressed": unref(state).tool.value === item.tool,
|
|
145
|
+
"aria-label": t.value[item.tool],
|
|
146
|
+
onClick: ($event) => pick(item.tool, false),
|
|
147
|
+
onDblclick: ($event) => pick(item.tool, true)
|
|
148
|
+
}, [(openBlock(), createBlock(resolveDynamicComponent(item.tool === "hand" && unref(state).panning.value ? unref(HandGrabIcon) : item.icon)))], 42, _hoisted_3)]),
|
|
149
|
+
_: 2
|
|
150
|
+
}, 1032, ["content", "shortcut"]);
|
|
151
|
+
}), 128))], 64);
|
|
152
|
+
}), 64)), createVNode(unref(DouTooltip), {
|
|
153
|
+
content: t.value.image,
|
|
154
|
+
shortcut: unref("i"),
|
|
155
|
+
placement: "bottom"
|
|
156
|
+
}, {
|
|
157
|
+
default: withCtx(() => [createElementVNode("button", {
|
|
158
|
+
type: "button",
|
|
159
|
+
class: normalizeClass(["dou-whiteboard-toolbar__button", { "is-busy": unref(state).uploading.value > 0 }]),
|
|
160
|
+
"aria-label": t.value.image,
|
|
161
|
+
"aria-busy": unref(state).uploading.value > 0 || void 0,
|
|
162
|
+
onClick: insertImage
|
|
163
|
+
}, [createVNode(unref(ImageIcon))], 10, _hoisted_4)]),
|
|
164
|
+
_: 1
|
|
165
|
+
}, 8, ["content", "shortcut"])], 34)], 8, _hoisted_1)) : createCommentVNode("", true);
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
export { whiteboard_toolbar_vue_vue_type_script_setup_true_lang_default as default };
|
|
170
|
+
|
|
171
|
+
//# sourceMappingURL=whiteboard-toolbar.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whiteboard-toolbar.vue_vue_type_script_setup_true_lang.js","names":["_unref","_openBlock","_createElementBlock","_createElementVNode","_normalizeClass","_Fragment","_renderList","_createCommentVNode","_createBlock","_withCtx","_resolveDynamicComponent","_createVNode"],"sources":["../../src/whiteboard/whiteboard-toolbar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n CircleIcon,\n CursorIcon,\n DiamondIcon,\n EraserIcon,\n HandGrabIcon,\n HandIcon,\n ImageIcon,\n PencilIcon,\n SquareIcon,\n StickyNoteIcon,\n TypeIcon,\n} from '@dou-ui/icons'\nimport { DouTooltip, scrollPositionOf } from 'dou-ui'\nimport { computed, onBeforeUnmount, ref, useTemplateRef, watch, type Component } from 'vue'\nimport { useFlowEditor } from '../context'\nimport { pickImages } from './image'\nimport { imageKey, whiteboardKeys, type WhiteboardTool } from './model'\nimport { boardState } from './state'\n\ndefineOptions({ name: 'DouWhiteboardToolbar' })\n\nconst ctx = useFlowEditor()\nconst state = boardState(ctx)\nconst t = computed(() => ctx.messages.value.board)\n\nconst groups: { tool: WhiteboardTool; icon: Component }[][] = [\n [\n { tool: 'select', icon: CursorIcon },\n { tool: 'hand', icon: HandIcon },\n ],\n [\n { tool: 'rect', icon: SquareIcon },\n { tool: 'ellipse', icon: CircleIcon },\n { tool: 'diamond', icon: DiamondIcon },\n ],\n [\n { tool: 'sticky', icon: StickyNoteIcon },\n { tool: 'text', icon: TypeIcon },\n ],\n [\n { tool: 'pen', icon: PencilIcon },\n { tool: 'eraser', icon: EraserIcon },\n ],\n]\n\n/** Tools that go back to select after one use, unless kept with a double click. */\nconst once = new Set<WhiteboardTool>(['rect', 'ellipse', 'diamond', 'sticky', 'text'])\n\n// A click picks the tool for one use; a double click keeps it. Focus goes\n// back to the canvas, where the tool is used and its keys work.\nfunction pick(tool: WhiteboardTool, keep: boolean) {\n state.tool.value = tool\n state.locked.value = keep && once.has(tool)\n ctx.root.value?.focus({ preventScroll: true })\n}\n\nfunction insertImage() {\n pickImages(ctx)\n}\n\n// Too narrow for every tool: one row that scrolls sideways, faded at the\n// side with more, and the tool in hand kept in view.\nconst el = useTemplateRef<HTMLElement>('el')\nconst more = ref({ start: false, end: false })\n/** Right to left; read when the row is laid out, not on every scroll. */\nlet rtl = false\nfunction measure() {\n const box = el.value\n if (!box) return\n // from the start, also right to left, and kept in range while the row bounces\n const left = Math.abs(scrollPositionOf(box, rtl).left)\n const rest = box.scrollWidth - box.clientWidth - left\n more.value = { start: left > 1, end: rest > 1 }\n}\nlet observer: ResizeObserver | undefined\nwatch(\n el,\n (box) => {\n observer?.disconnect()\n if (!box || typeof ResizeObserver === 'undefined') return\n observer = new ResizeObserver(() => {\n rtl = getComputedStyle(box).direction === 'rtl'\n measure()\n })\n observer.observe(box)\n },\n { flush: 'post' },\n)\nonBeforeUnmount(() => observer?.disconnect())\nwatch(\n () => state.tool.value,\n () => {\n const box = el.value\n const button = box?.querySelector<HTMLElement>('[aria-pressed=\"true\"]')\n if (!box || !button || box.scrollWidth <= box.clientWidth) return\n const start = button.offsetLeft - 24\n const end = button.offsetLeft + button.offsetWidth + 24 - box.clientWidth\n if (box.scrollLeft > start) box.scrollLeft = start\n else if (box.scrollLeft < end) box.scrollLeft = end\n },\n { flush: 'post' },\n)\n</script>\n\n<template>\n <div\n v-if=\"!ctx.readonly.value\"\n class=\"dou-whiteboard-toolbar\"\n data-flow-overlay\n role=\"toolbar\"\n :aria-label=\"t.tools\"\n >\n <div\n ref=\"el\"\n class=\"dou-whiteboard-toolbar__scroll\"\n :class=\"{ 'has-more-start': more.start, 'has-more-end': more.end }\"\n @scroll.passive=\"measure\"\n >\n <template v-for=\"(group, i) in groups\" :key=\"i\">\n <span v-if=\"i\" class=\"dou-whiteboard-toolbar__divider\" />\n <DouTooltip\n v-for=\"item in group\"\n :key=\"item.tool\"\n :content=\"t[item.tool]\"\n :shortcut=\"whiteboardKeys[item.tool]\"\n placement=\"bottom\"\n >\n <button\n type=\"button\"\n class=\"dou-whiteboard-toolbar__button\"\n :class=\"{ 'is-locked': state.tool.value === item.tool && state.locked.value }\"\n :aria-pressed=\"state.tool.value === item.tool\"\n :aria-label=\"t[item.tool]\"\n @click=\"pick(item.tool, false)\"\n @dblclick=\"pick(item.tool, true)\"\n >\n <component\n :is=\"item.tool === 'hand' && state.panning.value ? HandGrabIcon : item.icon\"\n />\n </button>\n </DouTooltip>\n </template>\n <DouTooltip :content=\"t.image\" :shortcut=\"imageKey\" placement=\"bottom\">\n <button\n type=\"button\"\n class=\"dou-whiteboard-toolbar__button\"\n :class=\"{ 'is-busy': state.uploading.value > 0 }\"\n :aria-label=\"t.image\"\n :aria-busy=\"state.uploading.value > 0 || undefined\"\n @click=\"insertImage\"\n >\n <ImageIcon />\n </button>\n </DouTooltip>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,76 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dou-ui/flow",
|
|
3
|
-
"version": "0.0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "DouUI 的流程编辑器:在无限画布上拖动节点、连接端口",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"vue",
|
|
7
|
+
"vue3",
|
|
8
|
+
"flow",
|
|
9
|
+
"node-editor",
|
|
10
|
+
"workflow",
|
|
11
|
+
"canvas"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "daidr <daidr@daidr.me>",
|
|
15
|
+
"homepage": "https://github.com/daidr/dou-ui#readme",
|
|
16
|
+
"bugs": "https://github.com/daidr/dou-ui/issues",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/daidr/dou-ui.git",
|
|
20
|
+
"directory": "packages/flow"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"sideEffects": [
|
|
24
|
+
"*.css",
|
|
25
|
+
"./dist/style.js"
|
|
26
|
+
],
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/types/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/types/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./collaboration": {
|
|
36
|
+
"types": "./dist/types/collaboration/index.d.ts",
|
|
37
|
+
"import": "./dist/collaboration/index.js"
|
|
38
|
+
},
|
|
39
|
+
"./whiteboard": {
|
|
40
|
+
"types": "./dist/types/whiteboard/index.d.ts",
|
|
41
|
+
"import": "./dist/whiteboard/index.js"
|
|
42
|
+
},
|
|
43
|
+
"./style": {
|
|
44
|
+
"types": "./dist/style.d.ts",
|
|
45
|
+
"import": "./dist/style.js"
|
|
46
|
+
},
|
|
47
|
+
"./style.css": "./dist/style.css",
|
|
48
|
+
"./package.json": "./package.json"
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"dist"
|
|
52
|
+
],
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "vite build && vue-tsc -p tsconfig.build.json && bun scripts/build-style.ts"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"dou-ui": "0.1.0-alpha.0",
|
|
58
|
+
"vue": "^3.5.0",
|
|
59
|
+
"yjs": "^13.6.0"
|
|
60
|
+
},
|
|
61
|
+
"peerDependenciesMeta": {
|
|
62
|
+
"yjs": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"@dou-ui/icons": "0.1.0-alpha.0"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"y-protocols": "^1.0.7",
|
|
71
|
+
"yjs": "^13.6.33"
|
|
72
|
+
},
|
|
73
|
+
"publishConfig": {
|
|
74
|
+
"access": "public"
|
|
75
|
+
}
|
|
76
|
+
}
|