@lvl99dotcom/paintcanvas 0.7.0 → 0.8.0
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/README.md +1 -0
- package/dist/lib/assets/index.d.ts +92 -0
- package/dist/lib/assets/index.js +106 -0
- package/dist/lib/assets/schema.d.ts +151 -0
- package/dist/lib/assets/schema.js +76 -0
- package/dist/lib/brushes/presetFile/index.d.ts +6 -27
- package/dist/lib/brushes/presetFile/index.js +34 -47
- package/dist/lib/brushes/types/index.d.ts +2 -11
- package/dist/lib/classes/AssetSync/index.d.ts +45 -0
- package/dist/lib/classes/AssetSync/index.js +80 -0
- package/dist/lib/classes/ColourPalettes/index.d.ts +83 -0
- package/dist/lib/classes/ColourPalettes/index.js +165 -0
- package/dist/lib/classes/CustomPresets/index.d.ts +14 -15
- package/dist/lib/classes/CustomPresets/index.js +25 -10
- package/dist/lib/classes/LayerAutosave/index.d.ts +9 -2
- package/dist/lib/classes/LayerAutosave/index.js +16 -6
- package/dist/lib/classes/PaintCanvas/index.d.ts +111 -23
- package/dist/lib/classes/PaintCanvas/index.js +219 -58
- package/dist/lib/classes/Palette/index.d.ts +3 -2
- package/dist/lib/classes/Palette/index.js +3 -2
- package/dist/lib/classes/ProfileGraphs/index.d.ts +13 -2
- package/dist/lib/classes/ProfileGraphs/index.js +22 -2
- package/dist/lib/classes/RemoteDocumentAutosave/index.d.ts +73 -0
- package/dist/lib/classes/RemoteDocumentAutosave/index.js +119 -0
- package/dist/lib/classes/SettingsAutosave/index.d.ts +7 -3
- package/dist/lib/classes/SettingsAutosave/index.js +28 -7
- package/dist/lib/classes/SettingsExtensions/index.d.ts +67 -0
- package/dist/lib/classes/SettingsExtensions/index.js +88 -0
- package/dist/lib/document/index.d.ts +61 -4
- package/dist/lib/document/index.js +173 -4
- package/dist/lib/document/schema.d.ts +154 -39
- package/dist/lib/document/schema.js +91 -25
- package/dist/lib/messages/schema.d.ts +176 -74
- package/dist/lib/messages/schema.js +2 -1
- package/dist/lib/palette/index.d.ts +8 -42
- package/dist/lib/palette/index.js +26 -59
- package/dist/lib/palette/schema.d.ts +111 -22
- package/dist/lib/palette/schema.js +51 -26
- package/dist/lib/presets/index.d.ts +1 -9
- package/dist/lib/presets/index.js +4 -10
- package/dist/lib/presets/schema.d.ts +118 -73
- package/dist/lib/presets/schema.js +28 -60
- package/dist/lib/profiles/profileFile/index.d.ts +10 -0
- package/dist/lib/profiles/profileFile/index.js +19 -0
- package/dist/lib/profiles/schema.d.ts +96 -3
- package/dist/lib/profiles/schema.js +31 -7
- package/dist/lib/schemas/index.d.ts +42 -0
- package/dist/lib/schemas/index.js +60 -0
- package/dist/lib/settings/index.d.ts +37 -22
- package/dist/lib/settings/index.js +78 -37
- package/dist/lib/settings/schema.d.ts +198 -76
- package/dist/lib/settings/schema.js +92 -86
- package/dist/lib/storage/index.d.ts +82 -3
- package/dist/lib/storage/index.js +82 -5
- package/dist/lib/validation/validators.generated.d.ts +19 -8
- package/dist/lib/validation/validators.generated.js +44716 -18900
- package/dist/lib/version/index.js +1 -1
- package/dist/locales/en-GB.js +23 -5
- package/dist/locales/en-US.js +23 -5
- package/dist/locales/fr.js +23 -5
- package/dist/locales/ja.js +23 -5
- package/dist/locales/ko.js +23 -5
- package/dist/locales/zh-Hans.js +23 -5
- package/dist/locales/zh-Hant.js +23 -5
- package/dist/package.js +1 -1
- package/dist/testing/app.d.ts +6 -2
- package/dist/testing/app.js +7 -2
- package/dist/testing/documentStore.d.ts +26 -0
- package/dist/testing/documentStore.js +31 -0
- package/dist/ui/elements/PaintCanvas/index.d.ts +6 -2
- package/dist/ui/elements/PaintCanvas/index.js +20 -6
- package/dist/ui/elements/PcAppSettings/index.d.ts +5 -6
- package/dist/ui/elements/PcAppSettings/index.js +17 -27
- package/dist/ui/elements/PcPanelBrushes/index.d.ts +1 -1
- package/dist/ui/elements/PcPanelBrushes/index.js +22 -28
- package/dist/ui/elements/PcPanelBrushes/style.js +1 -1
- package/dist/ui/elements/PcPanelColours/index.d.ts +56 -19
- package/dist/ui/elements/PcPanelColours/index.js +251 -104
- package/dist/ui/elements/PcPanelColours/style.js +1 -1
- package/dist/ui/elements/PcStats/index.d.ts +8 -4
- package/dist/ui/elements/PcStats/index.js +39 -5
- package/locales/en-GB.json +23 -5
- package/locales/en-US.json +23 -5
- package/locales/fr.json +23 -5
- package/locales/ja.json +23 -5
- package/locales/ko.json +23 -5
- package/locales/zh-Hans.json +23 -5
- package/locales/zh-Hant.json +23 -5
- package/package.json +2 -1
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import style_default from "./style.js";
|
|
2
|
-
import { PALETTE_FILE_FORMAT } from "../../../lib/palette/schema.js";
|
|
3
2
|
import { ICON_CONTROLS_CSS, NO_TEXT_SELECTION_CSS, PILLS_CSS } from "../../styles/index.js";
|
|
3
|
+
import "../../../lib/palette/schema.js";
|
|
4
4
|
import { defineElement, emit } from "../../base/index.js";
|
|
5
5
|
import { PcPanel } from "../PcPanel/index.js";
|
|
6
6
|
import ChangeController from "../../ChangeController/index.js";
|
|
7
7
|
import "../PcColourPair/index.js";
|
|
8
8
|
import "../PcMenu/index.js";
|
|
9
|
+
import "../PcContextMenu/index.js";
|
|
9
10
|
import { CANCEL_CHOICE } from "../PcDialog/index.js";
|
|
10
11
|
import { hexToHsl, hexToRgb, hslToHex, normaliseHex, rgbToHex } from "../../../lib/utils/colour/index.js";
|
|
11
|
-
import {
|
|
12
|
+
import { colourPaletteFile } from "../../../lib/palette/index.js";
|
|
13
|
+
import { DEFAULT_PALETTE_ID } from "../../../lib/classes/ColourPalettes/index.js";
|
|
14
|
+
import { AssetFileError } from "../../../lib/assets/index.js";
|
|
15
|
+
import { askConfirm, askText } from "../../ask/index.js";
|
|
12
16
|
import { JSON_FILE_TYPE, saveFile } from "../../../lib/rendering/screenshot/index.js";
|
|
13
17
|
import { html, nothing, unsafeCSS } from "lit";
|
|
14
18
|
import { live } from "lit/directives/live.js";
|
|
@@ -115,11 +119,23 @@ var MODELS = ["rgb", "hsl"];
|
|
|
115
119
|
var LONG_PRESS_MS = 500;
|
|
116
120
|
/** How far a touch can move and still count as held still (CSS pixels) */
|
|
117
121
|
var LONG_PRESS_SLOP = 10;
|
|
118
|
-
/**
|
|
119
|
-
var
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
/** Whether a saved colour is in one of the user's palettes (PaintCanvas's can't be changed) */
|
|
123
|
+
var isEditable = ({ palette }) => palette !== DEFAULT_PALETTE_ID;
|
|
124
|
+
/** Actions in a palette's menu */
|
|
125
|
+
var PALETTE_ACTIONS = [
|
|
126
|
+
"rename",
|
|
127
|
+
"export",
|
|
128
|
+
"delete"
|
|
129
|
+
];
|
|
130
|
+
/** Translation keys of the messages shown when importing a palette file fails, by reason */
|
|
131
|
+
var IMPORT_ERROR_KEYS = {
|
|
132
|
+
invalid: "paintCanvas.palette.fileIncompatible",
|
|
133
|
+
unsupported: "paintCanvas.palette.fileUnsupported"
|
|
122
134
|
};
|
|
135
|
+
/**
|
|
136
|
+
* The translation key of the message shown when importing a palette file fails.
|
|
137
|
+
*/
|
|
138
|
+
var importErrorKey = (error) => error instanceof AssetFileError && IMPORT_ERROR_KEYS[error.reason] || "paintCanvas.palette.fileReadFailed";
|
|
123
139
|
/** The dialog's choice that deletes the colour */
|
|
124
140
|
var DELETE_CHOICE = "delete";
|
|
125
141
|
/**
|
|
@@ -128,11 +144,14 @@ var DELETE_CHOICE = "delete";
|
|
|
128
144
|
var clampWhole = (value, max) => Math.round(Math.min(max, Math.max(0, value)));
|
|
129
145
|
/**
|
|
130
146
|
* The colour palette menu: the foreground and background colours (the selected one is configured), its hex value, RGB
|
|
131
|
-
* and HSL sliders, the
|
|
147
|
+
* and HSL sliders, the colour palettes (the user's own above the one PaintCanvas comes with), and buttons to make a
|
|
148
|
+
* palette and to import and export the user's palettes as a JSON file.
|
|
132
149
|
*
|
|
133
150
|
* - Pressing the foreground or background colour selects it.
|
|
134
|
-
* - Pressing a saved colour sets the selected colour
|
|
135
|
-
*
|
|
151
|
+
* - Pressing a saved colour sets the selected colour (changing it afterwards doesn't change the palette); a palette's [+]
|
|
152
|
+
* saves the selected colour in it. PaintCanvas's palette can't be changed.
|
|
153
|
+
* - Each of the user's palettes has a ⋮ menu to rename, export or delete it (deleting asks first).
|
|
154
|
+
* - A colour in one of the user's palettes is deleted, after asking, by clicking it with Alt/Option held (the cursor shows an "X"), from its
|
|
136
155
|
* menu (right-click, a long press on touch screens, or the context menu key), or with Delete or Backspace. Arrow keys,
|
|
137
156
|
* Home and End move between saved colours.
|
|
138
157
|
* - Escape closes it (closes the canvas's open panel).
|
|
@@ -158,6 +177,10 @@ var PcPanelColours = class extends PcPanel {
|
|
|
158
177
|
unsafeCSS(PILLS_CSS),
|
|
159
178
|
unsafeCSS(style_default)
|
|
160
179
|
];
|
|
180
|
+
/** Asks the user to confirm, in a dialog (replaceable for tests) */
|
|
181
|
+
confirm = (options) => askConfirm(this.renderRoot, options);
|
|
182
|
+
/** Asks the user for text, in a dialog (replaceable for tests) */
|
|
183
|
+
prompt = (options) => askText(this.renderRoot, options);
|
|
161
184
|
/** Saves exported files (replaceable for tests) */
|
|
162
185
|
saveFile = (blob, name) => saveFile(blob, name, void 0, JSON_FILE_TYPE);
|
|
163
186
|
/** The HSL values shown, kept while they give the selected colour (so hue stays put for greys) */
|
|
@@ -166,13 +189,20 @@ var PcPanelColours = class extends PcPanel {
|
|
|
166
189
|
s: 0,
|
|
167
190
|
l: 0
|
|
168
191
|
};
|
|
169
|
-
/** The saved colour that is reached with Tab (the others with arrow keys) */
|
|
170
|
-
|
|
192
|
+
/** The saved colour that is reached with Tab in its palette (the others with arrow keys; other palettes' first) */
|
|
193
|
+
focused = {
|
|
194
|
+
palette: DEFAULT_PALETTE_ID,
|
|
195
|
+
index: 0
|
|
196
|
+
};
|
|
171
197
|
/** A touch being held on a saved colour, until it opens its menu */
|
|
172
198
|
press;
|
|
173
199
|
/** Whether a long press opened a menu, so the click that follows is ignored */
|
|
174
200
|
longPressed = false;
|
|
175
|
-
changes = new ChangeController(this, () => [
|
|
201
|
+
changes = new ChangeController(this, () => [
|
|
202
|
+
this.app,
|
|
203
|
+
this.app?.palette,
|
|
204
|
+
this.app?.palettes
|
|
205
|
+
]);
|
|
176
206
|
onKey = (event) => {
|
|
177
207
|
if (event.key === "Alt") this.toggleAttribute("deleting", event.type === "keydown");
|
|
178
208
|
};
|
|
@@ -203,8 +233,36 @@ var PcPanelColours = class extends PcPanel {
|
|
|
203
233
|
super.willUpdate(changed);
|
|
204
234
|
if (!this.app) return;
|
|
205
235
|
if (hslToHex(this.hsl) !== this.colour) this.hsl = hexToHsl(this.colour);
|
|
206
|
-
const
|
|
207
|
-
this.
|
|
236
|
+
const shown = this.shown().find(({ id }) => id === this.focused.palette);
|
|
237
|
+
this.focused = shown ? {
|
|
238
|
+
palette: shown.id,
|
|
239
|
+
index: Math.max(0, Math.min(this.focused.index, shown.colours.length - 1))
|
|
240
|
+
} : {
|
|
241
|
+
palette: DEFAULT_PALETTE_ID,
|
|
242
|
+
index: 0
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/** The palettes shown: the user's own, then the one PaintCanvas comes with (named after the app) */
|
|
246
|
+
shown() {
|
|
247
|
+
const app = this.app;
|
|
248
|
+
return [...app.palettes.items.map((palette) => ({
|
|
249
|
+
...palette,
|
|
250
|
+
own: true
|
|
251
|
+
})), {
|
|
252
|
+
id: DEFAULT_PALETTE_ID,
|
|
253
|
+
name: app.names.app,
|
|
254
|
+
colours: app.palette.colours,
|
|
255
|
+
own: false
|
|
256
|
+
}];
|
|
257
|
+
}
|
|
258
|
+
/** A palette's colours */
|
|
259
|
+
coloursOf(palette) {
|
|
260
|
+
const app = this.app;
|
|
261
|
+
return palette === "paintcanvas" ? app.palette.colours : app.palettes.get(palette)?.colours ?? [];
|
|
262
|
+
}
|
|
263
|
+
/** The saved colour at a position */
|
|
264
|
+
colourAt({ palette, index }) {
|
|
265
|
+
return this.coloursOf(palette)[index];
|
|
208
266
|
}
|
|
209
267
|
/** Set the selected colour */
|
|
210
268
|
setColour(colour) {
|
|
@@ -272,33 +330,34 @@ var PcPanelColours = class extends PcPanel {
|
|
|
272
330
|
this.setColour(hslToHex(this.hsl));
|
|
273
331
|
this.requestUpdate();
|
|
274
332
|
}
|
|
275
|
-
/** Set the selected colour from a saved colour, or ask to delete
|
|
276
|
-
onSwatchClick(event,
|
|
277
|
-
this.
|
|
333
|
+
/** Set the selected colour from a saved colour, or ask to delete one of the user's with Alt/Option held */
|
|
334
|
+
onSwatchClick(event, swatch) {
|
|
335
|
+
this.focused = swatch;
|
|
278
336
|
if (this.longPressed) {
|
|
279
337
|
this.longPressed = false;
|
|
280
338
|
return;
|
|
281
339
|
}
|
|
282
|
-
if (event.altKey) {
|
|
283
|
-
this.confirming =
|
|
340
|
+
if (event.altKey && isEditable(swatch)) {
|
|
341
|
+
this.confirming = swatch;
|
|
284
342
|
return;
|
|
285
343
|
}
|
|
286
|
-
this.setColour(this.
|
|
344
|
+
this.setColour(this.colourAt(swatch));
|
|
287
345
|
}
|
|
288
|
-
/** Open a
|
|
289
|
-
onSwatchContextMenu(event,
|
|
346
|
+
/** Open the menu of a colour in one of the user's palettes where it was right-clicked */
|
|
347
|
+
onSwatchContextMenu(event, swatch) {
|
|
348
|
+
if (!isEditable(swatch)) return;
|
|
290
349
|
event.preventDefault();
|
|
291
|
-
this.
|
|
350
|
+
this.focused = swatch;
|
|
292
351
|
this.menu = {
|
|
293
|
-
|
|
352
|
+
...swatch,
|
|
294
353
|
x: event.clientX,
|
|
295
354
|
y: event.clientY
|
|
296
355
|
};
|
|
297
356
|
}
|
|
298
357
|
/** Start waiting for a touch held on a saved colour to open its menu */
|
|
299
|
-
onSwatchPointerDown(event,
|
|
358
|
+
onSwatchPointerDown(event, swatch) {
|
|
300
359
|
this.longPressed = false;
|
|
301
|
-
if (event.pointerType !== "touch") return;
|
|
360
|
+
if (event.pointerType !== "touch" || !isEditable(swatch)) return;
|
|
302
361
|
this.cancelPress();
|
|
303
362
|
const { clientX: x, clientY: y } = event;
|
|
304
363
|
this.press = {
|
|
@@ -307,9 +366,9 @@ var PcPanelColours = class extends PcPanel {
|
|
|
307
366
|
timer: setTimeout(() => {
|
|
308
367
|
this.press = void 0;
|
|
309
368
|
this.longPressed = true;
|
|
310
|
-
this.
|
|
369
|
+
this.focused = swatch;
|
|
311
370
|
this.menu = {
|
|
312
|
-
|
|
371
|
+
...swatch,
|
|
313
372
|
x,
|
|
314
373
|
y
|
|
315
374
|
};
|
|
@@ -330,26 +389,28 @@ var PcPanelColours = class extends PcPanel {
|
|
|
330
389
|
* Move between saved colours, ask to delete one, or open its menu, with the keyboard. Keys used here don't reach the
|
|
331
390
|
* keyboard shortcuts (e.g. Delete doesn't also delete the masked image data).
|
|
332
391
|
*/
|
|
333
|
-
onSwatchKeyDown(event,
|
|
334
|
-
|
|
392
|
+
onSwatchKeyDown(event, swatch) {
|
|
393
|
+
const { palette, index } = swatch;
|
|
394
|
+
const editable = isEditable(swatch);
|
|
395
|
+
if (editable && (event.key === "Delete" || event.key === "Backspace")) {
|
|
335
396
|
event.preventDefault();
|
|
336
397
|
event.stopPropagation();
|
|
337
|
-
this.confirming =
|
|
398
|
+
this.confirming = swatch;
|
|
338
399
|
return;
|
|
339
400
|
}
|
|
340
|
-
if (event.key === "ContextMenu" || event.shiftKey && event.key === "F10") {
|
|
401
|
+
if (editable && (event.key === "ContextMenu" || event.shiftKey && event.key === "F10")) {
|
|
341
402
|
event.preventDefault();
|
|
342
403
|
event.stopPropagation();
|
|
343
404
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
344
405
|
this.menu = {
|
|
345
|
-
|
|
406
|
+
...swatch,
|
|
346
407
|
x: rect.left,
|
|
347
408
|
y: rect.bottom
|
|
348
409
|
};
|
|
349
410
|
return;
|
|
350
411
|
}
|
|
351
|
-
const last = this.
|
|
352
|
-
const columns = this.columns();
|
|
412
|
+
const last = this.coloursOf(palette).length - 1;
|
|
413
|
+
const columns = this.columns(palette);
|
|
353
414
|
const next = {
|
|
354
415
|
ArrowRight: index + 1,
|
|
355
416
|
ArrowLeft: index - 1,
|
|
@@ -361,34 +422,85 @@ var PcPanelColours = class extends PcPanel {
|
|
|
361
422
|
if (next === void 0 || next < 0 || next > last) return;
|
|
362
423
|
event.preventDefault();
|
|
363
424
|
event.stopPropagation();
|
|
364
|
-
this.focusSwatch(
|
|
425
|
+
this.focusSwatch({
|
|
426
|
+
palette,
|
|
427
|
+
index: next
|
|
428
|
+
});
|
|
365
429
|
}
|
|
366
|
-
/** How many saved colours fit in a row */
|
|
367
|
-
columns() {
|
|
368
|
-
const grid = this.renderRoot.querySelector(
|
|
430
|
+
/** How many saved colours fit in a row of a palette */
|
|
431
|
+
columns(palette) {
|
|
432
|
+
const grid = this.renderRoot.querySelector(`.swatches[data-palette="${palette}"]`);
|
|
369
433
|
const width = grid.querySelector(".swatch").offsetWidth;
|
|
370
434
|
return width > 0 ? Math.max(1, Math.floor(grid.clientWidth / width)) : 1;
|
|
371
435
|
}
|
|
372
436
|
/** Focus a saved colour */
|
|
373
|
-
async focusSwatch(
|
|
374
|
-
this.
|
|
437
|
+
async focusSwatch(swatch) {
|
|
438
|
+
this.focused = swatch;
|
|
375
439
|
this.requestUpdate();
|
|
376
440
|
await this.updateComplete;
|
|
377
|
-
this.renderRoot.querySelector(`.swatch[data-index="${index}"]`)?.focus();
|
|
441
|
+
this.renderRoot.querySelector(`.swatches[data-palette="${swatch.palette}"] .swatch[data-index="${swatch.index}"]`)?.focus();
|
|
378
442
|
}
|
|
379
|
-
/** Save the selected colour */
|
|
380
|
-
onAdd() {
|
|
381
|
-
this.app?.
|
|
443
|
+
/** Save the selected colour in one of the user's palettes */
|
|
444
|
+
onAdd(palette) {
|
|
445
|
+
this.app?.palettes.addColour(palette, this.colour);
|
|
382
446
|
}
|
|
383
447
|
/** Delete the saved colour that was asked about, if confirmed */
|
|
384
448
|
onConfirm(event) {
|
|
385
449
|
event.stopPropagation();
|
|
386
|
-
const
|
|
450
|
+
const swatch = this.confirming;
|
|
387
451
|
this.confirming = void 0;
|
|
388
|
-
const
|
|
389
|
-
if (event.detail.value === DELETE_CHOICE) palette.
|
|
390
|
-
const count = palette.
|
|
391
|
-
if (count > 0) this.focusSwatch(
|
|
452
|
+
const app = this.app;
|
|
453
|
+
if (event.detail.value === DELETE_CHOICE) app.palettes.removeColour(swatch.palette, swatch.index);
|
|
454
|
+
const count = this.coloursOf(swatch.palette).length;
|
|
455
|
+
if (count > 0) this.focusSwatch({
|
|
456
|
+
palette: swatch.palette,
|
|
457
|
+
index: Math.min(swatch.index, count - 1)
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Make a palette, asking for its name. The user is its author (see `PaintCanvas.author`).
|
|
462
|
+
*/
|
|
463
|
+
async createPalette() {
|
|
464
|
+
const app = this.app;
|
|
465
|
+
if (!app) return void 0;
|
|
466
|
+
const name = await this.prompt({
|
|
467
|
+
heading: this.t("paintCanvas.palette.newPaletteHeading"),
|
|
468
|
+
label: this.t("paintCanvas.palette.name"),
|
|
469
|
+
value: this.t("paintCanvas.palette.defaultName"),
|
|
470
|
+
confirm: this.t("paintCanvas.common.save"),
|
|
471
|
+
cancel: this.t("paintCanvas.common.cancel")
|
|
472
|
+
});
|
|
473
|
+
return name === null ? void 0 : app.palettes.create(name, [], app.author);
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Do one of a palette's menu actions: rename it (asking for a name), export it, or delete it (asking first).
|
|
477
|
+
*/
|
|
478
|
+
async actOnPalette(id, action) {
|
|
479
|
+
const app = this.app;
|
|
480
|
+
const palette = app?.palettes.get(id);
|
|
481
|
+
if (!app || !palette) return;
|
|
482
|
+
if (action === "export") {
|
|
483
|
+
await this.exportFile([palette]);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (action === "rename") {
|
|
487
|
+
const name = await this.prompt({
|
|
488
|
+
heading: this.t("paintCanvas.palette.renameHeading"),
|
|
489
|
+
label: this.t("paintCanvas.palette.name"),
|
|
490
|
+
value: palette.name,
|
|
491
|
+
confirm: this.t("paintCanvas.common.save"),
|
|
492
|
+
cancel: this.t("paintCanvas.common.cancel")
|
|
493
|
+
});
|
|
494
|
+
if (name !== null) app.palettes.rename(id, name);
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
if (await this.confirm({
|
|
498
|
+
heading: this.t("paintCanvas.palette.deletePaletteHeading"),
|
|
499
|
+
message: this.t("paintCanvas.palette.deletePaletteConfirm", { name: palette.name }),
|
|
500
|
+
confirm: this.t("paintCanvas.common.delete"),
|
|
501
|
+
cancel: this.t("paintCanvas.common.cancel"),
|
|
502
|
+
cancelling: true
|
|
503
|
+
})) app.palettes.remove(id);
|
|
392
504
|
}
|
|
393
505
|
/** Close the palette with Escape (unless a dialog or menu is open, which closes first) */
|
|
394
506
|
onKeyDown(event) {
|
|
@@ -398,51 +510,40 @@ var PcPanelColours = class extends PcPanel {
|
|
|
398
510
|
this.app?.closePanel();
|
|
399
511
|
}
|
|
400
512
|
/**
|
|
401
|
-
* Import the
|
|
513
|
+
* Import the palettes in a colour palette file as the user's own, replacing ones with the same IDs.
|
|
402
514
|
*/
|
|
403
515
|
async importFile(file) {
|
|
404
516
|
const app = this.app;
|
|
405
517
|
if (!app) return;
|
|
406
|
-
let text;
|
|
407
|
-
try {
|
|
408
|
-
text = await file.text();
|
|
409
|
-
} catch {
|
|
410
|
-
this.toastError(PALETTE_FILE_ERRORS.read);
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
518
|
try {
|
|
414
|
-
const
|
|
415
|
-
const count = app.
|
|
519
|
+
const palettes = colourPaletteFile.parse(await file.text());
|
|
520
|
+
const count = app.palettes.merge(palettes);
|
|
416
521
|
emit(this, "pc-toast", {
|
|
417
522
|
message: this.t("paintCanvas.palette.imported", { count }),
|
|
418
523
|
kind: "success"
|
|
419
524
|
});
|
|
420
525
|
} catch (error) {
|
|
421
|
-
this
|
|
526
|
+
emit(this, "pc-toast", {
|
|
527
|
+
message: this.t(importErrorKey(error)),
|
|
528
|
+
kind: "error"
|
|
529
|
+
});
|
|
422
530
|
}
|
|
423
531
|
}
|
|
424
532
|
/**
|
|
425
|
-
* Export the
|
|
533
|
+
* Export palettes (the user's own by default) as a colour palette file, or say there are none.
|
|
426
534
|
*/
|
|
427
|
-
async exportFile() {
|
|
535
|
+
async exportFile(palettes = this.app?.palettes.items ?? []) {
|
|
428
536
|
const app = this.app;
|
|
429
537
|
if (!app) return;
|
|
430
538
|
try {
|
|
431
|
-
await this.saveFile(new Blob([
|
|
432
|
-
} catch {
|
|
539
|
+
await this.saveFile(new Blob([colourPaletteFile.write(palettes)], { type: "application/json" }), colourPaletteFile.fileName(void 0, app.names.filePrefix));
|
|
540
|
+
} catch (error) {
|
|
433
541
|
emit(this, "pc-toast", {
|
|
434
|
-
message: this.t("paintCanvas.palette.exportFailed"),
|
|
542
|
+
message: this.t(error instanceof AssetFileError && error.reason === "empty" ? "paintCanvas.palette.nothingToExport" : "paintCanvas.palette.exportFailed"),
|
|
435
543
|
kind: "error"
|
|
436
544
|
});
|
|
437
545
|
}
|
|
438
546
|
}
|
|
439
|
-
/** Show a palette file error (one of `PALETTE_FILE_ERRORS`) in the chosen language */
|
|
440
|
-
toastError(message) {
|
|
441
|
-
emit(this, "pc-toast", {
|
|
442
|
-
message: this.t(PALETTE_FILE_ERROR_KEYS[message]),
|
|
443
|
-
kind: "error"
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
547
|
/** The colour model tabs and the selected model's sliders */
|
|
447
548
|
renderChannels() {
|
|
448
549
|
const rgb = hexToRgb(this.colour);
|
|
@@ -499,44 +600,71 @@ var PcPanelColours = class extends PcPanel {
|
|
|
499
600
|
</div>
|
|
500
601
|
</div>`;
|
|
501
602
|
}
|
|
502
|
-
/**
|
|
503
|
-
|
|
504
|
-
const colours =
|
|
603
|
+
/** A palette: its name (and the ⋮ menu of the user's own), its colours and its [+] button */
|
|
604
|
+
renderPalette(palette) {
|
|
605
|
+
const { colours, id } = palette;
|
|
505
606
|
const canAdd = !colours.includes(this.colour) && colours.length < 1e3;
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
607
|
+
const focused = this.focused.palette === id ? this.focused.index : 0;
|
|
608
|
+
const add = this.t("paintCanvas.palette.add", {
|
|
609
|
+
colour: this.colour,
|
|
610
|
+
name: palette.name
|
|
611
|
+
});
|
|
612
|
+
const menu = PALETTE_ACTIONS.map((action) => ({
|
|
613
|
+
value: action,
|
|
614
|
+
label: this.t(`paintCanvas.palette.${action}Palette`),
|
|
615
|
+
danger: action === "delete"
|
|
616
|
+
}));
|
|
617
|
+
return html`<section class="palette-group" data-palette=${id}>
|
|
618
|
+
<div class="palette-heading">
|
|
619
|
+
<h3 id="palette-${id}">${palette.name}</h3>
|
|
620
|
+
${palette.own ? html`<pc-context-menu
|
|
621
|
+
label=${this.t("paintCanvas.palette.paletteActions", { name: palette.name })}
|
|
622
|
+
.items=${menu}
|
|
623
|
+
@pc-select=${(event) => void this.actOnPalette(id, event.detail.value)}
|
|
624
|
+
></pc-context-menu>` : nothing}
|
|
625
|
+
</div>
|
|
626
|
+
<div
|
|
627
|
+
class="swatches"
|
|
628
|
+
data-palette=${id}
|
|
629
|
+
role="group"
|
|
630
|
+
aria-labelledby="palette-${id}"
|
|
631
|
+
>
|
|
632
|
+
${colours.map((colour, index) => {
|
|
633
|
+
const swatch = {
|
|
634
|
+
palette: id,
|
|
635
|
+
index
|
|
636
|
+
};
|
|
637
|
+
return html`<button
|
|
512
638
|
type="button"
|
|
513
639
|
class="swatch"
|
|
514
640
|
data-index=${index}
|
|
515
641
|
style="--colour: ${colour}"
|
|
516
642
|
title=${colour}
|
|
517
643
|
aria-label=${colour}
|
|
518
|
-
aria-haspopup
|
|
644
|
+
aria-haspopup=${palette.own ? "menu" : nothing}
|
|
519
645
|
aria-pressed=${colour === this.colour}
|
|
520
|
-
tabindex=${index ===
|
|
521
|
-
@click=${(e) => this.onSwatchClick(e,
|
|
522
|
-
@contextmenu=${(e) => this.onSwatchContextMenu(e,
|
|
523
|
-
@pointerdown=${(e) => this.onSwatchPointerDown(e,
|
|
646
|
+
tabindex=${index === focused ? 0 : -1}
|
|
647
|
+
@click=${(e) => this.onSwatchClick(e, swatch)}
|
|
648
|
+
@contextmenu=${(e) => this.onSwatchContextMenu(e, swatch)}
|
|
649
|
+
@pointerdown=${(e) => this.onSwatchPointerDown(e, swatch)}
|
|
524
650
|
@pointermove=${this.onSwatchPointerMove}
|
|
525
651
|
@pointerup=${this.cancelPress}
|
|
526
652
|
@pointercancel=${this.cancelPress}
|
|
527
|
-
@keydown=${(e) => this.onSwatchKeyDown(e,
|
|
528
|
-
></button
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
653
|
+
@keydown=${(e) => this.onSwatchKeyDown(e, swatch)}
|
|
654
|
+
></button>`;
|
|
655
|
+
})}
|
|
656
|
+
${palette.own ? html`<button
|
|
657
|
+
type="button"
|
|
658
|
+
class="add"
|
|
659
|
+
title=${add}
|
|
660
|
+
aria-label=${add}
|
|
661
|
+
?disabled=${!canAdd}
|
|
662
|
+
@click=${() => this.onAdd(id)}
|
|
663
|
+
>
|
|
664
|
+
+
|
|
665
|
+
</button>` : nothing}
|
|
666
|
+
</div>
|
|
667
|
+
</section>`;
|
|
540
668
|
}
|
|
541
669
|
/** The saved colour's menu, while open */
|
|
542
670
|
renderMenu() {
|
|
@@ -551,12 +679,18 @@ var PcPanelColours = class extends PcPanel {
|
|
|
551
679
|
open
|
|
552
680
|
.x=${menu.x}
|
|
553
681
|
.y=${menu.y}
|
|
554
|
-
label=${this.t("paintCanvas.palette.colourActions", { colour: this.
|
|
682
|
+
label=${this.t("paintCanvas.palette.colourActions", { colour: this.colourAt(menu) })}
|
|
555
683
|
.items=${items}
|
|
556
|
-
@pc-select=${() => this.confirming =
|
|
684
|
+
@pc-select=${() => this.confirming = {
|
|
685
|
+
palette: menu.palette,
|
|
686
|
+
index: menu.index
|
|
687
|
+
}}
|
|
557
688
|
@pc-close=${() => {
|
|
558
689
|
this.menu = void 0;
|
|
559
|
-
if (this.confirming === void 0) this.focusSwatch(
|
|
690
|
+
if (this.confirming === void 0) this.focusSwatch({
|
|
691
|
+
palette: menu.palette,
|
|
692
|
+
index: menu.index
|
|
693
|
+
});
|
|
560
694
|
}}
|
|
561
695
|
></pc-menu>`;
|
|
562
696
|
}
|
|
@@ -609,8 +743,21 @@ var PcPanelColours = class extends PcPanel {
|
|
|
609
743
|
</div>
|
|
610
744
|
${this.renderChannels()}
|
|
611
745
|
</div>
|
|
612
|
-
|
|
746
|
+
<div
|
|
747
|
+
class="palettes"
|
|
748
|
+
role="group"
|
|
749
|
+
aria-label=${this.t("paintCanvas.palette.saved")}
|
|
750
|
+
>
|
|
751
|
+
${this.shown().map((palette) => this.renderPalette(palette))}
|
|
752
|
+
</div>
|
|
613
753
|
<div class="actions">
|
|
754
|
+
<button
|
|
755
|
+
type="button"
|
|
756
|
+
class="pill-s new-palette"
|
|
757
|
+
@click=${() => void this.createPalette()}
|
|
758
|
+
>
|
|
759
|
+
${this.t("paintCanvas.palette.newPalette")}
|
|
760
|
+
</button>
|
|
614
761
|
<button
|
|
615
762
|
type="button"
|
|
616
763
|
class="pill-s import"
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/ui/elements/PcPanelColours/style.css?inline
|
|
2
|
-
var style_default = ".palette {\n display: flex;\n flex-direction: column;\n gap: var(--pc-space-2);\n}\n\n/* The colours and their hex value beside the colour model's sliders */\n.top {\n display: flex;\n gap: var(--pc-space-2);\n}\n.current {\n display: flex;\n flex: none;\n flex-direction: column;\n width: 76px;\n border: 1px solid var(--pc-border);\n}\n.current pc-colour-pair {\n --pc-colour-pair-size: 76px;\n}\n.hex {\n box-sizing: border-box;\n width: 100%;\n min-height: var(--pc-control-size);\n padding: var(--pc-space-1);\n border: 0;\n border-top: 1px solid var(--pc-border);\n background: var(--pc-surface);\n color: var(--pc-text);\n font: inherit;\n font-size: var(--pc-font-size-small);\n text-align: center;\n font-variant-numeric: tabular-nums;\n}\n.hex[aria-invalid=\"true\"] {\n outline: 2px solid var(--pc-dismiss-text);\n outline-offset: -2px;\n}\n.hex:focus-visible {\n outline: var(--pc-focus-width) solid var(--pc-focus);\n outline-offset: -3px;\n}\n\n.channels {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-width: 0;\n border: 1px solid var(--pc-border);\n}\n[role=\"tablist\"] {\n display: flex;\n}\n[role=\"tab\"] {\n flex: 1;\n min-height: 28px;\n border: 0;\n border-bottom: 1px solid var(--pc-border);\n background: var(--pc-surface-active);\n color: var(--pc-text);\n font: inherit;\n cursor: pointer;\n}\n[role=\"tab\"] + [role=\"tab\"] {\n border-left: 1px solid var(--pc-border);\n}\n[role=\"tab\"][aria-selected=\"true\"] {\n border-bottom-color: transparent;\n background: var(--pc-surface);\n font-weight: bold;\n}\n[role=\"tab\"]:focus-visible {\n outline: var(--pc-focus-width) solid var(--pc-focus);\n outline-offset: -3px;\n}\n.sliders {\n display: grid;\n flex: 1;\n grid-template-columns: auto minmax(0, 1fr) 3.6em;\n gap: var(--pc-space-1);\n align-items: center;\n padding: var(--pc-space-1) var(--pc-space-2);\n background: var(--pc-surface);\n}\n.letter {\n font-weight: bold;\n}\n/* Each slider's track shows the colours its values give (--track, set per slider), under a round white handle with a\n dark outline that shows on any colour */\n.sliders input[type=\"range\"] {\n width: 100%;\n min-width: 0;\n height: 20px;\n margin: 0;\n background: transparent;\n appearance: none;\n -webkit-appearance: none;\n cursor: pointer;\n}\n.sliders input[type=\"range\"]::-webkit-slider-runnable-track {\n height: 10px;\n border: 1px solid var(--pc-border);\n border-radius: var(--pc-radius-pill);\n background: var(--track);\n}\n.sliders input[type=\"range\"]::-moz-range-track {\n height: 10px;\n border: 1px solid var(--pc-border);\n border-radius: var(--pc-radius-pill);\n background: var(--track);\n}\n.sliders input[type=\"range\"]::-webkit-slider-thumb {\n width: 16px;\n height: 16px;\n margin-top: -4px;\n border: 2px solid #000000;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 0 0 1px #ffffff;\n -webkit-appearance: none;\n}\n.sliders input[type=\"range\"]::-moz-range-thumb {\n box-sizing: border-box;\n width: 16px;\n height: 16px;\n border: 2px solid #000000;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 0 0 1px #ffffff;\n}\n.sliders input[type=\"number\"] {\n box-sizing: border-box;\n width: 100%;\n padding: 2px var(--pc-space-1);\n border: 1px solid var(--pc-border);\n background: var(--pc-surface);\n color: var(--pc-text);\n font: inherit;\n font-size: var(--pc-font-size-small);\n font-variant-numeric: tabular-nums;\n}\n.sliders input:focus-visible {\n outline: var(--pc-focus-width) solid var(--pc-focus);\n outline-offset: 1px;\n}\n\n/*
|
|
2
|
+
var style_default = ".palette {\n display: flex;\n flex-direction: column;\n gap: var(--pc-space-2);\n}\n\n/* The colours and their hex value beside the colour model's sliders */\n.top {\n display: flex;\n gap: var(--pc-space-2);\n}\n.current {\n display: flex;\n flex: none;\n flex-direction: column;\n width: 76px;\n border: 1px solid var(--pc-border);\n}\n.current pc-colour-pair {\n --pc-colour-pair-size: 76px;\n}\n.hex {\n box-sizing: border-box;\n width: 100%;\n min-height: var(--pc-control-size);\n padding: var(--pc-space-1);\n border: 0;\n border-top: 1px solid var(--pc-border);\n background: var(--pc-surface);\n color: var(--pc-text);\n font: inherit;\n font-size: var(--pc-font-size-small);\n text-align: center;\n font-variant-numeric: tabular-nums;\n}\n.hex[aria-invalid=\"true\"] {\n outline: 2px solid var(--pc-dismiss-text);\n outline-offset: -2px;\n}\n.hex:focus-visible {\n outline: var(--pc-focus-width) solid var(--pc-focus);\n outline-offset: -3px;\n}\n\n.channels {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-width: 0;\n border: 1px solid var(--pc-border);\n}\n[role=\"tablist\"] {\n display: flex;\n}\n[role=\"tab\"] {\n flex: 1;\n min-height: 28px;\n border: 0;\n border-bottom: 1px solid var(--pc-border);\n background: var(--pc-surface-active);\n color: var(--pc-text);\n font: inherit;\n cursor: pointer;\n}\n[role=\"tab\"] + [role=\"tab\"] {\n border-left: 1px solid var(--pc-border);\n}\n[role=\"tab\"][aria-selected=\"true\"] {\n border-bottom-color: transparent;\n background: var(--pc-surface);\n font-weight: bold;\n}\n[role=\"tab\"]:focus-visible {\n outline: var(--pc-focus-width) solid var(--pc-focus);\n outline-offset: -3px;\n}\n.sliders {\n display: grid;\n flex: 1;\n grid-template-columns: auto minmax(0, 1fr) 3.6em;\n gap: var(--pc-space-1);\n align-items: center;\n padding: var(--pc-space-1) var(--pc-space-2);\n background: var(--pc-surface);\n}\n.letter {\n font-weight: bold;\n}\n/* Each slider's track shows the colours its values give (--track, set per slider), under a round white handle with a\n dark outline that shows on any colour */\n.sliders input[type=\"range\"] {\n width: 100%;\n min-width: 0;\n height: 20px;\n margin: 0;\n background: transparent;\n appearance: none;\n -webkit-appearance: none;\n cursor: pointer;\n}\n.sliders input[type=\"range\"]::-webkit-slider-runnable-track {\n height: 10px;\n border: 1px solid var(--pc-border);\n border-radius: var(--pc-radius-pill);\n background: var(--track);\n}\n.sliders input[type=\"range\"]::-moz-range-track {\n height: 10px;\n border: 1px solid var(--pc-border);\n border-radius: var(--pc-radius-pill);\n background: var(--track);\n}\n.sliders input[type=\"range\"]::-webkit-slider-thumb {\n width: 16px;\n height: 16px;\n margin-top: -4px;\n border: 2px solid #000000;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 0 0 1px #ffffff;\n -webkit-appearance: none;\n}\n.sliders input[type=\"range\"]::-moz-range-thumb {\n box-sizing: border-box;\n width: 16px;\n height: 16px;\n border: 2px solid #000000;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 0 0 1px #ffffff;\n}\n.sliders input[type=\"number\"] {\n box-sizing: border-box;\n width: 100%;\n padding: 2px var(--pc-space-1);\n border: 1px solid var(--pc-border);\n background: var(--pc-surface);\n color: var(--pc-text);\n font: inherit;\n font-size: var(--pc-font-size-small);\n font-variant-numeric: tabular-nums;\n}\n.sliders input:focus-visible {\n outline: var(--pc-focus-width) solid var(--pc-focus);\n outline-offset: 1px;\n}\n\n/* The palettes, the user's own above PaintCanvas's, scrolling together */\n.palettes {\n display: flex;\n flex-direction: column;\n gap: var(--pc-space-2);\n max-height: 264px;\n overflow-y: auto;\n}\n.palette-heading {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--pc-space-1);\n min-height: var(--pc-control-size);\n}\n.palette-heading h3 {\n overflow: hidden;\n margin: 0;\n font-size: var(--pc-font-size-small);\n font-weight: 600;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* A palette's colours: square swatches in a grid */\n.swatches {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(32px, 1fr));\n align-content: start;\n border: 1px solid var(--pc-border);\n background: var(--pc-bar);\n}\n.swatch,\n.add {\n aspect-ratio: 1;\n min-width: 32px;\n padding: 0;\n border: 0;\n border-right: 1px solid var(--pc-border);\n border-bottom: 1px solid var(--pc-border);\n cursor: pointer;\n}\n.swatch {\n background: var(--colour);\n /* Long presses open the colour's menu instead of the browser's */\n -webkit-touch-callout: none;\n touch-action: manipulation;\n}\n.swatch[aria-pressed=\"true\"] {\n box-shadow:\n inset 0 0 0 2px #ffffff,\n inset 0 0 0 3px #000000;\n}\n:host([deleting]) .swatch {\n cursor: var(--pc-delete-cursor);\n}\n.add {\n background: var(--pc-surface);\n color: var(--pc-text);\n font: inherit;\n font-size: 20px;\n font-weight: bold;\n}\n.add:hover:not(:disabled) {\n background: var(--pc-surface-hover);\n}\n.add:disabled {\n color: var(--pc-disabled);\n cursor: default;\n}\n.swatch:focus-visible,\n.add:focus-visible {\n position: relative;\n z-index: 1;\n outline: var(--pc-focus-width) solid var(--pc-focus);\n outline-offset: -3px;\n}\n\n.actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--pc-space-2);\n}\n/* New palette has a row of its own, above Import and Export */\n.actions button.pill-s {\n flex: 1;\n}\n.actions button.new-palette {\n flex-basis: 100%;\n}\n";
|
|
3
3
|
export { style_default as default };
|
|
@@ -16,10 +16,12 @@ export declare const COLOUR_INTERVAL_MS = 100;
|
|
|
16
16
|
export declare const formatBytes: (bytes: number, locale?: string) => string;
|
|
17
17
|
/**
|
|
18
18
|
* A line of small text about the canvas: its size; while the drawing is kept in the browser, how much its layer
|
|
19
|
-
* images take there; the zoom level;
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* images take there; the zoom level; the colour under the pointer (with a swatch; a dash when the pointer isn't over the
|
|
20
|
+
* canvas); and, on the right, while the drawing is being saved to a remote store (see
|
|
21
|
+
* `PaintCanvas.useRemoteDocumentStore`), a progress bar, or that saving there failed. The colour follows the pointer
|
|
22
|
+
* at most every `COLOUR_INTERVAL_MS`, and isn't read while a stroke is drawn (the next pointer move after it reads it).
|
|
23
|
+
* It's not announced to screen readers as it changes, as it changes with every pointer move; saving to the remote store
|
|
24
|
+
* is.
|
|
23
25
|
*
|
|
24
26
|
* @example
|
|
25
27
|
* html`<pc-stats .app=${app}></pc-stats>`
|
|
@@ -66,4 +68,6 @@ export declare class PcStats extends PcElement {
|
|
|
66
68
|
*/
|
|
67
69
|
private follow;
|
|
68
70
|
render(): import("lit").TemplateResult<1> | typeof nothing;
|
|
71
|
+
/** Saving to the remote store, while under way or after it failed */
|
|
72
|
+
private renderRemote;
|
|
69
73
|
}
|