@onesy/ui-react
Version:
UI for React
1,406 lines (1,349 loc) • 51.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _utils = require("@onesy/utils");
var _styleReact = require("@onesy/style-react");
var _date = require("@onesy/date");
var _Line = _interopRequireDefault(require("../Line"));
var _utils2 = require("../utils");
var _jsxRuntime = require("react/jsx-runtime");
const _excluded = ["ref", "valueDefault", "onChange", "minZoom", "maxZoom", "grid", "settings", "className"];
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
const useStyle = (0, _styleReact.style)(theme => ({
root: {
position: 'relative'
},
canvas: {
position: 'absolute',
inset: 0,
width: '100%',
height: '100%',
imageRendering: 'pixelated',
background: '#fff',
appearance: 'none',
border: 'none',
userSelect: 'none',
transition: theme.methods.transitions.make('opacity'),
'&[disabled]': {
opacity: 0.7,
pointerEvents: 'none'
}
},
ui: {
zIndex: 0
},
object: {
cursor: 'crosshair'
},
pen: {
cursor: 'crosshair'
},
pan: {
cursor: 'grab'
},
panning: {
cursor: 'grabbing'
},
zoom: {
cursor: 'zoom-in'
},
eraser: {
cursor: 'not-allowed'
},
image: {
cursor: 'copy'
},
text: {
cursor: 'text'
}
}), {
name: 'onesy-Whiteboard'
});
const colorSelect = 'hsl(244deg 64% 64%)';
const colorSelectBackground = 'hsla(244deg 64% 64% / 4%)';
const Whiteboard = props_ => {
var _theme$ui, _theme$ui2, _theme$elements;
const theme = (0, _styleReact.useOnesyTheme)();
const props = _objectSpread(_objectSpread(_objectSpread({}, theme === null || theme === void 0 || (_theme$ui = theme.ui) === null || _theme$ui === void 0 || (_theme$ui = _theme$ui.elements) === null || _theme$ui === void 0 || (_theme$ui = _theme$ui.all) === null || _theme$ui === void 0 || (_theme$ui = _theme$ui.props) === null || _theme$ui === void 0 ? void 0 : _theme$ui.default), theme === null || theme === void 0 || (_theme$ui2 = theme.ui) === null || _theme$ui2 === void 0 || (_theme$ui2 = _theme$ui2.elements) === null || _theme$ui2 === void 0 || (_theme$ui2 = _theme$ui2.onesyWhiteboard) === null || _theme$ui2 === void 0 || (_theme$ui2 = _theme$ui2.props) === null || _theme$ui2 === void 0 ? void 0 : _theme$ui2.default), props_);
const Line = (theme === null || theme === void 0 || (_theme$elements = theme.elements) === null || _theme$elements === void 0 ? void 0 : _theme$elements.Line) || _Line.default;
const {
ref,
valueDefault,
onChange: onChangeProps,
// 10%
minZoom = 10,
// 400%
maxZoom = 4000,
grid: gridProps = true,
settings = {
lineCap: 'round',
lineJoin: 'round',
lineWidth: 10,
fillStyle: 'lightgreen',
strokeStyle: 'lightgreen',
globalAlpha: 0.44
},
className
} = props,
other = (0, _objectWithoutProperties2.default)(props, _excluded);
const {
classes
} = useStyle();
const [size, setSize] = _react.default.useState({});
const [tool, setTool] = _react.default.useState('select');
const [mouseDown, setMouseDown] = _react.default.useState(false);
const [grid, setGrid] = _react.default.useState(gridProps);
const [loaded, setLoaded] = _react.default.useState(false);
const refs = {
root: _react.default.useRef(null),
ui: _react.default.useRef(null),
interactive: _react.default.useRef(null),
on: _react.default.useRef(false),
items: _react.default.useRef(valueDefault || []),
previous: _react.default.useRef({
x: 0,
y: 0
}),
previousMouse: _react.default.useRef({
x: 0,
y: 0
}),
moveStarted: _react.default.useRef(false),
undo: _react.default.useRef([]),
redo: _react.default.useRef([]),
move: _react.default.useRef({
x: 0,
y: 0
}),
offset: _react.default.useRef({
x: 0,
y: 0
}),
start: _react.default.useRef({
x: 0,
y: 0
}),
end: _react.default.useRef({
x: 0,
y: 0
}),
scale: _react.default.useRef(1),
mouseDown: _react.default.useRef(mouseDown),
mouseMove: _react.default.useRef({
current: {
x: 0,
y: 0
},
previous: undefined,
delta: {
x: 0,
y: 0
}
}),
tool: _react.default.useRef(tool),
previousTool: _react.default.useRef(tool),
toolUpdateAuto: _react.default.useRef(false),
remove: _react.default.useRef([]),
grid: _react.default.useRef(grid),
typing: _react.default.useRef(false),
image: _react.default.useRef((0, _utils.isEnvironment)('browser') && new Image()),
aspectRatio: _react.default.useRef(1),
select: _react.default.useRef(null),
textActive: _react.default.useRef(null),
textSettings: _react.default.useRef({
lineHeight: 20,
padding: 5,
fillStyle: 'black'
})
};
refs.mouseDown.current = mouseDown;
refs.tool.current = tool;
refs.grid.current = grid;
const init = () => {
// Todo
// items
// load all of the images in memory and attach theme to items as image elements
// once it's all done, setLoaded(true), render
setTimeout(() => {
render();
setLoaded(true);
}, 40);
};
_react.default.useEffect(() => {
if (!['zoom'].includes(tool)) refs.previousTool.current = tool;
}, [tool]);
const onChange = () => {
if ((0, _utils.is)('function', onChangeProps)) onChangeProps(refs.items.current);
};
const getItems = (selected = undefined) => refs.items.current.filter(item => selected === undefined || item.se === selected);
const getItem = () => refs.items.current[refs.items.current.length - 1];
const filterItems = () => {
const toRemove = refs.items.current.filter(item_0 => {
var _item_0$s;
if (refs.tool.current === 'text' && item_0 !== refs.textActive.current) item_0.se = false;
const lines = ((_item_0$s = item_0.s) === null || _item_0$s === void 0 ? void 0 : _item_0$s.lines) || [];
return !(item_0.v !== 't' || item_0 === refs.textActive.current || lines.length > 1 || lines[0].length);
});
if (toRemove.length) remove(toRemove);
};
const add = toAdd => {
const itemsAdd = (Array.isArray(toAdd) ? toAdd : [toAdd]).filter(Boolean);
const items = getItems();
// add to undo stack snapshot of current state
refs.undo.current.push([...items]);
// clear redo stack
refs.redo.current = [];
refs.items.current.push(...itemsAdd);
};
const remove = toRemove_0 => {
const itemsRemove = (Array.isArray(toRemove_0) ? toRemove_0 : [toRemove_0]).filter(Boolean);
const items_0 = getItems();
const IDs = itemsRemove === null || itemsRemove === void 0 ? void 0 : itemsRemove.map(item_1 => item_1.i);
const toRemoveIDs = items_0.filter(item_2 => IDs.includes(item_2.i)).map(item_3 => item_3.i);
if (!toRemoveIDs) return;
// add to undo stack snapshot of current state
refs.undo.current.push([...items_0]);
// clear redo stack
refs.redo.current = [];
refs.items.current = refs.items.current.filter(item_4 => !toRemoveIDs.includes(item_4.i));
};
const reset = () => {
refs.on.current = false;
refs.moveStarted.current = false;
refs.image.current = null;
// new move start
refs.offset.current.x = refs.move.current.x;
refs.offset.current.y = refs.move.current.y;
};
const transform = coordinate => coordinate / refs.scale.current;
const selectAll = () => {
return [...refs.items.current].filter(Boolean).map(item_5 => {
item_5.se = true;
return item_5;
});
};
const unselectAll = eventReact => {
const event = (eventReact === null || eventReact === void 0 ? void 0 : eventReact.nativeEvent) || eventReact;
const shift = event === null || event === void 0 ? void 0 : event.shiftKey;
return [...refs.items.current].filter(Boolean).map(item_6 => {
if (shift) return item_6;
item_6.se = false;
return item_6;
});
};
const onInteractionDown = (body, eventReact_0) => {
const event_0 = (eventReact_0 === null || eventReact_0 === void 0 ? void 0 : eventReact_0.nativeEvent) || eventReact_0;
const {
offsetX: x,
offsetY: y,
clientX,
clientY
} = body;
refs.on.current = true;
refs.previous.current = {
x,
y
};
refs.mouseMove.current = {
current: {
x: 0,
y: 0
},
previous: undefined,
delta: {
x: 0,
y: 0
}
};
const shift_0 = event_0 === null || event_0 === void 0 ? void 0 : event_0.shiftKey;
const ui = refs.ui.current.getContext('2d');
const rect = refs.ui.current.getBoundingClientRect();
refs.start.current.x = clientX - rect.left;
refs.start.current.y = clientY - rect.top;
refs.textActive.current = null;
const start = refs.start.current;
const startTransformed = {
x: transform(start.x - refs.move.current.x),
y: transform(start.y - refs.move.current.y)
};
Object.keys(settings).forEach(item_ => ui[item_] = settings[item_]);
let item_7;
const items_1 = getItems();
const t = refs.tool.current;
refs.select.current = null;
if (t === 'select') {
// z-index top to bottom order
const itemsReversed = [...items_1].reverse();
const itemsClicked = itemsReversed.filter(item__0 => {
return item__0.c && startTransformed.x >= item__0.c[0] && startTransformed.x <= item__0.c[0] + item__0.c[2] && startTransformed.y >= item__0.c[1] && startTransformed.y <= item__0.c[1] + item__0.c[3];
});
const itemsSelected = getItems(true);
const clicked = itemsClicked[0];
if (!clicked) {
unselectAll();
refs.select.current = {
p: [],
ar: []
};
}
if (!shift_0 && !(clicked !== null && clicked !== void 0 && clicked.se && itemsSelected.length > 1)) unselectAll();
if (clicked) {
clicked.se = shift_0 ? !clicked.se : true;
}
} else if (t === 'text') {
const {
lineHeight,
padding
} = refs.textSettings.current;
const selectedText = items_1.find(item__1 => item__1.c && startTransformed.x >= item__1.c[0] && startTransformed.x <= item__1.c[0] + item__1.c[2] && startTransformed.y >= item__1.c[1] && startTransformed.y <= item__1.c[1] + item__1.c[3]);
if (selectedText) {
var _selectedText$s;
refs.textActive.current = selectedText;
selectedText.se = true;
const relativeY = startTransformed.y - selectedText.c[1] - padding;
const lineIndex = Math.floor(relativeY / lineHeight);
const clickedLine = ((_selectedText$s = selectedText.s) === null || _selectedText$s === void 0 || (_selectedText$s = _selectedText$s.lines) === null || _selectedText$s === void 0 ? void 0 : _selectedText$s[lineIndex]) || '';
const relativeX = startTransformed.x - selectedText.c[0] - padding;
let charIndex = clickedLine.length;
for (let i = 0; i < clickedLine.length; i++) {
if (relativeX < ui.measureText(clickedLine.slice(0, i + 1)).width) {
charIndex = i;
break;
}
}
selectedText.s.cursor = {
line: lineIndex,
char: charIndex
};
} else {
item_7 = {
i: (0, _utils.getID)(),
v: 't',
p: [startTransformed.x, startTransformed.y],
ar: [15, lineHeight + padding * 2],
s: _objectSpread(_objectSpread({}, refs.textSettings.current), {}, {
lines: [''],
cursor: {
line: 0,
char: 0
}
}),
se: true,
a: _date.OnesyDate.milliseconds
};
refs.textActive.current = item_7;
}
} else {
// pen
if (t === 'pen') {
// point
item_7 = {
i: (0, _utils.getID)(),
v: 'dp',
p: [transform(x - refs.move.current.x), transform(y - refs.move.current.y)],
ar: [ui.lineWidth / 2, 0, Math.PI * 2],
s: (0, _utils.copy)(settings),
a: _date.OnesyDate.milliseconds
};
}
// circle, rectangle, line, line-arrow
if (['circle', 'rectangle', 'triangle', 'line', 'line-arrow'].includes(t)) {
item_7 = {
i: (0, _utils.getID)(),
p: [],
ar: [],
s: (0, _utils.copy)(settings),
a: _date.OnesyDate.milliseconds
};
}
// pan
if (t === 'pan') {
// new move start
refs.offset.current.x = refs.move.current.x;
refs.offset.current.y = refs.move.current.y;
}
// image
else if (t === 'image' && refs.image.current.complete && refs.image.current.src) {
refs.aspectRatio.current = refs.image.current.width / refs.image.current.height;
// Todo
// add url of the image
// instead of embeding the image
item_7 = {
i: (0, _utils.getID)(),
v: 'i',
p: [],
ar: [],
s: {
// Todo
// remove in the future
image: refs.image.current,
aspectRatio: refs.aspectRatio.current
},
a: _date.OnesyDate.milliseconds
};
}
}
if (item_7) add(item_7);
filterItems();
// render
render();
setMouseDown(true);
};
const onMouseDown = event_1 => {
const {
offsetX,
offsetY,
clientX: clientX_0,
clientY: clientY_0
} = event_1.nativeEvent;
onInteractionDown({
offsetX,
offsetY,
clientX: clientX_0,
clientY: clientY_0
}, event_1);
};
const onTouchStart = event_2 => {
// Get the first touch point
const touch = event_2.touches[0];
const {
clientX: clientX_1,
clientY: clientY_1
} = touch;
let {
offsetX: offsetX_0,
offsetY: offsetY_0
} = touch;
const targetElement = touch.target;
if (targetElement instanceof HTMLElement) {
// Get the bounding rectangle of the target element
const rect_0 = targetElement.getBoundingClientRect();
// Calculate the offsetX and offsetY
offsetX_0 = touch.clientX - rect_0.left;
offsetY_0 = touch.clientY - rect_0.top;
}
onInteractionDown({
offsetX: offsetX_0,
offsetY: offsetY_0,
clientX: clientX_1,
clientY: clientY_1
}, event_2);
};
const removeItems = () => {
// remove
if (refs.remove.current.length) {
const toRemove_1 = [];
for (const item_8 of refs.remove.current) {
const index = refs.items.current.findIndex(itemItems => itemItems === item_8);
if (index > -1) toRemove_1.push(item_8);
}
if (toRemove_1.length) remove(toRemove_1);
refs.remove.current = [];
}
};
const onUpdateCoordinates = () => {
const items_2 = getItems();
items_2.forEach(item_9 => {
const p = (item_9 === null || item_9 === void 0 ? void 0 : item_9.p) || [];
const ar = (item_9 === null || item_9 === void 0 ? void 0 : item_9.ar) || [];
const s = (item_9 === null || item_9 === void 0 ? void 0 : item_9.s) || {};
if (p.length) {
// cache
// x1, y1, width. height for position on the screen
const v = item_9.v;
// draw point
if (v === 'dp') {
const lineWidth = s.lineWidth || 10;
item_9.c = [p[0] - lineWidth / 2, p[1] - lineWidth / 2, lineWidth, lineWidth];
}
// draw line
else if (v === 'dl') {
const x_0 = [];
const y_0 = [];
for (let i_0 = 0; i_0 < p.length; i_0 += 2) {
x_0.push(p[i_0]);
y_0.push(p[i_0 + 1]);
}
const xMin = Math.min(...x_0);
const yMin = Math.min(...y_0);
const xMax = Math.max(...x_0);
const yMax = Math.max(...y_0);
item_9.c = [xMin, yMin, xMax - xMin, yMax - yMin];
}
// object line, object arrow
else if (['ol', 'oa'].includes(v)) {
const x_1 = [p[0], ar[0]];
const y_1 = [p[1], ar[1]];
const xMin_0 = Math.min(...x_1);
const yMin_0 = Math.min(...y_1);
const xMax_0 = Math.max(...x_1);
const yMax_0 = Math.max(...y_1);
item_9.c = [xMin_0, yMin_0, xMax_0 - xMin_0, yMax_0 - yMin_0];
}
// object rectangle, object square
else if (['or', 'os'].includes(v)) {
item_9.c = [...p, ...ar];
}
// object circle, object ellipse
else if (['oc', 'oe'].includes(v)) {
if (v === 'oc') {
item_9.c = [p[0] - ar[0], p[1] - ar[0], ar[0] * 2, ar[0] * 2];
} else {
item_9.c = [p[0] - ar[0], p[1] - ar[1], ar[0] * 2, ar[1] * 2];
}
}
// object triangle, object triangle equilateral
else if (['ot', 'ote'].includes(v)) {
const [x1, y1, x2] = p;
const {
height
} = s;
item_9.c = [x1, y1 - height, x2 - x1, height];
}
// image
else if (['i', 't'].includes(v)) {
item_9.c = [...p, ...ar];
}
}
});
};
const onSelect = () => {
const select = refs.select.current;
if (!select) return;
const px1 = select.p[0];
const px2 = px1 + select.ar[0];
const py1 = select.p[1];
const py2 = py1 + select.ar[1];
const min = {
x: Math.min(px1, px2),
y: Math.min(py1, py2)
};
const max = {
x: Math.max(px1, px2),
y: Math.max(py1, py2)
};
const items_3 = getItems();
items_3.forEach(item_10 => {
const {
c
} = item_10;
const [x1_0, y1_0] = c;
let [x2_0, y2] = c;
x2_0 = x1_0 + x2_0;
y2 = y1_0 + y2;
const minItem = {
x: Math.min(x1_0, x2_0),
y: Math.min(y1_0, y2)
};
const maxItem = {
x: Math.max(x1_0, x2_0),
y: Math.max(y1_0, y2)
};
const selected_0 = minItem.x >= min.x && maxItem.x <= max.x && minItem.y >= min.y && maxItem.y <= max.y;
if (selected_0) item_10.se = true;
});
};
const onMouseUp = event_3 => {
if (refs.mouseDown.current) {
refs.select.current = null;
// update coordinates
onUpdateCoordinates();
// reset
reset();
// remove
removeItems();
console.log('items', refs.items.current);
// onChange
onChange();
setMouseDown(false);
if (['circle', 'rectangle', 'triangle', 'line', 'line-arrow', 'image'].includes(refs.previousTool.current)) {
setTool('select');
}
render();
}
};
const updateTextBoxDimensions = item_11 => {
const ui_0 = refs.ui.current.getContext('2d');
const {
lineHeight: lineHeight_0,
padding: padding_0
} = refs.textSettings.current;
ui_0.font = '16px Arial';
const maxWidth = Math.max(...item_11.s.lines.map(line => ui_0.measureText(line).width));
item_11.ar[0] = maxWidth + padding_0 * 2.5;
item_11.ar[1] = item_11.s.lines.length * lineHeight_0 + padding_0 * 2;
};
const getPath = item_12 => {
const path = new Path2D();
const {
v: v_0,
p: p_0,
ar: ar_0
} = item_12;
// draw line
if (v_0 === 'dl') {
const points = (0, _utils.arrayToParts)(p_0, 2);
for (let i_1 = 0; i_1 < points.length - 1; i_1++) {
const current = points[i_1];
const next = points[i_1 + 1];
// calculate the control point for the curve
const midX = (current[0] + next[0]) / 2;
const midY = (current[1] + next[1]) / 2;
if (i_1 === 0) {
// start from the first point
path.moveTo(current[0], current[1]);
}
path.quadraticCurveTo(current[0], current[1], midX, midY);
}
}
// draw point, object circle
else if (['dp', 'oc'].includes(v_0) && ar_0.length === 3) {
path.arc(p_0[0], p_0[1], ...ar_0);
}
// object ellipse
else if (v_0 === 'oe' && ar_0.length === 5) {
path.ellipse(p_0[0], p_0[1], ...ar_0);
}
// object rectangle
else if (['or', 'os'].includes(v_0)) {
path.roundRect(p_0[0], p_0[1], ...ar_0);
}
// object line
else if (['ol', 'oa'].includes(v_0) && ar_0.length === 2) {
path.moveTo(p_0[0], p_0[1]);
path.lineTo(...ar_0);
// draw an arrow
if (v_0 === 'oa') {
// Length of the arrowhead
const headLength = 40;
const angle = Math.atan2(ar_0[1] - p_0[1], ar_0[0] - p_0[0]);
path.moveTo(ar_0[0], ar_0[1]);
path.lineTo(ar_0[0] - headLength * Math.cos(angle - Math.PI / 6), ar_0[1] - headLength * Math.sin(angle - Math.PI / 6));
path.moveTo(ar_0[0], ar_0[1]);
path.lineTo(ar_0[0] - headLength * Math.cos(angle + Math.PI / 6), ar_0[1] - headLength * Math.sin(angle + Math.PI / 6));
}
}
// object triangle
else if (['ot', 'ote'].includes(v_0)) {
path.moveTo(p_0[0], p_0[1]);
path.lineTo(p_0[2], p_0[3]);
path.lineTo(p_0[4], p_0[5]);
path.closePath();
}
return path;
};
const draw = item_13 => {
var _item_13$s2, _item_13$s3;
const ui_1 = refs.ui.current.getContext('2d');
// settings
Object.keys(item_13.s || {}).forEach(key => {
var _item_13$s;
return ui_1[key] = (_item_13$s = item_13.s) === null || _item_13$s === void 0 ? void 0 : _item_13$s[key];
});
ui_1.globalAlpha = refs.remove.current.includes(item_13) ? 0.25 : ((_item_13$s2 = item_13.s) === null || _item_13$s2 === void 0 ? void 0 : _item_13$s2.globalAlpha) !== undefined ? (_item_13$s3 = item_13.s) === null || _item_13$s3 === void 0 ? void 0 : _item_13$s3.globalAlpha : 1;
ui_1.beginPath();
const path_0 = getPath(item_13);
const v_1 = item_13.v;
if (['dp'].includes(v_1)) ui_1.fill(path_0);else if (['dl', 'oc', 'oe', 'or', 'os', 'ol', 'oa', 'ot', 'ote'].includes(v_1)) ui_1.stroke(path_0);
};
const drawGrid = () => {
const uiCanvas = refs.ui.current;
const ui_2 = refs.ui.current.getContext('2d');
const zoom = refs.scale.current;
const gridSize = 70;
const offsetX_1 = refs.move.current.x / zoom;
const offsetY_1 = refs.move.current.y / zoom;
// Calculate start positions based on offsets
const startX = Math.floor(-offsetX_1 / gridSize) * gridSize;
const startY = Math.floor(-offsetY_1 / gridSize) * gridSize;
const width = uiCanvas.clientWidth * 1.5 / (zoom < 1 ? zoom : 1);
const height_0 = uiCanvas.clientHeight * 1.5 / (zoom < 1 ? zoom : 1);
if (gridSize < 30) return;
// Draw main grid lines
ui_2.globalAlpha = 1;
ui_2.lineWidth = (zoom < 0.5 ? 0.3 : zoom <= 1 ? 0.5 : 0.7) / zoom;
ui_2.strokeStyle = '#ccc';
// grid
for (let x_2 = startX; x_2 < width + Math.abs(startX); x_2 += gridSize) {
ui_2.beginPath();
ui_2.moveTo(x_2, startY);
ui_2.lineTo(x_2, height_0 + startY);
ui_2.stroke();
}
for (let y_2 = startY; y_2 < height_0 + Math.abs(startY); y_2 += gridSize) {
ui_2.beginPath();
ui_2.moveTo(startX, y_2);
ui_2.lineTo(width + startX, y_2);
ui_2.stroke();
}
// subgrid
if (gridSize * zoom > 100) {
// Draw subgrid lines if zoomed in
const subGridSize = gridSize / 5;
ui_2.lineWidth = (zoom <= 5 ? 0.6 : zoom <= 10 ? 0.8 : 1) / zoom;
ui_2.strokeStyle = '#ddd';
const dash = zoom < 1 ? 3 * zoom : 3 / zoom;
ui_2.setLineDash([dash, dash]);
for (let x_3 = startX; x_3 < width + Math.abs(startX); x_3 += subGridSize) {
// without overlap
if (!(x_3 % gridSize)) continue;
ui_2.beginPath();
ui_2.moveTo(x_3, startY);
ui_2.lineTo(x_3, height_0 + startY);
ui_2.stroke();
}
for (let y_3 = startY; y_3 < height_0 + Math.abs(startY); y_3 += subGridSize) {
// without overlap
if (!(y_3 % gridSize)) continue;
ui_2.beginPath();
ui_2.moveTo(startX, y_3);
ui_2.lineTo(width + startX, y_3);
ui_2.stroke();
}
ui_2.setLineDash([]); // Reset line dash
}
};
const drawImage = item_14 => {
const ui_3 = refs.ui.current.getContext('2d');
ui_3.globalAlpha = 1;
ui_3.drawImage(item_14.s.image || refs.image.current, ...item_14.p, ...item_14.ar);
};
const drawCursor = item_15 => {
if (!item_15 || !item_15.s.cursor) return;
const ui_4 = refs.ui.current.getContext('2d');
const {
line: line_0,
char
} = item_15.s.cursor;
const currentLine = item_15.s.lines[line_0] || '';
const textWidth = ui_4.measureText(currentLine.slice(0, char)).width;
const {
padding: padding_1,
lineHeight: lineHeight_1
} = refs.textSettings.current;
const cursorX = item_15.p[0] + padding_1 + textWidth;
const cursorY = item_15.p[1] + padding_1 + (line_0 + 1) * lineHeight_1;
ui_4.fillStyle = 'black';
ui_4.fillRect(cursorX, cursorY - lineHeight_1 + 3, 2, lineHeight_1 - 5);
};
const drawText = item_16 => {
const ui_5 = refs.ui.current.getContext('2d');
const zoom_0 = refs.scale.current;
const [x_4, y_4] = item_16.p;
const [width_0, height_1] = item_16.ar;
const {
lineHeight: lineHeight_2,
padding: padding_2,
fillStyle
} = refs.textSettings.current;
const selected_1 = refs.tool.current === 'text' && item_16.se;
// Draw the box
ui_5.globalAlpha = 1;
ui_5.fillStyle = 'transparent';
ui_5.fillRect(x_4, y_4, width_0, height_1);
ui_5.lineWidth = 1 / zoom_0;
ui_5.strokeStyle = selected_1 ? colorSelect : 'transparent';
ui_5.strokeRect(x_4, y_4, width_0, height_1);
// Draw the text
ui_5.fillStyle = fillStyle || 'black';
ui_5.font = '16px Arial';
item_16.s.lines.forEach((line_1, index_0) => {
ui_5.fillText(line_1, x_4 + padding_2, y_4 + padding_2 + (index_0 + 1) * lineHeight_2 - 5);
});
if (selected_1) drawCursor(item_16);
};
const drawSelect = item_17 => {
const ui_6 = refs.ui.current.getContext('2d');
const [x_5, y_5, width_1, height_2] = item_17.c || [];
const path_1 = new Path2D();
path_1.rect(x_5, y_5, width_1, height_2);
ui_6.globalAlpha = 1;
ui_6.strokeStyle = colorSelect;
ui_6.lineCap = 'square';
ui_6.lineJoin = 'bevel';
ui_6.lineWidth = 1 / refs.scale.current;
ui_6.stroke(path_1);
};
const drawSelection = () => {
const ui_7 = refs.ui.current.getContext('2d');
const zoom_1 = refs.scale.current;
// canvas selection
const select_0 = refs.select.current;
if (select_0) {
ui_7.globalAlpha = 1;
ui_7.globalCompositeOperation = 'source-over';
ui_7.lineWidth = 1 / zoom_1;
ui_7.lineCap = 'square';
ui_7.lineJoin = 'bevel';
ui_7.strokeStyle = colorSelect;
ui_7.fillStyle = colorSelectBackground;
const path_2 = getPath(select_0);
ui_7.fill(path_2);
ui_7.stroke(path_2);
}
};
const render = () => {
const ui_8 = refs.ui.current.getContext('2d');
const items_4 = refs.items.current.filter(Boolean);
// methods
ui_8.clearRect(0, 0, refs.ui.current.width, refs.ui.current.height);
ui_8.save();
// pan
ui_8.translate(refs.move.current.x, refs.move.current.y);
// zoom
ui_8.scale(refs.scale.current, refs.scale.current);
// grid
if (refs.grid.current) drawGrid();
// draw
items_4.forEach(item_18 => {
// image
if (item_18.v === 'i' && item_18.ar.length === 2) drawImage(item_18);
// text
else if (item_18.v === 't') drawText(item_18);
// other
else draw(item_18);
// select
if (item_18.se) drawSelect(item_18);
});
// canvas selection
drawSelection();
ui_8.restore();
};
// Snap angle to nearest multiple of 15 degrees
const snapToAngle = (dx, dy) => {
// Current angle in radians
const angle_0 = Math.atan2(dy, dx);
// Snap to nearest 15 degrees
const snappedAngle = Math.round(angle_0 / (Math.PI / 12)) * (Math.PI / 12);
// Length of the vector
const length = Math.sqrt(dx * dx + dy * dy);
return {
x: Math.cos(snappedAngle) * length,
y: Math.sin(snappedAngle) * length
};
};
const onMoveItems = (x_6, y_6) => {
const itemsSelected_0 = getItems(true);
itemsSelected_0.forEach(item_19 => {
const v_2 = item_19.v;
// draw line
if (v_2 === 'dl') {
item_19.p = item_19.p.map((value, index_1) => {
return index_1 % 2 ? value + y_6 : value + x_6;
});
}
// rectangle, draw point, object circle, ellipse, object line, object arrow, object triangle, image, text
if (['or', 'os', 'dp', 'oc', 'oe', 'ol', 'oa', 'ot', 'ote', 'i', 't'].includes(v_2)) {
item_19.p[0] += x_6;
item_19.p[1] += y_6;
}
// object line
if (['ol', 'oa'].includes(v_2)) {
item_19.ar[0] += x_6;
item_19.ar[1] += y_6;
}
// object triangle
if (['ot', 'ote'].includes(v_2)) {
item_19.p[2] += x_6;
item_19.p[4] += x_6;
item_19.p[3] += y_6;
item_19.p[5] += y_6;
}
});
onUpdateCoordinates();
};
const onMove = (body_0, event_4) => {
if (!refs.on.current) return;
const {
offsetX: x_7,
offsetY: y_7,
clientX: clientX_2,
clientY: clientY_2
} = body_0;
const xo = transform(x_7 - refs.move.current.x);
const yo = transform(y_7 - refs.move.current.y);
const ui_9 = refs.ui.current.getContext('2d');
const rect_1 = refs.ui.current.getBoundingClientRect();
const currentX = clientX_2 - rect_1.left;
const currentY = clientY_2 - rect_1.top;
const start_0 = refs.start.current;
const startTransformed_0 = {
x: transform(start_0.x - refs.move.current.x),
y: transform(start_0.y - refs.move.current.y)
};
const item_20 = getItem();
const items_5 = getItems();
const t_0 = refs.tool.current;
const shiftKey = event_4.shiftKey;
const zoom_2 = refs.scale.current;
refs.mouseMove.current.current = {
x: clientX_2 / zoom_2,
y: clientY_2 / zoom_2
};
refs.mouseMove.current.delta = {
x: refs.mouseMove.current.previous ? refs.mouseMove.current.current.x - refs.mouseMove.current.previous.x : 0,
y: refs.mouseMove.current.previous ? refs.mouseMove.current.current.y - refs.mouseMove.current.previous.y : 0
};
refs.mouseMove.current.previous = _objectSpread({}, refs.mouseMove.current.current);
const delta = refs.mouseMove.current.delta;
// select
if (t_0 === 'select') {
if (!refs.moveStarted.current) refs.moveStarted.current = true;
if (refs.select.current) {
unselectAll();
const width_2 = currentX - start_0.x;
const height_3 = currentY - start_0.y;
const isSquare = shiftKey;
const radius = 0;
if (isSquare) {
const side = Math.min(Math.abs(width_2), Math.abs(height_3));
refs.select.current.v = 'os';
refs.select.current.p = [startTransformed_0.x, startTransformed_0.y];
refs.select.current.ar = [transform(Math.sign(width_2) * side), transform(Math.sign(height_3) * side), radius];
} else {
refs.select.current.v = 'or';
refs.select.current.p = [startTransformed_0.x, startTransformed_0.y];
refs.select.current.ar = [transform(width_2), transform(height_3), radius];
}
} else onMoveItems(delta.x, delta.y);
}
// pen
else if (t_0 === 'pen' && item_20) {
// same path from draw point, to move
if (!refs.moveStarted.current) {
item_20.v = 'dl';
refs.moveStarted.current = true;
}
// Add the current point to the path
item_20.p.push(xo, yo);
}
// pan
else if (t_0 === 'pan') {
refs.move.current.x = x_7 - refs.previous.current.x + refs.offset.current.x;
refs.move.current.y = y_7 - refs.previous.current.y + refs.offset.current.y;
}
// eraser
else if (t_0 === 'eraser') {
// find all items that x, y collides with, with certain radius
for (const i_2 of items_5) {
const isPointInStroke = ui_9.isPointInStroke(getPath(i_2), xo, yo);
if (isPointInStroke) refs.remove.current.push(i_2);
}
}
// object line, object arrow
else if (['line', 'line-arrow'].includes(t_0)) {
const snapAt15Degrees = shiftKey;
let endX = currentX;
let endY = currentY;
if (snapAt15Degrees) {
const snapped = snapToAngle(currentX - start_0.x, currentY - start_0.y);
endX = start_0.x + snapped.x;
endY = start_0.y + snapped.y;
}
item_20.v = t_0 === 'line' ? 'ol' : 'oa';
item_20.p = [startTransformed_0.x, startTransformed_0.y];
item_20.ar = [transform(endX - refs.move.current.x), transform(endY - refs.move.current.y)];
}
// object circle
else if (t_0 === 'circle') {
const width_3 = currentX - start_0.x;
const height_4 = currentY - start_0.y;
const isCircle = shiftKey;
if (isCircle) {
const radius_0 = Math.min(Math.abs(width_3), Math.abs(height_4)) / 2;
const centerX = start_0.x + Math.sign(width_3) * radius_0;
const centerY = start_0.y + Math.sign(height_4) * radius_0;
item_20.v = 'oc';
item_20.p = [transform(centerX - refs.move.current.x), transform(centerY - refs.move.current.y)];
item_20.ar = [transform(radius_0), 0, Math.PI * 2];
} else {
item_20.v = 'oe';
item_20.p = [transform(start_0.x + width_3 / 2 - refs.move.current.x), transform(start_0.y + height_4 / 2 - refs.move.current.y)];
item_20.ar = [transform(Math.abs(width_3) / 2), transform(Math.abs(height_4) / 2), 0, 0, Math.PI * 2];
}
}
// object rectangle
else if (t_0 === 'rectangle') {
const width_4 = currentX - start_0.x;
const height_5 = currentY - start_0.y;
const isSquare_0 = shiftKey;
const radius_1 = 0;
if (isSquare_0) {
const side_0 = Math.min(Math.abs(width_4), Math.abs(height_5));
item_20.v = 'os';
item_20.p = [startTransformed_0.x, startTransformed_0.y];
item_20.ar = [transform(Math.sign(width_4) * side_0), transform(Math.sign(height_5) * side_0), radius_1];
} else {
item_20.v = 'or';
item_20.p = [startTransformed_0.x, startTransformed_0.y];
item_20.ar = [transform(width_4), transform(height_5), radius_1];
}
}
// object triangle
else if (['triangle'].includes(t_0)) {
const endX_0 = xo;
const endY_0 = yo;
const base = Math.abs(endX_0 - startTransformed_0.x);
const height_6 = shiftKey ? base * Math.sqrt(3) / 2 : Math.abs(endY_0 - startTransformed_0.y);
const points_0 = [startTransformed_0.x, startTransformed_0.y, endX_0, startTransformed_0.y, startTransformed_0.x + (endX_0 - startTransformed_0.x) / 2, startTransformed_0.y - height_6];
item_20.v = shiftKey ? 'ote' : 'ot';
item_20.p = points_0;
item_20.s = _objectSpread(_objectSpread({}, item_20.s), {}, {
height: height_6
});
}
// image
else if (t_0 === 'image' && refs.image.current.complete && refs.image.current.src) {
const width_5 = transform(currentX - start_0.x);
const height_7 = transform(currentY - start_0.y);
const keepAspectRatio = !shiftKey;
let currentWidth;
let currentHeight;
if (keepAspectRatio) {
if (Math.abs(width_5 / refs.aspectRatio.current) <= Math.abs(height_7)) {
currentWidth = width_5;
currentHeight = width_5 / refs.aspectRatio.current;
} else {
currentWidth = height_7 * refs.aspectRatio.current;
currentHeight = height_7;
}
} else {
currentWidth = width_5;
currentHeight = height_7;
}
if (keepAspectRatio) {
if (width_5 < 0 && currentWidth > 0 || width_5 > 0 && currentWidth < 0) currentWidth *= -1;
if (height_7 < 0 && currentHeight > 0 || height_7 > 0 && currentHeight < 0) currentHeight *= -1;
}
item_20.p = [startTransformed_0.x, startTransformed_0.y];
item_20.ar = [currentWidth, currentHeight];
}
// select box
onSelect();
// render
render();
};
const onMouseMove = event_5 => {
const {
offsetX: offsetX_2,
offsetY: offsetY_2,
clientX: clientX_3,
clientY: clientY_3
} = event_5;
onMove({
offsetX: offsetX_2,
offsetY: offsetY_2,
clientX: clientX_3,
clientY: clientY_3
}, event_5);
};
const onTouchMove = event_6 => {
// Get the first touch point
const touch_0 = event_6.touches[0];
const {
clientX: clientX_4,
clientY: clientY_4
} = touch_0;
let {
offsetX: offsetX_3,
offsetY: offsetY_3
} = touch_0;
const targetElement_0 = touch_0.target;
if (targetElement_0 instanceof HTMLElement) {
// Get the bounding rectangle of the target element
const rect_2 = targetElement_0.getBoundingClientRect();
// Calculate the offsetX and offsetY
offsetX_3 = touch_0.clientX - rect_2.left;
offsetY_3 = touch_0.clientY - rect_2.top;
}
onMove({
offsetX: offsetX_3,
offsetY: offsetY_3,
clientX: clientX_4,
clientY: clientY_4
}, event_6);
};
const undo = () => {
if (!refs.undo.current.length) return;
// add current state to redo
refs.redo.current.push([...getItems()]);
// restore the undo state
refs.items.current = refs.undo.current.pop();
// render
render();
};
const redo = () => {
if (!refs.redo.current.length) return;
// add current state to undo
refs.undo.current.push([...getItems()]);
// restore the redo state
refs.items.current = refs.redo.current.pop();
// render
render();
};
const onWheel = eventReact_1 => {
const event_7 = eventReact_1.nativeEvent;
// zoom
if (event_7.metaKey || event_7.ctrlKey) {
setTool('zoom');
refs.toolUpdateAuto.current = true;
const zoomFactor = 1.054;
const mouseX = event_7.offsetX;
const mouseY = event_7.offsetY;
const scale = refs.scale.current;
// Convert mouse position to canvas coordinates
const canvasX = (mouseX - refs.move.current.x) / scale;
const canvasY = (mouseY - refs.move.current.y) / scale;
// Adjust scale
const zoomIn = event_7.deltaY < 0;
const newScale = zoomIn ? scale * zoomFactor : scale / zoomFactor;
if (newScale <= maxZoom / 100 && newScale >= minZoom / 100) {
// Update origin to focus on mouse position
refs.move.current.x -= canvasX * (newScale - scale);
refs.move.current.y -= canvasY * (newScale - scale);
refs.scale.current = newScale;
render();
}
}
// pan
else if (!refs.mouseDown.current) {
refs.move.current.x -= event_7.deltaX;
refs.move.current.y -= event_7.deltaY;
render();
}
};
const onPaste = event_8 => {
event_8.preventDefault();
// Get clipboard data
const items_6 = Array.from(event_8.clipboardData.items);
// Loop through clipboard items to find an image
for (const item_21 of items_6) {
if (item_21.type.startsWith('image/')) {
// Get the image file
const blob = item_21.getAsFile();
refs.image.current = new Image();
// Load the image and draw it on the canvas
refs.image.current.onload = () => {
refs.aspectRatio.current = refs.image.current.width / refs.image.current.height;
// Todo
// 1) Upload the image first, than read it in image src
// 2) Add url of the image
// instead of embeding the image
const item__2 = {
i: (0, _utils.getID)(),
v: 'i',
p: [],
ar: [],
s: {
// Todo
// remove in the future
image: refs.image.current,
aspectRatio: refs.aspectRatio.current
},
a: _date.OnesyDate.milliseconds
};
add(item__2);
setTool('image');
};
// Create an object URL for the blob and set it as the image source
refs.image.current.src = URL.createObjectURL(blob);
break;
}
}
};
_react.default.useEffect(() => {
const method = () => {
const width_6 = refs.root.current.offsetWidth;
const height_8 = refs.root.current.offsetHeight;
setSize({
width: width_6,
height: height_8
});
};
const onKeyUp = event_9 => {
if (refs.toolUpdateAuto.current) setTool(refs.previousTool.current || 'pen');
};
const onKeyDown = async event_10 => {
refs.toolUpdateAuto.current = false;
const {
key: key_0
} = event_10;
const itemsAll = [...refs.items.current].filter(Boolean);
const t_1 = refs.tool.current;
const zoom_3 = refs.scale.current;
if (['a', 'A'].includes(key_0) && (event_10.metaKey || event_10.ctrlKey)) {
event_10.preventDefault();
selectAll();
render();
} else if (t_1 === 'select' && ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Backspace'].includes(key_0)) {
const value_0 = event_10.shiftKey ? 10 : 1;
if (key_0 === 'ArrowUp') onMoveItems(0, -value_0 / zoom_3);
if (key_0 === 'ArrowDown') onMoveItems(0, value_0 / zoom_3);
if (key_0 === 'ArrowLeft') onMoveItems(-value_0 / zoom_3, 0);
if (key_0 === 'ArrowRight') onMoveItems(value_0 / zoom_3, 0);
if (key_0 === 'Backspace') {
const toRemove_2 = [];
refs.items.current.forEach(item_22 => {
if (item_22.se) toRemove_2.push(item_22);
});
if (toRemove_2.length) remove(toRemove_2);
}
render();
} else if (key_0 === 'Escape') {
setTool('select');
refs.textActive.current = null;
unselectAll();
filterItems();
render();
} else if (tool === 'text') {
const selectedTextBox = itemsAll.find(item_23 => item_23.v === 't' && item_23.se);
if (!selectedTextBox) return;
const {
line: line_2,
char: char_0
} = selectedTextBox.s.cursor;
const lines_0 = selectedTextBox.s.lines;
const currentLine_0 = lines_0[line_2];
if (['ArrowLeft', 'ArrowRight'].includes(key_0)) {
var _lines_0$line_, _lines_0$selectedText2;
event_10.preventDefault();
selectedTextBox.s.cursor.char += key_0 === 'ArrowLeft' ? -1 : 1;
if (selectedTextBox.s.cursor.char < 0) {
var _lines_0$selectedText;
selectedTextBox.s.cursor.line--;
selectedTextBox.s.cursor.char = (_lines_0$selectedText = lines_0[selectedTextBox.s.cursor.line]) === null || _lines_0$selectedText === void 0 ? void 0 : _lines_0$selectedText.length;
} else if (selectedTextBox.s.cursor.char > ((_lines_0$line_ = lines_0[line_2]) === null || _lines_0$line_ === void 0 ? void 0 : _lines_0$line_.length) && line_2 !== lines_0.length - 1) {
selectedTextBox.s.cursor.line++;
selectedTextBox.s.cursor.char = 0;
}
selectedTextBox.s.cursor.line = (0, _utils.clamp)(selectedTextBox.s.cursor.line, 0, lines_0.length - 1);
selectedTextBox.s.cursor.char = (0, _utils.clamp)(selectedTextBox.s.cursor.char, 0, (_lines_0$selectedText2 = lines_0[selectedTextBox.s.cursor.line]) === null || _lines_0$selectedText2 === void 0 ? void 0 : _lines_0$selectedText2.length);
}
if (['ArrowUp', 'ArrowDown'].includes(key_0)) {
var _lines_0$selectedText3;
event_10.preventDefault();
selectedTextBox.s.cursor.line += key_0 === 'ArrowUp' ? -1 : 1;
selectedTextBox.s.cursor.line = (0, _utils.clamp)(selectedTextBox.s.cursor.line, 0, lines_0.length - 1);
selectedTextBox.s.cursor.char = (0, _utils.clamp)(selectedTextBox.s.cursor.char, 0, (_lines_0$selectedText3 = lines_0[selectedTextBox.s.cursor.line]) === null || _lines_0$selectedText3 === void 0 ? void 0 : _lines_0$selectedText3.length);
} else if (key_0 === 'Enter') {
event_10.preventDefault();
const newLine = currentLine_0.slice(char_0);
lines_0[line_2] = currentLine_0.slice(0, char_0);
lines_0.splice(line_2 + 1, 0, newLine);
selectedTextBox.s.cursor.line++;
selectedTextBox.s.cursor.char = 0;
} else if (key_0 === 'Backspace') {
event_10.preventDefault();
if (char_0 > 0) {
lines_0[line_2] = currentLine_0.slice(0, char_0 - 1) + currentLine_0.slice(char_0);
selectedTextBox.s.cursor.char--;
} else if (line_2 > 0) {
const prevLine = lines_0[line_2 - 1];
selectedTextBox.s.cursor.char = prevLine.length;
lines_0[line_2 - 1] += lines_0[line_2];
lines_0.splice(line_2, 1);
selectedTextBox.s.cursor.line--;
}
} else if (key_0.length === 1) {
if ([' '].includes(key_0)) event_10.preventDefault();
let textClipboard = '';
const isPaste = (event_10.ctrlKey || event_10.metaKey) && ['v', 'V'].includes(key_0);
if (isPaste) {
try {
textClipboard = await window.navigator.clipboard.readText();
} catch (error) {}
}
const text = isPaste ? textClipboard : key_0;
selectedTextBox.s.lines[line_2] = currentLine_0.slice(0, char_0) + text + currentLine_0.slice(char_0);
selectedTextBox.s.cursor.char += text.length;
}
updateTextBoxDimensions(selectedTextBox);
selectedTextBox.c = [...selectedTextBox.p, ...selectedTextBox.ar];
render();
} else {
if (event_10.metaKey && key_0 === 'z') {
if (event_10.shiftKey) redo();else undo();
}
if (key_0 === ' ') {
refs.toolUpdateAuto.current = true;
setTool('pan');
}
// tools
if (event_10.shiftKey) {
if (['E', 'D', 'P', 'S', 'C', 'R', 'I', 'L', 'A', 'T', 'G'].includes(key_0)) refs.toolUpdateAuto.current = false;
if (key_0 === 'E') setTool('eraser');
if (key_0 === 'D') setTool('pen');
if (key_0 === 'P') setTool('pan');
if (key_0 === 'S') setTool('select');
if (key_0 === 'C') setTool('circle');
if (key_0 === 'R') setTool('rectangle');
if (key_0 === 'I') setTool('triangle');
if (key_0 === 'L') setTool('line');
if (key_0 === 'A') setTool('line-arrow');
if (key_0 === 'T') setTool('text');
if (key_0 === 'G') {
setGrid(previous => !previous);
render();
}
}
}
};
window.addEventListener('resize', method);
window.document.addEventListener('mouseup', onMouseUp);
window.document.addEventListener('touchend', onMouseUp);
window.document.addEventListener('mousemove', onMouseMove);
window.document.addEventListener('touchmove', onTouchMove);
window.document.addEventListener('keyup', onKeyUp);
window.document.addEventListener('keydown', onKeyDown);
window.document.addEventListener('paste', onPaste);
method();
init();
return () => {
window.removeEventListener('resize', method);
window.document.removeEventListener('mouseup', onMouseUp);
window.document.removeEventListener('touchend', onMouseUp);
window.document.removeEventListener('mousemove', onMouseMove);
window.document.removeEventListener('touchmove', onTouchMove);
window.document.removeEventListener('keyup', onKeyUp);
window.document.removeEventListener('keydown', onKeyDown);
window.document.removeEventListener('paste', onPaste);
};
}, []);
const onChangeInputFile = event_11 => {
const file = event_11.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = eventReader => {
refs.image.current = new Image();
refs.image.current.src = eventReader.target.result;
refs.toolUpdateAuto.current = true;
event_11.target.value = '';
setTool('image');
};
reader.readAsDataURL(file);
}
};
const propsCanvas = {
width: size.width,
height: size.height,
disabled: !loaded,
style: {
width: size.width,
height: size.height
}
};
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(Line, _objectSpread(_objectSpread({
ref: item_24 => {
if (ref) {
if ((0, _utils.is)('function', ref)) ref(item_24);else ref.current = item_24;
}
refs.root.current = item_24;
},
flex