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.
Files changed (161) hide show
  1. package/README.md +12 -5
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +5 -2
  4. package/dist/runtime/canvas.d.ts +21 -0
  5. package/dist/runtime/canvas.js +49 -0
  6. package/dist/runtime/components/Button.vue +2 -1
  7. package/dist/runtime/components/Canvas/REQUIREMENTS.md +174 -0
  8. package/dist/runtime/components/Canvas/components/Stage.d.vue.ts +3 -0
  9. package/dist/runtime/components/Canvas/components/Stage.vue +150 -0
  10. package/dist/runtime/components/Canvas/components/Stage.vue.d.ts +3 -0
  11. package/dist/runtime/components/Canvas/components/ToolButton.d.vue.ts +24 -0
  12. package/dist/runtime/components/Canvas/components/ToolButton.vue +62 -0
  13. package/dist/runtime/components/Canvas/components/ToolButton.vue.d.ts +24 -0
  14. package/dist/runtime/components/Canvas/components/Toolbar.d.vue.ts +24 -0
  15. package/dist/runtime/components/Canvas/components/Toolbar.vue +48 -0
  16. package/dist/runtime/components/Canvas/components/Toolbar.vue.d.ts +24 -0
  17. package/dist/runtime/components/Canvas/composables/useCanvasHistory.d.ts +17 -0
  18. package/dist/runtime/components/Canvas/composables/useCanvasHistory.js +76 -0
  19. package/dist/runtime/components/Canvas/composables/useCanvasNodes.d.ts +13 -0
  20. package/dist/runtime/components/Canvas/composables/useCanvasNodes.js +60 -0
  21. package/dist/runtime/components/Canvas/composables/useCanvasSetup.d.ts +5 -0
  22. package/dist/runtime/components/Canvas/composables/useCanvasSetup.js +19 -0
  23. package/dist/runtime/components/Canvas/context.d.ts +38 -0
  24. package/dist/runtime/components/Canvas/context.js +11 -0
  25. package/dist/runtime/components/Canvas/index.d.vue.ts +77 -0
  26. package/dist/runtime/components/Canvas/index.vue +208 -0
  27. package/dist/runtime/components/Canvas/index.vue.d.ts +77 -0
  28. package/dist/runtime/components/Canvas/registry.d.ts +1 -0
  29. package/dist/runtime/components/Canvas/registry.js +2 -0
  30. package/dist/runtime/components/Canvas/tools/ColorPickerWidget.d.vue.ts +7 -0
  31. package/dist/runtime/components/Canvas/tools/ColorPickerWidget.vue +32 -0
  32. package/dist/runtime/components/Canvas/tools/ColorPickerWidget.vue.d.ts +7 -0
  33. package/dist/runtime/components/Canvas/tools/clearTool.d.ts +1 -0
  34. package/dist/runtime/components/Canvas/tools/clearTool.js +16 -0
  35. package/dist/runtime/components/Canvas/tools/colorPickerTool.d.ts +6 -0
  36. package/dist/runtime/components/Canvas/tools/colorPickerTool.js +15 -0
  37. package/dist/runtime/components/Canvas/tools/drawTool.d.ts +16 -0
  38. package/dist/runtime/components/Canvas/tools/drawTool.js +92 -0
  39. package/dist/runtime/components/Canvas/tools/eraseTool.d.ts +5 -0
  40. package/dist/runtime/components/Canvas/tools/eraseTool.js +62 -0
  41. package/dist/runtime/components/Canvas/tools/exportTool.d.ts +18 -0
  42. package/dist/runtime/components/Canvas/tools/exportTool.js +89 -0
  43. package/dist/runtime/components/Canvas/tools/highlightTool.d.ts +11 -0
  44. package/dist/runtime/components/Canvas/tools/highlightTool.js +51 -0
  45. package/dist/runtime/components/Canvas/tools/hitTest.d.ts +20 -0
  46. package/dist/runtime/components/Canvas/tools/hitTest.js +111 -0
  47. package/dist/runtime/components/Canvas/tools/imageTool.d.ts +18 -0
  48. package/dist/runtime/components/Canvas/tools/imageTool.js +163 -0
  49. package/dist/runtime/components/Canvas/tools/moveTool.d.ts +5 -0
  50. package/dist/runtime/components/Canvas/tools/moveTool.js +94 -0
  51. package/dist/runtime/components/Canvas/tools/redoTool.d.ts +1 -0
  52. package/dist/runtime/components/Canvas/tools/redoTool.js +17 -0
  53. package/dist/runtime/components/Canvas/tools/resizeTool.d.ts +7 -0
  54. package/dist/runtime/components/Canvas/tools/resizeTool.js +132 -0
  55. package/dist/runtime/components/Canvas/tools/rotateTool.d.ts +5 -0
  56. package/dist/runtime/components/Canvas/tools/rotateTool.js +109 -0
  57. package/dist/runtime/components/Canvas/tools/textTool.d.ts +14 -0
  58. package/dist/runtime/components/Canvas/tools/textTool.js +99 -0
  59. package/dist/runtime/components/Canvas/tools/tooltips/Clear.d.vue.ts +3 -0
  60. package/dist/runtime/components/Canvas/tools/tooltips/Clear.vue +12 -0
  61. package/dist/runtime/components/Canvas/tools/tooltips/Clear.vue.d.ts +3 -0
  62. package/dist/runtime/components/Canvas/tools/tooltips/Draw.d.vue.ts +3 -0
  63. package/dist/runtime/components/Canvas/tools/tooltips/Draw.vue +12 -0
  64. package/dist/runtime/components/Canvas/tools/tooltips/Draw.vue.d.ts +3 -0
  65. package/dist/runtime/components/Canvas/tools/tooltips/Erase.d.vue.ts +3 -0
  66. package/dist/runtime/components/Canvas/tools/tooltips/Erase.vue +12 -0
  67. package/dist/runtime/components/Canvas/tools/tooltips/Erase.vue.d.ts +3 -0
  68. package/dist/runtime/components/Canvas/tools/tooltips/Export.d.vue.ts +3 -0
  69. package/dist/runtime/components/Canvas/tools/tooltips/Export.vue +13 -0
  70. package/dist/runtime/components/Canvas/tools/tooltips/Export.vue.d.ts +3 -0
  71. package/dist/runtime/components/Canvas/tools/tooltips/Highlight.d.vue.ts +3 -0
  72. package/dist/runtime/components/Canvas/tools/tooltips/Highlight.vue +12 -0
  73. package/dist/runtime/components/Canvas/tools/tooltips/Highlight.vue.d.ts +3 -0
  74. package/dist/runtime/components/Canvas/tools/tooltips/Image.d.vue.ts +3 -0
  75. package/dist/runtime/components/Canvas/tools/tooltips/Image.vue +13 -0
  76. package/dist/runtime/components/Canvas/tools/tooltips/Image.vue.d.ts +3 -0
  77. package/dist/runtime/components/Canvas/tools/tooltips/Move.d.vue.ts +3 -0
  78. package/dist/runtime/components/Canvas/tools/tooltips/Move.vue +13 -0
  79. package/dist/runtime/components/Canvas/tools/tooltips/Move.vue.d.ts +3 -0
  80. package/dist/runtime/components/Canvas/tools/tooltips/Redo.d.vue.ts +3 -0
  81. package/dist/runtime/components/Canvas/tools/tooltips/Redo.vue +13 -0
  82. package/dist/runtime/components/Canvas/tools/tooltips/Redo.vue.d.ts +3 -0
  83. package/dist/runtime/components/Canvas/tools/tooltips/Resize.d.vue.ts +3 -0
  84. package/dist/runtime/components/Canvas/tools/tooltips/Resize.vue +13 -0
  85. package/dist/runtime/components/Canvas/tools/tooltips/Resize.vue.d.ts +3 -0
  86. package/dist/runtime/components/Canvas/tools/tooltips/Rotate.d.vue.ts +3 -0
  87. package/dist/runtime/components/Canvas/tools/tooltips/Rotate.vue +13 -0
  88. package/dist/runtime/components/Canvas/tools/tooltips/Rotate.vue.d.ts +3 -0
  89. package/dist/runtime/components/Canvas/tools/tooltips/Text.d.vue.ts +3 -0
  90. package/dist/runtime/components/Canvas/tools/tooltips/Text.vue +13 -0
  91. package/dist/runtime/components/Canvas/tools/tooltips/Text.vue.d.ts +3 -0
  92. package/dist/runtime/components/Canvas/tools/tooltips/Transform.d.vue.ts +3 -0
  93. package/dist/runtime/components/Canvas/tools/tooltips/Transform.vue +14 -0
  94. package/dist/runtime/components/Canvas/tools/tooltips/Transform.vue.d.ts +3 -0
  95. package/dist/runtime/components/Canvas/tools/tooltips/Undo.d.vue.ts +3 -0
  96. package/dist/runtime/components/Canvas/tools/tooltips/Undo.vue +13 -0
  97. package/dist/runtime/components/Canvas/tools/tooltips/Undo.vue.d.ts +3 -0
  98. package/dist/runtime/components/Canvas/tools/transformHandles.d.ts +74 -0
  99. package/dist/runtime/components/Canvas/tools/transformHandles.js +191 -0
  100. package/dist/runtime/components/Canvas/tools/transformTool.d.ts +7 -0
  101. package/dist/runtime/components/Canvas/tools/transformTool.js +210 -0
  102. package/dist/runtime/components/Canvas/tools/undoTool.d.ts +1 -0
  103. package/dist/runtime/components/Canvas/tools/undoTool.js +17 -0
  104. package/dist/runtime/components/Canvas/types.d.ts +125 -0
  105. package/dist/runtime/components/Canvas/types.js +3 -0
  106. package/dist/runtime/components/CheckBox.vue +6 -3
  107. package/dist/runtime/components/CheckboxGroup.vue +2 -1
  108. package/dist/runtime/components/ControlElement.d.vue.ts +5 -0
  109. package/dist/runtime/components/ControlElement.vue +19 -3
  110. package/dist/runtime/components/ControlElement.vue.d.ts +5 -0
  111. package/dist/runtime/components/DateRangePicker.vue +16 -4
  112. package/dist/runtime/components/Icon.vue +2 -2
  113. package/dist/runtime/components/Input.vue +2 -1
  114. package/dist/runtime/components/ListItem.d.vue.ts +29 -0
  115. package/dist/runtime/components/ListItem.vue +72 -0
  116. package/dist/runtime/components/ListItem.vue.d.ts +29 -0
  117. package/dist/runtime/components/LocaleSwitcher.d.vue.ts +13 -0
  118. package/dist/runtime/components/LocaleSwitcher.vue +43 -0
  119. package/dist/runtime/components/LocaleSwitcher.vue.d.ts +13 -0
  120. package/dist/runtime/components/NavButton.vue +2 -1
  121. package/dist/runtime/components/NumberInput/Horizontal.vue +2 -1
  122. package/dist/runtime/components/NumberInput/Vertical.vue +2 -1
  123. package/dist/runtime/components/NumberInput/index.vue +2 -1
  124. package/dist/runtime/components/RadioButton.vue +2 -1
  125. package/dist/runtime/components/Selector.vue +24 -22
  126. package/dist/runtime/components/SwitchButton.vue +2 -1
  127. package/dist/runtime/components/Tag.d.vue.ts +3 -2
  128. package/dist/runtime/components/Tag.vue +1 -0
  129. package/dist/runtime/components/Tag.vue.d.ts +3 -2
  130. package/dist/runtime/components/TaggableSelector.d.vue.ts +16 -0
  131. package/dist/runtime/components/TaggableSelector.vue +35 -0
  132. package/dist/runtime/components/TaggableSelector.vue.d.ts +16 -0
  133. package/dist/runtime/components/Textarea.vue +2 -1
  134. package/dist/runtime/components/Tooltip.vue +17 -7
  135. package/dist/runtime/components/ZoomableContainer.d.vue.ts +48 -0
  136. package/dist/runtime/components/ZoomableContainer.vue +238 -0
  137. package/dist/runtime/components/ZoomableContainer.vue.d.ts +48 -0
  138. package/dist/runtime/components/gallery/Carousel.vue +1 -1
  139. package/dist/runtime/components/gallery/CarouselPreview.d.vue.ts +31 -0
  140. package/dist/runtime/components/gallery/CarouselPreview.vue +64 -0
  141. package/dist/runtime/components/gallery/CarouselPreview.vue.d.ts +31 -0
  142. package/dist/runtime/components/view/Dates.vue +5 -3
  143. package/dist/runtime/components/view/KeyBinds.d.vue.ts +7 -0
  144. package/dist/runtime/components/view/KeyBinds.vue +36 -0
  145. package/dist/runtime/components/view/KeyBinds.vue.d.ts +7 -0
  146. package/dist/runtime/components/view/Text.vue +4 -4
  147. package/dist/runtime/composables/useInertia.d.ts +10 -0
  148. package/dist/runtime/composables/useInertia.js +49 -0
  149. package/dist/runtime/composables/usePinchZoom.d.ts +13 -0
  150. package/dist/runtime/composables/usePinchZoom.js +66 -0
  151. package/dist/runtime/composables/useValidation.js +11 -1
  152. package/dist/runtime/i18n/en.json +20 -0
  153. package/dist/runtime/i18n/index.d.ts +11 -0
  154. package/dist/runtime/i18n/index.js +19 -0
  155. package/dist/runtime/i18n/uk.json +20 -0
  156. package/dist/runtime/index.d.ts +8 -1
  157. package/dist/runtime/index.js +19 -1
  158. package/dist/runtime/plugins/i18n.d.ts +2 -0
  159. package/dist/runtime/plugins/i18n.js +18 -0
  160. package/dist/runtime/utils/icon-registry.js +13 -1
  161. 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>;
@@ -0,0 +1,3 @@
1
+ export function defineCanvasTool(tool) {
2
+ return tool;
3
+ }
@@ -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="[appearance, layout, `size-${size}`, { 'has-error': error, group }]"
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 && 'Start date must be before end date.'"
29
+ :error="!dateIsCorrect ? t('dateRangePicker.startBeforeEnd') : null"
28
30
  >
29
31
  <div class="date-range-picker">
30
- <orio-date-picker v-model:date="dates.startDate" :month />
31
- <orio-date-picker v-model:date="dates.endDate" :month />
32
- <orio-check-box v-model="present"> Present </orio-check-box>
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="orio-icon"
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
- .orio-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)}.orio-icon :deep(svg){fill:currentColor;height:100%;width:100%}
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>