@excalidraw/math 0.18.0-4e758db → 0.18.0-4f68076
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev/index.js +8 -2
- package/dist/dev/index.js.map +2 -2
- package/dist/prod/index.js +1 -1
- package/dist/types/common/src/constants.d.ts +10 -0
- package/dist/types/common/src/utils.d.ts +5 -0
- package/dist/types/element/src/binding.d.ts +13 -7
- package/dist/types/element/src/collision.d.ts +14 -5
- package/dist/types/element/src/duplicate.d.ts +60 -0
- package/dist/types/element/src/index.d.ts +1 -0
- package/dist/types/element/src/listMarker.d.ts +34 -0
- package/dist/types/element/src/newElement.d.ts +15 -1
- package/dist/types/element/src/renderElement.d.ts +21 -4
- package/dist/types/element/src/shape.d.ts +15 -1
- package/dist/types/element/src/textElement.d.ts +7 -0
- package/dist/types/element/src/utils.d.ts +8 -1
- package/dist/types/element/src/zindex.d.ts +1 -1
- package/dist/types/excalidraw/actions/actionAddToLibrary.d.ts +30 -3
- package/dist/types/excalidraw/actions/actionBoundText.d.ts +20 -2
- package/dist/types/excalidraw/actions/actionCanvas.d.ts +70 -7
- package/dist/types/excalidraw/actions/actionClipboard.d.ts +20 -2
- package/dist/types/excalidraw/actions/actionCropEditor.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +30 -3
- package/dist/types/excalidraw/actions/actionDeselect.d.ts +13 -1
- package/dist/types/excalidraw/actions/actionElementLink.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionElementLock.d.ts +20 -2
- package/dist/types/excalidraw/actions/actionExport.d.ts +20 -2
- package/dist/types/excalidraw/actions/actionFrame.d.ts +30 -3
- package/dist/types/excalidraw/actions/actionGroup.d.ts +20 -2
- package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionLink.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionMenu.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionProperties.d.ts +20 -2
- package/dist/types/excalidraw/actions/actionSelectAll.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionStyles.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionToggleArrowBinding.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionToggleMidpointSnapping.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionToggleShowHints.d.ts +197 -0
- package/dist/types/excalidraw/actions/actionToggleStats.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +10 -1
- package/dist/types/excalidraw/actions/actionToggleZenMode.d.ts +10 -1
- package/dist/types/excalidraw/actions/index.d.ts +1 -0
- package/dist/types/excalidraw/actions/types.d.ts +1 -1
- package/dist/types/excalidraw/appState.d.ts +2 -0
- package/dist/types/excalidraw/components/App.arrowText.d.ts +5 -39
- package/dist/types/excalidraw/components/App.clipboard.d.ts +31 -0
- package/dist/types/excalidraw/components/App.d.ts +82 -262
- package/dist/types/excalidraw/components/App.duplicate.d.ts +101 -0
- package/dist/types/excalidraw/components/App.modifiers.d.ts +38 -0
- package/dist/types/excalidraw/components/App.pan.d.ts +62 -0
- package/dist/types/excalidraw/components/App.selectionTool.d.ts +57 -0
- package/dist/types/excalidraw/components/App.text.d.ts +146 -0
- package/dist/types/excalidraw/components/App.textTool.d.ts +140 -0
- package/dist/types/excalidraw/components/App.viewport.d.ts +41 -1
- package/dist/types/excalidraw/components/App.wheel.d.ts +3 -10
- package/dist/types/excalidraw/components/ColorPicker/Picker.d.ts +2 -0
- package/dist/types/excalidraw/components/ColorPicker/colorTopPicksDnD.d.ts +11 -0
- package/dist/types/excalidraw/components/FileDropOverlay.d.ts +2 -0
- package/dist/types/excalidraw/components/FontPicker/FontPicker.d.ts +4 -1
- package/dist/types/excalidraw/components/FontPicker/FontPickerList.d.ts +6 -1
- package/dist/types/excalidraw/components/FontPicker/fontTopPicksDnD.d.ts +12 -0
- package/dist/types/excalidraw/components/LibraryMenuSection.d.ts +6 -2
- package/dist/types/excalidraw/components/LibraryUnit.d.ts +7 -2
- package/dist/types/excalidraw/components/Tooltip.d.ts +15 -1
- package/dist/types/excalidraw/components/TopPicksDnD/TopPicksContextMenu.d.ts +14 -0
- package/dist/types/excalidraw/components/TopPicksDnD/TopPicksTip.d.ts +11 -0
- package/dist/types/excalidraw/components/TopPicksDnD/topPicksDnD.d.ts +58 -0
- package/dist/types/excalidraw/components/main-menu/DefaultItems.d.ts +1 -0
- package/dist/types/excalidraw/data/blob.d.ts +20 -2
- package/dist/types/excalidraw/data/json.d.ts +10 -1
- package/dist/types/excalidraw/renderOverrides.d.ts +9 -0
- package/dist/types/excalidraw/scene/Renderer.d.ts +14 -1
- package/dist/types/excalidraw/scene/types.d.ts +2 -1
- package/dist/types/excalidraw/types.d.ts +92 -19
- package/dist/types/excalidraw/viewport.d.ts +23 -1
- package/dist/types/excalidraw/wysiwyg/textWysiwyg.d.ts +12 -1
- package/package.json +2 -2
- package/dist/types/excalidraw/components/ColorPicker/topPicksDnD.d.ts +0 -31
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import type App from "./App";
|
|
3
|
+
/**
|
|
4
|
+
* The drag-pan: a pointer drag that moves the canvas — the wheel or the
|
|
5
|
+
* secondary button, the main button while space is held or the hand tool
|
|
6
|
+
* is active, or any button in view mode. One session at a time, owning its
|
|
7
|
+
* window listeners and teardown; wheel input is gated on it (see
|
|
8
|
+
* `AppWheel`).
|
|
9
|
+
*
|
|
10
|
+
* A secondary-button session is a pan only once the pointer travels past
|
|
11
|
+
* the drag threshold; released before that, it is a right-click. The
|
|
12
|
+
* platform's `contextmenu` event opens the menu for a right-click where it
|
|
13
|
+
* follows the release (Windows), as it always has; where it comes with the
|
|
14
|
+
* press (macOS, Linux) it is swallowed — a drag cannot be told from a
|
|
15
|
+
* click yet — and the session opens the menu on release instead.
|
|
16
|
+
*/
|
|
17
|
+
export declare class AppPan {
|
|
18
|
+
private app;
|
|
19
|
+
private dependencies;
|
|
20
|
+
/** space held down turns a main-button drag into a pan */
|
|
21
|
+
private spaceHeld;
|
|
22
|
+
private active;
|
|
23
|
+
/** the secondary-button session, while one is active */
|
|
24
|
+
private secondary;
|
|
25
|
+
/** the platform fires `contextmenu` on mouseup (Windows) or on mousedown
|
|
26
|
+
* (macOS, Linux); the one belonging to a secondary-button session is not a
|
|
27
|
+
* new click, whichever side of the session it lands on */
|
|
28
|
+
private suppressNextContextMenu;
|
|
29
|
+
/** applies the pointer move the session is holding back for its next
|
|
30
|
+
* frame, if any */
|
|
31
|
+
private pendingMoveFlush;
|
|
32
|
+
private teardown;
|
|
33
|
+
constructor(app: App, dependencies: {
|
|
34
|
+
/** pointers currently down (a two-finger gesture is not a pan) */
|
|
35
|
+
getPointerCount: () => number;
|
|
36
|
+
/** a scrollbar being dragged (App's own drag, not a pan session) */
|
|
37
|
+
isDraggingScrollBar: () => boolean;
|
|
38
|
+
});
|
|
39
|
+
isActive: () => boolean;
|
|
40
|
+
isSpaceHeld: () => boolean;
|
|
41
|
+
setSpaceHeld: (held: boolean) => void;
|
|
42
|
+
/**
|
|
43
|
+
* Whether the pointer is navigating the viewport rather than acting on the
|
|
44
|
+
* scene — space held to pan, a pan in progress, a scrollbar drag, or the
|
|
45
|
+
* hand tool. Hover and cursor then belong to the navigation.
|
|
46
|
+
*/
|
|
47
|
+
isNavigating: () => boolean;
|
|
48
|
+
/** applies the pointer move still waiting for its frame, if any */
|
|
49
|
+
flushMove: () => void;
|
|
50
|
+
/** ends the active session, if any — pointerup may never arrive (the user
|
|
51
|
+
* tabs away, a new pointerdown lands first) */
|
|
52
|
+
end: () => void;
|
|
53
|
+
/**
|
|
54
|
+
* Whether a `contextmenu` event belongs to a secondary-button session and
|
|
55
|
+
* must not open the menu: it came with the press (the session decides on
|
|
56
|
+
* release), or it follows a release that turned out to be a drag.
|
|
57
|
+
*/
|
|
58
|
+
consumesContextMenuEvent: () => boolean;
|
|
59
|
+
/** starts a session for the pointerdown if it qualifies; returns whether
|
|
60
|
+
* it did */
|
|
61
|
+
start: (event: React.PointerEvent<HTMLElement> | MouseEvent) => boolean;
|
|
62
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ExcalidrawElement, NonDeletedSceneElementsMap } from "@excalidraw/element/types";
|
|
2
|
+
import type React from "react";
|
|
3
|
+
import type { PointerDownState } from "../types";
|
|
4
|
+
import type App from "./App";
|
|
5
|
+
/**
|
|
6
|
+
* The selection tool's (and the lasso's) selection: what a pointer down
|
|
7
|
+
* selects, what a click (a pointer up without a drag) does to the selection —
|
|
8
|
+
* including alt-click cycling through the overlapping elements — and the
|
|
9
|
+
* selection's transform handles (resizing, rotating, cropping).
|
|
10
|
+
*/
|
|
11
|
+
export declare class AppSelectionTool {
|
|
12
|
+
private app;
|
|
13
|
+
constructor(app: App);
|
|
14
|
+
clearSelectionIfNotUsingSelection: () => void;
|
|
15
|
+
/**
|
|
16
|
+
* @returns whether the pointer event has been completely handled
|
|
17
|
+
*/
|
|
18
|
+
handleSelectionOnPointerDown: (event: React.PointerEvent<HTMLElement>, pointerDownState: PointerDownState) => boolean;
|
|
19
|
+
maybeHandleCrop: (pointerDownState: PointerDownState, event: MouseEvent | KeyboardEvent) => boolean;
|
|
20
|
+
maybeHandleResize: (pointerDownState: PointerDownState, event: MouseEvent | KeyboardEvent) => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Updates the selection on a click (no drag): the element below the
|
|
23
|
+
* selected one on an alt-click, the clicked element added to or removed
|
|
24
|
+
* from the selection with shift, or selected, and the selection cleared
|
|
25
|
+
* by a click hitting only a bounding box.
|
|
26
|
+
*
|
|
27
|
+
* @returns whether the pointer event has been completely handled
|
|
28
|
+
*/
|
|
29
|
+
handleSelectionOnPointerUp: (childEvent: PointerEvent, pointerDownState: PointerDownState, elementsMap: NonDeletedSceneElementsMap) => boolean;
|
|
30
|
+
clearSelection(hitElement: ExcalidrawElement | null): void;
|
|
31
|
+
isASelectedElement(hitElement: ExcalidrawElement | null): boolean;
|
|
32
|
+
isHittingCommonBoundingBoxOfSelectedElements(point: Readonly<{
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
}>, selectedElements: readonly ExcalidrawElement[]): boolean;
|
|
36
|
+
/** whether an alt-click on the selection (over other elements) cycles it */
|
|
37
|
+
canCycleSelection: () => boolean;
|
|
38
|
+
/**
|
|
39
|
+
* The selectable unit (an element, or the group a click would select) an
|
|
40
|
+
* element belongs to. Inside an edited group, its elements are units of
|
|
41
|
+
* their own.
|
|
42
|
+
*/
|
|
43
|
+
private getSelectableUnit;
|
|
44
|
+
/**
|
|
45
|
+
* The selected unit, if an alt-click can cycle away from it: exactly one
|
|
46
|
+
* is selected, and neither the linear nor the crop editor is open.
|
|
47
|
+
*/
|
|
48
|
+
private getCyclableSelectedUnit;
|
|
49
|
+
/**
|
|
50
|
+
* The element an alt-click selects: the selectable unit below the selected
|
|
51
|
+
* one among the hit elements, wrapping around to the topmost — or `null`
|
|
52
|
+
* unless it's an alt-click, the selection can cycle, and it's under the
|
|
53
|
+
* pointer. Inside an edited group, it cycles through the group's elements
|
|
54
|
+
* only, never leaving the group.
|
|
55
|
+
*/
|
|
56
|
+
private getSelectionCycleTarget;
|
|
57
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { type Bounds, type StylesPanelMode } from "@excalidraw/common";
|
|
2
|
+
import type { ArrowEndpoint } from "@excalidraw/element";
|
|
3
|
+
import type { ExcalidrawElement, ExcalidrawTextContainer, ExcalidrawTextElement, NonDeleted, NonDeletedExcalidrawElement } from "@excalidraw/element/types";
|
|
4
|
+
import { textWysiwyg } from "../wysiwyg/textWysiwyg";
|
|
5
|
+
import type App from "./App";
|
|
6
|
+
import type { AppState, Offsets, ViewportUIName } from "../types";
|
|
7
|
+
type AppTextDependencies = {
|
|
8
|
+
getContainer: () => HTMLDivElement | null;
|
|
9
|
+
getStylesPanelMode: () => StylesPanelMode;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Texts, but for the text tool's pointer interaction (`AppTextTool`):
|
|
13
|
+
*
|
|
14
|
+
* - the editing session: what text to edit, or create, and where
|
|
15
|
+
* (`startTextEditing`), and the editor's lifecycle (`handleTextWysiwyg`)
|
|
16
|
+
* - the part of the canvas a typed or pasted text is kept within
|
|
17
|
+
* (`getTextViewportOffsets`, `getMaxTextWidth`)
|
|
18
|
+
* - the queries that find the text or container to edit at a position
|
|
19
|
+
* - the handle that turns a fixed-width text back into a growing one
|
|
20
|
+
*
|
|
21
|
+
* Every way into editing ends up here: Enter, double-click, pointerup on a
|
|
22
|
+
* selected text or container, the text tool, a drag-created text or sticky
|
|
23
|
+
* note, and a sticky note dropped from the toolbar.
|
|
24
|
+
*/
|
|
25
|
+
export declare class AppText {
|
|
26
|
+
private app;
|
|
27
|
+
private dependencies;
|
|
28
|
+
constructor(app: App, dependencies: AppTextDependencies);
|
|
29
|
+
textWysiwygSubmitHandler: ReturnType<typeof textWysiwyg> | null;
|
|
30
|
+
private getTextCreationGridPoint;
|
|
31
|
+
/**
|
|
32
|
+
* The side panels, besides the sidebar, that a typed or pasted text is
|
|
33
|
+
* kept clear of: the stats panel, and the full styles panel (desktop),
|
|
34
|
+
* which shows next to a text while it's edited, and once it's pasted and
|
|
35
|
+
* selected.
|
|
36
|
+
*/
|
|
37
|
+
getTextSidePanels: () => ViewportUIName[];
|
|
38
|
+
/**
|
|
39
|
+
* The part of the canvas a typed or pasted text is kept within, as offsets
|
|
40
|
+
* from its edges (screen px): all of it but the sidebar and the side
|
|
41
|
+
* panels (see getTextSidePanels), less some room at each side. The stats
|
|
42
|
+
* panel covers the top of a side only, and counts only for a text beside
|
|
43
|
+
* it: one (given by its scene bounds) with rows within that room of it.
|
|
44
|
+
*/
|
|
45
|
+
getTextViewportOffsets: (textBounds?: Bounds) => Required<Offsets>;
|
|
46
|
+
/**
|
|
47
|
+
* The widest a text may grow to as it's typed or pasted, in scene units:
|
|
48
|
+
* TEXT_MAX_WRAP_WIDTH, or less, so that a text never outgrows the part of
|
|
49
|
+
* the canvas it's kept within.
|
|
50
|
+
*/
|
|
51
|
+
getMaxTextWidth: (offsets: Required<Offsets>) => number;
|
|
52
|
+
handleTextWysiwyg(element: NonDeleted<ExcalidrawTextElement>, { isExistingElement, initialCaretSceneCoords, initialSelection, }: {
|
|
53
|
+
isExistingElement?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* supply null if no caret positioning is desired, and instead
|
|
56
|
+
* text should be auto-selected
|
|
57
|
+
*/
|
|
58
|
+
initialCaretSceneCoords?: {
|
|
59
|
+
x: number;
|
|
60
|
+
y: number;
|
|
61
|
+
} | null;
|
|
62
|
+
/** range of the text to select (takes precedence over the caret) */
|
|
63
|
+
initialSelection?: {
|
|
64
|
+
start: number;
|
|
65
|
+
end: number;
|
|
66
|
+
} | null;
|
|
67
|
+
}): void;
|
|
68
|
+
private getSelectedTextElement;
|
|
69
|
+
getSelectedTextEditingContainerAtPosition(hitElement: NonDeletedExcalidrawElement | null, sceneCoords: {
|
|
70
|
+
x: number;
|
|
71
|
+
y: number;
|
|
72
|
+
}): ExcalidrawTextContainer | null | undefined;
|
|
73
|
+
getTextElementAtPosition(x: number, y: number): NonDeleted<ExcalidrawTextElement> | null;
|
|
74
|
+
isHittingTextAutoResizeHandle: (selectedElements: NonDeleted<ExcalidrawElement>[], point: Readonly<{
|
|
75
|
+
x: number;
|
|
76
|
+
y: number;
|
|
77
|
+
}>) => boolean;
|
|
78
|
+
handleTextAutoResizeHandlePointerDown: (selectedElements: NonDeleted<ExcalidrawElement>[], point: Readonly<{
|
|
79
|
+
x: number;
|
|
80
|
+
y: number;
|
|
81
|
+
}>) => boolean;
|
|
82
|
+
/**
|
|
83
|
+
* The text container at a position — an arrow hit on its path, any other
|
|
84
|
+
* container hit anywhere in its bounds (frames are skipped so a container
|
|
85
|
+
* inside one can be hit, and a frame's children are only hit inside it,
|
|
86
|
+
* where they are drawn). Purely positional: the selection plays no part.
|
|
87
|
+
*
|
|
88
|
+
* Only what hides the rest ends the search — a filled element or an image
|
|
89
|
+
* (as for arrow binding), or an arrow — so containers below a transparent
|
|
90
|
+
* one stay in reach whatever their z-order. Of the containers found, the
|
|
91
|
+
* innermost one centered on the position wins, since that is where its
|
|
92
|
+
* label would go (an arrow counting as innermost: it is pointed at, not just
|
|
93
|
+
* enclosing); failing that, the top-most.
|
|
94
|
+
*/
|
|
95
|
+
getTextBindableContainerAtPosition(x: number, y: number): NonDeleted<ExcalidrawTextContainer>;
|
|
96
|
+
/**
|
|
97
|
+
* Whether a text element's content is still being authored.
|
|
98
|
+
*
|
|
99
|
+
* Creating a text reverts the tool to selection during pointerdown, so the
|
|
100
|
+
* pointerup that follows looks like an ordinary canvas click and would
|
|
101
|
+
* capture the still-empty element as a history entry of its own. Undo would
|
|
102
|
+
* then rewind only the typing, restoring an invisible, zero-content element
|
|
103
|
+
* (and, for an endpoint label, leaving the arrow bound to it) rather than
|
|
104
|
+
* removing it. The editor's own submit captures the finished text instead,
|
|
105
|
+
* so the whole create-and-type lands in a single entry.
|
|
106
|
+
*/
|
|
107
|
+
isEditingTextContent(): boolean;
|
|
108
|
+
startTextEditing: ({ sceneX, sceneY, insertAtParentCenter, container, autoEdit, initialCaretSceneCoords, initialSelection, arrowEndpoint, textElement, }: {
|
|
109
|
+
/** X position to insert text at */
|
|
110
|
+
sceneX: number;
|
|
111
|
+
/** Y position to insert text at */
|
|
112
|
+
sceneY: number;
|
|
113
|
+
/** whether to attempt to insert at element center if applicable */
|
|
114
|
+
insertAtParentCenter?: boolean;
|
|
115
|
+
container?: ExcalidrawTextContainer | null;
|
|
116
|
+
autoEdit?: boolean;
|
|
117
|
+
initialCaretSceneCoords?: {
|
|
118
|
+
x: number;
|
|
119
|
+
y: number;
|
|
120
|
+
};
|
|
121
|
+
/** range of an existing text to select (takes precedence over the caret) */
|
|
122
|
+
initialSelection?: {
|
|
123
|
+
start: number;
|
|
124
|
+
end: number;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* creates the text as a label for this arrow endpoint: the binding then
|
|
128
|
+
* dictates the text's position and alignment, overriding (sceneX, sceneY)
|
|
129
|
+
*/
|
|
130
|
+
arrowEndpoint?: ArrowEndpoint | null;
|
|
131
|
+
/**
|
|
132
|
+
* the text to edit: an element to edit exactly that one; `null` to always
|
|
133
|
+
* create, never adopting a selected text or one under the pointer;
|
|
134
|
+
* `undefined` to resolve it here — a single selected text, the label of a
|
|
135
|
+
* selected or passed arrow container, else the text at (sceneX, sceneY)
|
|
136
|
+
*/
|
|
137
|
+
textElement?: NonDeleted<ExcalidrawTextElement> | null;
|
|
138
|
+
}) => void;
|
|
139
|
+
getTextWysiwygSnappedToCenterPosition(x: number, y: number, appState: AppState, container?: ExcalidrawTextContainer | null): {
|
|
140
|
+
viewportX: number;
|
|
141
|
+
viewportY: number;
|
|
142
|
+
elementCenterX: number;
|
|
143
|
+
elementCenterY: number;
|
|
144
|
+
} | undefined;
|
|
145
|
+
}
|
|
146
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { ArrowEndpoint } from "@excalidraw/element";
|
|
2
|
+
import type { ExcalidrawTextContainer, ExcalidrawTextElement, NonDeleted } from "@excalidraw/element/types";
|
|
3
|
+
import type React from "react";
|
|
4
|
+
import type App from "./App";
|
|
5
|
+
import type { PointerDownState } from "../types";
|
|
6
|
+
type ScenePoint = {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
};
|
|
10
|
+
/** the modifier state a target depends on — off a pointer or keyboard event */
|
|
11
|
+
export type Modifiers = Pick<KeyboardEvent, "ctrlKey" | "metaKey">;
|
|
12
|
+
/** What a text-tool click at a position does. */
|
|
13
|
+
export type TextToolTarget =
|
|
14
|
+
/** binds a new text to a free arrow endpoint */
|
|
15
|
+
{
|
|
16
|
+
type: "endpoint";
|
|
17
|
+
endpoint: ArrowEndpoint;
|
|
18
|
+
}
|
|
19
|
+
/** edits this text (a label included, at its derived position) */
|
|
20
|
+
| {
|
|
21
|
+
type: "text";
|
|
22
|
+
element: NonDeleted<ExcalidrawTextElement>;
|
|
23
|
+
}
|
|
24
|
+
/** binds a new label to this empty container (an arrow included) */
|
|
25
|
+
| {
|
|
26
|
+
type: "container";
|
|
27
|
+
element: NonDeleted<ExcalidrawTextContainer>;
|
|
28
|
+
}
|
|
29
|
+
/** creates free text at the pointer */
|
|
30
|
+
| {
|
|
31
|
+
type: "free";
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* The text tool's pointer interaction.
|
|
35
|
+
*
|
|
36
|
+
* Everything hangs off one question — what would a click at this position
|
|
37
|
+
* do (`getTargetAt`)? — answered once and used for the hover affordance
|
|
38
|
+
* (`appState.textToolHover`), the cursor and the pointerdown itself, so the
|
|
39
|
+
* affordance can never promise something the click won't deliver.
|
|
40
|
+
*
|
|
41
|
+
* A click on an empty container's center is armed on pointerdown and
|
|
42
|
+
* committed on pointerup as a bound label; dragging past the autowrap
|
|
43
|
+
* threshold first turns it into a free fixed-width text at the origin
|
|
44
|
+
* instead.
|
|
45
|
+
*
|
|
46
|
+
* Text editing itself (`app.text.startTextEditing`, see `AppText`) is
|
|
47
|
+
* shared with Enter, double-click and the other entry points.
|
|
48
|
+
*/
|
|
49
|
+
export declare class AppTextTool {
|
|
50
|
+
private app;
|
|
51
|
+
constructor(app: App);
|
|
52
|
+
/**
|
|
53
|
+
* A click on an empty container's center, armed on pointerdown and decided
|
|
54
|
+
* on the pointer's way out: a click binds a label, a drag creates free
|
|
55
|
+
* text instead. Deferring is what keeps the drag from first binding to
|
|
56
|
+
* (and provisionally enlarging) the container.
|
|
57
|
+
*/
|
|
58
|
+
private pending;
|
|
59
|
+
/**
|
|
60
|
+
* The modifiers the hover was last resolved with — what a refresh without
|
|
61
|
+
* an event of its own (the viewport moving under a still pointer) uses.
|
|
62
|
+
*/
|
|
63
|
+
private lastModifiers;
|
|
64
|
+
/**
|
|
65
|
+
* What a click at this position would do, in the order the click resolves
|
|
66
|
+
* it: a free arrow endpoint (the smaller, more deliberate target; z-aware,
|
|
67
|
+
* and off while ctrl/cmd disables binding) → the text under the pointer,
|
|
68
|
+
* which the click edits → an empty container near its center, which gets
|
|
69
|
+
* a label unless ctrl/cmd opts out → free text at the pointer.
|
|
70
|
+
*
|
|
71
|
+
* Ctrl/cmd is "no binding" throughout the tool, as elsewhere in the
|
|
72
|
+
* editor. For the container it is read off the event rather than the
|
|
73
|
+
* arrow-binding preference: a label is not an arrow binding.
|
|
74
|
+
*/
|
|
75
|
+
getTargetAt: (scenePointer: ScenePoint, modifiers: Modifiers) => TextToolTarget;
|
|
76
|
+
/**
|
|
77
|
+
* Keeps `appState.textToolHover` — the affordance for what a click would
|
|
78
|
+
* do — in sync with the pointer, and returns the target (for the cursor).
|
|
79
|
+
* Suppressed while something else owns the interaction: a text being
|
|
80
|
+
* edited or drag-sized, a multi-point element, a box selection, a drag of
|
|
81
|
+
* the selection, or the pointer over a scrollbar.
|
|
82
|
+
*/
|
|
83
|
+
updateHover: (scenePointer: ScenePoint, modifiers: Modifiers, isOverScrollBar?: boolean) => TextToolTarget | null;
|
|
84
|
+
/**
|
|
85
|
+
* Re-resolves the hover — and the cursor that goes with it — where the
|
|
86
|
+
* pointer last was, for what changes a click's outcome without the pointer
|
|
87
|
+
* moving: the ctrl/cmd toggle (pass its event), or the viewport scrolling
|
|
88
|
+
* or zooming under the pointer (no event; the last modifiers stand). The
|
|
89
|
+
* scene position is re-derived from the pointer's viewport position, so a
|
|
90
|
+
* moved viewport resolves what is under the pointer now.
|
|
91
|
+
*
|
|
92
|
+
* Nothing to refresh with another tool or without a hovering pointer — a
|
|
93
|
+
* finger never hovers (its last move is where it lifted), and the
|
|
94
|
+
* affordance a press armed is cleared when the press resolves or is
|
|
95
|
+
* canceled. The cursor is left to viewport navigation (space/wheel
|
|
96
|
+
* panning, a scrollbar drag, the hand tool), as on pointermove.
|
|
97
|
+
*/
|
|
98
|
+
refresh: (modifiers?: Modifiers) => void;
|
|
99
|
+
/**
|
|
100
|
+
* Drops a pending center click without acting on it — the tool was left,
|
|
101
|
+
* the browser took the pointer (pointercancel), or a second finger turned
|
|
102
|
+
* the press into a pinch/pan — so no pointerup of ours will decide it. The
|
|
103
|
+
* outline it armed goes with it: while pending, the hover is that click's.
|
|
104
|
+
*/
|
|
105
|
+
cancel: () => void;
|
|
106
|
+
clearHover: () => void;
|
|
107
|
+
private setHover;
|
|
108
|
+
/**
|
|
109
|
+
* The cursor for what a click would do: a pointer over the arrow anchors
|
|
110
|
+
* text would attach to, a text cursor over text the click would edit, the
|
|
111
|
+
* tool's crosshair otherwise — also while the affordance is suppressed
|
|
112
|
+
* (editing, drag-sizing), where a click has nothing to point at.
|
|
113
|
+
*/
|
|
114
|
+
cursorFor: (target: TextToolTarget | null) => string;
|
|
115
|
+
handlePointerDown: (event: React.PointerEvent<HTMLElement>, pointerDownState: PointerDownState) => void;
|
|
116
|
+
/**
|
|
117
|
+
* The pointer-move half of a pending center click. Once the pointer has
|
|
118
|
+
* moved past the autowrap threshold the click is a drag: free text is
|
|
119
|
+
* created at the origin and sized by the drag from here on. Horizontal
|
|
120
|
+
* only (a text is only ever sized that way) and in screen space, and
|
|
121
|
+
* deliberately wider than the generic drag threshold so a jittery click
|
|
122
|
+
* still binds. Returns whether a pending click owned the move.
|
|
123
|
+
*/
|
|
124
|
+
handlePointerMove: (event: PointerEvent, pointerDownState: PointerDownState) => boolean;
|
|
125
|
+
/**
|
|
126
|
+
* The pointer-up half: a genuine pointerup binds the label. The
|
|
127
|
+
* missing-pointerup cleanup replays this with the pointerdown event (a
|
|
128
|
+
* second finger landing mid-press), and a tool switch orphans the click —
|
|
129
|
+
* both discard it instead.
|
|
130
|
+
*/
|
|
131
|
+
handlePointerUp: (event: PointerEvent, pointerDownState: PointerDownState) => void;
|
|
132
|
+
private isDrag;
|
|
133
|
+
private resolvePending;
|
|
134
|
+
/**
|
|
135
|
+
* The click has been acted on: drop the affordance, revert the tool unless
|
|
136
|
+
* it is locked, restore the cursor.
|
|
137
|
+
*/
|
|
138
|
+
private finish;
|
|
139
|
+
}
|
|
140
|
+
export {};
|
|
@@ -40,6 +40,43 @@ export declare class AppViewport {
|
|
|
40
40
|
* user pan/zoom input. */
|
|
41
41
|
get isLockedTransitionPending(): boolean;
|
|
42
42
|
invalidateUIOffset: (name: ViewportUIName) => void;
|
|
43
|
+
/**
|
|
44
|
+
* The side a rendered side UI (`data-viewport-ui="side"`) docks to, and
|
|
45
|
+
* how far it reaches into the canvas from it, in screen px.
|
|
46
|
+
*/
|
|
47
|
+
private measureSide;
|
|
48
|
+
/**
|
|
49
|
+
* The side a named surface docks to while it's hidden, and how far it
|
|
50
|
+
* reaches into the canvas from it: as last measured, else approximately.
|
|
51
|
+
*/
|
|
52
|
+
private getReservedSide;
|
|
53
|
+
private querySideUI;
|
|
54
|
+
/**
|
|
55
|
+
* Where a rendered side UI is, relative to the editor's container, in
|
|
56
|
+
* screen px; null when it isn't rendered.
|
|
57
|
+
*/
|
|
58
|
+
getSideUIRect: (name: ViewportUIName) => {
|
|
59
|
+
left: number;
|
|
60
|
+
right: number;
|
|
61
|
+
top: number;
|
|
62
|
+
bottom: number;
|
|
63
|
+
} | null;
|
|
64
|
+
/**
|
|
65
|
+
* How far the named side UIs reach into the canvas, in screen px, from
|
|
66
|
+
* the left and the right: the part of the canvas they cover. Zero at a
|
|
67
|
+
* side none of them is rendered at — e.g. with the sidebar closed, or on
|
|
68
|
+
* phones, where it's an overlay that doesn't count as viewport UI — unless
|
|
69
|
+
* a hidden one is reserved (see `ViewportOffsetsOptions.reserve`).
|
|
70
|
+
*/
|
|
71
|
+
getSideInsets: (names: readonly ViewportUIName[], opts?: Pick<ViewportOffsetsOptions, "reserve">) => {
|
|
72
|
+
left: number;
|
|
73
|
+
right: number;
|
|
74
|
+
};
|
|
75
|
+
/** How far the sidebar reaches into the canvas (see `getSideInsets`). */
|
|
76
|
+
getSidebarInsets: () => {
|
|
77
|
+
left: number;
|
|
78
|
+
right: number;
|
|
79
|
+
};
|
|
43
80
|
/**
|
|
44
81
|
* Resolves user-supplied viewport offsets into concrete per-side pixel
|
|
45
82
|
* values. Static sides take precedence over UI-derived sides.
|
|
@@ -54,7 +91,10 @@ export declare class AppViewport {
|
|
|
54
91
|
resolveInitialViewport: (opts: Omit<SetViewportOptions, "animation">, elementsMap: NonDeletedSceneElementsMap, appState: AppState) => (Viewport & {
|
|
55
92
|
scrollConstraints: ScrollConstraints | null;
|
|
56
93
|
}) | null;
|
|
57
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* Navigates to a target and optionally installs scroll/zoom constraints.
|
|
96
|
+
* Navigating stops following a collaborator, as a user's pan does.
|
|
97
|
+
*/
|
|
58
98
|
setViewport: (opts: SetViewportOptions | null) => void;
|
|
59
99
|
/** Use when changing scrollX/scrollY/zoom based on user interaction. */
|
|
60
100
|
translate: <K extends keyof AppState>(state: AppState | Pick<AppState, K> | null | ((prevState: Readonly<AppState>, props: Readonly<AppProps>) => AppState | Pick<AppState, K> | null), opts?: {
|
|
@@ -4,19 +4,12 @@ import type App from "./App";
|
|
|
4
4
|
* pointer (`viewport.lastPosition`) — on ctrl/cmd+wheel (which is also how
|
|
5
5
|
* a trackpad pinch is delivered), while the wheel button itself is held
|
|
6
6
|
* down, or on a plain wheel when the input device is a mouse
|
|
7
|
-
* (`appState.inputDevice
|
|
7
|
+
* (`appState.inputDevice`). Shift+wheel pans horizontally;
|
|
8
|
+
* ctrl/cmd+shift+wheel pans vertically.
|
|
8
9
|
*/
|
|
9
10
|
export declare class AppWheel {
|
|
10
11
|
private app;
|
|
11
|
-
|
|
12
|
-
constructor(app: App, dependencies: {
|
|
13
|
-
/** whether a drag-pan (wheel button, space+drag, hand tool) is in
|
|
14
|
-
* progress — wheel input is ignored meanwhile */
|
|
15
|
-
isPanning: () => boolean;
|
|
16
|
-
/** applies the pointer movement the drag-pan is holding back for its
|
|
17
|
-
* next frame, if any */
|
|
18
|
-
flushPanMove: () => void;
|
|
19
|
-
});
|
|
12
|
+
constructor(app: App);
|
|
20
13
|
/** the editor surfaces whose wheel input the editor consumes; everywhere
|
|
21
14
|
* else (menus, sidebars, …) the DOM keeps scrolling. The frame-name labels
|
|
22
15
|
* are DOM, but sit inside the container this listener is attached to */
|
|
@@ -16,6 +16,8 @@ interface PickerProps {
|
|
|
16
16
|
onEscape: (event: React.KeyboardEvent | KeyboardEvent) => void;
|
|
17
17
|
showHotKey?: boolean;
|
|
18
18
|
excludedColors?: readonly string[];
|
|
19
|
+
/** present only while the top picks are customized */
|
|
20
|
+
onResetTopPicks?: () => void;
|
|
19
21
|
}
|
|
20
22
|
export declare const Picker: React.ForwardRefExoticComponent<PickerProps & React.RefAttributes<unknown>>;
|
|
21
23
|
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TopPicksDnD } from "../TopPicksDnD/topPicksDnD";
|
|
2
|
+
export type ColorPickerDnD = TopPicksDnD<string>;
|
|
3
|
+
export declare const ColorPickerDnDContext: import("react").Context<ColorPickerDnD | null>;
|
|
4
|
+
export declare const useColorPickerDnD: () => ColorPickerDnD | null;
|
|
5
|
+
/** pinning colors from the picker popup (palette/shades/custom) or the
|
|
6
|
+
* active-color trigger to the top-picks strip, and reordering the strip */
|
|
7
|
+
export declare const useColorTopPicksDnD: ({ enabled, picks, onPicksChange, }: {
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
picks: readonly string[];
|
|
10
|
+
onPicksChange: (picks: string[]) => void;
|
|
11
|
+
}) => ColorPickerDnD;
|
|
@@ -12,11 +12,14 @@ interface FontPickerProps {
|
|
|
12
12
|
isOpened: boolean;
|
|
13
13
|
selectedFontFamily: FontFamilyValues | null;
|
|
14
14
|
hoveredFontFamily: FontFamilyValues | null;
|
|
15
|
+
/** user-customized top picks (`appState.fontTopPicks`) */
|
|
16
|
+
topPicks: readonly FontFamilyValues[] | null;
|
|
15
17
|
onSelect: (fontFamily: FontFamilyValues) => void;
|
|
18
|
+
onTopPicksChange: (fontTopPicks: FontFamilyValues[] | null) => void;
|
|
16
19
|
onHover: (fontFamily: FontFamilyValues) => void;
|
|
17
20
|
onLeave: () => void;
|
|
18
21
|
onPopupChange: (open: boolean) => void;
|
|
19
22
|
compactMode?: boolean;
|
|
20
23
|
}
|
|
21
|
-
export declare const FontPicker: React.MemoExoticComponent<({ isOpened, selectedFontFamily, hoveredFontFamily, onSelect, onHover, onLeave, onPopupChange, compactMode, }: FontPickerProps) => import("react/jsx-runtime").JSX.Element>;
|
|
24
|
+
export declare const FontPicker: React.MemoExoticComponent<({ isOpened, selectedFontFamily, hoveredFontFamily, topPicks, onSelect, onTopPicksChange, onHover, onLeave, onPopupChange, compactMode, }: FontPickerProps) => import("react/jsx-runtime").JSX.Element>;
|
|
22
25
|
export {};
|
|
@@ -3,6 +3,7 @@ import { type FontFamilyValues } from "@excalidraw/element/types";
|
|
|
3
3
|
import type { ValueOf } from "@excalidraw/common/utility-types";
|
|
4
4
|
import { DropDownMenuItemBadgeType } from "../dropdownMenu/DropdownMenuItem";
|
|
5
5
|
import type { JSX } from "react";
|
|
6
|
+
import type { ExcalidrawFontFace } from "../../fonts/ExcalidrawFontFace";
|
|
6
7
|
export interface FontDescriptor {
|
|
7
8
|
value: number;
|
|
8
9
|
icon: JSX.Element;
|
|
@@ -21,6 +22,10 @@ interface FontPickerListProps {
|
|
|
21
22
|
onLeave: () => void;
|
|
22
23
|
onOpen: () => void;
|
|
23
24
|
onClose: () => void;
|
|
25
|
+
/** present only while the top picks are customized */
|
|
26
|
+
onResetTopPicks?: () => void;
|
|
24
27
|
}
|
|
25
|
-
export declare const
|
|
28
|
+
export declare const getFontFamilyIcon: (fontFamily: FontFamilyValues) => JSX.Element;
|
|
29
|
+
export declare const getFontFamilyLabel: (fontFamily: FontFamilyValues, fontFaces: ExcalidrawFontFace[]) => string;
|
|
30
|
+
export declare const FontPickerList: React.MemoExoticComponent<({ selectedFontFamily, hoveredFontFamily, onSelect, onHover, onLeave, onOpen, onClose, onResetTopPicks, }: FontPickerListProps) => import("react/jsx-runtime").JSX.Element>;
|
|
26
31
|
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FontFamilyValues } from "@excalidraw/element/types";
|
|
2
|
+
import type { TopPicksDnD } from "../TopPicksDnD/topPicksDnD";
|
|
3
|
+
export type FontPickerDnD = TopPicksDnD<FontFamilyValues>;
|
|
4
|
+
export declare const FontPickerDnDContext: import("react").Context<FontPickerDnD | null>;
|
|
5
|
+
export declare const useFontPickerDnD: () => FontPickerDnD | null;
|
|
6
|
+
/** pinning fonts from the font picker list to the top-picks strip, and
|
|
7
|
+
* reordering the strip */
|
|
8
|
+
export declare const useFontTopPicksDnD: ({ enabled, picks, onPicksChange, }: {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
picks: readonly FontFamilyValues[];
|
|
11
|
+
onPicksChange: (picks: FontFamilyValues[]) => void;
|
|
12
|
+
}) => FontPickerDnD;
|
|
@@ -15,9 +15,13 @@ interface Props {
|
|
|
15
15
|
isItemSelected: (id: LibraryItem["id"] | null) => boolean;
|
|
16
16
|
svgCache: SvgCache;
|
|
17
17
|
itemsRenderedPerBatch: number;
|
|
18
|
+
/** larger items with their name below */
|
|
19
|
+
showNames?: boolean;
|
|
18
20
|
}
|
|
19
|
-
export declare const LibraryMenuSectionGrid: ({ children, }: {
|
|
21
|
+
export declare const LibraryMenuSectionGrid: ({ children, showNames, }: {
|
|
20
22
|
children: ReactNode;
|
|
23
|
+
/** fewer columns, for items rendered with `showNames` */
|
|
24
|
+
showNames?: boolean;
|
|
21
25
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
22
|
-
export declare const LibraryMenuSection: React.MemoExoticComponent<({ items, onItemSelectToggle, onItemDrag, isItemSelected, onClick, svgCache, itemsRenderedPerBatch, }: Props) => import("react/jsx-runtime").JSX.Element>;
|
|
26
|
+
export declare const LibraryMenuSection: React.MemoExoticComponent<({ items, onItemSelectToggle, onItemDrag, isItemSelected, onClick, svgCache, itemsRenderedPerBatch, showNames, }: Props) => import("react/jsx-runtime").JSX.Element>;
|
|
23
27
|
export {};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import "./LibraryUnit.scss";
|
|
2
2
|
import type { LibraryItem } from "../types";
|
|
3
3
|
import type { SvgCache } from "../hooks/useLibraryItemSvg";
|
|
4
|
-
export declare const LibraryUnit: import("react").MemoExoticComponent<({ id, elements, isPending, onClick, selected, onToggle, onDrag, svgCache, }: {
|
|
4
|
+
export declare const LibraryUnit: import("react").MemoExoticComponent<({ id, name, showName, elements, isPending, onClick, selected, onToggle, onDrag, svgCache, }: {
|
|
5
5
|
id: LibraryItem["id"] | /** for pending item */ null;
|
|
6
|
+
name?: LibraryItem["name"];
|
|
7
|
+
/** render larger, with the name below the item */
|
|
8
|
+
showName?: boolean;
|
|
6
9
|
elements?: LibraryItem["elements"];
|
|
7
10
|
isPending?: boolean;
|
|
8
11
|
onClick: (id: LibraryItem["id"] | null) => void;
|
|
@@ -11,4 +14,6 @@ export declare const LibraryUnit: import("react").MemoExoticComponent<({ id, ele
|
|
|
11
14
|
onDrag: (id: string, event: React.DragEvent) => void;
|
|
12
15
|
svgCache: SvgCache;
|
|
13
16
|
}) => import("react/jsx-runtime").JSX.Element>;
|
|
14
|
-
export declare const EmptyLibraryUnit: (
|
|
17
|
+
export declare const EmptyLibraryUnit: ({ showName }: {
|
|
18
|
+
showName?: boolean;
|
|
19
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -7,12 +7,26 @@ export declare const updateTooltipPosition: (tooltip: HTMLDivElement, item: {
|
|
|
7
7
|
width: number;
|
|
8
8
|
height: number;
|
|
9
9
|
}, position?: "bottom" | "top") => void;
|
|
10
|
+
export declare const hideTooltip: () => void;
|
|
11
|
+
/**
|
|
12
|
+
* Shows the tooltip for `item`. For elements that can't be wrapped
|
|
13
|
+
* in <Tooltip>. Pair with `hideTooltip()`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const showTooltip: (item: HTMLElement, label: string, { long, delay, position, }?: {
|
|
16
|
+
long?: boolean;
|
|
17
|
+
/** show after a short delay (unless a tooltip was visible just now) */
|
|
18
|
+
delay?: boolean;
|
|
19
|
+
position?: "bottom" | "top";
|
|
20
|
+
}) => void;
|
|
10
21
|
type TooltipProps = {
|
|
11
22
|
children: React.ReactNode;
|
|
12
23
|
label: string;
|
|
13
24
|
long?: boolean;
|
|
14
25
|
style?: React.CSSProperties;
|
|
26
|
+
className?: string;
|
|
15
27
|
disabled?: boolean;
|
|
28
|
+
/** show after a short delay (unless a tooltip was visible just now) */
|
|
29
|
+
delay?: boolean;
|
|
16
30
|
};
|
|
17
|
-
export declare const Tooltip: ({ children, label, long, style, disabled, }: TooltipProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
31
|
+
export declare const Tooltip: ({ children, label, long, style, className, disabled, delay, }: TooltipProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
18
32
|
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* right-click context menu of a customizable top-picks strip, resetting it
|
|
4
|
+
* to its default picks. Renders the strip as-is when not customizable.
|
|
5
|
+
*/
|
|
6
|
+
export declare const TopPicksContextMenu: ({ children, onReset, isCustomized, resetLabel, }: {
|
|
7
|
+
/** the strip (must accept a ref — used as the menu trigger) */
|
|
8
|
+
children: ReactElement;
|
|
9
|
+
/** present when the strip is user-customizable */
|
|
10
|
+
onReset?: () => void;
|
|
11
|
+
/** whether custom picks are currently applied (enables the reset item) */
|
|
12
|
+
isCustomized: boolean;
|
|
13
|
+
resetLabel: string;
|
|
14
|
+
}) => import("react/jsx-runtime").JSX.Element;
|