orio-ui 1.19.0 → 1.23.2
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 +12 -5
- package/dist/module.json +1 -1
- package/dist/module.mjs +5 -2
- package/dist/runtime/canvas.d.ts +21 -0
- package/dist/runtime/canvas.js +49 -0
- package/dist/runtime/components/Button.vue +2 -1
- package/dist/runtime/components/Canvas/REQUIREMENTS.md +174 -0
- package/dist/runtime/components/Canvas/components/Stage.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/components/Stage.vue +150 -0
- package/dist/runtime/components/Canvas/components/Stage.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/components/ToolButton.d.vue.ts +24 -0
- package/dist/runtime/components/Canvas/components/ToolButton.vue +62 -0
- package/dist/runtime/components/Canvas/components/ToolButton.vue.d.ts +24 -0
- package/dist/runtime/components/Canvas/components/Toolbar.d.vue.ts +24 -0
- package/dist/runtime/components/Canvas/components/Toolbar.vue +48 -0
- package/dist/runtime/components/Canvas/components/Toolbar.vue.d.ts +24 -0
- package/dist/runtime/components/Canvas/composables/useCanvasHistory.d.ts +17 -0
- package/dist/runtime/components/Canvas/composables/useCanvasHistory.js +76 -0
- package/dist/runtime/components/Canvas/composables/useCanvasNodes.d.ts +13 -0
- package/dist/runtime/components/Canvas/composables/useCanvasNodes.js +60 -0
- package/dist/runtime/components/Canvas/composables/useCanvasSetup.d.ts +5 -0
- package/dist/runtime/components/Canvas/composables/useCanvasSetup.js +19 -0
- package/dist/runtime/components/Canvas/context.d.ts +38 -0
- package/dist/runtime/components/Canvas/context.js +11 -0
- package/dist/runtime/components/Canvas/index.d.vue.ts +77 -0
- package/dist/runtime/components/Canvas/index.vue +208 -0
- package/dist/runtime/components/Canvas/index.vue.d.ts +77 -0
- package/dist/runtime/components/Canvas/registry.d.ts +1 -0
- package/dist/runtime/components/Canvas/registry.js +2 -0
- package/dist/runtime/components/Canvas/tools/ColorPickerWidget.d.vue.ts +7 -0
- package/dist/runtime/components/Canvas/tools/ColorPickerWidget.vue +32 -0
- package/dist/runtime/components/Canvas/tools/ColorPickerWidget.vue.d.ts +7 -0
- package/dist/runtime/components/Canvas/tools/clearTool.d.ts +1 -0
- package/dist/runtime/components/Canvas/tools/clearTool.js +16 -0
- package/dist/runtime/components/Canvas/tools/colorPickerTool.d.ts +6 -0
- package/dist/runtime/components/Canvas/tools/colorPickerTool.js +15 -0
- package/dist/runtime/components/Canvas/tools/drawTool.d.ts +16 -0
- package/dist/runtime/components/Canvas/tools/drawTool.js +92 -0
- package/dist/runtime/components/Canvas/tools/eraseTool.d.ts +5 -0
- package/dist/runtime/components/Canvas/tools/eraseTool.js +62 -0
- package/dist/runtime/components/Canvas/tools/exportTool.d.ts +18 -0
- package/dist/runtime/components/Canvas/tools/exportTool.js +89 -0
- package/dist/runtime/components/Canvas/tools/highlightTool.d.ts +11 -0
- package/dist/runtime/components/Canvas/tools/highlightTool.js +51 -0
- package/dist/runtime/components/Canvas/tools/hitTest.d.ts +20 -0
- package/dist/runtime/components/Canvas/tools/hitTest.js +111 -0
- package/dist/runtime/components/Canvas/tools/imageTool.d.ts +18 -0
- package/dist/runtime/components/Canvas/tools/imageTool.js +163 -0
- package/dist/runtime/components/Canvas/tools/moveTool.d.ts +5 -0
- package/dist/runtime/components/Canvas/tools/moveTool.js +94 -0
- package/dist/runtime/components/Canvas/tools/redoTool.d.ts +1 -0
- package/dist/runtime/components/Canvas/tools/redoTool.js +17 -0
- package/dist/runtime/components/Canvas/tools/resizeTool.d.ts +7 -0
- package/dist/runtime/components/Canvas/tools/resizeTool.js +132 -0
- package/dist/runtime/components/Canvas/tools/rotateTool.d.ts +5 -0
- package/dist/runtime/components/Canvas/tools/rotateTool.js +109 -0
- package/dist/runtime/components/Canvas/tools/textTool.d.ts +14 -0
- package/dist/runtime/components/Canvas/tools/textTool.js +99 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Clear.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Clear.vue +12 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Clear.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Draw.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Draw.vue +12 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Draw.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Erase.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Erase.vue +12 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Erase.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Export.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Export.vue +13 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Export.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Highlight.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Highlight.vue +12 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Highlight.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Image.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Image.vue +13 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Image.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Move.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Move.vue +13 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Move.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Redo.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Redo.vue +13 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Redo.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Resize.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Resize.vue +13 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Resize.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Rotate.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Rotate.vue +13 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Rotate.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Text.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Text.vue +13 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Text.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Transform.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Transform.vue +14 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Transform.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Undo.d.vue.ts +3 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Undo.vue +13 -0
- package/dist/runtime/components/Canvas/tools/tooltips/Undo.vue.d.ts +3 -0
- package/dist/runtime/components/Canvas/tools/transformHandles.d.ts +74 -0
- package/dist/runtime/components/Canvas/tools/transformHandles.js +191 -0
- package/dist/runtime/components/Canvas/tools/transformTool.d.ts +7 -0
- package/dist/runtime/components/Canvas/tools/transformTool.js +210 -0
- package/dist/runtime/components/Canvas/tools/undoTool.d.ts +1 -0
- package/dist/runtime/components/Canvas/tools/undoTool.js +17 -0
- package/dist/runtime/components/Canvas/types.d.ts +125 -0
- package/dist/runtime/components/Canvas/types.js +3 -0
- package/dist/runtime/components/CheckBox.vue +6 -3
- package/dist/runtime/components/CheckboxGroup.vue +2 -1
- package/dist/runtime/components/ControlElement.d.vue.ts +5 -0
- package/dist/runtime/components/ControlElement.vue +19 -3
- package/dist/runtime/components/ControlElement.vue.d.ts +5 -0
- package/dist/runtime/components/DateRangePicker.vue +16 -4
- package/dist/runtime/components/Icon.vue +2 -2
- package/dist/runtime/components/Input.vue +2 -1
- package/dist/runtime/components/ListItem.d.vue.ts +29 -0
- package/dist/runtime/components/ListItem.vue +72 -0
- package/dist/runtime/components/ListItem.vue.d.ts +29 -0
- package/dist/runtime/components/LocaleSwitcher.d.vue.ts +13 -0
- package/dist/runtime/components/LocaleSwitcher.vue +43 -0
- package/dist/runtime/components/LocaleSwitcher.vue.d.ts +13 -0
- package/dist/runtime/components/NavButton.vue +2 -1
- package/dist/runtime/components/NumberInput/Horizontal.vue +2 -1
- package/dist/runtime/components/NumberInput/Vertical.vue +2 -1
- package/dist/runtime/components/NumberInput/index.vue +2 -1
- package/dist/runtime/components/RadioButton.vue +2 -1
- package/dist/runtime/components/Selector.vue +24 -22
- package/dist/runtime/components/SwitchButton.vue +2 -1
- package/dist/runtime/components/Tag.d.vue.ts +3 -2
- package/dist/runtime/components/Tag.vue +1 -0
- package/dist/runtime/components/Tag.vue.d.ts +3 -2
- package/dist/runtime/components/TaggableSelector.d.vue.ts +16 -0
- package/dist/runtime/components/TaggableSelector.vue +35 -0
- package/dist/runtime/components/TaggableSelector.vue.d.ts +16 -0
- package/dist/runtime/components/Textarea.vue +2 -1
- package/dist/runtime/components/Tooltip.vue +17 -7
- package/dist/runtime/components/ZoomableContainer.d.vue.ts +48 -0
- package/dist/runtime/components/ZoomableContainer.vue +238 -0
- package/dist/runtime/components/ZoomableContainer.vue.d.ts +48 -0
- package/dist/runtime/components/gallery/Carousel.vue +1 -1
- package/dist/runtime/components/gallery/CarouselPreview.d.vue.ts +31 -0
- package/dist/runtime/components/gallery/CarouselPreview.vue +64 -0
- package/dist/runtime/components/gallery/CarouselPreview.vue.d.ts +31 -0
- package/dist/runtime/components/view/Dates.vue +5 -3
- package/dist/runtime/components/view/KeyBinds.d.vue.ts +7 -0
- package/dist/runtime/components/view/KeyBinds.vue +36 -0
- package/dist/runtime/components/view/KeyBinds.vue.d.ts +7 -0
- package/dist/runtime/components/view/Text.vue +4 -4
- package/dist/runtime/composables/useInertia.d.ts +10 -0
- package/dist/runtime/composables/useInertia.js +49 -0
- package/dist/runtime/composables/usePinchZoom.d.ts +13 -0
- package/dist/runtime/composables/usePinchZoom.js +66 -0
- package/dist/runtime/composables/useValidation.js +11 -1
- package/dist/runtime/i18n/en.json +20 -0
- package/dist/runtime/i18n/index.d.ts +11 -0
- package/dist/runtime/i18n/index.js +19 -0
- package/dist/runtime/i18n/uk.json +20 -0
- package/dist/runtime/index.d.ts +8 -1
- package/dist/runtime/index.js +19 -1
- package/dist/runtime/plugins/i18n.d.ts +2 -0
- package/dist/runtime/plugins/i18n.js +18 -0
- package/dist/runtime/utils/icon-registry.js +13 -1
- package/package.json +9 -4
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { defineCanvasTool } from "../types.js";
|
|
2
|
+
import {
|
|
3
|
+
findTopNode,
|
|
4
|
+
getNodeBounds,
|
|
5
|
+
hitTestNode,
|
|
6
|
+
renderHighlightRect,
|
|
7
|
+
toLocalPoint
|
|
8
|
+
} from "./hitTest.js";
|
|
9
|
+
import {
|
|
10
|
+
computeResizePatch,
|
|
11
|
+
cursorForHandle,
|
|
12
|
+
hitHandle,
|
|
13
|
+
normalizeAngleDelta,
|
|
14
|
+
renderResizeHandles,
|
|
15
|
+
renderRotationHandle
|
|
16
|
+
} from "./transformHandles.js";
|
|
17
|
+
import TransformTooltip from "./tooltips/Transform.vue";
|
|
18
|
+
const RESIZE_HANDLES = [
|
|
19
|
+
"n",
|
|
20
|
+
"s",
|
|
21
|
+
"e",
|
|
22
|
+
"w",
|
|
23
|
+
"nw",
|
|
24
|
+
"ne",
|
|
25
|
+
"sw",
|
|
26
|
+
"se"
|
|
27
|
+
];
|
|
28
|
+
const ALL_HANDLES = [...RESIZE_HANDLES, "rotate"];
|
|
29
|
+
export function transformTool(options = {}) {
|
|
30
|
+
let selectedNodeId = null;
|
|
31
|
+
let mode = null;
|
|
32
|
+
let hoveredHandle = null;
|
|
33
|
+
let activeHandle = null;
|
|
34
|
+
let dragCtx = null;
|
|
35
|
+
let prevAngle = 0;
|
|
36
|
+
let accumulatedRotation = 0;
|
|
37
|
+
let lastX = 0;
|
|
38
|
+
let lastY = 0;
|
|
39
|
+
function reset() {
|
|
40
|
+
mode = null;
|
|
41
|
+
activeHandle = null;
|
|
42
|
+
dragCtx = null;
|
|
43
|
+
}
|
|
44
|
+
function clearSelection(api) {
|
|
45
|
+
if (selectedNodeId) {
|
|
46
|
+
selectedNodeId = null;
|
|
47
|
+
hoveredHandle = null;
|
|
48
|
+
api.setCursor(null);
|
|
49
|
+
api.requestRender();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return defineCanvasTool({
|
|
53
|
+
id: "transform",
|
|
54
|
+
label: "Transform",
|
|
55
|
+
icon: "transform",
|
|
56
|
+
cursor: "default",
|
|
57
|
+
tooltip: TransformTooltip,
|
|
58
|
+
defaultOptions: {
|
|
59
|
+
radius: 10,
|
|
60
|
+
minSize: 8,
|
|
61
|
+
...options
|
|
62
|
+
},
|
|
63
|
+
onPointerDown(e, api) {
|
|
64
|
+
if (selectedNodeId) {
|
|
65
|
+
const node2 = api.getNode(selectedNodeId);
|
|
66
|
+
if (node2) {
|
|
67
|
+
const handle = hitHandle(node2, e, { handles: ALL_HANDLES });
|
|
68
|
+
const bounds = getNodeBounds(node2);
|
|
69
|
+
const center = {
|
|
70
|
+
x: bounds.x + bounds.width / 2,
|
|
71
|
+
y: bounds.y + bounds.height / 2
|
|
72
|
+
};
|
|
73
|
+
if (handle === "rotate") {
|
|
74
|
+
mode = "rotate";
|
|
75
|
+
accumulatedRotation = node2.rotation ?? 0;
|
|
76
|
+
prevAngle = Math.atan2(e.y - center.y, e.x - center.x);
|
|
77
|
+
api.setCursor("none");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (handle && handle !== "rotate") {
|
|
81
|
+
mode = "resize";
|
|
82
|
+
activeHandle = handle;
|
|
83
|
+
dragCtx = {
|
|
84
|
+
original: {
|
|
85
|
+
...node2,
|
|
86
|
+
data: JSON.parse(JSON.stringify(node2.data))
|
|
87
|
+
},
|
|
88
|
+
originalBounds: bounds,
|
|
89
|
+
startLocal: toLocalPoint(node2, e)
|
|
90
|
+
};
|
|
91
|
+
api.setCursor("none");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const tools = api.getTools();
|
|
95
|
+
const toolMap = new Map(tools.map((t) => [t.id, t]));
|
|
96
|
+
if (hitTestNode(node2, e, api.options.radius, toolMap)) {
|
|
97
|
+
mode = "move";
|
|
98
|
+
lastX = e.x;
|
|
99
|
+
lastY = e.y;
|
|
100
|
+
api.setCursor("grabbing");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const node = findTopNode(e, api, api.options.radius);
|
|
106
|
+
selectedNodeId = node ? node.id : null;
|
|
107
|
+
hoveredHandle = null;
|
|
108
|
+
api.requestRender();
|
|
109
|
+
},
|
|
110
|
+
onPointerMove(e, api) {
|
|
111
|
+
if (mode && selectedNodeId && e.buttons !== 0) {
|
|
112
|
+
const node = api.getNode(selectedNodeId);
|
|
113
|
+
if (!node) return;
|
|
114
|
+
if (mode === "resize" && activeHandle && dragCtx) {
|
|
115
|
+
const local = toLocalPoint(dragCtx.original, e);
|
|
116
|
+
const patch = computeResizePatch(activeHandle, local, dragCtx, {
|
|
117
|
+
minSize: api.options.minSize
|
|
118
|
+
});
|
|
119
|
+
if (patch) api.updateNode(selectedNodeId, patch);
|
|
120
|
+
api.setCursor("none");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (mode === "rotate") {
|
|
124
|
+
const b = getNodeBounds(node);
|
|
125
|
+
const angle = Math.atan2(
|
|
126
|
+
e.y - (b.y + b.height / 2),
|
|
127
|
+
e.x - (b.x + b.width / 2)
|
|
128
|
+
);
|
|
129
|
+
accumulatedRotation += normalizeAngleDelta(angle - prevAngle);
|
|
130
|
+
prevAngle = angle;
|
|
131
|
+
api.updateNode(selectedNodeId, { rotation: accumulatedRotation });
|
|
132
|
+
api.setCursor("none");
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (mode === "move") {
|
|
136
|
+
const dx = e.x - lastX;
|
|
137
|
+
const dy = e.y - lastY;
|
|
138
|
+
lastX = e.x;
|
|
139
|
+
lastY = e.y;
|
|
140
|
+
const patch = {
|
|
141
|
+
x: node.x + dx,
|
|
142
|
+
y: node.y + dy
|
|
143
|
+
};
|
|
144
|
+
if (Array.isArray(node.data?.points)) {
|
|
145
|
+
const data = node.data;
|
|
146
|
+
patch.data = {
|
|
147
|
+
...node.data,
|
|
148
|
+
points: data.points.map((p) => ({ x: p.x + dx, y: p.y + dy }))
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
api.updateNode(selectedNodeId, patch);
|
|
152
|
+
api.setCursor("grabbing");
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (selectedNodeId) {
|
|
157
|
+
const node = api.getNode(selectedNodeId);
|
|
158
|
+
if (node) {
|
|
159
|
+
const handle = hitHandle(node, e, { handles: ALL_HANDLES });
|
|
160
|
+
if (handle !== hoveredHandle) {
|
|
161
|
+
hoveredHandle = handle;
|
|
162
|
+
api.requestRender();
|
|
163
|
+
}
|
|
164
|
+
if (handle) {
|
|
165
|
+
api.setCursor(cursorForHandle(handle, node.rotation));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const tools = api.getTools();
|
|
169
|
+
const toolMap = new Map(tools.map((t) => [t.id, t]));
|
|
170
|
+
if (hitTestNode(node, e, api.options.radius, toolMap)) {
|
|
171
|
+
api.setCursor("grab");
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
api.setCursor(null);
|
|
177
|
+
},
|
|
178
|
+
onPointerUp(_e, api) {
|
|
179
|
+
reset();
|
|
180
|
+
api.setCursor(null);
|
|
181
|
+
},
|
|
182
|
+
onDeactivate(api) {
|
|
183
|
+
reset();
|
|
184
|
+
api.setCursor(null);
|
|
185
|
+
clearSelection(api);
|
|
186
|
+
},
|
|
187
|
+
onKeyDown(e, api) {
|
|
188
|
+
if (e.key === "Escape" && selectedNodeId) {
|
|
189
|
+
clearSelection(api);
|
|
190
|
+
e.preventDefault();
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
renderOverlay(ctx, api) {
|
|
194
|
+
if (!selectedNodeId) return;
|
|
195
|
+
const node = api.getNode(selectedNodeId);
|
|
196
|
+
if (!node) {
|
|
197
|
+
selectedNodeId = null;
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
renderHighlightRect(ctx, node);
|
|
201
|
+
renderResizeHandles(ctx, node, {
|
|
202
|
+
handles: RESIZE_HANDLES,
|
|
203
|
+
hovered: mode === "resize" ? activeHandle : hoveredHandle && hoveredHandle !== "rotate" ? hoveredHandle : null
|
|
204
|
+
});
|
|
205
|
+
renderRotationHandle(ctx, node, {
|
|
206
|
+
hovered: mode === "rotate" || hoveredHandle === "rotate"
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function undoTool(): import("../types.js").CanvasTool<unknown, Record<string, unknown>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineCanvasTool } from "../types.js";
|
|
2
|
+
import UndoTooltip from "./tooltips/Undo.vue";
|
|
3
|
+
export function undoTool() {
|
|
4
|
+
return defineCanvasTool({
|
|
5
|
+
id: "undo",
|
|
6
|
+
label: "Undo",
|
|
7
|
+
icon: "undo",
|
|
8
|
+
kind: "action",
|
|
9
|
+
tooltip: UndoTooltip,
|
|
10
|
+
action(api) {
|
|
11
|
+
api.undo();
|
|
12
|
+
},
|
|
13
|
+
disabled(api) {
|
|
14
|
+
return !api.canUndo.value;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { Component, ComputedRef, Ref } from "vue";
|
|
2
|
+
import type { IconName } from "../../utils/icon-registry.js";
|
|
3
|
+
export interface CanvasPoint {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
}
|
|
7
|
+
export interface CanvasNode<TData = unknown> {
|
|
8
|
+
id: string;
|
|
9
|
+
/** Matches the id of the tool that owns (renders) this node. */
|
|
10
|
+
type: string;
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
width?: number;
|
|
14
|
+
height?: number;
|
|
15
|
+
rotation?: number;
|
|
16
|
+
/** When true, future interaction tools should skip this node. */
|
|
17
|
+
frozen?: boolean;
|
|
18
|
+
zIndex?: number;
|
|
19
|
+
data: TData;
|
|
20
|
+
}
|
|
21
|
+
export interface CanvasPointerEvent {
|
|
22
|
+
/** Canvas-space x (origin is the top-left of the stage). */
|
|
23
|
+
x: number;
|
|
24
|
+
/** Canvas-space y. */
|
|
25
|
+
y: number;
|
|
26
|
+
/** Viewport-space x — useful for positioning HTML overlays. */
|
|
27
|
+
clientX: number;
|
|
28
|
+
/** Viewport-space y. */
|
|
29
|
+
clientY: number;
|
|
30
|
+
/** Pressed buttons bitmask from the underlying PointerEvent. */
|
|
31
|
+
buttons: number;
|
|
32
|
+
originalEvent: PointerEvent;
|
|
33
|
+
}
|
|
34
|
+
export interface CanvasToolApi<TOptions extends Record<string, unknown> = Record<string, unknown>> {
|
|
35
|
+
/** Reactive, mutable options bag for this tool. */
|
|
36
|
+
options: TOptions;
|
|
37
|
+
/** All current nodes — treat as read-only; use helpers to mutate. */
|
|
38
|
+
nodes: Ref<CanvasNode[]>;
|
|
39
|
+
addNode: (node: Omit<CanvasNode, "id"> & {
|
|
40
|
+
id?: string;
|
|
41
|
+
}) => CanvasNode;
|
|
42
|
+
updateNode: (id: string, patch: Partial<Omit<CanvasNode, "id">>) => void;
|
|
43
|
+
removeNode: (id: string) => void;
|
|
44
|
+
getNode: (id: string) => CanvasNode | undefined;
|
|
45
|
+
clear: () => void;
|
|
46
|
+
/** Schedule a redraw on the next animation frame. */
|
|
47
|
+
requestRender: () => void;
|
|
48
|
+
/** The stage's root element — mount overlay DOM here. */
|
|
49
|
+
stageEl: () => HTMLElement | null;
|
|
50
|
+
/** Current canvas size in CSS pixels. */
|
|
51
|
+
size: () => {
|
|
52
|
+
width: number;
|
|
53
|
+
height: number;
|
|
54
|
+
};
|
|
55
|
+
/** Undo the last action. */
|
|
56
|
+
undo: () => void;
|
|
57
|
+
/** Redo the last undone action. */
|
|
58
|
+
redo: () => void;
|
|
59
|
+
/** Whether there's anything to undo. */
|
|
60
|
+
canUndo: ComputedRef<boolean>;
|
|
61
|
+
/** Whether there's anything to redo. */
|
|
62
|
+
canRedo: ComputedRef<boolean>;
|
|
63
|
+
/** Read/write another tool's reactive options. */
|
|
64
|
+
getToolOptions: <T extends Record<string, unknown>>(id: string) => T;
|
|
65
|
+
/** All registered tools — useful for hit-testing across tool types. */
|
|
66
|
+
getTools: () => CanvasTool[];
|
|
67
|
+
/**
|
|
68
|
+
* Override the stage cursor — pass `null` to fall back to the active tool's
|
|
69
|
+
* static `cursor`. Use for hover-state feedback (resize handles, rotation
|
|
70
|
+
* handle, etc.).
|
|
71
|
+
*/
|
|
72
|
+
setCursor: (cursor: string | null) => void;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Tool kind determines how the toolbar renders the tool:
|
|
76
|
+
* - `"interaction"` (default) — activates on click, receives pointer events on the stage.
|
|
77
|
+
* - `"action"` — fires `action()` on click, never becomes the active tool.
|
|
78
|
+
* - `"widget"` — renders a custom `toolbar` component instead of a button.
|
|
79
|
+
*/
|
|
80
|
+
export type CanvasToolKind = "interaction" | "action" | "widget";
|
|
81
|
+
export interface CanvasTool<TNodeData = unknown, TOptions extends Record<string, unknown> = Record<string, unknown>> {
|
|
82
|
+
/** Stable id — also used as `node.type` for nodes produced by this tool. */
|
|
83
|
+
id: string;
|
|
84
|
+
label?: string;
|
|
85
|
+
/** Icon name from the Orio icon registry. */
|
|
86
|
+
icon?: IconName | (string & {});
|
|
87
|
+
/** CSS cursor applied to the stage while this tool is active. */
|
|
88
|
+
cursor?: string;
|
|
89
|
+
tooltip?: Component;
|
|
90
|
+
/**
|
|
91
|
+
* Tool kind. Defaults to `"interaction"`.
|
|
92
|
+
* - `"interaction"` — standard pointer tool (draw, text, etc.)
|
|
93
|
+
* - `"action"` — one-shot action (undo, redo, clear)
|
|
94
|
+
* - `"widget"` — renders a custom component in the toolbar
|
|
95
|
+
*/
|
|
96
|
+
kind?: CanvasToolKind;
|
|
97
|
+
/** For action tools: callback fired when the button is clicked. */
|
|
98
|
+
action?: (api: CanvasToolApi<TOptions>) => void;
|
|
99
|
+
/** For action tools: reactive disabled state. */
|
|
100
|
+
disabled?: (api: CanvasToolApi<TOptions>) => boolean;
|
|
101
|
+
/** For widget tools: Vue component rendered in the toolbar instead of a button. */
|
|
102
|
+
toolbar?: Component;
|
|
103
|
+
defaultOptions?: TOptions;
|
|
104
|
+
onPointerDown?: (e: CanvasPointerEvent, api: CanvasToolApi<TOptions>) => void;
|
|
105
|
+
onPointerMove?: (e: CanvasPointerEvent, api: CanvasToolApi<TOptions>) => void;
|
|
106
|
+
onPointerUp?: (e: CanvasPointerEvent, api: CanvasToolApi<TOptions>) => void;
|
|
107
|
+
onActivate?: (api: CanvasToolApi<TOptions>) => void;
|
|
108
|
+
onDeactivate?: (api: CanvasToolApi<TOptions>) => void;
|
|
109
|
+
onKeyDown?: (e: KeyboardEvent, api: CanvasToolApi<TOptions>) => void;
|
|
110
|
+
render?: (ctx: CanvasRenderingContext2D, node: CanvasNode<TNodeData>) => void;
|
|
111
|
+
/** Draw overlay graphics after all nodes have been rendered. */
|
|
112
|
+
renderOverlay?: (ctx: CanvasRenderingContext2D, api: CanvasToolApi<TOptions>) => void;
|
|
113
|
+
/**
|
|
114
|
+
* Hit-test a node against a point. Used by the erase tool (and future
|
|
115
|
+
* selection tools) to determine if a pointer intersects this node.
|
|
116
|
+
* Return `true` if the node is "hit".
|
|
117
|
+
*
|
|
118
|
+
* @param node The node to test.
|
|
119
|
+
* @param point The pointer position in canvas-space.
|
|
120
|
+
* @param radius The eraser/selection radius in CSS pixels.
|
|
121
|
+
*/
|
|
122
|
+
hitTest?: (node: CanvasNode<TNodeData>, point: CanvasPoint, radius: number) => boolean;
|
|
123
|
+
}
|
|
124
|
+
/** Author-facing helper that preserves generics on a tool definition. */
|
|
125
|
+
export declare function defineCanvasTool<TNodeData = unknown, TOptions extends Record<string, unknown> = Record<string, unknown>>(tool: CanvasTool<TNodeData, TOptions>): CanvasTool<TNodeData, TOptions>;
|
|
@@ -9,12 +9,13 @@ const props = defineProps({
|
|
|
9
9
|
id: { type: String, required: false },
|
|
10
10
|
label: { type: String, required: false },
|
|
11
11
|
layout: { type: String, required: false },
|
|
12
|
-
size: { type: String, required: false }
|
|
12
|
+
size: { type: String, required: false },
|
|
13
|
+
fill: { type: Boolean, required: false }
|
|
13
14
|
});
|
|
14
15
|
</script>
|
|
15
16
|
|
|
16
17
|
<template>
|
|
17
|
-
<orio-control-element v-bind="props" class="checkbox">
|
|
18
|
+
<orio-control-element v-bind="props" class="checkbox" fill>
|
|
18
19
|
<label class="checkbox-label">
|
|
19
20
|
<input
|
|
20
21
|
v-model="modelValue"
|
|
@@ -47,6 +48,9 @@ const props = defineProps({
|
|
|
47
48
|
.checkbox {
|
|
48
49
|
--box-size: var(--control-icon-size, 1rem);
|
|
49
50
|
}
|
|
51
|
+
.checkbox .checkbox-label {
|
|
52
|
+
vertical-align: baseline;
|
|
53
|
+
}
|
|
50
54
|
.checkbox-label {
|
|
51
55
|
position: relative;
|
|
52
56
|
user-select: none;
|
|
@@ -60,7 +64,6 @@ const props = defineProps({
|
|
|
60
64
|
position: absolute;
|
|
61
65
|
inset: 0;
|
|
62
66
|
width: var(--box-size);
|
|
63
|
-
height: 1rem;
|
|
64
67
|
margin: 0;
|
|
65
68
|
opacity: 0;
|
|
66
69
|
}
|
|
@@ -5,7 +5,8 @@ const props = defineProps({
|
|
|
5
5
|
error: { type: [String, null], required: false, default: null },
|
|
6
6
|
label: { type: String, required: false },
|
|
7
7
|
layout: { type: String, required: false, default: "vertical" },
|
|
8
|
-
size: { type: String, required: false, default: "md" }
|
|
8
|
+
size: { type: String, required: false, default: "md" },
|
|
9
|
+
fill: { type: Boolean, required: false }
|
|
9
10
|
});
|
|
10
11
|
const modelValue = defineModel({ type: Array, ...{ default: () => [] } });
|
|
11
12
|
function isChecked(value) {
|
|
@@ -31,6 +31,10 @@ export interface ControlProps {
|
|
|
31
31
|
* Size of the control and its inner elements
|
|
32
32
|
*/
|
|
33
33
|
size?: ControlSize;
|
|
34
|
+
/**
|
|
35
|
+
* Whether element should fill the container
|
|
36
|
+
*/
|
|
37
|
+
fill?: boolean;
|
|
34
38
|
}
|
|
35
39
|
declare var __VLS_7: {
|
|
36
40
|
id: string;
|
|
@@ -45,6 +49,7 @@ declare const __VLS_base: import("vue").DefineComponent<ControlProps, {}, {}, {}
|
|
|
45
49
|
id: string;
|
|
46
50
|
layout: ControlLayout;
|
|
47
51
|
size: ControlSize;
|
|
52
|
+
fill: boolean;
|
|
48
53
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
49
54
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
50
55
|
declare const _default: typeof __VLS_export;
|
|
@@ -9,7 +9,8 @@ const props = defineProps({
|
|
|
9
9
|
id: { type: String, required: false, default: () => useId() },
|
|
10
10
|
label: { type: String, required: false },
|
|
11
11
|
layout: { type: String, required: false, default: "vertical" },
|
|
12
|
-
size: { type: String, required: false, default: "md" }
|
|
12
|
+
size: { type: String, required: false, default: "md" },
|
|
13
|
+
fill: { type: Boolean, required: false, default: false }
|
|
13
14
|
});
|
|
14
15
|
provideControlSize(toRef(props, "size"));
|
|
15
16
|
const sizeStyle = computed(() => sizeTokens[props.size]);
|
|
@@ -18,7 +19,12 @@ const sizeStyle = computed(() => sizeTokens[props.size]);
|
|
|
18
19
|
<template>
|
|
19
20
|
<div
|
|
20
21
|
class="control"
|
|
21
|
-
:class="[
|
|
22
|
+
:class="[
|
|
23
|
+
appearance,
|
|
24
|
+
layout,
|
|
25
|
+
`size-${size}`,
|
|
26
|
+
{ 'has-error': error, group, fill }
|
|
27
|
+
]"
|
|
22
28
|
:style="sizeStyle"
|
|
23
29
|
v-bind="{
|
|
24
30
|
...$attrs,
|
|
@@ -48,6 +54,7 @@ const sizeStyle = computed(() => sizeTokens[props.size]);
|
|
|
48
54
|
display: flex;
|
|
49
55
|
flex-direction: column;
|
|
50
56
|
gap: 0.1rem;
|
|
57
|
+
border-radius: var(--control-radius);
|
|
51
58
|
}
|
|
52
59
|
.control .control-label {
|
|
53
60
|
font-size: var(--control-label-font-size);
|
|
@@ -60,10 +67,19 @@ const sizeStyle = computed(() => sizeTokens[props.size]);
|
|
|
60
67
|
color: var(--color-danger);
|
|
61
68
|
font-size: var(--control-label-font-size);
|
|
62
69
|
}
|
|
70
|
+
.control.fill .slot-wrapper {
|
|
71
|
+
display: flex;
|
|
72
|
+
}
|
|
73
|
+
.control.fill .slot-wrapper > * {
|
|
74
|
+
flex: 1;
|
|
75
|
+
}
|
|
63
76
|
.control .slot-wrapper :deep(*) {
|
|
64
77
|
font-size: var(--control-font-size);
|
|
65
78
|
}
|
|
66
|
-
.control.has-error .slot-wrapper {
|
|
79
|
+
.control.has-error .slot-wrapper:not(:has(:deep(.error-fields))) {
|
|
80
|
+
border: 1px solid var(--color-danger);
|
|
81
|
+
}
|
|
82
|
+
.control.has-error .slot-wrapper :deep(.error-fields .slot-wrapper > *) {
|
|
67
83
|
border: 1px solid var(--color-danger);
|
|
68
84
|
}
|
|
69
85
|
.control.has-error .slot-wrapper :deep(*) {
|
|
@@ -31,6 +31,10 @@ export interface ControlProps {
|
|
|
31
31
|
* Size of the control and its inner elements
|
|
32
32
|
*/
|
|
33
33
|
size?: ControlSize;
|
|
34
|
+
/**
|
|
35
|
+
* Whether element should fill the container
|
|
36
|
+
*/
|
|
37
|
+
fill?: boolean;
|
|
34
38
|
}
|
|
35
39
|
declare var __VLS_7: {
|
|
36
40
|
id: string;
|
|
@@ -45,6 +49,7 @@ declare const __VLS_base: import("vue").DefineComponent<ControlProps, {}, {}, {}
|
|
|
45
49
|
id: string;
|
|
46
50
|
layout: ControlLayout;
|
|
47
51
|
size: ControlSize;
|
|
52
|
+
fill: boolean;
|
|
48
53
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
49
54
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
50
55
|
declare const _default: typeof __VLS_export;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { ref, watch, computed } from "vue";
|
|
3
|
+
import { useI18n } from "vue-i18n";
|
|
3
4
|
defineProps({
|
|
4
5
|
month: { type: Boolean, required: false }
|
|
5
6
|
});
|
|
7
|
+
const { t } = useI18n();
|
|
6
8
|
const dates = defineModel("dates", { type: Object, ...{ required: true } });
|
|
7
9
|
const present = ref(dates.value.endDate !== "" && !dates.value.endDate);
|
|
8
10
|
watch(present, (value) => {
|
|
@@ -24,12 +26,22 @@ defineExpose({ dateIsCorrect });
|
|
|
24
26
|
<template>
|
|
25
27
|
<orio-control-element
|
|
26
28
|
v-bind="$attrs"
|
|
27
|
-
:error="!dateIsCorrect
|
|
29
|
+
:error="!dateIsCorrect ? t('dateRangePicker.startBeforeEnd') : null"
|
|
28
30
|
>
|
|
29
31
|
<div class="date-range-picker">
|
|
30
|
-
<orio-date-picker
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
<orio-date-picker
|
|
33
|
+
v-model:date="dates.startDate"
|
|
34
|
+
class="error-fields"
|
|
35
|
+
:month
|
|
36
|
+
/>
|
|
37
|
+
<orio-date-picker
|
|
38
|
+
v-model:date="dates.endDate"
|
|
39
|
+
class="error-fields"
|
|
40
|
+
:month
|
|
41
|
+
/>
|
|
42
|
+
<orio-check-box v-model="present">
|
|
43
|
+
{{ t("dateRangePicker.present") }}
|
|
44
|
+
</orio-check-box>
|
|
33
45
|
</div>
|
|
34
46
|
</orio-control-element>
|
|
35
47
|
</template>
|
|
@@ -15,12 +15,12 @@ const sizeValue = computed(() => {
|
|
|
15
15
|
|
|
16
16
|
<template>
|
|
17
17
|
<span
|
|
18
|
-
class="
|
|
18
|
+
class="icon"
|
|
19
19
|
:style="{ color, width: sizeValue, height: sizeValue }"
|
|
20
20
|
v-html="iconSvg"
|
|
21
21
|
/>
|
|
22
22
|
</template>
|
|
23
23
|
|
|
24
24
|
<style scoped>
|
|
25
|
-
.
|
|
25
|
+
.icon{align-items:center;display:inline-flex;flex-shrink:0;height:var(--control-icon-size,1.5em);justify-content:center;width:var(--control-icon-size,1.5em)}.icon :deep(svg){fill:currentColor;height:100%;width:100%}
|
|
26
26
|
</style>
|
|
@@ -6,7 +6,8 @@ const props = defineProps({
|
|
|
6
6
|
group: { type: Boolean, required: false },
|
|
7
7
|
id: { type: String, required: false },
|
|
8
8
|
label: { type: String, required: false },
|
|
9
|
-
size: { type: String, required: false }
|
|
9
|
+
size: { type: String, required: false },
|
|
10
|
+
fill: { type: Boolean, required: false }
|
|
10
11
|
});
|
|
11
12
|
const modelValue = defineModel({ type: String, ...{ default: "" } });
|
|
12
13
|
</script>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface ListItemProps {
|
|
2
|
+
selectable?: boolean;
|
|
3
|
+
}
|
|
4
|
+
type __VLS_Props = ListItemProps;
|
|
5
|
+
type __VLS_ModelProps = {
|
|
6
|
+
"selected"?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
9
|
+
declare var __VLS_1: {}, __VLS_8: {}, __VLS_10: {};
|
|
10
|
+
type __VLS_Slots = {} & {
|
|
11
|
+
start?: (props: typeof __VLS_1) => any;
|
|
12
|
+
} & {
|
|
13
|
+
default?: (props: typeof __VLS_8) => any;
|
|
14
|
+
} & {
|
|
15
|
+
end?: (props: typeof __VLS_10) => any;
|
|
16
|
+
};
|
|
17
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
18
|
+
"update:selected": (value: boolean | undefined) => any;
|
|
19
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
20
|
+
"onUpdate:selected"?: ((value: boolean | undefined) => any) | undefined;
|
|
21
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
23
|
+
declare const _default: typeof __VLS_export;
|
|
24
|
+
export default _default;
|
|
25
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
26
|
+
new (): {
|
|
27
|
+
$slots: S;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useSlots } from "vue";
|
|
3
|
+
const { selectable = false } = defineProps({
|
|
4
|
+
selectable: { type: Boolean, required: false }
|
|
5
|
+
});
|
|
6
|
+
const slots = useSlots();
|
|
7
|
+
const selected = defineModel("selected", { type: Boolean });
|
|
8
|
+
function toggle() {
|
|
9
|
+
if (!selectable) return;
|
|
10
|
+
selected.value = !selected.value;
|
|
11
|
+
}
|
|
12
|
+
function onKeydown(event) {
|
|
13
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
14
|
+
event.preventDefault();
|
|
15
|
+
toggle();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<li
|
|
22
|
+
class="list-item"
|
|
23
|
+
:class="{ selectable, selected }"
|
|
24
|
+
:tabindex="selectable ? 0 : void 0"
|
|
25
|
+
:role="selectable ? 'checkbox' : void 0"
|
|
26
|
+
:aria-checked="selectable ? selected : void 0"
|
|
27
|
+
@click="toggle"
|
|
28
|
+
@keydown="onKeydown"
|
|
29
|
+
>
|
|
30
|
+
<div v-if="!!slots.start || selectable" class="boundary">
|
|
31
|
+
<slot name="start">
|
|
32
|
+
<orio-check-box :model-value="selected" />
|
|
33
|
+
</slot>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="content">
|
|
36
|
+
<slot />
|
|
37
|
+
</div>
|
|
38
|
+
<div v-if="!!slots.end" class="boundary">
|
|
39
|
+
<slot name="end" />
|
|
40
|
+
</div>
|
|
41
|
+
</li>
|
|
42
|
+
</template>
|
|
43
|
+
|
|
44
|
+
<style scoped>
|
|
45
|
+
.list-item {
|
|
46
|
+
width: 100%;
|
|
47
|
+
display: flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: 0.5rem;
|
|
50
|
+
padding: 0.5rem;
|
|
51
|
+
user-select: none;
|
|
52
|
+
}
|
|
53
|
+
.list-item.selectable {
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
}
|
|
56
|
+
.list-item {
|
|
57
|
+
transition: background-color 0.15s ease, color 0.15s ease;
|
|
58
|
+
}
|
|
59
|
+
.list-item.selected {
|
|
60
|
+
background-color: var(--color-accent);
|
|
61
|
+
color: var(--color-accent-soft-darker);
|
|
62
|
+
}
|
|
63
|
+
.list-item:hover:not(.selected) {
|
|
64
|
+
background-color: var(--color-surface);
|
|
65
|
+
}
|
|
66
|
+
.list-item .content {
|
|
67
|
+
flex-grow: 1;
|
|
68
|
+
}
|
|
69
|
+
.list-item .boundary {
|
|
70
|
+
display: flex;
|
|
71
|
+
}
|
|
72
|
+
</style>
|