js-draw 1.14.0 → 1.16.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/Editor.css +288 -1
- package/dist/bundle.js +2 -2
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.js +5 -0
- package/dist/cjs/components/util/StrokeSmoother.js +11 -4
- package/dist/cjs/rendering/caching/CacheRecordManager.js +1 -1
- package/dist/cjs/rendering/renderers/CanvasRenderer.js +1 -1
- package/dist/cjs/testing/sendHtmlSwipe.d.ts +4 -0
- package/dist/cjs/testing/sendHtmlSwipe.js +14 -0
- package/dist/cjs/toolbar/EdgeToolbar.d.ts +1 -0
- package/dist/cjs/toolbar/EdgeToolbar.js +30 -110
- package/dist/cjs/toolbar/IconProvider.d.ts +1 -0
- package/dist/cjs/toolbar/IconProvider.js +27 -0
- package/dist/cjs/toolbar/localization.d.ts +28 -1
- package/dist/cjs/toolbar/localization.js +30 -1
- package/dist/cjs/toolbar/utils/HelpDisplay.d.ts +37 -0
- package/dist/cjs/toolbar/utils/HelpDisplay.js +442 -0
- package/dist/cjs/toolbar/utils/HelpDisplay.test.d.ts +1 -0
- package/dist/cjs/toolbar/utils/localization.d.ts +9 -0
- package/dist/cjs/toolbar/utils/localization.js +11 -0
- package/dist/cjs/toolbar/utils/makeDraggable.d.ts +16 -0
- package/dist/cjs/toolbar/utils/makeDraggable.js +130 -0
- package/dist/cjs/toolbar/widgets/ActionButtonWidget.d.ts +7 -0
- package/dist/cjs/toolbar/widgets/ActionButtonWidget.js +14 -2
- package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +8 -1
- package/dist/cjs/toolbar/widgets/BaseWidget.js +25 -3
- package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.d.ts +3 -1
- package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +19 -4
- package/dist/cjs/toolbar/widgets/HandToolWidget.d.ts +3 -1
- package/dist/cjs/toolbar/widgets/HandToolWidget.js +19 -7
- package/dist/cjs/toolbar/widgets/InsertImageWidget.js +1 -0
- package/dist/cjs/toolbar/widgets/PenToolWidget.d.ts +4 -2
- package/dist/cjs/toolbar/widgets/PenToolWidget.js +27 -8
- package/dist/cjs/toolbar/widgets/SelectionToolWidget.d.ts +3 -1
- package/dist/cjs/toolbar/widgets/SelectionToolWidget.js +19 -5
- package/dist/cjs/toolbar/widgets/components/makeColorInput.d.ts +2 -0
- package/dist/cjs/toolbar/widgets/components/makeColorInput.js +17 -7
- package/dist/cjs/toolbar/widgets/components/makeGridSelector.d.ts +6 -0
- package/dist/cjs/toolbar/widgets/components/makeGridSelector.js +3 -0
- package/dist/cjs/tools/FindTool.js +18 -5
- package/dist/cjs/tools/PanZoom.d.ts +8 -2
- package/dist/cjs/tools/PanZoom.js +29 -10
- package/dist/cjs/tools/SelectionTool/Selection.js +16 -2
- package/dist/cjs/util/addLongPressOrHoverCssClasses.d.ts +3 -1
- package/dist/cjs/util/addLongPressOrHoverCssClasses.js +2 -1
- package/dist/cjs/util/cloneElementWithStyles.d.ts +6 -0
- package/dist/cjs/util/cloneElementWithStyles.js +32 -0
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.mjs +5 -0
- package/dist/mjs/components/util/StrokeSmoother.mjs +11 -4
- package/dist/mjs/rendering/caching/CacheRecordManager.mjs +1 -1
- package/dist/mjs/rendering/renderers/CanvasRenderer.mjs +1 -1
- package/dist/mjs/testing/sendHtmlSwipe.d.ts +4 -0
- package/dist/mjs/testing/sendHtmlSwipe.mjs +12 -0
- package/dist/mjs/toolbar/EdgeToolbar.d.ts +1 -0
- package/dist/mjs/toolbar/EdgeToolbar.mjs +30 -110
- package/dist/mjs/toolbar/IconProvider.d.ts +1 -0
- package/dist/mjs/toolbar/IconProvider.mjs +27 -0
- package/dist/mjs/toolbar/localization.d.ts +28 -1
- package/dist/mjs/toolbar/localization.mjs +30 -1
- package/dist/mjs/toolbar/utils/HelpDisplay.d.ts +37 -0
- package/dist/mjs/toolbar/utils/HelpDisplay.mjs +437 -0
- package/dist/mjs/toolbar/utils/HelpDisplay.test.d.ts +1 -0
- package/dist/mjs/toolbar/utils/localization.d.ts +9 -0
- package/dist/mjs/toolbar/utils/localization.mjs +8 -0
- package/dist/mjs/toolbar/utils/makeDraggable.d.ts +16 -0
- package/dist/mjs/toolbar/utils/makeDraggable.mjs +128 -0
- package/dist/mjs/toolbar/widgets/ActionButtonWidget.d.ts +7 -0
- package/dist/mjs/toolbar/widgets/ActionButtonWidget.mjs +14 -2
- package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +8 -1
- package/dist/mjs/toolbar/widgets/BaseWidget.mjs +25 -3
- package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.d.ts +3 -1
- package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.mjs +19 -4
- package/dist/mjs/toolbar/widgets/HandToolWidget.d.ts +3 -1
- package/dist/mjs/toolbar/widgets/HandToolWidget.mjs +19 -7
- package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +1 -0
- package/dist/mjs/toolbar/widgets/PenToolWidget.d.ts +4 -2
- package/dist/mjs/toolbar/widgets/PenToolWidget.mjs +27 -8
- package/dist/mjs/toolbar/widgets/SelectionToolWidget.d.ts +3 -1
- package/dist/mjs/toolbar/widgets/SelectionToolWidget.mjs +19 -5
- package/dist/mjs/toolbar/widgets/components/makeColorInput.d.ts +2 -0
- package/dist/mjs/toolbar/widgets/components/makeColorInput.mjs +17 -7
- package/dist/mjs/toolbar/widgets/components/makeGridSelector.d.ts +6 -0
- package/dist/mjs/toolbar/widgets/components/makeGridSelector.mjs +3 -0
- package/dist/mjs/tools/FindTool.mjs +18 -5
- package/dist/mjs/tools/PanZoom.d.ts +8 -2
- package/dist/mjs/tools/PanZoom.mjs +29 -10
- package/dist/mjs/tools/SelectionTool/Selection.mjs +16 -2
- package/dist/mjs/util/addLongPressOrHoverCssClasses.d.ts +3 -1
- package/dist/mjs/util/addLongPressOrHoverCssClasses.mjs +2 -1
- package/dist/mjs/util/cloneElementWithStyles.d.ts +6 -0
- package/dist/mjs/util/cloneElementWithStyles.mjs +30 -0
- package/dist/mjs/version.mjs +1 -1
- package/package.json +3 -3
- package/src/toolbar/EdgeToolbar.scss +23 -2
- package/src/toolbar/toolbar.scss +2 -0
- package/src/toolbar/utils/HelpDisplay.scss +315 -0
- package/src/toolbar/widgets/components/makeColorInput.scss +7 -0
- package/src/tools/SelectionTool/SelectionTool.scss +4 -0
@@ -15,6 +15,7 @@ import { keyPressEventFromHTMLEvent, keyUpEventFromHTMLEvent } from '../../inp
|
|
15
15
|
import { toolbarCSSPrefix } from '../constants.mjs';
|
16
16
|
import DropdownLayoutManager from './layout/DropdownLayoutManager.mjs';
|
17
17
|
import addLongPressOrHoverCssClasses from '../../util/addLongPressOrHoverCssClasses.mjs';
|
18
|
+
import HelpDisplay from '../utils/HelpDisplay.mjs';
|
18
19
|
/**
|
19
20
|
* A set of labels that allow toolbar themes to treat buttons differently.
|
20
21
|
*/
|
@@ -127,17 +128,30 @@ class BaseWidget {
|
|
127
128
|
}
|
128
129
|
// Add content to the widget's associated dropdown menu.
|
129
130
|
// Returns true if such a menu should be created, false otherwise.
|
130
|
-
fillDropdown(dropdown) {
|
131
|
+
fillDropdown(dropdown, helpDisplay) {
|
131
132
|
if (Object.keys(this.subWidgets).length === 0) {
|
132
133
|
return false;
|
133
134
|
}
|
134
135
|
for (const widgetId in this.subWidgets) {
|
135
136
|
const widget = this.subWidgets[widgetId];
|
136
|
-
widget.addTo(dropdown);
|
137
|
+
const widgetElement = widget.addTo(dropdown);
|
137
138
|
widget.setIsToplevel(false);
|
139
|
+
// Add help information
|
140
|
+
const helpText = widget.getHelpText();
|
141
|
+
if (helpText) {
|
142
|
+
helpDisplay?.registerTextHelpForElement(widgetElement, helpText);
|
143
|
+
}
|
138
144
|
}
|
139
145
|
return true;
|
140
146
|
}
|
147
|
+
/**
|
148
|
+
* Should return a 1-2 sentence description of the widget.
|
149
|
+
*
|
150
|
+
* At present, this is only used if this widget has an associated dropdown.
|
151
|
+
*/
|
152
|
+
getHelpText() {
|
153
|
+
return undefined;
|
154
|
+
}
|
141
155
|
/** @deprecated Renamed to `setUpButtonEventListeners`. */
|
142
156
|
setupActionBtnClickListener(button) {
|
143
157
|
return this.setUpButtonEventListeners(button);
|
@@ -229,10 +243,15 @@ class BaseWidget {
|
|
229
243
|
this.container.replaceChildren();
|
230
244
|
this.button.replaceChildren(this.icon, this.label);
|
231
245
|
this.container.appendChild(this.button);
|
246
|
+
const helpDisplay = new HelpDisplay(content => this.editor.createHTMLOverlay(content), this.editor);
|
247
|
+
const helpText = this.getHelpText();
|
248
|
+
if (helpText) {
|
249
|
+
helpDisplay.registerTextHelpForElement(this.dropdownContent, [this.getTitle(), helpText].join('\n\n'));
|
250
|
+
}
|
232
251
|
// Clear the dropdownContainer in case this element is being moved to another
|
233
252
|
// parent.
|
234
253
|
this.dropdownContent.replaceChildren();
|
235
|
-
__classPrivateFieldSet(this, _BaseWidget_hasDropdown, this.fillDropdown(this.dropdownContent), "f");
|
254
|
+
__classPrivateFieldSet(this, _BaseWidget_hasDropdown, this.fillDropdown(this.dropdownContent, helpDisplay), "f");
|
236
255
|
if (__classPrivateFieldGet(this, _BaseWidget_hasDropdown, "f")) {
|
237
256
|
this.button.classList.add('has-dropdown');
|
238
257
|
// We're re-creating the dropdown.
|
@@ -258,6 +277,9 @@ class BaseWidget {
|
|
258
277
|
this.focus();
|
259
278
|
}
|
260
279
|
});
|
280
|
+
if (helpDisplay.hasHelpText()) {
|
281
|
+
this.dropdown.appendChild(helpDisplay.createToggleButton());
|
282
|
+
}
|
261
283
|
this.dropdown.appendChild(this.dropdownContent);
|
262
284
|
}
|
263
285
|
this.setDropdownVisible(false);
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import Editor from '../../Editor';
|
2
2
|
import { ToolbarLocalization } from '../localization';
|
3
3
|
import BaseWidget from './BaseWidget';
|
4
|
+
import HelpDisplay from '../utils/HelpDisplay';
|
4
5
|
export default class DocumentPropertiesWidget extends BaseWidget {
|
5
6
|
private updateDropdownContent;
|
6
7
|
constructor(editor: Editor, localizationTable?: ToolbarLocalization);
|
@@ -18,6 +19,7 @@ export default class DocumentPropertiesWidget extends BaseWidget {
|
|
18
19
|
/** Returns the type of the topmost background component */
|
19
20
|
private getBackgroundType;
|
20
21
|
private updateImportExportRectSize;
|
22
|
+
protected getHelpText(): string;
|
21
23
|
private static idCounter;
|
22
|
-
protected fillDropdown(dropdown: HTMLElement): boolean;
|
24
|
+
protected fillDropdown(dropdown: HTMLElement, helpDisplay?: HelpDisplay): boolean;
|
23
25
|
}
|
@@ -90,7 +90,10 @@ class DocumentPropertiesWidget extends BaseWidget {
|
|
90
90
|
this.editor.dispatch(this.editor.image.setImportExportRect(newRect));
|
91
91
|
this.editor.queueRerender();
|
92
92
|
}
|
93
|
-
|
93
|
+
getHelpText() {
|
94
|
+
return this.localizationTable.pageDropdown__baseHelpText;
|
95
|
+
}
|
96
|
+
fillDropdown(dropdown, helpDisplay) {
|
94
97
|
const container = document.createElement('div');
|
95
98
|
container.classList.add(`${toolbarCSSPrefix}spacedList`, `${toolbarCSSPrefix}nonbutton-controls-main-list`, `${toolbarCSSPrefix}document-properties-widget`);
|
96
99
|
// Background color input
|
@@ -98,7 +101,7 @@ class DocumentPropertiesWidget extends BaseWidget {
|
|
98
101
|
const backgroundColorRow = document.createElement('div');
|
99
102
|
const backgroundColorLabel = document.createElement('label');
|
100
103
|
backgroundColorLabel.innerText = this.localizationTable.backgroundColor;
|
101
|
-
const { input: colorInput, container: backgroundColorInputContainer, setValue: setBgColorInputValue } = makeColorInput(this.editor, color => {
|
104
|
+
const { input: colorInput, container: backgroundColorInputContainer, setValue: setBgColorInputValue, registerWithHelpTextDisplay: registerHelpForInputs, } = makeColorInput(this.editor, color => {
|
102
105
|
if (!color.eq(this.getBackgroundColor())) {
|
103
106
|
this.setBackgroundColor(color);
|
104
107
|
}
|
@@ -106,9 +109,16 @@ class DocumentPropertiesWidget extends BaseWidget {
|
|
106
109
|
colorInput.id = `${toolbarCSSPrefix}docPropertiesColorInput-${DocumentPropertiesWidget.idCounter++}`;
|
107
110
|
backgroundColorLabel.htmlFor = colorInput.id;
|
108
111
|
backgroundColorRow.replaceChildren(backgroundColorLabel, backgroundColorInputContainer);
|
109
|
-
|
112
|
+
const registerWithHelp = (helpDisplay) => {
|
113
|
+
if (!helpDisplay) {
|
114
|
+
return;
|
115
|
+
}
|
116
|
+
helpDisplay?.registerTextHelpForElement(backgroundColorRow, this.localizationTable.pageDropdown__backgroundColorHelpText);
|
117
|
+
registerHelpForInputs(helpDisplay);
|
118
|
+
};
|
119
|
+
return { setBgColorInputValue, backgroundColorRow, registerWithHelp, };
|
110
120
|
};
|
111
|
-
const { backgroundColorRow, setBgColorInputValue } = makeBackgroundColorInput();
|
121
|
+
const { backgroundColorRow, setBgColorInputValue, registerWithHelp: registerBackgroundRowWithHelp, } = makeBackgroundColorInput();
|
112
122
|
const makeCheckboxRow = (labelText, onChange) => {
|
113
123
|
const rowContainer = document.createElement('div');
|
114
124
|
const labelElement = document.createElement('label');
|
@@ -189,6 +199,11 @@ class DocumentPropertiesWidget extends BaseWidget {
|
|
189
199
|
aboutButton.onclick = () => {
|
190
200
|
this.editor.showAboutDialog();
|
191
201
|
};
|
202
|
+
// Add help text
|
203
|
+
registerBackgroundRowWithHelp(helpDisplay);
|
204
|
+
helpDisplay?.registerTextHelpForElement(useGridRow, this.localizationTable.pageDropdown__gridCheckboxHelpText);
|
205
|
+
helpDisplay?.registerTextHelpForElement(auroresizeRow, this.localizationTable.pageDropdown__autoresizeCheckboxHelpText);
|
206
|
+
helpDisplay?.registerTextHelpForElement(aboutButton, this.localizationTable.pageDropdown__aboutButtonHelpText);
|
192
207
|
this.updateDropdownContent = () => {
|
193
208
|
setBgColorInputValue(this.getBackgroundColor());
|
194
209
|
const autoresize = this.editor.image.getAutoresizeEnabled();
|
@@ -3,6 +3,7 @@ import PanZoom from '../../tools/PanZoom';
|
|
3
3
|
import { ToolbarLocalization } from '../localization';
|
4
4
|
import BaseToolWidget from './BaseToolWidget';
|
5
5
|
import { SavedToolbuttonState } from './BaseWidget';
|
6
|
+
import HelpDisplay from '../utils/HelpDisplay';
|
6
7
|
export default class HandToolWidget extends BaseToolWidget {
|
7
8
|
private allowTogglingBaseTool;
|
8
9
|
protected overridePanZoomTool: PanZoom;
|
@@ -13,7 +14,8 @@ export default class HandToolWidget extends BaseToolWidget {
|
|
13
14
|
protected getTitle(): string;
|
14
15
|
protected createIcon(): Element;
|
15
16
|
protected handleClick(): void;
|
16
|
-
protected
|
17
|
+
protected getHelpText(): string;
|
18
|
+
protected fillDropdown(dropdown: HTMLElement, helpDisplay?: HelpDisplay): boolean;
|
17
19
|
setSelected(selected: boolean): void;
|
18
20
|
serializeState(): SavedToolbuttonState;
|
19
21
|
deserializeFrom(state: SavedToolbuttonState): void;
|
@@ -6,7 +6,7 @@ import { toolbarCSSPrefix } from '../constants.mjs';
|
|
6
6
|
import BaseToolWidget from './BaseToolWidget.mjs';
|
7
7
|
import BaseWidget from './BaseWidget.mjs';
|
8
8
|
import makeSeparator from './components/makeSeparator.mjs';
|
9
|
-
const makeZoomControl = (localizationTable, editor) => {
|
9
|
+
const makeZoomControl = (localizationTable, editor, helpDisplay) => {
|
10
10
|
const zoomLevelRow = document.createElement('div');
|
11
11
|
const increaseButton = document.createElement('button');
|
12
12
|
const decreaseButton = document.createElement('button');
|
@@ -55,15 +55,20 @@ const makeZoomControl = (localizationTable, editor) => {
|
|
55
55
|
const addToHistory = false;
|
56
56
|
editor.dispatch(Viewport.transformBy(editor.viewport.canvasToScreenTransform.inverse()), addToHistory);
|
57
57
|
};
|
58
|
+
helpDisplay?.registerTextHelpForElement(increaseButton, localizationTable.handDropdown__zoomInHelpText);
|
59
|
+
helpDisplay?.registerTextHelpForElement(decreaseButton, localizationTable.handDropdown__zoomOutHelpText);
|
60
|
+
helpDisplay?.registerTextHelpForElement(resetViewButton, localizationTable.handDropdown__resetViewHelpText);
|
61
|
+
helpDisplay?.registerTextHelpForElement(zoomLevelDisplay, localizationTable.handDropdown__zoomDisplayHelpText);
|
58
62
|
return zoomLevelRow;
|
59
63
|
};
|
60
64
|
class HandModeWidget extends BaseWidget {
|
61
|
-
constructor(editor, tool, flag, makeIcon, title, localizationTable) {
|
65
|
+
constructor(editor, tool, flag, makeIcon, title, helpText, localizationTable) {
|
62
66
|
super(editor, `pan-mode-${flag}`, localizationTable);
|
63
67
|
this.tool = tool;
|
64
68
|
this.flag = flag;
|
65
69
|
this.makeIcon = makeIcon;
|
66
70
|
this.title = title;
|
71
|
+
this.helpText = helpText;
|
67
72
|
editor.notifier.on(EditorEventType.ToolUpdated, toolEvt => {
|
68
73
|
if (toolEvt.kind === EditorEventType.ToolUpdated && toolEvt.tool === tool) {
|
69
74
|
const allEnabled = !!(tool.getMode() & PanZoomMode.SinglePointerGestures);
|
@@ -93,6 +98,9 @@ class HandModeWidget extends BaseWidget {
|
|
93
98
|
fillDropdown(_dropdown) {
|
94
99
|
return false;
|
95
100
|
}
|
101
|
+
getHelpText() {
|
102
|
+
return this.helpText;
|
103
|
+
}
|
96
104
|
}
|
97
105
|
export default class HandToolWidget extends BaseToolWidget {
|
98
106
|
constructor(editor,
|
@@ -117,8 +125,8 @@ export default class HandToolWidget extends BaseToolWidget {
|
|
117
125
|
this.container.classList.add('dropdownShowable');
|
118
126
|
}
|
119
127
|
// Controls for the overriding hand tool.
|
120
|
-
const touchPanningWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoomMode.OneFingerTouchGestures, () => this.editor.icons.makeTouchPanningIcon(), localizationTable.touchPanning, localizationTable);
|
121
|
-
const rotationLockWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoomMode.RotationLocked, () => this.editor.icons.makeRotationLockIcon(), localizationTable.lockRotation, localizationTable);
|
128
|
+
const touchPanningWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoomMode.OneFingerTouchGestures, () => this.editor.icons.makeTouchPanningIcon(), localizationTable.touchPanning, localizationTable.handDropdown__touchPanningHelpText, localizationTable);
|
129
|
+
const rotationLockWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoomMode.RotationLocked, () => this.editor.icons.makeRotationLockIcon(), localizationTable.lockRotation, localizationTable.handDropdown__lockRotationHelpText, localizationTable);
|
122
130
|
this.addSubWidget(touchPanningWidget);
|
123
131
|
this.addSubWidget(rotationLockWidget);
|
124
132
|
}
|
@@ -149,13 +157,17 @@ export default class HandToolWidget extends BaseToolWidget {
|
|
149
157
|
this.setDropdownVisible(!this.isDropdownVisible());
|
150
158
|
}
|
151
159
|
}
|
152
|
-
|
153
|
-
|
160
|
+
getHelpText() {
|
161
|
+
return this.localizationTable.handDropdown__baseHelpText;
|
162
|
+
}
|
163
|
+
fillDropdown(dropdown, helpDisplay) {
|
164
|
+
super.fillDropdown(dropdown, helpDisplay);
|
154
165
|
// The container for all actions that come after the toolbar buttons.
|
155
166
|
const nonbuttonActionContainer = document.createElement('div');
|
156
167
|
nonbuttonActionContainer.classList.add(`${toolbarCSSPrefix}nonbutton-controls-main-list`);
|
157
168
|
makeSeparator().addTo(nonbuttonActionContainer);
|
158
|
-
|
169
|
+
const zoomControl = makeZoomControl(this.localizationTable, this.editor, helpDisplay);
|
170
|
+
nonbuttonActionContainer.appendChild(zoomControl);
|
159
171
|
dropdown.appendChild(nonbuttonActionContainer);
|
160
172
|
return true;
|
161
173
|
}
|
@@ -95,6 +95,7 @@ class InsertImageWidget extends BaseWidget {
|
|
95
95
|
imageAltTextLabel.htmlFor = altTextInputId;
|
96
96
|
imageAltTextLabel.innerText = this.localizationTable.inputAltText;
|
97
97
|
this.imageAltTextInput.type = 'text';
|
98
|
+
this.imageAltTextInput.placeholder = this.localizationTable.describeTheImage;
|
98
99
|
this.statusView.setAttribute('aria-live', 'polite');
|
99
100
|
this.submitButton.innerText = this.localizationTable.submit;
|
100
101
|
this.selectedFiles.onUpdateAndNow(async (files) => {
|
@@ -5,6 +5,7 @@ import { KeyPressEvent } from '../../inputEvents';
|
|
5
5
|
import { ToolbarLocalization } from '../localization';
|
6
6
|
import BaseToolWidget from './BaseToolWidget';
|
7
7
|
import { SavedToolbuttonState } from './BaseWidget';
|
8
|
+
import HelpDisplay from '../utils/HelpDisplay';
|
8
9
|
export interface PenTypeRecord {
|
9
10
|
name: string;
|
10
11
|
id: string;
|
@@ -24,11 +25,12 @@ export default class PenToolWidget extends BaseToolWidget {
|
|
24
25
|
private createIconForRecord;
|
25
26
|
protected createIcon(): Element;
|
26
27
|
private createPenTypeSelector;
|
27
|
-
protected createStrokeCorrectionOptions(): {
|
28
|
+
protected createStrokeCorrectionOptions(helpOverlay?: HelpDisplay): {
|
28
29
|
update: () => void;
|
29
30
|
addTo: (parent: HTMLElement) => void;
|
30
31
|
};
|
31
|
-
protected
|
32
|
+
protected getHelpText(): string;
|
33
|
+
protected fillDropdown(dropdown: HTMLElement, helpDisplay?: HelpDisplay): boolean;
|
32
34
|
protected onKeyPress(event: KeyPressEvent): boolean;
|
33
35
|
serializeState(): SavedToolbuttonState;
|
34
36
|
deserializeFrom(state: SavedToolbuttonState): void;
|
@@ -116,7 +116,7 @@ class PenToolWidget extends BaseToolWidget {
|
|
116
116
|
return this.createIconForRecord(this.getCurrentPenType());
|
117
117
|
}
|
118
118
|
// Creates a widget that allows selecting different pen types
|
119
|
-
createPenTypeSelector() {
|
119
|
+
createPenTypeSelector(helpOverlay) {
|
120
120
|
const allChoices = this.penTypes.map((penType, index) => {
|
121
121
|
return {
|
122
122
|
id: index,
|
@@ -132,6 +132,7 @@ class PenToolWidget extends BaseToolWidget {
|
|
132
132
|
};
|
133
133
|
penSelector.value.onUpdate(onSelectorUpdate);
|
134
134
|
shapeSelector.value.onUpdate(onSelectorUpdate);
|
135
|
+
helpOverlay?.registerTextHelpForElements([penSelector.getRootElement(), shapeSelector.getRootElement()], this.localizationTable.penDropdown__penTypeHelpText);
|
135
136
|
return {
|
136
137
|
setValue: (penTypeIndex) => {
|
137
138
|
penSelector.value.set(penTypeIndex);
|
@@ -147,7 +148,7 @@ class PenToolWidget extends BaseToolWidget {
|
|
147
148
|
},
|
148
149
|
};
|
149
150
|
}
|
150
|
-
createStrokeCorrectionOptions() {
|
151
|
+
createStrokeCorrectionOptions(helpOverlay) {
|
151
152
|
const container = document.createElement('div');
|
152
153
|
container.classList.add('action-button-row', `${toolbarCSSPrefix}-pen-tool-toggle-buttons`);
|
153
154
|
const addToggleButton = (labelText, icon) => {
|
@@ -171,6 +172,9 @@ class PenToolWidget extends BaseToolWidget {
|
|
171
172
|
setOnInputListener(listener) {
|
172
173
|
onChangeListener = listener;
|
173
174
|
},
|
175
|
+
addHelpText(text) {
|
176
|
+
helpOverlay?.registerTextHelpForElement(button, text);
|
177
|
+
},
|
174
178
|
};
|
175
179
|
button.onclick = () => {
|
176
180
|
result.setChecked(!checked);
|
@@ -185,6 +189,9 @@ class PenToolWidget extends BaseToolWidget {
|
|
185
189
|
autocorrectOption.setOnInputListener(enabled => {
|
186
190
|
this.tool.setStrokeAutocorrectEnabled(enabled);
|
187
191
|
});
|
192
|
+
// Help text
|
193
|
+
autocorrectOption.addHelpText(this.localizationTable.penDropdown__autocorrectHelpText);
|
194
|
+
stabilizationOption.addHelpText(this.localizationTable.penDropdown__stabilizationHelpText);
|
188
195
|
return {
|
189
196
|
update: () => {
|
190
197
|
stabilizationOption.setChecked(!!this.tool.getInputMapper());
|
@@ -192,30 +199,42 @@ class PenToolWidget extends BaseToolWidget {
|
|
192
199
|
},
|
193
200
|
addTo: (parent) => {
|
194
201
|
parent.appendChild(container);
|
195
|
-
}
|
202
|
+
},
|
196
203
|
};
|
197
204
|
}
|
198
|
-
|
205
|
+
getHelpText() {
|
206
|
+
return this.localizationTable.penDropdown__baseHelpText;
|
207
|
+
}
|
208
|
+
fillDropdown(dropdown, helpDisplay) {
|
199
209
|
const container = document.createElement('div');
|
200
210
|
container.classList.add(`${toolbarCSSPrefix}spacedList`, `${toolbarCSSPrefix}nonbutton-controls-main-list`);
|
201
211
|
// Thickness: Value of the input is squared to allow for finer control/larger values.
|
202
212
|
const { container: thicknessRow, setValue: setThickness } = makeThicknessSlider(this.editor, thickness => {
|
203
213
|
this.tool.setThickness(thickness);
|
204
214
|
});
|
205
|
-
const penTypeSelect = this.createPenTypeSelector();
|
206
215
|
const colorRow = document.createElement('div');
|
207
216
|
const colorLabel = document.createElement('label');
|
208
|
-
const
|
217
|
+
const colorInputControl = makeColorInput(this.editor, color => {
|
209
218
|
this.tool.setColor(color);
|
210
219
|
});
|
220
|
+
const { input: colorInput, container: colorInputContainer } = colorInputControl;
|
211
221
|
colorInput.id = `${toolbarCSSPrefix}colorInput${PenToolWidget.idCounter++}`;
|
212
222
|
colorLabel.innerText = this.localizationTable.colorLabel;
|
213
223
|
colorLabel.setAttribute('for', colorInput.id);
|
214
224
|
colorRow.appendChild(colorLabel);
|
215
225
|
colorRow.appendChild(colorInputContainer);
|
216
|
-
|
226
|
+
// Autocorrect and stabilization options
|
227
|
+
const toggleButtonRow = this.createStrokeCorrectionOptions(helpDisplay);
|
228
|
+
const penTypeSelect = this.createPenTypeSelector(helpDisplay);
|
229
|
+
// Add help text for color and thickness last, as these are likely to be
|
230
|
+
// features users are least interested in.
|
231
|
+
helpDisplay?.registerTextHelpForElement(colorRow, this.localizationTable.penDropdown__colorHelpText);
|
232
|
+
if (helpDisplay) {
|
233
|
+
colorInputControl.registerWithHelpTextDisplay(helpDisplay);
|
234
|
+
}
|
235
|
+
helpDisplay?.registerTextHelpForElement(thicknessRow, this.localizationTable.penDropdown__thicknessHelpText);
|
217
236
|
this.updateInputs = () => {
|
218
|
-
|
237
|
+
colorInputControl.setValue(this.tool.getColor());
|
219
238
|
setThickness(this.tool.getThickness());
|
220
239
|
penTypeSelect.updateIcons();
|
221
240
|
// Update the selected stroke factory.
|
@@ -3,6 +3,7 @@ import SelectionTool from '../../tools/SelectionTool/SelectionTool';
|
|
3
3
|
import { KeyPressEvent } from '../../inputEvents';
|
4
4
|
import { ToolbarLocalization } from '../localization';
|
5
5
|
import BaseToolWidget from './BaseToolWidget';
|
6
|
+
import HelpDisplay from '../utils/HelpDisplay';
|
6
7
|
export default class SelectionToolWidget extends BaseToolWidget {
|
7
8
|
private tool;
|
8
9
|
private updateFormatMenu;
|
@@ -11,5 +12,6 @@ export default class SelectionToolWidget extends BaseToolWidget {
|
|
11
12
|
protected onKeyPress(event: KeyPressEvent): boolean;
|
12
13
|
protected getTitle(): string;
|
13
14
|
protected createIcon(): Element;
|
14
|
-
protected
|
15
|
+
protected getHelpText(): string;
|
16
|
+
protected fillDropdown(dropdown: HTMLElement, helpDisplay?: HelpDisplay): boolean;
|
15
17
|
}
|
@@ -13,7 +13,7 @@ const makeFormatMenu = (editor, selectionTool, localizationTable) => {
|
|
13
13
|
container.classList.add('selection-format-menu', `${toolbarCSSPrefix}spacedList`, `${toolbarCSSPrefix}indentedList`);
|
14
14
|
const colorRow = document.createElement('div');
|
15
15
|
const colorLabel = document.createElement('label');
|
16
|
-
const
|
16
|
+
const colorInputControl = makeColorInput(editor, color => {
|
17
17
|
const selection = selectionTool.getSelection();
|
18
18
|
if (selection) {
|
19
19
|
const updateStyleCommands = [];
|
@@ -26,6 +26,7 @@ const makeFormatMenu = (editor, selectionTool, localizationTable) => {
|
|
26
26
|
editor.dispatch(unitedCommand);
|
27
27
|
}
|
28
28
|
});
|
29
|
+
const { input: colorInput, container: colorInputContainer } = colorInputControl;
|
29
30
|
colorLabel.innerText = localizationTable.colorLabel;
|
30
31
|
const update = () => {
|
31
32
|
const selection = selectionTool.getSelection();
|
@@ -41,12 +42,12 @@ const makeFormatMenu = (editor, selectionTool, localizationTable) => {
|
|
41
42
|
}
|
42
43
|
}
|
43
44
|
}
|
44
|
-
|
45
|
+
colorInputControl.setValue(Color4.average(colors));
|
45
46
|
}
|
46
47
|
else {
|
47
48
|
colorInput.disabled = true;
|
48
49
|
container.classList.add('disabled');
|
49
|
-
|
50
|
+
colorInputControl.setValue(Color4.transparent);
|
50
51
|
}
|
51
52
|
};
|
52
53
|
colorRow.replaceChildren(colorLabel, colorInputContainer);
|
@@ -56,6 +57,10 @@ const makeFormatMenu = (editor, selectionTool, localizationTable) => {
|
|
56
57
|
parent.appendChild(container);
|
57
58
|
},
|
58
59
|
update,
|
60
|
+
registerHelpText: (helpDisplay) => {
|
61
|
+
helpDisplay.registerTextHelpForElement(colorRow, localizationTable.selectionDropdown__changeColorHelpText);
|
62
|
+
colorInputControl.registerWithHelpTextDisplay(helpDisplay);
|
63
|
+
},
|
59
64
|
};
|
60
65
|
};
|
61
66
|
export default class SelectionToolWidget extends BaseToolWidget {
|
@@ -66,16 +71,19 @@ export default class SelectionToolWidget extends BaseToolWidget {
|
|
66
71
|
const resizeButton = new ActionButtonWidget(editor, 'resize-btn', () => editor.icons.makeResizeImageToSelectionIcon(), this.localizationTable.resizeImageToSelection, () => {
|
67
72
|
this.resizeImageToSelection();
|
68
73
|
}, localization);
|
74
|
+
resizeButton.setHelpText(this.localizationTable.selectionDropdown__resizeToHelpText);
|
69
75
|
const deleteButton = new ActionButtonWidget(editor, 'delete-btn', () => editor.icons.makeDeleteSelectionIcon(), this.localizationTable.deleteSelection, () => {
|
70
76
|
const selection = this.tool.getSelection();
|
71
77
|
this.editor.dispatch(selection.deleteSelectedObjects());
|
72
78
|
this.tool.clearSelection();
|
73
79
|
}, localization);
|
80
|
+
deleteButton.setHelpText(this.localizationTable.selectionDropdown__deleteHelpText);
|
74
81
|
const duplicateButton = new ActionButtonWidget(editor, 'duplicate-btn', () => editor.icons.makeDuplicateSelectionIcon(), this.localizationTable.duplicateSelection, async () => {
|
75
82
|
const selection = this.tool.getSelection();
|
76
83
|
this.editor.dispatch(await selection.duplicateSelectedObjects());
|
77
84
|
this.setDropdownVisible(false);
|
78
85
|
}, localization);
|
86
|
+
duplicateButton.setHelpText(this.localizationTable.selectionDropdown__duplicateHelpText);
|
79
87
|
this.addSubWidget(resizeButton);
|
80
88
|
this.addSubWidget(deleteButton);
|
81
89
|
this.addSubWidget(duplicateButton);
|
@@ -124,8 +132,11 @@ export default class SelectionToolWidget extends BaseToolWidget {
|
|
124
132
|
createIcon() {
|
125
133
|
return this.editor.icons.makeSelectionIcon();
|
126
134
|
}
|
127
|
-
|
128
|
-
|
135
|
+
getHelpText() {
|
136
|
+
return this.localizationTable.selectionDropdown__baseHelpText;
|
137
|
+
}
|
138
|
+
fillDropdown(dropdown, helpDisplay) {
|
139
|
+
super.fillDropdown(dropdown, helpDisplay);
|
129
140
|
const controlsContainer = document.createElement('div');
|
130
141
|
controlsContainer.classList.add(`${toolbarCSSPrefix}nonbutton-controls-main-list`);
|
131
142
|
dropdown.appendChild(controlsContainer);
|
@@ -133,6 +144,9 @@ export default class SelectionToolWidget extends BaseToolWidget {
|
|
133
144
|
const formatMenu = makeFormatMenu(this.editor, this.tool, this.localizationTable);
|
134
145
|
formatMenu.addTo(controlsContainer);
|
135
146
|
this.updateFormatMenu = () => formatMenu.update();
|
147
|
+
if (helpDisplay) {
|
148
|
+
formatMenu.registerHelpText(helpDisplay);
|
149
|
+
}
|
136
150
|
formatMenu.update();
|
137
151
|
return true;
|
138
152
|
}
|
@@ -1,10 +1,12 @@
|
|
1
1
|
import { Color4 } from '@js-draw/math';
|
2
2
|
import Editor from '../../../Editor';
|
3
|
+
import type HelpDisplay from '../../utils/HelpDisplay';
|
3
4
|
type OnColorChangeListener = (color: Color4) => void;
|
4
5
|
export declare const makeColorInput: (editor: Editor, onColorChange: OnColorChangeListener) => {
|
5
6
|
input: HTMLInputElement;
|
6
7
|
container: HTMLSpanElement;
|
7
8
|
setValue: (color: Color4 | string) => void;
|
8
9
|
closePicker: () => void;
|
10
|
+
registerWithHelpTextDisplay: (helpDisplay: HelpDisplay) => void;
|
9
11
|
};
|
10
12
|
export default makeColorInput;
|
@@ -3,13 +3,16 @@ import PipetteTool from '../../../tools/PipetteTool.mjs';
|
|
3
3
|
import { EditorEventType } from '../../../types.mjs';
|
4
4
|
// Returns [ color input, input container, callback to change the color value ].
|
5
5
|
export const makeColorInput = (editor, onColorChange) => {
|
6
|
-
const
|
6
|
+
const container = document.createElement('span');
|
7
|
+
const inputWrapper = document.createElement('span');
|
7
8
|
const colorInput = document.createElement('input');
|
8
9
|
colorInput.type = 'button';
|
9
10
|
colorInput.classList.add('coloris_input');
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
container.classList.add('color-input-container');
|
12
|
+
inputWrapper.classList.add('color-input-wrapper');
|
13
|
+
inputWrapper.appendChild(colorInput);
|
14
|
+
container.appendChild(inputWrapper);
|
15
|
+
const pipetteController = addPipetteTool(editor, container, (color) => {
|
13
16
|
colorInput.value = color.toHexString();
|
14
17
|
onInputEnd();
|
15
18
|
// Update the color preview, if it exists (may be managed by Coloris).
|
@@ -44,7 +47,7 @@ export const makeColorInput = (editor, onColorChange) => {
|
|
44
47
|
open: true,
|
45
48
|
});
|
46
49
|
pipetteController.cancel();
|
47
|
-
|
50
|
+
container.classList.add('picker-open');
|
48
51
|
// Focus the Coloris color picker, if it exists.
|
49
52
|
// Don't focus the text input within the color picker, however,
|
50
53
|
// as this displays a keyboard on mobile devices.
|
@@ -60,7 +63,7 @@ export const makeColorInput = (editor, onColorChange) => {
|
|
60
63
|
onInputEnd();
|
61
64
|
// Restore focus to the input that opened the color picker
|
62
65
|
colorInput.focus();
|
63
|
-
|
66
|
+
container.classList.remove('picker-open');
|
64
67
|
};
|
65
68
|
colorInput.addEventListener('close', () => {
|
66
69
|
onClose();
|
@@ -76,13 +79,17 @@ export const makeColorInput = (editor, onColorChange) => {
|
|
76
79
|
};
|
77
80
|
return {
|
78
81
|
input: colorInput,
|
79
|
-
container
|
82
|
+
container,
|
80
83
|
setValue: setColorInputValue,
|
81
84
|
closePicker: () => {
|
82
85
|
if (isOpen) {
|
83
86
|
onInputEnd();
|
84
87
|
}
|
85
88
|
},
|
89
|
+
registerWithHelpTextDisplay: (helpDisplay) => {
|
90
|
+
helpDisplay.registerTextHelpForElement(inputWrapper, editor.localization.colorPickerToggleHelpText);
|
91
|
+
pipetteController.registerWithHelpTextDisplay(helpDisplay);
|
92
|
+
},
|
86
93
|
};
|
87
94
|
};
|
88
95
|
const addPipetteTool = (editor, container, onColorChange) => {
|
@@ -136,6 +143,9 @@ const addPipetteTool = (editor, container, onColorChange) => {
|
|
136
143
|
cancel: () => {
|
137
144
|
endColorSelectMode();
|
138
145
|
},
|
146
|
+
registerWithHelpTextDisplay: (helpDisplay) => {
|
147
|
+
helpDisplay.registerTextHelpForElement(pipetteButton, editor.localization.colorPickerPipetteHelpText);
|
148
|
+
},
|
139
149
|
};
|
140
150
|
};
|
141
151
|
export default makeColorInput;
|
@@ -7,8 +7,14 @@ interface GridSelectChoice<ChoiceIdType> {
|
|
7
7
|
}
|
8
8
|
interface GridSelector<ChoiceIdType> {
|
9
9
|
value: MutableReactiveValue<ChoiceIdType>;
|
10
|
+
/**
|
11
|
+
* Connects this grid selector with `other` such that only one item in
|
12
|
+
* either this or `other` can be selected at a time.
|
13
|
+
*/
|
10
14
|
linkWith: (other: GridSelector<ChoiceIdType>) => void;
|
15
|
+
/** Re-builds the icons shown in the grid selector. */
|
11
16
|
updateIcons: () => void;
|
17
|
+
getRootElement: () => HTMLElement;
|
12
18
|
addTo: (parent: HTMLElement) => void;
|
13
19
|
/** Used internally @internal */
|
14
20
|
_radiogroupName: string;
|
@@ -2,6 +2,7 @@
|
|
2
2
|
//
|
3
3
|
// @packageDocumentation
|
4
4
|
import TextComponent from '../components/TextComponent.mjs';
|
5
|
+
import ImageComponent from '../components/ImageComponent.mjs';
|
5
6
|
import BaseTool from './BaseTool.mjs';
|
6
7
|
import { toggleFindVisibleShortcutId } from './keybindings.mjs';
|
7
8
|
const cssPrefix = 'find-tool';
|
@@ -20,11 +21,23 @@ export default class FindTool extends BaseTool {
|
|
20
21
|
return true;
|
21
22
|
}
|
22
23
|
getMatches(searchFor) {
|
23
|
-
|
24
|
-
const
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
const lowerSearchFor = searchFor.toLocaleLowerCase();
|
25
|
+
const matchingComponents = this.editor.image.getAllElements().filter(component => {
|
26
|
+
let text = '';
|
27
|
+
if (component instanceof TextComponent) {
|
28
|
+
text = component.getText();
|
29
|
+
}
|
30
|
+
else if (component instanceof ImageComponent) {
|
31
|
+
text = component.getAltText() ?? '';
|
32
|
+
}
|
33
|
+
else {
|
34
|
+
return false;
|
35
|
+
}
|
36
|
+
const hasLowercaseMatch = text.toLocaleLowerCase().indexOf(lowerSearchFor) !== -1;
|
37
|
+
const hasSameCaseMatch = text.indexOf(searchFor) !== -1;
|
38
|
+
return hasLowercaseMatch || hasSameCaseMatch;
|
39
|
+
});
|
40
|
+
return matchingComponents.map(match => match.getBBox());
|
28
41
|
}
|
29
42
|
focusCurrentMatch() {
|
30
43
|
const matches = this.getMatches(this.searchInput.value);
|
@@ -24,13 +24,14 @@ export default class PanZoom extends BaseTool {
|
|
24
24
|
private readonly initialRotationSnapAngle;
|
25
25
|
private readonly afterRotationStartSnapAngle;
|
26
26
|
private readonly pinchZoomStartThreshold;
|
27
|
-
private
|
28
|
-
private
|
27
|
+
private startTouchDist;
|
28
|
+
private lastTouchDist;
|
29
29
|
private lastScreenCenter;
|
30
30
|
private lastTimestamp;
|
31
31
|
private lastPointerDownTimestamp;
|
32
32
|
private initialTouchAngle;
|
33
33
|
private initialViewportRotation;
|
34
|
+
private initialViewportScale;
|
34
35
|
private isScaling;
|
35
36
|
private isRotating;
|
36
37
|
private inertialScroller;
|
@@ -43,6 +44,11 @@ export default class PanZoom extends BaseTool {
|
|
43
44
|
private updateVelocity;
|
44
45
|
private getCenterDelta;
|
45
46
|
private toSnappedRotationDelta;
|
47
|
+
/**
|
48
|
+
* Given a scale update, `scaleFactor`, returns a new scale factor snapped
|
49
|
+
* to a power of two (if within some tolerance of that scale).
|
50
|
+
*/
|
51
|
+
private toSnappedScaleFactor;
|
46
52
|
private handleTwoFingerMove;
|
47
53
|
private handleOneFingerMove;
|
48
54
|
onPointerMove({ allPointers }: PointerEvt): void;
|