js-draw 0.0.4 → 0.0.5
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/CHANGELOG.md +6 -0
- package/README.md +95 -0
- package/build_tools/BundledFile.ts +167 -0
- package/build_tools/bundle.ts +11 -0
- package/dist/build_tools/BundledFile.d.ts +13 -0
- package/dist/build_tools/BundledFile.js +157 -0
- package/dist/build_tools/bundle.d.ts +1 -0
- package/dist/build_tools/bundle.js +5 -0
- package/dist/bundle.js +1 -0
- package/dist/src/Display.js +4 -1
- package/dist/src/Editor.d.ts +8 -1
- package/dist/src/Editor.js +22 -5
- package/dist/src/bundle/bundled.d.ts +4 -0
- package/dist/src/bundle/bundled.js +5 -0
- package/dist/src/localization.d.ts +1 -1
- package/dist/src/localization.js +2 -2
- package/dist/src/toolbar/HTMLToolbar.d.ts +1 -2
- package/dist/src/toolbar/HTMLToolbar.js +2 -20
- package/dist/src/toolbar/localization.d.ts +20 -0
- package/dist/src/toolbar/localization.js +19 -0
- package/dist/src/toolbar/types.d.ts +0 -19
- package/dist/src/tools/SelectionTool.js +2 -1
- package/dist-test/test-dist-bundle.html +35 -0
- package/package.json +12 -3
- package/src/Display.ts +3 -1
- package/src/Editor.css +0 -1
- package/src/Editor.ts +42 -10
- package/src/EditorImage.test.ts +5 -3
- package/src/bundle/bundled.ts +7 -0
- package/src/localization.ts +2 -3
- package/src/toolbar/HTMLToolbar.ts +2 -24
- package/src/toolbar/localization.ts +44 -0
- package/src/toolbar/types.ts +0 -22
- package/src/tools/SelectionTool.test.ts +1 -1
- package/src/tools/SelectionTool.ts +1 -1
package/CHANGELOG.md
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
|
2
|
+
# 0.0.5
|
3
|
+
* Configuration options:
|
4
|
+
- Ability to disable touch panning
|
5
|
+
- The `new Editor(container, ...)` constructor now takes a configuration object as its second argument.
|
6
|
+
* A pre-bundled version of `js-draw` is now distributed.
|
7
|
+
|
2
8
|
# 0.0.4
|
3
9
|
* Preset shapes
|
4
10
|
* Arrow
|
package/README.md
CHANGED
@@ -23,6 +23,18 @@ const editor = new Editor(document.body);
|
|
23
23
|
The `import js-draw/styles` step requires a bundler that can import `.css` files. For example, [`webpack` with `css-loader`.](https://webpack.js.org/loaders/css-loader/)
|
24
24
|
|
25
25
|
|
26
|
+
If you're not using a bundler, consider using the pre-bundled editor:
|
27
|
+
```html
|
28
|
+
<!-- Replace 0.0.5 with the latest version of js-draw -->
|
29
|
+
<script src="https://cdn.jsdelivr.net/npm/js-draw@0.0.5/dist/bundle.js"></script>
|
30
|
+
<script>
|
31
|
+
const editor = new jsdraw.Editor(document.body);
|
32
|
+
editor.addToolbar();
|
33
|
+
editor.getRootElement().style.height = '600px';
|
34
|
+
</script>
|
35
|
+
```
|
36
|
+
|
37
|
+
|
26
38
|
## Adding a toolbar
|
27
39
|
|
28
40
|
To create a toolbar with the default tools:
|
@@ -74,3 +86,86 @@ but exports to
|
|
74
86
|
|
75
87
|
which **does** contain the `<circle/>` element.
|
76
88
|
|
89
|
+
## Settings/configuration
|
90
|
+
### Disabling touchpad panning
|
91
|
+
|
92
|
+
Touchpad/mousewheel pan gestures can conflict with gestures used to scroll the document. To turn off touchpad pan gestures (and scrolling the editor with the mousewheel),
|
93
|
+
```ts
|
94
|
+
const editor = new Editor(document.body, {
|
95
|
+
wheelEventsEnabled: false,
|
96
|
+
});
|
97
|
+
```
|
98
|
+
|
99
|
+
### Localization
|
100
|
+
|
101
|
+
See [src/localization.ts](src/localization.ts) for a list of strings.
|
102
|
+
|
103
|
+
Some of the default strings in the editor might be overridden like this:
|
104
|
+
```ts
|
105
|
+
const editor = new Editor(document.body, {
|
106
|
+
// Example partial Spanish localization
|
107
|
+
localization: {
|
108
|
+
// Not all translated strings need to be specified. If a string isn't given,
|
109
|
+
// the English (default) localization will be used
|
110
|
+
|
111
|
+
// Strings for the main editor interface
|
112
|
+
// (see src/localization.ts)
|
113
|
+
loading: (percentage: number) => `Cargando: ${percentage}%...`,
|
114
|
+
imageEditor: 'Editor de dibujos',
|
115
|
+
|
116
|
+
undoAnnouncement: (commandDescription: string) => `${commandDescription} fue deshecho`,
|
117
|
+
redoAnnouncement: (commandDescription: string) => `${commandDescription} fue rehecho`,
|
118
|
+
|
119
|
+
// Strings for the toolbar
|
120
|
+
// (see src/toolbar/localization.ts)
|
121
|
+
pen: 'Lapiz',
|
122
|
+
eraser: 'Borrador',
|
123
|
+
select: 'Selecciona',
|
124
|
+
touchDrawing: 'Dibuja con un dedo',
|
125
|
+
thicknessLabel: 'Tamaño: ',
|
126
|
+
colorLabel: 'Color: ',
|
127
|
+
|
128
|
+
...
|
129
|
+
},
|
130
|
+
});
|
131
|
+
```
|
132
|
+
|
133
|
+
|
134
|
+
## Changing the editor's color theme
|
135
|
+
|
136
|
+
The editor's color theme is specified using CSS. Its default theme looks like this:
|
137
|
+
```css
|
138
|
+
.imageEditorContainer {
|
139
|
+
/* Deafult colors for the editor -- light mode */
|
140
|
+
|
141
|
+
--primary-background-color: white;
|
142
|
+
--primary-background-color-transparent: rgba(255, 255, 255, 0.5);
|
143
|
+
--secondary-background-color: #faf;
|
144
|
+
--primary-foreground-color: black;
|
145
|
+
--secondary-foreground-color: black;
|
146
|
+
}
|
147
|
+
|
148
|
+
@media (prefers-color-scheme: dark) {
|
149
|
+
.imageEditorContainer {
|
150
|
+
/* Deafult colors for the editor -- dark mode */
|
151
|
+
|
152
|
+
--primary-background-color: #151515;
|
153
|
+
--primary-background-color-transparent: rgba(50, 50, 50, 0.5);
|
154
|
+
--secondary-background-color: #607;
|
155
|
+
--primary-foreground-color: white;
|
156
|
+
--secondary-foreground-color: white;
|
157
|
+
}
|
158
|
+
}
|
159
|
+
```
|
160
|
+
|
161
|
+
To override it, use a more specific CSS selector to set the theme variables. For example,
|
162
|
+
```css
|
163
|
+
body .imageEditorContainer {
|
164
|
+
--primary-background-color: green;
|
165
|
+
--primary-background-color-transparent: rgba(255, 240, 200, 0.5);
|
166
|
+
--secondary-background-color: yellow;
|
167
|
+
--primary-foreground-color: black;
|
168
|
+
--secondary-foreground-color: black;
|
169
|
+
}
|
170
|
+
```
|
171
|
+
disables the dark theme and creates a theme that primarially uses yellow/green colors.
|
@@ -0,0 +1,167 @@
|
|
1
|
+
// This file is taken from Joplin: https://github.com/laurent22/joplin
|
2
|
+
// js-draw was originally created as a part of a pull request for joplin. This
|
3
|
+
// is part of the functionality from Joplin it requires.
|
4
|
+
|
5
|
+
import { dirname, extname, basename } from 'path';
|
6
|
+
import TerserPlugin from 'terser-webpack-plugin';
|
7
|
+
|
8
|
+
import webpack from 'webpack';
|
9
|
+
|
10
|
+
export default class BundledFile {
|
11
|
+
private readonly bundleBaseName: string;
|
12
|
+
private readonly rootFileDirectory: string;
|
13
|
+
private readonly outputDirectory: string;
|
14
|
+
private readonly outputFilename: string;
|
15
|
+
|
16
|
+
public constructor(
|
17
|
+
public readonly bundleName: string,
|
18
|
+
private readonly sourceFilePath: string,
|
19
|
+
outputFilepath?: string,
|
20
|
+
) {
|
21
|
+
this.rootFileDirectory = dirname(sourceFilePath);
|
22
|
+
this.bundleBaseName = basename(sourceFilePath, extname(sourceFilePath));
|
23
|
+
|
24
|
+
if (outputFilepath) {
|
25
|
+
this.outputDirectory = dirname(outputFilepath);
|
26
|
+
this.outputFilename = basename(outputFilepath);
|
27
|
+
} else {
|
28
|
+
this.outputDirectory = this.rootFileDirectory;
|
29
|
+
this.outputFilename = `${this.bundleBaseName}.bundle.js`;
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
private getWebpackOptions(mode: 'production' | 'development'): webpack.Configuration {
|
34
|
+
const config: webpack.Configuration = {
|
35
|
+
mode,
|
36
|
+
entry: this.sourceFilePath,
|
37
|
+
output: {
|
38
|
+
path: this.outputDirectory,
|
39
|
+
filename: this.outputFilename,
|
40
|
+
|
41
|
+
library: {
|
42
|
+
type: 'window',
|
43
|
+
name: this.bundleName,
|
44
|
+
},
|
45
|
+
},
|
46
|
+
// See https://webpack.js.org/guides/typescript/
|
47
|
+
module: {
|
48
|
+
rules: [
|
49
|
+
{
|
50
|
+
// Include .tsx to include react components
|
51
|
+
test: /\.tsx?$/i,
|
52
|
+
use: 'ts-loader',
|
53
|
+
exclude: /node_modules/,
|
54
|
+
},
|
55
|
+
{
|
56
|
+
test: /\.css$/i,
|
57
|
+
use: ['style-loader', 'css-loader'],
|
58
|
+
},
|
59
|
+
],
|
60
|
+
},
|
61
|
+
optimization: {
|
62
|
+
minimizer: [
|
63
|
+
// Don't create separate files for comments.
|
64
|
+
// See https://stackoverflow.com/a/65650316/17055750
|
65
|
+
new TerserPlugin({
|
66
|
+
extractComments: false,
|
67
|
+
}),
|
68
|
+
],
|
69
|
+
},
|
70
|
+
// Increase the minimum size required
|
71
|
+
// to trigger warnings.
|
72
|
+
// See https://stackoverflow.com/a/53517149/17055750
|
73
|
+
performance: {
|
74
|
+
maxAssetSize: 2_000_000, // 2-ish MiB
|
75
|
+
maxEntrypointSize: 2_000_000,
|
76
|
+
},
|
77
|
+
resolve: {
|
78
|
+
extensions: ['.tsx', '.ts', '.js'],
|
79
|
+
},
|
80
|
+
};
|
81
|
+
|
82
|
+
return config;
|
83
|
+
}
|
84
|
+
|
85
|
+
private handleErrors(err: Error | undefined | null, stats: webpack.Stats | undefined): boolean {
|
86
|
+
let failed = false;
|
87
|
+
|
88
|
+
if (err) {
|
89
|
+
console.error(`Error: ${err.name}`, err.message, err.stack);
|
90
|
+
failed = true;
|
91
|
+
} else if (stats?.hasErrors() || stats?.hasWarnings()) {
|
92
|
+
const data = stats.toJson();
|
93
|
+
|
94
|
+
if (data.warnings && data.warningsCount) {
|
95
|
+
console.warn('Warnings: ', data.warningsCount);
|
96
|
+
for (const warning of data.warnings) {
|
97
|
+
// Stack contains the message
|
98
|
+
if (warning.stack) {
|
99
|
+
console.warn(warning.stack);
|
100
|
+
} else {
|
101
|
+
console.warn(warning.message);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
if (data.errors && data.errorsCount) {
|
106
|
+
console.error('Errors: ', data.errorsCount);
|
107
|
+
for (const error of data.errors) {
|
108
|
+
if (error.stack) {
|
109
|
+
console.error(error.stack);
|
110
|
+
} else {
|
111
|
+
console.error(error.message);
|
112
|
+
}
|
113
|
+
console.error();
|
114
|
+
}
|
115
|
+
|
116
|
+
failed = true;
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
return failed;
|
121
|
+
}
|
122
|
+
|
123
|
+
// Create a minified JS file in the same directory as `this.sourceFilePath` with
|
124
|
+
// the same name.
|
125
|
+
public build() {
|
126
|
+
const compiler = webpack(this.getWebpackOptions('production'));
|
127
|
+
return new Promise<void>((resolve, reject) => {
|
128
|
+
console.info(`Building bundle: ${this.bundleName}...`);
|
129
|
+
|
130
|
+
compiler.run((err, stats) => {
|
131
|
+
let failed = this.handleErrors(err, stats);
|
132
|
+
|
133
|
+
// Clean up.
|
134
|
+
compiler.close(async (error) => {
|
135
|
+
if (error) {
|
136
|
+
console.error('Error cleaning up:', error);
|
137
|
+
failed = true;
|
138
|
+
}
|
139
|
+
if (!failed) {
|
140
|
+
console.log('☑ Done building! ☑');
|
141
|
+
resolve();
|
142
|
+
} else {
|
143
|
+
reject();
|
144
|
+
}
|
145
|
+
});
|
146
|
+
});
|
147
|
+
});
|
148
|
+
}
|
149
|
+
|
150
|
+
public startWatching() {
|
151
|
+
const compiler = webpack(this.getWebpackOptions('development'));
|
152
|
+
const watchOptions = {
|
153
|
+
ignored: [
|
154
|
+
'**/node_modules',
|
155
|
+
'**/dist',
|
156
|
+
],
|
157
|
+
};
|
158
|
+
|
159
|
+
console.info('Watching bundle: ', this.bundleName);
|
160
|
+
compiler.watch(watchOptions, async (err, stats) => {
|
161
|
+
const failed = this.handleErrors(err, stats);
|
162
|
+
if (!failed) {
|
163
|
+
console.log('☑ Built! ☑');
|
164
|
+
}
|
165
|
+
});
|
166
|
+
}
|
167
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { dirname } from 'path';
|
2
|
+
import BundledFile from './BundledFile';
|
3
|
+
|
4
|
+
const rootDir = dirname(__dirname);
|
5
|
+
const mainBundle = new BundledFile(
|
6
|
+
'jsdraw',
|
7
|
+
`${rootDir}/src/bundle/bundled.ts`,
|
8
|
+
`${rootDir}/dist/bundle.js`,
|
9
|
+
);
|
10
|
+
|
11
|
+
void mainBundle.build();
|
@@ -0,0 +1,13 @@
|
|
1
|
+
export default class BundledFile {
|
2
|
+
readonly bundleName: string;
|
3
|
+
private readonly sourceFilePath;
|
4
|
+
private readonly bundleBaseName;
|
5
|
+
private readonly rootFileDirectory;
|
6
|
+
private readonly outputDirectory;
|
7
|
+
private readonly outputFilename;
|
8
|
+
constructor(bundleName: string, sourceFilePath: string, outputFilepath?: string);
|
9
|
+
private getWebpackOptions;
|
10
|
+
private handleErrors;
|
11
|
+
build(): Promise<void>;
|
12
|
+
startWatching(): void;
|
13
|
+
}
|
@@ -0,0 +1,157 @@
|
|
1
|
+
// This file is taken from Joplin: https://github.com/laurent22/joplin
|
2
|
+
// js-draw was originally created as a part of a pull request for joplin. This
|
3
|
+
// is part of the functionality from Joplin it requires.
|
4
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
5
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
6
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
7
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
8
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
9
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
10
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
11
|
+
});
|
12
|
+
};
|
13
|
+
import { dirname, extname, basename } from 'path';
|
14
|
+
import TerserPlugin from 'terser-webpack-plugin';
|
15
|
+
import webpack from 'webpack';
|
16
|
+
export default class BundledFile {
|
17
|
+
constructor(bundleName, sourceFilePath, outputFilepath) {
|
18
|
+
this.bundleName = bundleName;
|
19
|
+
this.sourceFilePath = sourceFilePath;
|
20
|
+
this.rootFileDirectory = dirname(sourceFilePath);
|
21
|
+
this.bundleBaseName = basename(sourceFilePath, extname(sourceFilePath));
|
22
|
+
if (outputFilepath) {
|
23
|
+
this.outputDirectory = dirname(outputFilepath);
|
24
|
+
this.outputFilename = basename(outputFilepath);
|
25
|
+
}
|
26
|
+
else {
|
27
|
+
this.outputDirectory = this.rootFileDirectory;
|
28
|
+
this.outputFilename = `${this.bundleBaseName}.bundle.js`;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
getWebpackOptions(mode) {
|
32
|
+
const config = {
|
33
|
+
mode,
|
34
|
+
entry: this.sourceFilePath,
|
35
|
+
output: {
|
36
|
+
path: this.outputDirectory,
|
37
|
+
filename: this.outputFilename,
|
38
|
+
library: {
|
39
|
+
type: 'window',
|
40
|
+
name: this.bundleName,
|
41
|
+
},
|
42
|
+
},
|
43
|
+
// See https://webpack.js.org/guides/typescript/
|
44
|
+
module: {
|
45
|
+
rules: [
|
46
|
+
{
|
47
|
+
// Include .tsx to include react components
|
48
|
+
test: /\.tsx?$/i,
|
49
|
+
use: 'ts-loader',
|
50
|
+
exclude: /node_modules/,
|
51
|
+
},
|
52
|
+
{
|
53
|
+
test: /\.css$/i,
|
54
|
+
use: ['style-loader', 'css-loader'],
|
55
|
+
},
|
56
|
+
],
|
57
|
+
},
|
58
|
+
optimization: {
|
59
|
+
minimizer: [
|
60
|
+
// Don't create separate files for comments.
|
61
|
+
// See https://stackoverflow.com/a/65650316/17055750
|
62
|
+
new TerserPlugin({
|
63
|
+
extractComments: false,
|
64
|
+
}),
|
65
|
+
],
|
66
|
+
},
|
67
|
+
// Increase the minimum size required
|
68
|
+
// to trigger warnings.
|
69
|
+
// See https://stackoverflow.com/a/53517149/17055750
|
70
|
+
performance: {
|
71
|
+
maxAssetSize: 2000000,
|
72
|
+
maxEntrypointSize: 2000000,
|
73
|
+
},
|
74
|
+
resolve: {
|
75
|
+
extensions: ['.tsx', '.ts', '.js'],
|
76
|
+
},
|
77
|
+
};
|
78
|
+
return config;
|
79
|
+
}
|
80
|
+
handleErrors(err, stats) {
|
81
|
+
let failed = false;
|
82
|
+
if (err) {
|
83
|
+
console.error(`Error: ${err.name}`, err.message, err.stack);
|
84
|
+
failed = true;
|
85
|
+
}
|
86
|
+
else if ((stats === null || stats === void 0 ? void 0 : stats.hasErrors()) || (stats === null || stats === void 0 ? void 0 : stats.hasWarnings())) {
|
87
|
+
const data = stats.toJson();
|
88
|
+
if (data.warnings && data.warningsCount) {
|
89
|
+
console.warn('Warnings: ', data.warningsCount);
|
90
|
+
for (const warning of data.warnings) {
|
91
|
+
// Stack contains the message
|
92
|
+
if (warning.stack) {
|
93
|
+
console.warn(warning.stack);
|
94
|
+
}
|
95
|
+
else {
|
96
|
+
console.warn(warning.message);
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
if (data.errors && data.errorsCount) {
|
101
|
+
console.error('Errors: ', data.errorsCount);
|
102
|
+
for (const error of data.errors) {
|
103
|
+
if (error.stack) {
|
104
|
+
console.error(error.stack);
|
105
|
+
}
|
106
|
+
else {
|
107
|
+
console.error(error.message);
|
108
|
+
}
|
109
|
+
console.error();
|
110
|
+
}
|
111
|
+
failed = true;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
return failed;
|
115
|
+
}
|
116
|
+
// Create a minified JS file in the same directory as `this.sourceFilePath` with
|
117
|
+
// the same name.
|
118
|
+
build() {
|
119
|
+
const compiler = webpack(this.getWebpackOptions('production'));
|
120
|
+
return new Promise((resolve, reject) => {
|
121
|
+
console.info(`Building bundle: ${this.bundleName}...`);
|
122
|
+
compiler.run((err, stats) => {
|
123
|
+
let failed = this.handleErrors(err, stats);
|
124
|
+
// Clean up.
|
125
|
+
compiler.close((error) => __awaiter(this, void 0, void 0, function* () {
|
126
|
+
if (error) {
|
127
|
+
console.error('Error cleaning up:', error);
|
128
|
+
failed = true;
|
129
|
+
}
|
130
|
+
if (!failed) {
|
131
|
+
console.log('☑ Done building! ☑');
|
132
|
+
resolve();
|
133
|
+
}
|
134
|
+
else {
|
135
|
+
reject();
|
136
|
+
}
|
137
|
+
}));
|
138
|
+
});
|
139
|
+
});
|
140
|
+
}
|
141
|
+
startWatching() {
|
142
|
+
const compiler = webpack(this.getWebpackOptions('development'));
|
143
|
+
const watchOptions = {
|
144
|
+
ignored: [
|
145
|
+
'**/node_modules',
|
146
|
+
'**/dist',
|
147
|
+
],
|
148
|
+
};
|
149
|
+
console.info('Watching bundle: ', this.bundleName);
|
150
|
+
compiler.watch(watchOptions, (err, stats) => __awaiter(this, void 0, void 0, function* () {
|
151
|
+
const failed = this.handleErrors(err, stats);
|
152
|
+
if (!failed) {
|
153
|
+
console.log('☑ Built! ☑');
|
154
|
+
}
|
155
|
+
}));
|
156
|
+
}
|
157
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|