@lvl99dotcom/paintcanvas 0.6.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 +3 -2
- 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 +124 -28
- package/dist/lib/classes/PaintCanvas/index.js +228 -63
- 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/classes/UiSettings/index.d.ts +24 -2
- package/dist/lib/classes/UiSettings/index.js +32 -7
- 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 +202 -77
- package/dist/lib/settings/schema.js +93 -86
- package/dist/lib/storage/index.d.ts +108 -3
- package/dist/lib/storage/index.js +119 -5
- package/dist/lib/validation/validators.generated.d.ts +19 -8
- package/dist/lib/validation/validators.generated.js +44723 -18889
- package/dist/lib/version/index.d.ts +25 -0
- package/dist/lib/version/index.js +35 -0
- package/dist/locales/en-GB.js +28 -5
- package/dist/locales/en-US.js +28 -5
- package/dist/locales/fr.js +28 -5
- package/dist/locales/ja.js +28 -5
- package/dist/locales/ko.js +28 -5
- package/dist/locales/zh-Hans.js +28 -5
- package/dist/locales/zh-Hant.js +28 -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 +19 -5
- package/dist/ui/elements/PaintCanvas/index.js +41 -10
- package/dist/ui/elements/PcAppSettings/index.d.ts +14 -7
- package/dist/ui/elements/PcAppSettings/index.js +58 -33
- package/dist/ui/elements/PcBrushConfig/index.d.ts +1 -0
- package/dist/ui/elements/PcBrushConfig/index.js +8 -9
- package/dist/ui/elements/PcBrushTest/index.d.ts +1 -0
- package/dist/ui/elements/PcBrushTest/index.js +8 -7
- package/dist/ui/elements/PcBrushTest/style.js +1 -1
- package/dist/ui/elements/PcButtonMenu/index.d.ts +88 -0
- package/dist/ui/elements/PcButtonMenu/index.js +125 -0
- package/dist/ui/elements/PcCanvas/index.d.ts +9 -0
- package/dist/ui/elements/PcCanvas/index.js +33 -17
- package/dist/ui/elements/PcClipboardTools/index.d.ts +7 -4
- package/dist/ui/elements/PcClipboardTools/index.js +20 -26
- package/dist/ui/elements/PcInputSettings/index.d.ts +2 -1
- package/dist/ui/elements/PcInputSettings/index.js +9 -15
- package/dist/ui/elements/PcLayerItem/index.d.ts +21 -6
- package/dist/ui/elements/PcLayerItem/index.js +53 -26
- package/dist/ui/elements/PcLayerItem/style.js +1 -1
- 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/PcSliderRange/index.js +3 -2
- package/dist/ui/elements/PcStats/index.d.ts +8 -4
- package/dist/ui/elements/PcStats/index.js +39 -5
- package/dist/ui/elements/PcToggleCheckbox/index.d.ts +13 -2
- package/dist/ui/elements/PcToggleCheckbox/index.js +27 -8
- package/dist/ui/elements/PcToolSettings/index.d.ts +1 -0
- package/dist/ui/elements/PcToolSettings/index.js +8 -8
- package/dist/ui/elements/PcVersion/index.d.ts +12 -0
- package/dist/ui/elements/PcVersion/index.js +43 -0
- package/dist/ui/index.d.ts +3 -1
- package/dist/ui/index.js +4 -2
- package/dist/ui/layout/index.d.ts +2 -2
- package/dist/ui/layout/index.js +2 -2
- package/locales/en-GB.json +28 -5
- package/locales/en-US.json +28 -5
- package/locales/fr.json +28 -5
- package/locales/ja.json +28 -5
- package/locales/ko.json +28 -5
- package/locales/zh-Hans.json +28 -5
- package/locales/zh-Hant.json +28 -5
- package/package.json +3 -2
|
@@ -5,8 +5,11 @@ import ChangeController from "../../ChangeController/index.js";
|
|
|
5
5
|
import { BlendMode } from "../../../lib/classes/Layer/index.js";
|
|
6
6
|
import { drawCheckerboard, fitSize } from "../../../lib/rendering/checkerboard/index.js";
|
|
7
7
|
import { CANCEL_CHOICE } from "../PcDialog/index.js";
|
|
8
|
+
import "../PcSliderRange/index.js";
|
|
9
|
+
import { askText } from "../../ask/index.js";
|
|
8
10
|
import { MENU_MARGIN, menuTop } from "../PcContextMenu/index.js";
|
|
9
11
|
import { html, nothing, unsafeCSS } from "lit";
|
|
12
|
+
import { live } from "lit/directives/live.js";
|
|
10
13
|
// src/ui/elements/PcLayerItem/index.ts
|
|
11
14
|
/** Blend mode options shown in the layer's select input */
|
|
12
15
|
var BLEND_MODE_OPTIONS = [
|
|
@@ -37,6 +40,10 @@ var BLEND_MODE_OPTIONS = [
|
|
|
37
40
|
];
|
|
38
41
|
/** Context menu options in display order, with the translation keys of their labels */
|
|
39
42
|
var LAYER_ACTIONS = [
|
|
43
|
+
{
|
|
44
|
+
action: "rename",
|
|
45
|
+
label: "paintCanvas.layers.rename"
|
|
46
|
+
},
|
|
40
47
|
{
|
|
41
48
|
action: "mask",
|
|
42
49
|
label: "paintCanvas.layers.createMask"
|
|
@@ -129,7 +136,9 @@ var DRAG_THRESHOLD = 4;
|
|
|
129
136
|
/** Event a row dispatches while its layer is dragged by its reorder handle (detail: {@link LayerDragDetail}) */
|
|
130
137
|
var LAYER_DRAG_EVENT = "pc-layer-drag";
|
|
131
138
|
/**
|
|
132
|
-
* One row in the layers menu: reorder handle, thumbnail and name (then opacity and blend mode under them), alpha lock
|
|
139
|
+
* One row in the layers menu: reorder handle, thumbnail and name (then opacity and blend mode under them), alpha lock
|
|
140
|
+
* (padlock) and visibility (eye) icons. Pressing anywhere on the row (its controls too) selects the layer, which is then
|
|
141
|
+
* shown with a purple background (`active`). "Rename…" in the actions menu asks for a new name.
|
|
133
142
|
* Dragging the handle (with mouse, pen or touch) reorders the layer: the row fires {@link LAYER_DRAG_EVENT} and the
|
|
134
143
|
* layers menu shows where it will land. Clicking or tapping the handle, pressing Enter or Space on it, or right-clicking
|
|
135
144
|
* it opens the layer's actions menu (which can also reorder it). Cmd/Ctrl + click on the thumbnail or name (or "Create
|
|
@@ -154,6 +163,10 @@ var PcLayerItem = class extends PcElement {
|
|
|
154
163
|
dropAction: {
|
|
155
164
|
attribute: "drop-action",
|
|
156
165
|
reflect: true
|
|
166
|
+
},
|
|
167
|
+
active: {
|
|
168
|
+
type: Boolean,
|
|
169
|
+
reflect: true
|
|
157
170
|
}
|
|
158
171
|
};
|
|
159
172
|
static styles = [
|
|
@@ -162,6 +175,8 @@ var PcLayerItem = class extends PcElement {
|
|
|
162
175
|
unsafeCSS(style_default),
|
|
163
176
|
unsafeCSS(WINDOWS_CSS)
|
|
164
177
|
];
|
|
178
|
+
/** Asks the user for the layer's new name (replaceable for tests) */
|
|
179
|
+
prompt = (options) => askText(this.renderRoot, options);
|
|
165
180
|
/** The pointer pressed on the reorder handle, where it was pressed, and whether it has started dragging */
|
|
166
181
|
press;
|
|
167
182
|
/** Whether to ignore the next click on the handle (it ended a drag) */
|
|
@@ -173,7 +188,15 @@ var PcLayerItem = class extends PcElement {
|
|
|
173
188
|
super();
|
|
174
189
|
this.menuOpen = false;
|
|
175
190
|
this.dragging = false;
|
|
191
|
+
this.active = false;
|
|
192
|
+
this.addEventListener("click", this.onClick);
|
|
176
193
|
}
|
|
194
|
+
/** Pressing anywhere on the row selects its layer, except in the dialogs it shows (e.g. after deleting it) */
|
|
195
|
+
onClick = (event) => {
|
|
196
|
+
const { stack, layer } = this;
|
|
197
|
+
if (!stack || !layer || !stack.layers.includes(layer)) return;
|
|
198
|
+
if (!event.composedPath().some((target) => target instanceof Element && target.matches("pc-dialog")) && stack.active !== layer) stack.select(layer.id);
|
|
199
|
+
};
|
|
177
200
|
/**
|
|
178
201
|
* Run a context menu action. Merging down, clearing and deleting ask for confirmation first (see `confirmed`).
|
|
179
202
|
*/
|
|
@@ -182,6 +205,9 @@ var PcLayerItem = class extends PcElement {
|
|
|
182
205
|
this.menuOpen = false;
|
|
183
206
|
if (!stack || !layer || !this.canRun(action)) return;
|
|
184
207
|
switch (action) {
|
|
208
|
+
case "rename":
|
|
209
|
+
this.rename(stack, layer);
|
|
210
|
+
break;
|
|
185
211
|
case "mask":
|
|
186
212
|
this.requestMask(layer, {
|
|
187
213
|
shiftKey: false,
|
|
@@ -360,10 +386,9 @@ var PcLayerItem = class extends PcElement {
|
|
|
360
386
|
}));
|
|
361
387
|
}
|
|
362
388
|
/**
|
|
363
|
-
*
|
|
389
|
+
* Cmd/Ctrl + click on the thumbnail or name makes a mask from the layer's alpha (the click also selects the layer).
|
|
364
390
|
*/
|
|
365
|
-
|
|
366
|
-
stack.select(layer.id);
|
|
391
|
+
onDetailsClick(event, layer) {
|
|
367
392
|
if (!event.metaKey && !event.ctrlKey) return;
|
|
368
393
|
const target = event.composedPath()[0];
|
|
369
394
|
if (!(target instanceof Element) || !target.matches(".thumbnail, .name")) return;
|
|
@@ -371,15 +396,21 @@ var PcLayerItem = class extends PcElement {
|
|
|
371
396
|
this.requestMask(layer, event);
|
|
372
397
|
}
|
|
373
398
|
/**
|
|
374
|
-
*
|
|
399
|
+
* Ask for the layer's new name and use it. Cancelling or an empty name leaves the name as it was.
|
|
375
400
|
*/
|
|
376
|
-
|
|
377
|
-
const
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
401
|
+
async rename(stack, layer) {
|
|
402
|
+
const name = (await this.prompt({
|
|
403
|
+
heading: this.t("paintCanvas.layers.renameTitle"),
|
|
404
|
+
label: this.t("paintCanvas.layers.name"),
|
|
405
|
+
value: layer.name,
|
|
406
|
+
confirm: this.t("paintCanvas.common.save"),
|
|
407
|
+
cancel: this.t("paintCanvas.common.cancel")
|
|
408
|
+
}))?.trim();
|
|
409
|
+
if (name && stack.layers.includes(layer)) stack.rename(layer.id, name);
|
|
410
|
+
}
|
|
411
|
+
willUpdate(changed) {
|
|
412
|
+
super.willUpdate(changed);
|
|
413
|
+
this.active = this.layer !== void 0 && this.stack?.active.id === this.layer.id;
|
|
383
414
|
}
|
|
384
415
|
updated() {
|
|
385
416
|
const id = this.layer?.id;
|
|
@@ -434,7 +465,6 @@ var PcLayerItem = class extends PcElement {
|
|
|
434
465
|
render() {
|
|
435
466
|
const { stack, layer } = this;
|
|
436
467
|
if (!stack || !layer) return html``;
|
|
437
|
-
const active = stack.active.id === layer.id;
|
|
438
468
|
return html`
|
|
439
469
|
<pc-context-menu
|
|
440
470
|
class="handle"
|
|
@@ -451,23 +481,20 @@ var PcLayerItem = class extends PcElement {
|
|
|
451
481
|
>
|
|
452
482
|
<div
|
|
453
483
|
class="details"
|
|
454
|
-
@click=${(e) => this.
|
|
484
|
+
@click=${(e) => this.onDetailsClick(e, layer)}
|
|
455
485
|
>
|
|
456
486
|
<canvas class="thumbnail" aria-hidden="true"></canvas>
|
|
457
|
-
<
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
/>
|
|
463
|
-
<input
|
|
464
|
-
type="range"
|
|
487
|
+
<span class="name" title=${layer.name}>${layer.name}</span>
|
|
488
|
+
<pc-slider-range
|
|
489
|
+
single
|
|
490
|
+
class="opacity"
|
|
491
|
+
label=${this.t("paintCanvas.common.opacity")}
|
|
465
492
|
min="0"
|
|
466
493
|
max="100"
|
|
467
|
-
|
|
468
|
-
.value=${
|
|
469
|
-
@change=${(e) => stack.update(layer.id, { opacity:
|
|
470
|
-
|
|
494
|
+
unit="%"
|
|
495
|
+
.value=${live(Math.round(layer.opacity * 100))}
|
|
496
|
+
@pc-change=${(e) => stack.update(layer.id, { opacity: e.detail.value / 100 })}
|
|
497
|
+
></pc-slider-range>
|
|
471
498
|
<select
|
|
472
499
|
aria-label=${this.t("paintCanvas.layers.blendMode")}
|
|
473
500
|
@change=${(e) => stack.update(layer.id, { blendMode: e.target.value })}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/ui/elements/PcLayerItem/style.css?inline
|
|
2
|
-
var style_default = "/* A white row with space around its parts. The middle column can shrink, so the row never grows wider than its panel */\n:host {\n display: grid;\n grid-template-columns: 30px minmax(0, 1fr) 30px 30px;\n align-items: center;\n column-gap: 6px;\n position: relative;\n padding: 6px;\n border: 1px solid var(--pc-surface-active);\n background: var(--pc-surface);\n}\n.name
|
|
2
|
+
var style_default = "/* A white row with space around its parts. The middle column can shrink, so the row never grows wider than its panel */\n:host {\n display: grid;\n grid-template-columns: 30px minmax(0, 1fr) 30px 30px;\n align-items: center;\n column-gap: 6px;\n position: relative;\n padding: 6px;\n border: 1px solid var(--pc-surface-active);\n background: var(--pc-surface);\n}\n/* The selected layer: purple, so it stands out */\n:host([active]) {\n border-color: var(--pc-accent);\n background: var(--pc-accent);\n color: var(--pc-accent-text);\n}\n:host([active]) .name {\n font-weight: bold;\n}\n/* The opacity slider's track and handle in the row's text colour, so they show on purple */\n:host([active]) .opacity {\n --pc-accent: var(--pc-accent-text);\n --pc-border: rgb(255 255 255 / 45%);\n}\n/* The name, on one line (cut short with \"…\"); renamed from the actions menu */\n.name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.thumbnail {\n width: 30px;\n height: 30px;\n}\n/* Thumbnail on the left and name on the right; under them, opacity, then blend mode, each the full width. The blend\n mode never sets its own width: browsers size dropdowns differently (Safari and Firefox as wide as the longest option,\n Chrome as the chosen one), which would otherwise push the row wider than its panel */\n.details {\n display: grid;\n grid-template-columns: 30px minmax(0, 1fr);\n align-items: center;\n gap: 4px 6px;\n min-width: 0;\n}\n.details .opacity,\n.details select {\n grid-column: 1 / -1;\n box-sizing: border-box;\n width: 100%;\n min-width: 0;\n}\n/* The reorder handle drags with mouse, pen or touch (touch drags it rather than scrolling the panel) */\n.handle {\n /* As tall as the row */\n align-self: stretch;\n}\n.handle::part(button) {\n min-width: 0;\n padding: 0;\n cursor: grab;\n touch-action: none;\n}\n/* While dragged: the row floats with the pointer, out of the list (the layers menu places it), and the cursor shows\n what dropping would do (\"+\" duplicates on \"New Layer\") */\n:host([dragging]) {\n position: fixed;\n z-index: 10;\n opacity: 0.9;\n background: Canvas;\n box-shadow: var(--pc-shadow);\n}\n:host([dragging]) .handle::part(button) {\n cursor: grabbing;\n}\n:host([drop-action=\"duplicate\"]) .handle::part(button) {\n cursor: copy;\n}\n:host([drop-action=\"none\"]) .handle::part(button) {\n cursor: no-drop;\n}\n/* Alpha lock and visibility: boxed icon toggles like the settings bar's, darker while on */\n.alpha-lock,\n.visibility {\n width: 30px;\n height: 30px;\n padding: 2px;\n border: 1px solid var(--pc-border);\n border-radius: 4px;\n background: var(--pc-surface);\n cursor: pointer;\n}\n.alpha-lock:hover,\n.visibility:hover {\n background: var(--pc-surface-hover);\n}\n.alpha-lock[aria-pressed=\"true\"],\n.visibility[aria-pressed=\"true\"] {\n background: var(--pc-surface-active);\n}\n.alpha-lock:focus-visible,\n.visibility:focus-visible {\n outline: var(--pc-focus-width) solid var(--pc-focus);\n}\n.alpha-lock img,\n.visibility img {\n display: block;\n width: 24px;\n height: 24px;\n margin: auto;\n}\n";
|
|
3
3
|
export { style_default as default };
|
|
@@ -102,7 +102,7 @@ export declare class PcPanelBrushes extends PcPanel {
|
|
|
102
102
|
*/
|
|
103
103
|
exportFile(): Promise<void>;
|
|
104
104
|
/**
|
|
105
|
-
*
|
|
105
|
+
* The message, in the chosen language, for importing or exporting a preset file failing.
|
|
106
106
|
*/
|
|
107
107
|
private presetFileError;
|
|
108
108
|
/**
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import style_default from "./style.js";
|
|
2
|
-
import { BRUSH_PRESET_FILE_FORMAT } from "../../../lib/presets/schema.js";
|
|
3
2
|
import { NO_TEXT_SELECTION_CSS, PILLS_CSS, WINDOWS_CSS } from "../../styles/index.js";
|
|
4
3
|
import { defineElement } from "../../base/index.js";
|
|
5
4
|
import { PcPanel } from "../PcPanel/index.js";
|
|
@@ -7,19 +6,25 @@ import { askConfirm, deletePresetQuestion } from "../../ask/index.js";
|
|
|
7
6
|
import "../PcBrushSize/index.js";
|
|
8
7
|
import ChangeController from "../../ChangeController/index.js";
|
|
9
8
|
import { groupPresetsByAuthor } from "../../../lib/brushes/authors/index.js";
|
|
10
|
-
import "../../../lib/
|
|
11
|
-
import {
|
|
9
|
+
import { brushPresetFile } from "../../../lib/brushes/presetFile/index.js";
|
|
10
|
+
import { AssetFileError } from "../../../lib/assets/index.js";
|
|
12
11
|
import { DELETE_CURSOR } from "../../../lib/rendering/cursors/index.js";
|
|
13
12
|
import { JSON_FILE_TYPE, saveFile } from "../../../lib/rendering/screenshot/index.js";
|
|
14
13
|
import { html, nothing, unsafeCSS } from "lit";
|
|
15
14
|
import { styleMap } from "lit/directives/style-map.js";
|
|
16
15
|
// src/ui/elements/PcPanelBrushes/index.ts
|
|
17
|
-
/** Translation keys of the preset file
|
|
16
|
+
/** Translation keys of the messages shown when importing or exporting a preset file fails, by reason */
|
|
18
17
|
var PRESET_FILE_ERROR_KEYS = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
import: {
|
|
19
|
+
invalid: "paintCanvas.presets.fileIncompatible",
|
|
20
|
+
unsupported: "paintCanvas.presets.fileUnsupported"
|
|
21
|
+
},
|
|
22
|
+
export: { empty: "paintCanvas.presets.nothingToExport" }
|
|
23
|
+
};
|
|
24
|
+
/** Translation keys of the messages shown when importing or exporting fails for any other reason */
|
|
25
|
+
var PRESET_FILE_FALLBACK_KEYS = {
|
|
26
|
+
import: "paintCanvas.presets.fileReadFailed",
|
|
27
|
+
export: "paintCanvas.presets.exportFailed"
|
|
23
28
|
};
|
|
24
29
|
/** Size the previews of presets without a family are measured against, so a 50px preset fills its tile */
|
|
25
30
|
var UNGROUPED_FULL_SIZE = 50;
|
|
@@ -149,18 +154,8 @@ var PcPanelBrushes = class extends PcPanel {
|
|
|
149
154
|
async importFile(file) {
|
|
150
155
|
const app = this.app;
|
|
151
156
|
if (!app) return;
|
|
152
|
-
let text;
|
|
153
|
-
try {
|
|
154
|
-
text = await file.text();
|
|
155
|
-
} catch {
|
|
156
|
-
this.emit("pc-toast", {
|
|
157
|
-
message: this.presetFileError(void 0, PRESET_FILE_ERRORS.read),
|
|
158
|
-
kind: "error"
|
|
159
|
-
});
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
157
|
try {
|
|
163
|
-
const presets =
|
|
158
|
+
const presets = brushPresetFile.parse(await file.text());
|
|
164
159
|
await app.customPresets.save(...presets);
|
|
165
160
|
this.emit("pc-toast", {
|
|
166
161
|
message: this.t("paintCanvas.presets.imported", { count: presets.length }),
|
|
@@ -168,7 +163,7 @@ var PcPanelBrushes = class extends PcPanel {
|
|
|
168
163
|
});
|
|
169
164
|
} catch (error) {
|
|
170
165
|
this.emit("pc-toast", {
|
|
171
|
-
message: this.presetFileError(error,
|
|
166
|
+
message: this.presetFileError(error, "import"),
|
|
172
167
|
kind: "error"
|
|
173
168
|
});
|
|
174
169
|
}
|
|
@@ -180,22 +175,21 @@ var PcPanelBrushes = class extends PcPanel {
|
|
|
180
175
|
const app = this.app;
|
|
181
176
|
if (!app) return;
|
|
182
177
|
try {
|
|
183
|
-
const json =
|
|
184
|
-
await this.saveFile(new Blob([json], { type: "application/json" }),
|
|
178
|
+
const json = brushPresetFile.write(app.customPresets.presets);
|
|
179
|
+
await this.saveFile(new Blob([json], { type: "application/json" }), brushPresetFile.fileName(void 0, app.names.filePrefix));
|
|
185
180
|
} catch (error) {
|
|
186
181
|
this.emit("pc-toast", {
|
|
187
|
-
message: this.presetFileError(error,
|
|
182
|
+
message: this.presetFileError(error, "export"),
|
|
188
183
|
kind: "error"
|
|
189
184
|
});
|
|
190
185
|
}
|
|
191
186
|
}
|
|
192
187
|
/**
|
|
193
|
-
*
|
|
188
|
+
* The message, in the chosen language, for importing or exporting a preset file failing.
|
|
194
189
|
*/
|
|
195
|
-
presetFileError(error,
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
return key ? this.t(key) : message;
|
|
190
|
+
presetFileError(error, direction) {
|
|
191
|
+
const key = error instanceof AssetFileError && PRESET_FILE_ERROR_KEYS[direction][error.reason] || PRESET_FILE_FALLBACK_KEYS[direction];
|
|
192
|
+
return this.t(key);
|
|
199
193
|
}
|
|
200
194
|
/**
|
|
201
195
|
* A preset group's heading in the chosen language ("My presets" and "Unknown" are translated; author names aren't).
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/ui/elements/PcPanelBrushes/style.css?inline
|
|
2
|
-
var style_default = "/* Narrower than other panels by default (set --pc-panel-width to change it) */\n:host {\n --pc-panel-default-width: 240px;\n}\n/* The current preset on one row: its shape, name and size */\n.current {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 44px;\n padding: 4px 8px;\n border: 1px solid var(--pc-border);\n background: var(--pc-surface);\n}\n.current-shape {\n flex: none;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n background: var(--pc-text);\n}\n.current-shape.image {\n border-radius: 0;\n mask-repeat: no-repeat;\n mask-size: contain;\n mask-position: center;\n}\n.name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.size {\n flex: none;\n align-self: stretch;\n margin: -4px -8px -4px 0;\n border-left: 1px solid var(--pc-border);\n}\n/* The presets scroll, at most 400px tall, or less so the whole menu fits under the settings bar in a shorter window */\n.presets {\n flex: 1 1 auto;\n min-height: 0;\n max-height: min(400px, calc(100vh - 180px));\n overflow-y: auto;\n}\nh3 {\n margin: 4px 0;\n font-size: 14px;\n}\nul {\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n align-content: start;\n margin: 0;\n padding: 0;\n list-style: none;\n border: 1px solid var(--pc-border);\n background: var(--pc-bar);\n}\n:host([deleting]) li button.custom {\n cursor: var(--pc-delete-cursor);\n}\n/* Create, Import and Export side by side */\n.actions {\n display: grid;\n grid-template-columns: repeat(
|
|
2
|
+
var style_default = "/* Narrower than other panels by default (set --pc-panel-width to change it) */\n:host {\n --pc-panel-default-width: 240px;\n}\n/* The current preset on one row: its shape, name and size */\n.current {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 44px;\n padding: 4px 8px;\n border: 1px solid var(--pc-border);\n background: var(--pc-surface);\n}\n.current-shape {\n flex: none;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n background: var(--pc-text);\n}\n.current-shape.image {\n border-radius: 0;\n mask-repeat: no-repeat;\n mask-size: contain;\n mask-position: center;\n}\n.name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.size {\n flex: none;\n align-self: stretch;\n margin: -4px -8px -4px 0;\n border-left: 1px solid var(--pc-border);\n}\n/* The presets scroll, at most 400px tall, or less so the whole menu fits under the settings bar in a shorter window */\n.presets {\n flex: 1 1 auto;\n min-height: 0;\n max-height: min(400px, calc(100vh - 180px));\n overflow-y: auto;\n}\nh3 {\n margin: 4px 0;\n font-size: 14px;\n}\nul {\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n align-content: start;\n margin: 0;\n padding: 0;\n list-style: none;\n border: 1px solid var(--pc-border);\n background: var(--pc-bar);\n}\n:host([deleting]) li button.custom {\n cursor: var(--pc-delete-cursor);\n}\n/* Create, Import and Export side by side */\n.actions {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 6px;\n}\n/* New brush has a row of its own, above Import and Export */\n.actions .new-preset {\n grid-column: 1 / -1;\n}\n.visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\nli button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n aspect-ratio: 1;\n padding: 0;\n border: none;\n border-right: 1px solid var(--pc-border);\n border-bottom: 1px solid var(--pc-border);\n background: var(--pc-bar);\n cursor: pointer;\n}\nli button:hover {\n background: var(--pc-surface-hover);\n}\nli button[aria-pressed=\"true\"] {\n background: var(--pc-surface-active);\n}\n.shape {\n background: var(--pc-text);\n border-radius: 50%;\n}\n.shape.image {\n border-radius: 0;\n mask-repeat: no-repeat;\n mask-size: 100% 100%;\n}\n";
|
|
3
3
|
export { style_default as default };
|
|
@@ -2,9 +2,12 @@ import { nothing, type PropertyValues } from "lit";
|
|
|
2
2
|
import { PcPanel } from "../PcPanel";
|
|
3
3
|
import "../PcColourPair";
|
|
4
4
|
import "../PcMenu";
|
|
5
|
+
import "../PcContextMenu";
|
|
5
6
|
import "../PcDialog";
|
|
6
7
|
import type { default as PaintCanvas } from "../../../lib/classes/PaintCanvas";
|
|
7
8
|
import { type Hsl, type Rgb } from "../../../lib/utils/colour";
|
|
9
|
+
import { type ColourPalette } from "../../../lib/palette";
|
|
10
|
+
import { type ConfirmFn, type PromptFn } from "../../ask";
|
|
8
11
|
import { type SaveMethod } from "../../../lib/rendering/screenshot";
|
|
9
12
|
/** The colour models the sliders can show */
|
|
10
13
|
export type ColourModel = "rgb" | "hsl";
|
|
@@ -21,13 +24,31 @@ export type ColourModel = "rgb" | "hsl";
|
|
|
21
24
|
export declare const channelGradient: (key: string, rgb: Rgb, hsl: Hsl) => string;
|
|
22
25
|
/** How long a touch is held on a saved colour to open its menu (milliseconds) */
|
|
23
26
|
export declare const LONG_PRESS_MS = 500;
|
|
27
|
+
/** A palette shown in the panel: one of the user's own, or the one PaintCanvas comes with */
|
|
28
|
+
interface ShownPalette {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
colours: readonly string[];
|
|
32
|
+
/** Whether it's one of the user's own (which can be renamed, exported and deleted) */
|
|
33
|
+
own: boolean;
|
|
34
|
+
}
|
|
35
|
+
/** A saved colour: its palette's ID and its position */
|
|
36
|
+
interface SwatchRef {
|
|
37
|
+
palette: string;
|
|
38
|
+
index: number;
|
|
39
|
+
}
|
|
40
|
+
/** Actions in a palette's menu */
|
|
41
|
+
declare const PALETTE_ACTIONS: readonly ["rename", "export", "delete"];
|
|
24
42
|
/**
|
|
25
43
|
* The colour palette menu: the foreground and background colours (the selected one is configured), its hex value, RGB
|
|
26
|
-
* and HSL sliders, the
|
|
44
|
+
* and HSL sliders, the colour palettes (the user's own above the one PaintCanvas comes with), and buttons to make a
|
|
45
|
+
* palette and to import and export the user's palettes as a JSON file.
|
|
27
46
|
*
|
|
28
47
|
* - Pressing the foreground or background colour selects it.
|
|
29
|
-
* - Pressing a saved colour sets the selected colour
|
|
30
|
-
*
|
|
48
|
+
* - Pressing a saved colour sets the selected colour (changing it afterwards doesn't change the palette); a palette's [+]
|
|
49
|
+
* saves the selected colour in it. PaintCanvas's palette can't be changed.
|
|
50
|
+
* - Each of the user's palettes has a ⋮ menu to rename, export or delete it (deleting asks first).
|
|
51
|
+
* - 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
|
|
31
52
|
* menu (right-click, a long press on touch screens, or the context menu key), or with Delete or Backspace. Arrow keys,
|
|
32
53
|
* Home and End move between saved colours.
|
|
33
54
|
* - Escape closes it (closes the canvas's open panel).
|
|
@@ -82,19 +103,22 @@ export declare class PcPanelColours extends PcPanel {
|
|
|
82
103
|
/** The hex value being typed, while it differs from the colour */
|
|
83
104
|
hexDraft?: string;
|
|
84
105
|
/** The saved colour whose menu is open, and where */
|
|
85
|
-
menu?: {
|
|
86
|
-
index: number;
|
|
106
|
+
menu?: SwatchRef & {
|
|
87
107
|
x: number;
|
|
88
108
|
y: number;
|
|
89
109
|
};
|
|
90
110
|
/** The saved colour being deleted, while asking */
|
|
91
|
-
confirming?:
|
|
111
|
+
confirming?: SwatchRef;
|
|
112
|
+
/** Asks the user to confirm, in a dialog (replaceable for tests) */
|
|
113
|
+
confirm: ConfirmFn;
|
|
114
|
+
/** Asks the user for text, in a dialog (replaceable for tests) */
|
|
115
|
+
prompt: PromptFn;
|
|
92
116
|
/** Saves exported files (replaceable for tests) */
|
|
93
117
|
saveFile: (blob: Blob, name: string) => Promise<SaveMethod | undefined>;
|
|
94
118
|
/** The HSL values shown, kept while they give the selected colour (so hue stays put for greys) */
|
|
95
119
|
private hsl;
|
|
96
|
-
/** The saved colour that is reached with Tab (the others with arrow keys) */
|
|
97
|
-
private
|
|
120
|
+
/** The saved colour that is reached with Tab in its palette (the others with arrow keys; other palettes' first) */
|
|
121
|
+
private focused;
|
|
98
122
|
/** A touch being held on a saved colour, until it opens its menu */
|
|
99
123
|
private press?;
|
|
100
124
|
/** Whether a long press opened a menu, so the click that follows is ignored */
|
|
@@ -108,6 +132,12 @@ export declare class PcPanelColours extends PcPanel {
|
|
|
108
132
|
/** The selected colour's value, e.g. `#000000` */
|
|
109
133
|
get colour(): string;
|
|
110
134
|
protected willUpdate(changed: PropertyValues<this>): void;
|
|
135
|
+
/** The palettes shown: the user's own, then the one PaintCanvas comes with (named after the app) */
|
|
136
|
+
shown(): ShownPalette[];
|
|
137
|
+
/** A palette's colours */
|
|
138
|
+
private coloursOf;
|
|
139
|
+
/** The saved colour at a position */
|
|
140
|
+
private colourAt;
|
|
111
141
|
/** Set the selected colour */
|
|
112
142
|
private setColour;
|
|
113
143
|
/** Select the pressed colour */
|
|
@@ -122,9 +152,9 @@ export declare class PcPanelColours extends PcPanel {
|
|
|
122
152
|
private selectModel;
|
|
123
153
|
/** Change one channel of the colour model shown */
|
|
124
154
|
private onChannel;
|
|
125
|
-
/** Set the selected colour from a saved colour, or ask to delete
|
|
155
|
+
/** Set the selected colour from a saved colour, or ask to delete one of the user's with Alt/Option held */
|
|
126
156
|
private onSwatchClick;
|
|
127
|
-
/** Open a
|
|
157
|
+
/** Open the menu of a colour in one of the user's palettes where it was right-clicked */
|
|
128
158
|
private onSwatchContextMenu;
|
|
129
159
|
/** Start waiting for a touch held on a saved colour to open its menu */
|
|
130
160
|
private onSwatchPointerDown;
|
|
@@ -137,30 +167,36 @@ export declare class PcPanelColours extends PcPanel {
|
|
|
137
167
|
* keyboard shortcuts (e.g. Delete doesn't also delete the masked image data).
|
|
138
168
|
*/
|
|
139
169
|
private onSwatchKeyDown;
|
|
140
|
-
/** How many saved colours fit in a row */
|
|
170
|
+
/** How many saved colours fit in a row of a palette */
|
|
141
171
|
private columns;
|
|
142
172
|
/** Focus a saved colour */
|
|
143
173
|
private focusSwatch;
|
|
144
|
-
/** Save the selected colour */
|
|
174
|
+
/** Save the selected colour in one of the user's palettes */
|
|
145
175
|
private onAdd;
|
|
146
176
|
/** Delete the saved colour that was asked about, if confirmed */
|
|
147
177
|
private onConfirm;
|
|
178
|
+
/**
|
|
179
|
+
* Make a palette, asking for its name. The user is its author (see `PaintCanvas.author`).
|
|
180
|
+
*/
|
|
181
|
+
createPalette(): Promise<ColourPalette | undefined>;
|
|
182
|
+
/**
|
|
183
|
+
* Do one of a palette's menu actions: rename it (asking for a name), export it, or delete it (asking first).
|
|
184
|
+
*/
|
|
185
|
+
actOnPalette(id: string, action: (typeof PALETTE_ACTIONS)[number]): Promise<void>;
|
|
148
186
|
/** Close the palette with Escape (unless a dialog or menu is open, which closes first) */
|
|
149
187
|
private onKeyDown;
|
|
150
188
|
/**
|
|
151
|
-
* Import the
|
|
189
|
+
* Import the palettes in a colour palette file as the user's own, replacing ones with the same IDs.
|
|
152
190
|
*/
|
|
153
191
|
importFile(file: File): Promise<void>;
|
|
154
192
|
/**
|
|
155
|
-
* Export the
|
|
193
|
+
* Export palettes (the user's own by default) as a colour palette file, or say there are none.
|
|
156
194
|
*/
|
|
157
|
-
exportFile(): Promise<void>;
|
|
158
|
-
/** Show a palette file error (one of `PALETTE_FILE_ERRORS`) in the chosen language */
|
|
159
|
-
private toastError;
|
|
195
|
+
exportFile(palettes?: readonly ColourPalette[]): Promise<void>;
|
|
160
196
|
/** The colour model tabs and the selected model's sliders */
|
|
161
197
|
private renderChannels;
|
|
162
|
-
/**
|
|
163
|
-
private
|
|
198
|
+
/** A palette: its name (and the ⋮ menu of the user's own), its colours and its [+] button */
|
|
199
|
+
private renderPalette;
|
|
164
200
|
/** The saved colour's menu, while open */
|
|
165
201
|
private renderMenu;
|
|
166
202
|
/** The dialog asking before deleting a saved colour, while asking */
|
|
@@ -169,3 +205,4 @@ export declare class PcPanelColours extends PcPanel {
|
|
|
169
205
|
protected get defaultLabel(): string;
|
|
170
206
|
protected renderBody(): import("lit").TemplateResult<1> | typeof nothing;
|
|
171
207
|
}
|
|
208
|
+
export {};
|