@lvl99dotcom/paintcanvas 0.5.0 → 0.7.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.
Files changed (120) hide show
  1. package/README.md +2 -2
  2. package/dist/lib/brushes/configRanges/index.d.ts +17 -0
  3. package/dist/lib/brushes/configRanges/index.js +31 -1
  4. package/dist/lib/brushes/params/index.d.ts +2 -1
  5. package/dist/lib/brushes/params/index.js +7 -4
  6. package/dist/lib/brushes/types/index.d.ts +8 -0
  7. package/dist/lib/classes/Layer/index.d.ts +10 -0
  8. package/dist/lib/classes/Layer/index.js +15 -1
  9. package/dist/lib/classes/LayerAutosave/index.d.ts +9 -15
  10. package/dist/lib/classes/LayerAutosave/index.js +30 -43
  11. package/dist/lib/classes/LayerStack/index.d.ts +15 -0
  12. package/dist/lib/classes/LayerStack/index.js +26 -2
  13. package/dist/lib/classes/PaintCanvas/index.d.ts +36 -5
  14. package/dist/lib/classes/PaintCanvas/index.js +45 -14
  15. package/dist/lib/classes/PngEncoder/index.d.ts +41 -0
  16. package/dist/lib/classes/PngEncoder/index.js +104 -0
  17. package/dist/lib/classes/ProfileGraphs/index.d.ts +87 -0
  18. package/dist/lib/classes/ProfileGraphs/index.js +148 -0
  19. package/dist/lib/classes/SettingsAutosave/index.d.ts +1 -1
  20. package/dist/lib/classes/SettingsAutosave/index.js +2 -1
  21. package/dist/lib/classes/UiSettings/index.d.ts +24 -2
  22. package/dist/lib/classes/UiSettings/index.js +32 -7
  23. package/dist/lib/messages/schema.d.ts +720 -0
  24. package/dist/lib/presets/schema.d.ts +360 -0
  25. package/dist/lib/presets/schema.js +8 -1
  26. package/dist/lib/profiles/index.d.ts +61 -0
  27. package/dist/lib/profiles/index.js +131 -0
  28. package/dist/lib/profiles/schema.d.ts +73 -0
  29. package/dist/lib/profiles/schema.js +53 -0
  30. package/dist/lib/rendering/sample/index.d.ts +11 -0
  31. package/dist/lib/rendering/sample/index.js +36 -5
  32. package/dist/lib/settings/index.d.ts +2 -1
  33. package/dist/lib/settings/index.js +4 -1
  34. package/dist/lib/settings/schema.d.ts +53 -1
  35. package/dist/lib/settings/schema.js +9 -2
  36. package/dist/lib/storage/index.d.ts +26 -0
  37. package/dist/lib/storage/index.js +38 -1
  38. package/dist/lib/validation/validators.generated.js +13061 -3675
  39. package/dist/lib/version/index.d.ts +25 -0
  40. package/dist/lib/version/index.js +35 -0
  41. package/dist/locales/en-GB.js +35 -0
  42. package/dist/locales/en-US.js +35 -0
  43. package/dist/locales/fr.js +35 -0
  44. package/dist/locales/ja.js +35 -0
  45. package/dist/locales/ko.js +35 -0
  46. package/dist/locales/zh-Hans.js +35 -0
  47. package/dist/locales/zh-Hant.js +35 -0
  48. package/dist/package.js +1 -1
  49. package/dist/ui/ask/index.d.ts +48 -0
  50. package/dist/ui/ask/index.js +67 -0
  51. package/dist/ui/base/index.d.ts +8 -1
  52. package/dist/ui/base/index.js +19 -4
  53. package/dist/ui/elements/PaintCanvas/index.d.ts +13 -3
  54. package/dist/ui/elements/PaintCanvas/index.js +25 -6
  55. package/dist/ui/elements/PaintCanvas/style.js +1 -1
  56. package/dist/ui/elements/PcAppSettings/index.d.ts +15 -7
  57. package/dist/ui/elements/PcAppSettings/index.js +53 -62
  58. package/dist/ui/elements/PcBrushConfig/index.d.ts +26 -14
  59. package/dist/ui/elements/PcBrushConfig/index.js +214 -145
  60. package/dist/ui/elements/PcBrushConfig/style.js +1 -1
  61. package/dist/ui/elements/PcBrushTest/index.d.ts +1 -0
  62. package/dist/ui/elements/PcBrushTest/index.js +15 -9
  63. package/dist/ui/elements/PcBrushTest/style.js +1 -1
  64. package/dist/ui/elements/PcButton/index.d.ts +12 -3
  65. package/dist/ui/elements/PcButton/index.js +18 -10
  66. package/dist/ui/elements/PcButtonMenu/index.d.ts +88 -0
  67. package/dist/ui/elements/PcButtonMenu/index.js +125 -0
  68. package/dist/ui/elements/PcCanvas/index.d.ts +15 -1
  69. package/dist/ui/elements/PcCanvas/index.js +42 -19
  70. package/dist/ui/elements/PcCanvas/style.js +1 -1
  71. package/dist/ui/elements/PcClipboardTools/index.d.ts +11 -7
  72. package/dist/ui/elements/PcClipboardTools/index.js +30 -29
  73. package/dist/ui/elements/PcDialog/index.d.ts +46 -10
  74. package/dist/ui/elements/PcDialog/index.js +102 -51
  75. package/dist/ui/elements/PcDialogWindow/index.d.ts +141 -0
  76. package/dist/ui/elements/PcDialogWindow/index.js +385 -0
  77. package/dist/ui/elements/PcInputSettings/index.d.ts +2 -1
  78. package/dist/ui/elements/PcInputSettings/index.js +9 -15
  79. package/dist/ui/elements/PcLayerItem/index.d.ts +21 -6
  80. package/dist/ui/elements/PcLayerItem/index.js +53 -26
  81. package/dist/ui/elements/PcLayerItem/style.js +1 -1
  82. package/dist/ui/elements/PcPanelBrushes/index.d.ts +3 -2
  83. package/dist/ui/elements/PcPanelBrushes/index.js +7 -5
  84. package/dist/ui/elements/PcPanelBrushes/style.js +1 -1
  85. package/dist/ui/elements/PcPanelColours/index.js +2 -2
  86. package/dist/ui/elements/PcPanelColours/style.js +1 -1
  87. package/dist/ui/elements/PcPanelLayers/index.js +1 -1
  88. package/dist/ui/elements/PcPanelLayers/style.js +1 -1
  89. package/dist/ui/elements/PcProfileEditor/index.d.ts +103 -0
  90. package/dist/ui/elements/PcProfileEditor/index.js +259 -0
  91. package/dist/ui/elements/PcProfileGraph/index.d.ts +84 -0
  92. package/dist/ui/elements/PcProfileGraph/index.js +317 -0
  93. package/dist/ui/elements/PcShortcutSettings/index.js +9 -13
  94. package/dist/ui/elements/PcSliderRange/index.d.ts +147 -0
  95. package/dist/ui/elements/PcSliderRange/index.js +308 -0
  96. package/dist/ui/elements/PcStats/index.d.ts +19 -4
  97. package/dist/ui/elements/PcStats/index.js +29 -13
  98. package/dist/ui/elements/PcToggleCheckbox/index.d.ts +13 -2
  99. package/dist/ui/elements/PcToggleCheckbox/index.js +27 -8
  100. package/dist/ui/elements/PcToolSettings/index.d.ts +1 -0
  101. package/dist/ui/elements/PcToolSettings/index.js +14 -14
  102. package/dist/ui/elements/PcVersion/index.d.ts +12 -0
  103. package/dist/ui/elements/PcVersion/index.js +43 -0
  104. package/dist/ui/icons/images/icon-profile-graph@2x.js +3 -0
  105. package/dist/ui/icons/index.d.ts +1 -1
  106. package/dist/ui/icons/index.js +2 -0
  107. package/dist/ui/index.d.ts +9 -2
  108. package/dist/ui/index.js +9 -2
  109. package/dist/ui/layout/index.d.ts +2 -2
  110. package/dist/ui/layout/index.js +2 -2
  111. package/dist/ui/styles/index.d.ts +21 -1
  112. package/dist/ui/styles/index.js +73 -14
  113. package/locales/en-GB.json +35 -0
  114. package/locales/en-US.json +35 -0
  115. package/locales/fr.json +35 -0
  116. package/locales/ja.json +35 -0
  117. package/locales/ko.json +35 -0
  118. package/locales/zh-Hans.json +35 -0
  119. package/locales/zh-Hant.json +35 -0
  120. package/package.json +25 -23
@@ -0,0 +1,308 @@
1
+ import { PcElement, defineElement, emit } from "../../base/index.js";
2
+ import { fitNumber } from "../PcNumberSlider/index.js";
3
+ import { css, html, nothing } from "lit";
4
+ import { live } from "lit/directives/live.js";
5
+ import { styleMap } from "lit/directives/style-map.js";
6
+ // src/ui/elements/PcSliderRange/index.ts
7
+ /**
8
+ * Where a value sits between `min` and `max`, from 0 to 1 (0 when they're the same).
9
+ *
10
+ * @example
11
+ * rangeFraction(25, 0, 100); // 0.25
12
+ */
13
+ var rangeFraction = (value, min, max) => max > min ? Math.min(1, Math.max(0, (value - min) / (max - min))) : 0;
14
+ /**
15
+ * A slider for a range: one track with two handles, the left for the lowest value (`low`) and the right for the highest
16
+ * (`high`), and a `<pc-number-slider>` for each on either side (dragged, or tapped to type). The two can't cross: the
17
+ * lowest is never above the highest. Values are kept within `min` and `max` and rounded to `step`.
18
+ *
19
+ * Pressing the track moves the nearest handle there and drags it. With keyboard focus on a handle, the arrow keys move
20
+ * it by `step`, Page Up and Page Down by `pageStep`, and Home and End as far as it can go. Touch, mouse and pen all work.
21
+ *
22
+ * With `single`, it's a slider for one value (`value`, from `min`): one handle, and one number slider before the track,
23
+ * or after it with `number-position="end"`. Use it for single values too, so they look and work the same as ranges.
24
+ *
25
+ * Fires `pc-input` (detail: `{ low, high }`) while a handle is dragged, and `pc-change` once it's let go, or when a value
26
+ * is changed with the keyboard or a number slider, after changing `low` and `high` themselves (and `value`, the same as
27
+ * `high`).
28
+ *
29
+ * @example
30
+ * html`<pc-slider-range label="Width" min="1" max="256" .low=${10} .high=${40}
31
+ * @pc-change=${(e) => setWidth(e.detail.low, e.detail.high)}></pc-slider-range>`
32
+ */
33
+ var PcSliderRange = class extends PcElement {
34
+ static properties = {
35
+ ...PcElement.properties,
36
+ low: { type: Number },
37
+ high: { type: Number },
38
+ min: { type: Number },
39
+ max: { type: Number },
40
+ step: { type: Number },
41
+ pageStep: {
42
+ type: Number,
43
+ attribute: "page-step"
44
+ },
45
+ unit: { type: String },
46
+ label: { type: String },
47
+ single: {
48
+ type: Boolean,
49
+ reflect: true
50
+ },
51
+ numberPosition: {
52
+ type: String,
53
+ attribute: "number-position"
54
+ },
55
+ disabled: {
56
+ type: Boolean,
57
+ reflect: true
58
+ },
59
+ dragging: { state: true }
60
+ };
61
+ static styles = [PcElement.styles, css`
62
+ :host {
63
+ display: flex;
64
+ align-items: center;
65
+ gap: var(--pc-space-2);
66
+ min-width: 0;
67
+ --pc-range-thumb: 16px;
68
+ }
69
+ :host([disabled]) {
70
+ opacity: 0.5;
71
+ }
72
+ pc-number-slider {
73
+ flex: none;
74
+ width: 4.5em;
75
+ }
76
+ /* The handles' centres reach the ends of the track */
77
+ .track {
78
+ position: relative;
79
+ flex: 1;
80
+ min-width: 60px;
81
+ height: 24px;
82
+ margin: 0 calc(var(--pc-range-thumb) / 2);
83
+ touch-action: none;
84
+ cursor: pointer;
85
+ }
86
+ :host([disabled]) .track {
87
+ cursor: default;
88
+ }
89
+ .rail,
90
+ .fill {
91
+ position: absolute;
92
+ top: 50%;
93
+ height: 4px;
94
+ border-radius: var(--pc-radius-pill);
95
+ transform: translateY(-50%);
96
+ }
97
+ /* The whole range: the same area the fill covers from min to max */
98
+ .rail {
99
+ left: 0;
100
+ right: 0;
101
+ background: var(--pc-border);
102
+ }
103
+ .fill {
104
+ background: var(--pc-accent);
105
+ }
106
+ /* A 24px target around each 16px thumb, for fingers */
107
+ .handle {
108
+ position: absolute;
109
+ top: 0;
110
+ display: flex;
111
+ align-items: center;
112
+ justify-content: center;
113
+ width: 24px;
114
+ height: 24px;
115
+ margin-left: -12px;
116
+ border-radius: 50%;
117
+ outline: none;
118
+ }
119
+ .handle::before {
120
+ content: "";
121
+ width: var(--pc-range-thumb);
122
+ height: var(--pc-range-thumb);
123
+ box-sizing: border-box;
124
+ border: 2px solid var(--pc-surface-raised);
125
+ border-radius: 50%;
126
+ background: var(--pc-accent);
127
+ box-shadow: var(--pc-shadow);
128
+ }
129
+ .handle:focus-visible::before {
130
+ outline: var(--pc-focus-width) solid var(--pc-focus);
131
+ outline-offset: 2px;
132
+ }
133
+ /* The handle being dragged stays on top, so it can be dragged off the other */
134
+ .handle.active {
135
+ z-index: 1;
136
+ }
137
+ `];
138
+ /** A single slider's value: the same as `high` */
139
+ get value() {
140
+ return this.high;
141
+ }
142
+ set value(value) {
143
+ this.high = value;
144
+ }
145
+ /** What `pc-input` and `pc-change` give */
146
+ get detail() {
147
+ return {
148
+ low: this.low,
149
+ high: this.high,
150
+ value: this.high
151
+ };
152
+ }
153
+ /** How far an end can go: not past the other end (a single slider's value can go down to `min`) */
154
+ limitsOf(end) {
155
+ if (end === "low") return [this.min, this.high];
156
+ return [this.single ? this.min : this.low, this.max];
157
+ }
158
+ /** An end's name for screen readers: a single slider's is its label */
159
+ endLabel(end) {
160
+ return this.single ? this.label : this.t(`paintCanvas.range.${end}`, { label: this.label });
161
+ }
162
+ constructor() {
163
+ super();
164
+ this.low = 0;
165
+ this.high = 100;
166
+ this.min = 0;
167
+ this.max = 100;
168
+ this.step = 1;
169
+ this.unit = "";
170
+ this.label = "";
171
+ this.single = false;
172
+ this.numberPosition = "start";
173
+ this.disabled = false;
174
+ }
175
+ /**
176
+ * Set one end, kept within `min` and `max`, rounded to `step`, and not past the other end, then tell listeners (with
177
+ * `pc-input` while dragging, or `pc-change`) if it changed.
178
+ *
179
+ * @example
180
+ * range.setEnd("high", 40); // high is 40, unless low is above it (then it's low)
181
+ */
182
+ setEnd(end, value, type = "pc-change") {
183
+ const [lowest, highest] = this.limitsOf(end);
184
+ const next = Math.min(highest, Math.max(lowest, fitNumber(value, this.min, this.max, this.step)));
185
+ if (next === this[end]) return;
186
+ this[end] = next;
187
+ emit(this, type, this.detail);
188
+ }
189
+ /** The value at a pointer's position along the track */
190
+ valueAt(event) {
191
+ const { left, width } = event.currentTarget.getBoundingClientRect();
192
+ const fraction = width > 0 ? (event.clientX - left) / width : 0;
193
+ return this.min + Math.min(1, Math.max(0, fraction)) * (this.max - this.min);
194
+ }
195
+ /** The end nearest a value: the high end when it's above both, or past the middle of two that meet */
196
+ nearestEnd(value) {
197
+ if (this.single) return "high";
198
+ if (value > this.high) return "high";
199
+ if (value < this.low) return "low";
200
+ return value - this.low > this.high - value ? "high" : "low";
201
+ }
202
+ onPointerDown(event) {
203
+ if (this.disabled || event.button > 0) return;
204
+ event.preventDefault();
205
+ const value = this.valueAt(event);
206
+ const end = this.nearestEnd(value);
207
+ this.dragging = end;
208
+ event.currentTarget.setPointerCapture?.(event.pointerId);
209
+ this.renderRoot.querySelector(`.handle.${end}`).focus();
210
+ this.setEnd(end, value, "pc-input");
211
+ }
212
+ onPointerMove(event) {
213
+ if (this.dragging) this.setEnd(this.dragging, this.valueAt(event), "pc-input");
214
+ }
215
+ onPointerUp() {
216
+ if (!this.dragging) return;
217
+ this.dragging = void 0;
218
+ emit(this, "pc-change", this.detail);
219
+ }
220
+ /** Move a handle with the arrow keys, Page Up and Page Down, Home and End */
221
+ onHandleKeyDown(event, end) {
222
+ if (this.disabled) return;
223
+ const page = this.pageStep ?? this.step * 10;
224
+ const value = this[end];
225
+ const next = {
226
+ ArrowRight: value + this.step,
227
+ ArrowUp: value + this.step,
228
+ ArrowLeft: value - this.step,
229
+ ArrowDown: value - this.step,
230
+ PageUp: value + page,
231
+ PageDown: value - page,
232
+ Home: this.min,
233
+ End: this.max
234
+ }[event.key];
235
+ if (next === void 0) return;
236
+ event.preventDefault();
237
+ this.setEnd(end, next);
238
+ }
239
+ /** One end's handle */
240
+ renderHandle(end) {
241
+ const value = this[end];
242
+ const [lowest, highest] = this.limitsOf(end);
243
+ return html`<div
244
+ class="handle ${end} ${this.dragging === end ? "active" : ""}"
245
+ part="handle"
246
+ role="slider"
247
+ tabindex=${this.disabled ? -1 : 0}
248
+ aria-label=${this.endLabel(end)}
249
+ aria-valuemin=${lowest}
250
+ aria-valuemax=${highest}
251
+ aria-valuenow=${value}
252
+ aria-valuetext=${`${value}${this.unit}`}
253
+ aria-disabled=${this.disabled ? "true" : nothing}
254
+ style=${styleMap({ left: `${rangeFraction(value, this.min, this.max) * 100}%` })}
255
+ @keydown=${(event) => this.onHandleKeyDown(event, end)}
256
+ ></div>`;
257
+ }
258
+ /** One end's number slider: it can't go past the other end */
259
+ renderNumber(end) {
260
+ const [lowest, highest] = this.limitsOf(end);
261
+ return html`<pc-number-slider
262
+ class=${end}
263
+ part="number"
264
+ label=${this.endLabel(end)}
265
+ min=${lowest}
266
+ max=${highest}
267
+ step=${this.step}
268
+ page-step=${this.pageStep ?? nothing}
269
+ unit=${this.unit}
270
+ ?disabled=${this.disabled}
271
+ .value=${live(this[end])}
272
+ @pc-change=${(event) => {
273
+ event.stopPropagation();
274
+ this.setEnd(end, event.detail.value);
275
+ }}
276
+ ></pc-number-slider>`;
277
+ }
278
+ render() {
279
+ const from = this.single ? 0 : rangeFraction(this.low, this.min, this.max) * 100;
280
+ const to = rangeFraction(this.high, this.min, this.max) * 100;
281
+ const before = this.single ? this.numberPosition === "end" ? nothing : this.renderNumber("high") : this.renderNumber("low");
282
+ const after = !this.single || this.numberPosition === "end" ? this.renderNumber("high") : nothing;
283
+ return html`${before}
284
+ <div
285
+ class="track"
286
+ part="track"
287
+ @pointerdown=${this.onPointerDown}
288
+ @pointermove=${this.onPointerMove}
289
+ @pointerup=${this.onPointerUp}
290
+ @pointercancel=${this.onPointerUp}
291
+ >
292
+ <div class="rail"></div>
293
+ <div
294
+ class="fill"
295
+ part="fill"
296
+ style=${styleMap({
297
+ left: `${from}%`,
298
+ right: `${100 - to}%`
299
+ })}
300
+ ></div>
301
+ ${this.single ? nothing : this.renderHandle("low")}
302
+ ${this.renderHandle("high")}
303
+ </div>
304
+ ${after}`;
305
+ }
306
+ };
307
+ defineElement("pc-slider-range", PcSliderRange);
308
+ export { PcSliderRange, rangeFraction };
@@ -1,6 +1,11 @@
1
1
  import { nothing, type PropertyValues } from "lit";
2
2
  import { PcElement } from "../../base";
3
3
  import type PaintCanvas from "../../../lib/classes/PaintCanvas";
4
+ /**
5
+ * The least time between reads of the colour under the pointer, in milliseconds. Each read draws every layer's pixels
6
+ * there, which is slow on phones.
7
+ */
8
+ export declare const COLOUR_INTERVAL_MS = 100;
4
9
  /**
5
10
  * A size in bytes in the largest unit it has at least one of, to one decimal place (whole bytes), for a locale.
6
11
  *
@@ -12,8 +17,9 @@ export declare const formatBytes: (bytes: number, locale?: string) => string;
12
17
  /**
13
18
  * A line of small text about the canvas: its size; while the drawing is kept in the browser, how much its layer
14
19
  * images take there; the zoom level; and the colour under the pointer (with a swatch; a dash when the pointer isn't
15
- * over the canvas). The colour follows the pointer at most once a frame. It's not announced to screen readers as it
16
- * changes, as it changes with every pointer move.
20
+ * over the canvas). The colour follows the pointer at most every `COLOUR_INTERVAL_MS`, and isn't read while a stroke is
21
+ * drawn (the next pointer move after it reads it). It's not announced to screen readers as it changes, as it changes
22
+ * with every pointer move.
17
23
  *
18
24
  * @example
19
25
  * html`<pc-stats .app=${app}></pc-stats>`
@@ -23,6 +29,9 @@ export declare class PcStats extends PcElement {
23
29
  app: {
24
30
  attribute: boolean;
25
31
  };
32
+ colour: {
33
+ state: boolean;
34
+ };
26
35
  translations: {
27
36
  attribute: boolean;
28
37
  };
@@ -38,11 +47,17 @@ export declare class PcStats extends PcElement {
38
47
  /** The canvas described */
39
48
  app?: PaintCanvas;
40
49
  private changes;
50
+ /** The colour under the pointer when it was last read, if it's over the canvas */
51
+ colour?: string;
41
52
  /** The canvas whose pointer is followed */
42
53
  private followed?;
43
- /** The animation frame the next update waits for, if any */
44
- private frame?;
54
+ /** The timer the next read of the colour waits for, if any */
55
+ private timer?;
45
56
  private readonly onPointer;
57
+ /**
58
+ * Read the colour under the followed canvas's pointer, unless a stroke is being drawn (reading would slow it down).
59
+ */
60
+ private readColour;
46
61
  connectedCallback(): void;
47
62
  disconnectedCallback(): void;
48
63
  protected willUpdate(changed: PropertyValues<this>): void;
@@ -4,6 +4,11 @@ import { zoomPercent } from "../PcToolSettings/index.js";
4
4
  import { css, html, nothing } from "lit";
5
5
  import { styleMap } from "lit/directives/style-map.js";
6
6
  // src/ui/elements/PcStats/index.ts
7
+ /**
8
+ * The least time between reads of the colour under the pointer, in milliseconds. Each read draws every layer's pixels
9
+ * there, which is slow on phones.
10
+ */
11
+ var COLOUR_INTERVAL_MS = 100;
7
12
  /** Units for sizes in bytes, each 1000 times the one before */
8
13
  var BYTE_UNITS = [
9
14
  "byte",
@@ -30,8 +35,9 @@ var formatBytes = (bytes, locale) => {
30
35
  /**
31
36
  * A line of small text about the canvas: its size; while the drawing is kept in the browser, how much its layer
32
37
  * images take there; the zoom level; and the colour under the pointer (with a swatch; a dash when the pointer isn't
33
- * over the canvas). The colour follows the pointer at most once a frame. It's not announced to screen readers as it
34
- * changes, as it changes with every pointer move.
38
+ * over the canvas). The colour follows the pointer at most every `COLOUR_INTERVAL_MS`, and isn't read while a stroke is
39
+ * drawn (the next pointer move after it reads it). It's not announced to screen readers as it changes, as it changes
40
+ * with every pointer move.
35
41
  *
36
42
  * @example
37
43
  * html`<pc-stats .app=${app}></pc-stats>`
@@ -39,7 +45,8 @@ var formatBytes = (bytes, locale) => {
39
45
  var PcStats = class extends PcElement {
40
46
  static properties = {
41
47
  ...PcElement.properties,
42
- app: { attribute: false }
48
+ app: { attribute: false },
49
+ colour: { state: true }
43
50
  };
44
51
  static styles = [PcElement.styles, css`
45
52
  :host {
@@ -79,14 +86,22 @@ var PcStats = class extends PcElement {
79
86
  ]);
80
87
  /** The canvas whose pointer is followed */
81
88
  followed;
82
- /** The animation frame the next update waits for, if any */
83
- frame;
89
+ /** The timer the next read of the colour waits for, if any */
90
+ timer;
84
91
  onPointer = () => {
85
- this.frame ??= requestAnimationFrame(() => {
86
- this.frame = void 0;
87
- this.requestUpdate();
88
- });
92
+ this.timer ??= setTimeout(() => {
93
+ this.timer = void 0;
94
+ this.readColour();
95
+ }, 100);
89
96
  };
97
+ /**
98
+ * Read the colour under the followed canvas's pointer, unless a stroke is being drawn (reading would slow it down).
99
+ */
100
+ readColour() {
101
+ const app = this.followed;
102
+ if (!app || app.strokes.drawing) return;
103
+ this.colour = app.pointer && app.sampleColour(app.pointer);
104
+ }
90
105
  connectedCallback() {
91
106
  super.connectedCallback();
92
107
  this.follow(this.app);
@@ -94,8 +109,6 @@ var PcStats = class extends PcElement {
94
109
  disconnectedCallback() {
95
110
  super.disconnectedCallback();
96
111
  this.follow(void 0);
97
- if (this.frame !== void 0) cancelAnimationFrame(this.frame);
98
- this.frame = void 0;
99
112
  }
100
113
  willUpdate(changed) {
101
114
  super.willUpdate(changed);
@@ -106,13 +119,16 @@ var PcStats = class extends PcElement {
106
119
  */
107
120
  follow(app) {
108
121
  this.followed?.removeEventListener("pointer", this.onPointer);
122
+ clearTimeout(this.timer);
123
+ this.timer = void 0;
124
+ this.colour = void 0;
109
125
  this.followed = app;
110
126
  app?.addEventListener("pointer", this.onPointer);
111
127
  }
112
128
  render() {
113
129
  const app = this.app;
114
130
  if (!app) return nothing;
115
- const colour = app.pointer && app.sampleColour(app.pointer);
131
+ const colour = this.colour;
116
132
  const autosave = app.autosave;
117
133
  return html`<ul
118
134
  part="stats"
@@ -141,4 +157,4 @@ var PcStats = class extends PcElement {
141
157
  }
142
158
  };
143
159
  defineElement("pc-stats", PcStats);
144
- export { PcStats, formatBytes };
160
+ export { COLOUR_INTERVAL_MS, PcStats, formatBytes };
@@ -1,10 +1,15 @@
1
1
  import { PcElement } from "../../base";
2
+ /** Sizes of the switch: `m` (20px high, the default) and `s` (16px high, e.g. in toolbars) */
3
+ export declare const TOGGLE_SIZES: readonly ["m", "s"];
4
+ export type ToggleSize = (typeof TOGGLE_SIZES)[number];
2
5
  /**
3
- * An on/off switch with its text (the element's content) beside it, e.g. for settings. Fires `change` when the user
4
- * turns it on or off.
6
+ * An on/off switch with its text (the element's content) beside it, e.g. for settings. Use it instead of plain
7
+ * checkboxes. It comes in two sizes (`size`: `m`, 20px high, by default, or `s`, 16px high), both pressable over at
8
+ * least 24px of height. Fires `change` when the user turns it on or off.
5
9
  *
6
10
  * @example
7
11
  * html`<pc-toggle-checkbox .checked=${pinchZoom} @change=${toggle}>Pinch to zoom</pc-toggle-checkbox>`
12
+ * html`<pc-toggle-checkbox size="s">Show stroke points</pc-toggle-checkbox>`
8
13
  */
9
14
  export declare class PcToggleCheckbox extends PcElement {
10
15
  static properties: {
@@ -16,6 +21,10 @@ export declare class PcToggleCheckbox extends PcElement {
16
21
  type: BooleanConstructor;
17
22
  reflect: boolean;
18
23
  };
24
+ size: {
25
+ type: StringConstructor;
26
+ reflect: boolean;
27
+ };
19
28
  translations: {
20
29
  attribute: boolean;
21
30
  };
@@ -30,6 +39,8 @@ export declare class PcToggleCheckbox extends PcElement {
30
39
  static styles: import("lit").CSSResultGroup[];
31
40
  checked: boolean;
32
41
  disabled: boolean;
42
+ /** The switch's size: `m` (default) or `s` */
43
+ size: ToggleSize;
33
44
  constructor();
34
45
  /** Follow the user's change, and tell listeners */
35
46
  private onChange;
@@ -2,12 +2,16 @@ import { PcElement, defineElement, emit } from "../../base/index.js";
2
2
  import { css, html } from "lit";
3
3
  import { live } from "lit/directives/live.js";
4
4
  // src/ui/elements/PcToggleCheckbox/index.ts
5
+ /** Sizes of the switch: `m` (20px high, the default) and `s` (16px high, e.g. in toolbars) */
6
+ var TOGGLE_SIZES = ["m", "s"];
5
7
  /**
6
- * An on/off switch with its text (the element's content) beside it, e.g. for settings. Fires `change` when the user
7
- * turns it on or off.
8
+ * An on/off switch with its text (the element's content) beside it, e.g. for settings. Use it instead of plain
9
+ * checkboxes. It comes in two sizes (`size`: `m`, 20px high, by default, or `s`, 16px high), both pressable over at
10
+ * least 24px of height. Fires `change` when the user turns it on or off.
8
11
  *
9
12
  * @example
10
13
  * html`<pc-toggle-checkbox .checked=${pinchZoom} @change=${toggle}>Pinch to zoom</pc-toggle-checkbox>`
14
+ * html`<pc-toggle-checkbox size="s">Show stroke points</pc-toggle-checkbox>`
11
15
  */
12
16
  var PcToggleCheckbox = class extends PcElement {
13
17
  static properties = {
@@ -19,15 +23,27 @@ var PcToggleCheckbox = class extends PcElement {
19
23
  disabled: {
20
24
  type: Boolean,
21
25
  reflect: true
26
+ },
27
+ size: {
28
+ type: String,
29
+ reflect: true
22
30
  }
23
31
  };
24
32
  static styles = [PcElement.styles, css`
25
33
  :host {
34
+ --pc-toggle-height: 20px;
35
+ --pc-toggle-width: 36px;
26
36
  display: flex;
27
37
  }
38
+ :host([size="s"]) {
39
+ --pc-toggle-height: 16px;
40
+ --pc-toggle-width: 28px;
41
+ }
28
42
  label {
29
43
  display: flex;
30
44
  flex: 1;
45
+ /* The pressable area is at least 24px high, whatever the switch's size */
46
+ min-height: 24px;
31
47
  gap: var(--pc-space-2);
32
48
  align-items: center;
33
49
  color: var(--pc-text);
@@ -42,8 +58,8 @@ var PcToggleCheckbox = class extends PcElement {
42
58
  input {
43
59
  position: relative;
44
60
  flex: none;
45
- width: 36px;
46
- height: 20px;
61
+ width: var(--pc-toggle-width);
62
+ height: var(--pc-toggle-height);
47
63
  margin: 0;
48
64
  border-radius: var(--pc-radius-pill);
49
65
  background: var(--pc-disabled);
@@ -54,8 +70,8 @@ var PcToggleCheckbox = class extends PcElement {
54
70
  position: absolute;
55
71
  top: 2px;
56
72
  left: 2px;
57
- width: 16px;
58
- height: 16px;
73
+ width: calc(var(--pc-toggle-height) - 4px);
74
+ height: calc(var(--pc-toggle-height) - 4px);
59
75
  border-radius: 50%;
60
76
  background: #ffffff;
61
77
  content: "";
@@ -65,7 +81,9 @@ var PcToggleCheckbox = class extends PcElement {
65
81
  background: var(--pc-accent);
66
82
  }
67
83
  input:checked::before {
68
- transform: translateX(16px);
84
+ transform: translateX(
85
+ calc(var(--pc-toggle-width) - var(--pc-toggle-height))
86
+ );
69
87
  }
70
88
  input:focus-visible {
71
89
  outline: var(--pc-focus-width) solid var(--pc-focus);
@@ -81,6 +99,7 @@ var PcToggleCheckbox = class extends PcElement {
81
99
  super();
82
100
  this.checked = false;
83
101
  this.disabled = false;
102
+ this.size = "m";
84
103
  }
85
104
  /** Follow the user's change, and tell listeners */
86
105
  onChange(event) {
@@ -102,4 +121,4 @@ var PcToggleCheckbox = class extends PcElement {
102
121
  }
103
122
  };
104
123
  defineElement("pc-toggle-checkbox", PcToggleCheckbox);
105
- export { PcToggleCheckbox };
124
+ export { PcToggleCheckbox, TOGGLE_SIZES };
@@ -3,6 +3,7 @@ import { PcElement } from "../../base";
3
3
  import PaintCanvas, { Tool } from "../../../lib/classes/PaintCanvas";
4
4
  import type { BrushConfig } from "../../../lib/brushes/types";
5
5
  import "../PcBrushSize";
6
+ import "../PcToggleCheckbox";
6
7
  import "../PcNumberSlider";
7
8
  import "../PcPopover";
8
9
  /** Settings varied with pen tilt by the tilt toggle */
@@ -8,6 +8,7 @@ import "../../../lib/classes/BrushSettings/index.js";
8
8
  import { MAX_ZOOM, MIN_ZOOM } from "../../../lib/classes/Viewport/index.js";
9
9
  import { iconLabel } from "../../icons/index.js";
10
10
  import "../PcBrushSize/index.js";
11
+ import "../PcToggleCheckbox/index.js";
11
12
  import "../PcNumberSlider/index.js";
12
13
  import "../PcPopover/index.js";
13
14
  import { html, nothing, svg, unsafeCSS } from "lit";
@@ -295,7 +296,7 @@ var PcToolSettings = class extends PcElement {
295
296
  })}
296
297
  <button
297
298
  type="button"
298
- class="configure"
299
+ class="configure pill-s"
299
300
  @click=${() => this.emit("pc-configure-brush", kind)}
300
301
  >
301
302
  ${this.t("paintCanvas.toolSettings.configure")}
@@ -359,14 +360,14 @@ var PcToolSettings = class extends PcElement {
359
360
  label: this.t("paintCanvas.toolSettings.maskSettings"),
360
361
  start: html`<button
361
362
  type="button"
362
- class="pill select-all"
363
+ class="pill-s select-all"
363
364
  @click=${() => app.selection.selectAll()}
364
365
  >
365
366
  ${this.t("paintCanvas.toolSettings.selectAll")}
366
367
  </button>
367
368
  <button
368
369
  type="button"
369
- class="pill invert"
370
+ class="pill-s invert"
370
371
  ?disabled=${!app.selection.active}
371
372
  @click=${() => app.selection.invert()}
372
373
  >
@@ -374,7 +375,7 @@ var PcToolSettings = class extends PcElement {
374
375
  </button>
375
376
  <button
376
377
  type="button"
377
- class="pill deselect"
378
+ class="pill-s deselect"
378
379
  ?disabled=${!app.selection.active}
379
380
  @click=${() => app.selection.clear()}
380
381
  >
@@ -430,15 +431,14 @@ var PcToolSettings = class extends PcElement {
430
431
  ${iconLabel(this.iconUrl(app.constrainProportions ? "linked" : "unlinked"), this.t("paintCanvas.toolSettings.constrainProportions"))}
431
432
  </label>
432
433
  ${side("height", this.t("paintCanvas.common.height"))}
433
- <label>
434
- <input
435
- type="checkbox"
436
- class="percent"
437
- .checked=${this.percent}
438
- @change=${(e) => this.percent = e.target.checked}
439
- />
434
+ <pc-toggle-checkbox
435
+ class="percent"
436
+ size="s"
437
+ .checked=${this.percent}
438
+ @change=${(e) => this.percent = e.detail.checked}
439
+ >
440
440
  ${this.t("paintCanvas.toolSettings.percent")}
441
- </label>
441
+ </pc-toggle-checkbox>
442
442
  <button
443
443
  type="button"
444
444
  class="icon-button flip-horizontal"
@@ -486,7 +486,7 @@ var PcToolSettings = class extends PcElement {
486
486
  </button>
487
487
  <button
488
488
  type="button"
489
- class="pill reset"
489
+ class="pill-s reset"
490
490
  ?disabled=${disabled}
491
491
  @click=${() => app.cancelTransform()}
492
492
  >
@@ -538,7 +538,7 @@ var PcToolSettings = class extends PcElement {
538
538
  </label>
539
539
  <button
540
540
  type="button"
541
- class="pill reset"
541
+ class="pill-s reset"
542
542
  @click=${() => view.zoomAt(centre, 1)}
543
543
  >
544
544
  ${this.t("paintCanvas.toolSettings.reset")}
@@ -0,0 +1,12 @@
1
+ import { PcElement } from "../../base";
2
+ /**
3
+ * PaintCanvas's version and the commit it was built from, e.g. "PaintCanvas v0.6.0 (ac12a0d)", as a link to its GitHub
4
+ * repository (opened in a new tab). For an app's settings or about panel.
5
+ *
6
+ * @example
7
+ * html`<pc-version></pc-version>`
8
+ */
9
+ export declare class PcVersion extends PcElement {
10
+ static styles: import("lit").CSSResultGroup[];
11
+ render(): import("lit").TemplateResult<1>;
12
+ }