@lvl99dotcom/paintcanvas 0.4.0 → 0.6.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 (224) hide show
  1. package/README.md +30 -15
  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/presets/round/index.d.ts +1 -1
  7. package/dist/lib/brushes/presets/round/index.js +12 -7
  8. package/dist/lib/brushes/presets/square/index.d.ts +1 -1
  9. package/dist/lib/brushes/presets/square/index.js +7 -3
  10. package/dist/lib/brushes/shapeImage/index.d.ts +7 -3
  11. package/dist/lib/brushes/shapeImage/index.js +15 -9
  12. package/dist/lib/brushes/shapes/index.d.ts +18 -0
  13. package/dist/lib/brushes/shapes/index.js +86 -0
  14. package/dist/lib/brushes/types/index.d.ts +8 -0
  15. package/dist/lib/classes/BrushSettings/index.d.ts +29 -2
  16. package/dist/lib/classes/BrushSettings/index.js +51 -14
  17. package/dist/lib/classes/KeyboardShortcuts/index.d.ts +31 -2
  18. package/dist/lib/classes/KeyboardShortcuts/index.js +66 -4
  19. package/dist/lib/classes/Layer/index.d.ts +10 -0
  20. package/dist/lib/classes/Layer/index.js +15 -1
  21. package/dist/lib/classes/LayerAutosave/index.d.ts +9 -15
  22. package/dist/lib/classes/LayerAutosave/index.js +30 -43
  23. package/dist/lib/classes/LayerStack/index.d.ts +15 -0
  24. package/dist/lib/classes/LayerStack/index.js +26 -2
  25. package/dist/lib/classes/PaintCanvas/index.d.ts +72 -3
  26. package/dist/lib/classes/PaintCanvas/index.js +106 -12
  27. package/dist/lib/classes/PngEncoder/index.d.ts +41 -0
  28. package/dist/lib/classes/PngEncoder/index.js +104 -0
  29. package/dist/lib/classes/ProfileGraphs/index.d.ts +87 -0
  30. package/dist/lib/classes/ProfileGraphs/index.js +148 -0
  31. package/dist/lib/classes/SettingsAutosave/index.d.ts +3 -2
  32. package/dist/lib/classes/SettingsAutosave/index.js +6 -3
  33. package/dist/lib/classes/UiSettings/index.d.ts +68 -0
  34. package/dist/lib/classes/UiSettings/index.js +82 -0
  35. package/dist/lib/messages/schema.d.ts +720 -0
  36. package/dist/lib/presets/schema.d.ts +360 -0
  37. package/dist/lib/presets/schema.js +8 -1
  38. package/dist/lib/profiles/index.d.ts +61 -0
  39. package/dist/lib/profiles/index.js +131 -0
  40. package/dist/lib/profiles/schema.d.ts +73 -0
  41. package/dist/lib/profiles/schema.js +53 -0
  42. package/dist/lib/rendering/sample/index.d.ts +11 -0
  43. package/dist/lib/rendering/sample/index.js +36 -5
  44. package/dist/lib/settings/index.d.ts +2 -1
  45. package/dist/lib/settings/index.js +7 -2
  46. package/dist/lib/settings/schema.d.ts +67 -0
  47. package/dist/lib/settings/schema.js +20 -0
  48. package/dist/lib/validation/validators.generated.js +13191 -3655
  49. package/dist/locales/en-GB.js +39 -2
  50. package/dist/locales/en-US.js +39 -2
  51. package/dist/locales/fr.js +39 -2
  52. package/dist/locales/ja.js +39 -2
  53. package/dist/locales/ko.js +39 -2
  54. package/dist/locales/zh-Hans.js +39 -2
  55. package/dist/locales/zh-Hant.js +39 -2
  56. package/dist/package.js +1 -1
  57. package/dist/testing/recordingCanvas.js +2 -1
  58. package/dist/ui/ask/index.d.ts +48 -0
  59. package/dist/ui/ask/index.js +67 -0
  60. package/dist/ui/base/index.d.ts +10 -3
  61. package/dist/ui/base/index.js +19 -4
  62. package/dist/ui/dismiss/index.d.ts +21 -0
  63. package/dist/ui/dismiss/index.js +27 -0
  64. package/dist/ui/drag/index.d.ts +51 -0
  65. package/dist/ui/drag/index.js +81 -0
  66. package/dist/ui/elements/PaintCanvas/index.d.ts +17 -12
  67. package/dist/ui/elements/PaintCanvas/index.js +36 -17
  68. package/dist/ui/elements/PaintCanvas/style.js +1 -1
  69. package/dist/ui/elements/PcAppSettings/index.d.ts +6 -6
  70. package/dist/ui/elements/PcAppSettings/index.js +21 -65
  71. package/dist/ui/elements/PcBrushConfig/index.d.ts +34 -16
  72. package/dist/ui/elements/PcBrushConfig/index.js +263 -153
  73. package/dist/ui/elements/PcBrushConfig/style.js +1 -1
  74. package/dist/ui/elements/PcBrushSize/index.d.ts +53 -0
  75. package/dist/ui/elements/PcBrushSize/index.js +66 -0
  76. package/dist/ui/elements/PcBrushTest/index.d.ts +26 -0
  77. package/dist/ui/elements/PcBrushTest/index.js +79 -6
  78. package/dist/ui/elements/PcBrushTest/style.js +1 -1
  79. package/dist/ui/elements/PcButton/index.d.ts +12 -3
  80. package/dist/ui/elements/PcButton/index.js +18 -10
  81. package/dist/ui/elements/PcCanvas/index.d.ts +27 -2
  82. package/dist/ui/elements/PcCanvas/index.js +63 -13
  83. package/dist/ui/elements/PcCanvas/style.js +1 -1
  84. package/dist/ui/elements/PcCanvasMap/style.js +1 -1
  85. package/dist/ui/elements/PcClipboardTools/index.d.ts +49 -0
  86. package/dist/ui/elements/PcClipboardTools/index.js +125 -0
  87. package/dist/ui/elements/PcContextMenu/index.d.ts +2 -2
  88. package/dist/ui/elements/PcDialog/index.d.ts +46 -10
  89. package/dist/ui/elements/PcDialog/index.js +102 -51
  90. package/dist/ui/elements/PcDialogWindow/index.d.ts +141 -0
  91. package/dist/ui/elements/PcDialogWindow/index.js +385 -0
  92. package/dist/ui/elements/PcInputSettings/index.d.ts +13 -0
  93. package/dist/ui/elements/PcInputSettings/index.js +16 -1
  94. package/dist/ui/elements/PcMenu/index.d.ts +48 -3
  95. package/dist/ui/elements/PcMenu/index.js +111 -19
  96. package/dist/ui/elements/PcNumberSlider/index.d.ts +137 -0
  97. package/dist/ui/elements/PcNumberSlider/index.js +247 -0
  98. package/dist/ui/elements/PcPane/index.d.ts +3 -1
  99. package/dist/ui/elements/PcPane/index.js +44 -7
  100. package/dist/ui/elements/PcPanel/index.d.ts +2 -2
  101. package/dist/ui/elements/PcPanel/index.js +8 -8
  102. package/dist/ui/elements/PcPanelBrushes/index.d.ts +5 -17
  103. package/dist/ui/elements/PcPanelBrushes/index.js +13 -48
  104. package/dist/ui/elements/PcPanelBrushes/style.js +1 -1
  105. package/dist/ui/elements/PcPanelColours/index.js +2 -2
  106. package/dist/ui/elements/PcPanelColours/style.js +1 -1
  107. package/dist/ui/elements/PcPanelLayers/index.js +1 -1
  108. package/dist/ui/elements/PcPanelLayers/style.js +1 -1
  109. package/dist/ui/elements/PcPopover/index.d.ts +39 -1
  110. package/dist/ui/elements/PcPopover/index.js +72 -4
  111. package/dist/ui/elements/PcProfileEditor/index.d.ts +103 -0
  112. package/dist/ui/elements/PcProfileEditor/index.js +259 -0
  113. package/dist/ui/elements/PcProfileGraph/index.d.ts +84 -0
  114. package/dist/ui/elements/PcProfileGraph/index.js +317 -0
  115. package/dist/ui/elements/PcShortcutSettings/index.js +9 -13
  116. package/dist/ui/elements/PcSliderRange/index.d.ts +147 -0
  117. package/dist/ui/elements/PcSliderRange/index.js +307 -0
  118. package/dist/ui/elements/PcStats/index.d.ts +19 -4
  119. package/dist/ui/elements/PcStats/index.js +29 -13
  120. package/dist/ui/elements/PcThemePicker/index.d.ts +17 -15
  121. package/dist/ui/elements/PcThemePicker/index.js +22 -21
  122. package/dist/ui/elements/PcToolSettings/index.d.ts +48 -9
  123. package/dist/ui/elements/PcToolSettings/index.js +382 -318
  124. package/dist/ui/elements/PcToolSettings/style.js +1 -1
  125. package/dist/ui/elements/PcToolbar/index.d.ts +15 -0
  126. package/dist/ui/elements/PcToolbar/index.js +55 -14
  127. package/dist/ui/elements/PcToolbar/style.js +1 -1
  128. package/dist/ui/icons/images/icon-brush@2x.js +3 -0
  129. package/dist/ui/icons/images/icon-circle-mask@2x.js +3 -0
  130. package/dist/ui/icons/images/icon-clipboard@2x.js +3 -0
  131. package/dist/ui/icons/images/icon-cog@2x.js +3 -0
  132. package/dist/ui/icons/images/icon-cursor@2x.js +3 -0
  133. package/dist/ui/icons/images/icon-diagonal-tlbr-size@2x.js +3 -0
  134. package/dist/ui/icons/images/icon-diagonal-trbl-size@2x.js +3 -0
  135. package/dist/ui/icons/images/icon-eraser@2x.js +3 -0
  136. package/dist/ui/icons/images/icon-eyedropper@2x.js +3 -0
  137. package/dist/ui/icons/images/icon-flip-horizontal@2x.js +3 -0
  138. package/dist/ui/icons/images/icon-flip-vertical@2x.js +3 -0
  139. package/dist/ui/icons/images/icon-focus-pen@2x.js +3 -0
  140. package/dist/ui/icons/images/icon-freehand-mask@2x.js +3 -0
  141. package/dist/ui/icons/images/icon-hidden@2x.js +3 -0
  142. package/dist/ui/icons/images/icon-horizontal-size@2x.js +3 -0
  143. package/dist/ui/icons/images/icon-layers@2x.js +3 -0
  144. package/dist/ui/icons/images/icon-linked@2x.js +3 -0
  145. package/dist/ui/icons/images/icon-locked@2x.js +3 -0
  146. package/dist/ui/icons/images/icon-moon@2x.js +3 -0
  147. package/dist/ui/icons/images/icon-pan@2x.js +3 -0
  148. package/dist/ui/icons/images/icon-polygon-mask@2x.js +3 -0
  149. package/dist/ui/icons/images/icon-pressure@2x.js +3 -0
  150. package/dist/ui/icons/images/icon-profile-graph@2x.js +3 -0
  151. package/dist/ui/icons/images/icon-randomise@2x.js +3 -0
  152. package/dist/ui/icons/images/icon-rectangle-mask@2x.js +3 -0
  153. package/dist/ui/icons/images/icon-redo@2x.js +3 -0
  154. package/dist/ui/icons/images/icon-rotate-90-left@2x.js +3 -0
  155. package/dist/ui/icons/images/icon-rotate-90-right@2x.js +3 -0
  156. package/dist/ui/icons/images/icon-rotate@2x.js +3 -0
  157. package/dist/ui/icons/images/icon-smoothing-bezier-cubic@2x.js +3 -0
  158. package/dist/ui/icons/images/icon-smoothing-bezier-quad@2x.js +3 -0
  159. package/dist/ui/icons/images/icon-smoothing-linear@2x.js +3 -0
  160. package/dist/ui/icons/images/icon-star@2x.js +3 -0
  161. package/dist/ui/icons/images/icon-sun@2x.js +3 -0
  162. package/dist/ui/icons/images/icon-tilt@2x.js +3 -0
  163. package/dist/ui/icons/images/icon-undo@2x.js +3 -0
  164. package/dist/ui/icons/images/icon-unlinked@2x.js +3 -0
  165. package/dist/ui/icons/images/icon-unlocked@2x.js +3 -0
  166. package/dist/ui/icons/images/icon-vertical-size@2x.js +3 -0
  167. package/dist/ui/icons/images/icon-visible@2x.js +3 -0
  168. package/dist/ui/icons/images/icon-zoom-in@2x.js +3 -0
  169. package/dist/ui/icons/images/icon-zoom-out@2x.js +3 -0
  170. package/dist/ui/icons/images/icon-zoom@2x.js +3 -0
  171. package/dist/ui/icons/index.d.ts +1 -1
  172. package/dist/ui/icons/index.js +86 -72
  173. package/dist/ui/index.d.ts +13 -3
  174. package/dist/ui/index.js +15 -4
  175. package/dist/ui/layout/index.d.ts +9 -1
  176. package/dist/ui/layout/index.js +11 -2
  177. package/dist/ui/styles/index.d.ts +21 -1
  178. package/dist/ui/styles/index.js +73 -14
  179. package/dist/ui/tokens/index.d.ts +5 -4
  180. package/dist/ui/tokens/index.js +12 -7
  181. package/locales/en-GB.json +39 -2
  182. package/locales/en-US.json +39 -2
  183. package/locales/fr.json +39 -2
  184. package/locales/ja.json +39 -2
  185. package/locales/ko.json +39 -2
  186. package/locales/zh-Hans.json +39 -2
  187. package/locales/zh-Hant.json +39 -2
  188. package/package.json +27 -18
  189. package/dist/ui/icons/images/brush.js +0 -3
  190. package/dist/ui/icons/images/circle-mask.js +0 -3
  191. package/dist/ui/icons/images/clipboard.js +0 -3
  192. package/dist/ui/icons/images/cursor.js +0 -3
  193. package/dist/ui/icons/images/eraser.js +0 -3
  194. package/dist/ui/icons/images/eyedropper.js +0 -3
  195. package/dist/ui/icons/images/flip-horizontal.js +0 -3
  196. package/dist/ui/icons/images/flip-vertical.js +0 -3
  197. package/dist/ui/icons/images/focus-pen.js +0 -3
  198. package/dist/ui/icons/images/freehand-mask.js +0 -3
  199. package/dist/ui/icons/images/hidden.js +0 -3
  200. package/dist/ui/icons/images/layers.js +0 -3
  201. package/dist/ui/icons/images/linked.js +0 -3
  202. package/dist/ui/icons/images/locked.js +0 -3
  203. package/dist/ui/icons/images/moon.js +0 -3
  204. package/dist/ui/icons/images/pan.js +0 -3
  205. package/dist/ui/icons/images/polygon-mask.js +0 -3
  206. package/dist/ui/icons/images/pressure.js +0 -3
  207. package/dist/ui/icons/images/randomise.js +0 -3
  208. package/dist/ui/icons/images/rectangle-mask.js +0 -3
  209. package/dist/ui/icons/images/redo.js +0 -3
  210. package/dist/ui/icons/images/rotate-90-left.js +0 -3
  211. package/dist/ui/icons/images/rotate-90-right.js +0 -3
  212. package/dist/ui/icons/images/smoothing-bezier-cubic.js +0 -3
  213. package/dist/ui/icons/images/smoothing-bezier-quad.js +0 -3
  214. package/dist/ui/icons/images/smoothing-linear.js +0 -3
  215. package/dist/ui/icons/images/star.js +0 -3
  216. package/dist/ui/icons/images/sun.js +0 -3
  217. package/dist/ui/icons/images/tilt.js +0 -3
  218. package/dist/ui/icons/images/undo.js +0 -3
  219. package/dist/ui/icons/images/unlinked.js +0 -3
  220. package/dist/ui/icons/images/unlocked.js +0 -3
  221. package/dist/ui/icons/images/visible.js +0 -3
  222. package/dist/ui/icons/images/zoom-in.js +0 -3
  223. package/dist/ui/icons/images/zoom-out.js +0 -3
  224. package/dist/ui/icons/images/zoom.js +0 -3
@@ -1,5 +1,6 @@
1
1
  import style_default from "./style.js";
2
2
  import { PcElement, defineElement, emit } from "../../base/index.js";
3
+ import { markDismissingPress } from "../../dismiss/index.js";
3
4
  import ChangeController from "../../ChangeController/index.js";
4
5
  import PaintCanvas, { Panel } from "../../../lib/classes/PaintCanvas/index.js";
5
6
  import KeyboardShortcuts, { SHORTCUT_EVENT } from "../../../lib/classes/KeyboardShortcuts/index.js";
@@ -13,7 +14,8 @@ import { DEFAULT_SIDE_MODES, STATE_EVENT, parseSideModes, sideModeFor } from "..
13
14
  import { hasToolSettings } from "../PcToolSettings/index.js";
14
15
  import "../PcPanel/index.js";
15
16
  import { PANE_COLLAPSE_EVENT, PcPane } from "../PcPane/index.js";
16
- import "../PcToolbar/index.js";
17
+ import { PcToolbar } from "../PcToolbar/index.js";
18
+ import "../PcClipboardTools/index.js";
17
19
  import "../PcCanvas/index.js";
18
20
  import "../PcCanvasMap/index.js";
19
21
  import "../PcPanelBrushes/index.js";
@@ -40,8 +42,10 @@ var TAKE_OVER_CHOICE = "take-over";
40
42
  * window), with slots to add or replace content:
41
43
  *
42
44
  * - `header`: across the top (empty by default)
43
- * - `left`: `<pc-toolbar>` (a pane) by default
44
- * - `top`: a horizontal `<pc-pane>` with `<pc-tool-settings>` (for tools that have settings) by default
45
+ * - `left`: `<pc-toolbar>` (a pane) by default; toolbars in the sides are minimised (their tools one button that opens a
46
+ * menu of them) while the layout is narrow
47
+ * - `top`: a horizontal `<pc-pane>` with `<pc-tool-settings>` (for tools that have settings) and, at its end,
48
+ * `<pc-clipboard-tools>` (cut, copy and paste; a ⋮ menu while the layout is narrow) by default
45
49
  * - `right`: a `<pc-pane>` with `<pc-panel-layers>` by default
46
50
  * - `center`: `<pc-canvas>` by default
47
51
  * - `overlay`: drawn over the canvas; `<pc-canvas-map>` by default
@@ -55,8 +59,9 @@ var TAKE_OVER_CHOICE = "take-over";
55
59
  *
56
60
  * Each side has a mode, chosen by the layout's width from `left-modes` and `right-modes` (default `"docked,
57
61
  * rail@600"`), which the layout gives the side's `<pc-pane>`s (see `PcPane`): `docked` beside the canvas; `rail`, a
58
- * column of buttons (one per panel) that open each panel over the canvas; or `floating`, the pane over the canvas as a
59
- * box that collapses to a button. Give side content in a `<pc-pane>` to have it follow the side's mode.
62
+ * column of buttons (one per panel) that open each panel over the canvas; `floating`, the pane over the canvas as a
63
+ * box that collapses to a button; or `overlay`, a rail over the canvas without a background (the canvas fills the
64
+ * width behind it). Give side content in a `<pc-pane>` to have it follow the side's mode.
60
65
  *
61
66
  * Reports its state for styling as attributes (`narrow`, `input="pen|touch|mouse"`, `ui-hidden`, `left-mode`,
62
67
  * `right-mode`) and as `pc-state-change` events (see `LayoutState`). Creates its own canvas unless given one, and
@@ -66,8 +71,8 @@ var TAKE_OVER_CHOICE = "take-over";
66
71
  * reloading the page (see `LayerAutosave`). While another window is drawing on it, the layout is blocked by a message
67
72
  * that offers to draw here instead. Fires `pc-toast` when the drawing can't be loaded or saved.
68
73
  *
69
- * With a `settings-store` name, the user's app settings (input settings, keyboard shortcuts, colour palette and
70
- * colours) are kept in the browser under that name (see `SettingsAutosave`). Fires `pc-toast` when they can't be.
74
+ * With a `settings-store` name, the user's app settings (input settings, keyboard shortcuts, colour palette, colours,
75
+ * theme and language) are kept in the browser under that name (see `SettingsAutosave`). Fires `pc-toast` when they can't be.
71
76
  *
72
77
  * @example
73
78
  * html`<paint-canvas style="height: 600px"></paint-canvas>`
@@ -137,7 +142,7 @@ var PaintCanvasElement = class extends PcElement {
137
142
  keys;
138
143
  /** The state last reported, to report only changes */
139
144
  reported;
140
- /** Space the floating sides cover over the canvas */
145
+ /** Space the floating and overlay sides cover over the canvas */
141
146
  floatingInsets = NO_INSETS;
142
147
  resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(([entry]) => {
143
148
  this.width = Math.round(entry?.contentRect.width ?? 0);
@@ -157,7 +162,7 @@ var PaintCanvasElement = class extends PcElement {
157
162
  onShortcut = (event) => {
158
163
  if (event.detail.type === "save") this.saveScreenshot();
159
164
  };
160
- onDocumentPointerDown = (event) => this.closePaletteOutside(event.composedPath());
165
+ onDocumentPointerDown = (event) => this.closePanelOutside(event);
161
166
  onPaneCollapse = () => this.requestUpdate();
162
167
  constructor() {
163
168
  super();
@@ -233,16 +238,18 @@ var PaintCanvasElement = class extends PcElement {
233
238
  const given = slot.assignedElements();
234
239
  return (given.length ? given : [...slot.children]).filter((element) => element instanceof PcPane);
235
240
  }
236
- /** Show each side's panes in the side's mode, facing the canvas */
241
+ /** Show each side's panes in the side's mode, facing the canvas, with toolbars minimised while the layout is narrow */
237
242
  setPaneModes() {
243
+ const narrow = this.width < this.narrowWidth;
238
244
  for (const side of SIDES) for (const pane of this.panesIn(side)) {
239
245
  pane.mode = this.modeOf(side);
240
246
  pane.edge = side;
247
+ if (pane instanceof PcToolbar) pane.minimised = narrow;
241
248
  }
242
249
  }
243
- /** Keep the canvas clear of floating sides when fitting it */
250
+ /** Keep the canvas clear of floating and overlay sides when fitting it */
244
251
  measureFloatingSides() {
245
- const width = (side) => this.panesIn(side).filter((pane) => pane.mode === "floating" && !pane.collapsed).reduce((widest, pane) => Math.max(widest, pane.getBoundingClientRect().width), 0);
252
+ const width = (side) => this.panesIn(side).filter((pane) => pane.mode === "floating" ? !pane.collapsed : pane.mode === "overlay").reduce((widest, pane) => Math.max(widest, pane.getBoundingClientRect().width), 0);
246
253
  const insets = {
247
254
  ...NO_INSETS,
248
255
  left: width("left"),
@@ -419,12 +426,16 @@ var PaintCanvasElement = class extends PcElement {
419
426
  </div>`;
420
427
  }
421
428
  /**
422
- * Close the colour palette on a press outside it and the colours that open it.
429
+ * Close the open panel (brush, eraser, layers, app menu or colour palette) on a press outside it and the button that
430
+ * opens it, marking the press (see `markDismissingPress`) so the canvas doesn't draw unless it's dragged. Presses in
431
+ * dialogs (e.g. one the panel opened) don't count as outside.
423
432
  */
424
- closePaletteOutside(path) {
425
- const app = this.app;
426
- if (app?.panel !== Panel.Palette) return;
427
- if (!path.some((target) => target instanceof Element && (target.localName === "pc-panel-colours" || target.localName === "pc-colour-pair"))) app.closePanel();
433
+ closePanelOutside(event) {
434
+ const panel = this.app?.panel;
435
+ if (!panel) return;
436
+ if (event.composedPath().some((target) => target instanceof Element && (target.classList.contains("panel") && target.getRootNode() === this.renderRoot || target.matches("dialog, pc-dialog, pc-dialog-window") || target.getAttribute("data-panel") === panel || panel === Panel.Palette && target.localName === "pc-colour-pair"))) return;
437
+ markDismissingPress(event);
438
+ this.app.closePanel();
428
439
  }
429
440
  /** The menus the toolbar opens, floating over the canvas beside it */
430
441
  renderPanels(app) {
@@ -473,6 +484,8 @@ var PaintCanvasElement = class extends PcElement {
473
484
  }];
474
485
  return html`<pc-dialog
475
486
  class="elsewhere"
487
+ inline
488
+ .dismissible=${false}
476
489
  heading=${this.t("paintCanvas.autosave.elsewhere")}
477
490
  message=${this.t("paintCanvas.autosave.elsewhereMessage")}
478
491
  .choices=${choices}
@@ -502,11 +515,17 @@ var PaintCanvasElement = class extends PcElement {
502
515
  .app=${app}
503
516
  @pc-configure-brush=${(event) => this.configure(event.detail)}
504
517
  ></pc-tool-settings
518
+ ><pc-clipboard-tools
519
+ slot="end"
520
+ .app=${app}
521
+ ?narrow=${this.width < this.narrowWidth}
522
+ ></pc-clipboard-tools
505
523
  ></pc-pane>` : nothing)}
506
524
  </div>
507
525
  <div
508
526
  class="center"
509
527
  part="center"
528
+ style="--pc-left-inset: ${this.floatingInsets.left}px"
510
529
  role="region"
511
530
  aria-label=${this.t("paintCanvas.layout.canvas")}
512
531
  ?inert=${blocked}
@@ -1,3 +1,3 @@
1
1
  // src/ui/elements/PaintCanvas/style.css?inline
2
- var style_default = "/* The layout: header across the top, footer across the bottom, sides left and right, and between them the tool\n settings, the canvas and the bottom bar. Empty areas take no space. */\n:host {\n position: relative;\n display: grid;\n grid-template:\n \"header header header\" auto\n \"left top right\" auto\n \"left center right\" 1fr\n \"left bottom right\" auto\n \"footer footer footer\" auto / auto 1fr auto;\n overflow: hidden;\n background: var(--pc-bar);\n font-family: var(--pc-font);\n font-size: var(--pc-font-size);\n}\nheader {\n grid-area: header;\n}\n.top {\n grid-area: top;\n min-width: 0;\n}\n/* The tool settings fill the top pane */\n.top pc-tool-settings {\n flex: 1;\n}\n.center {\n position: relative;\n grid-area: center;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n.bottom {\n grid-area: bottom;\n min-width: 0;\n}\nfooter {\n grid-area: footer;\n}\n.side {\n position: relative;\n z-index: 3;\n display: flex;\n min-height: 0;\n}\n/* A side's panes fill it */\n.side pc-pane,\n.side pc-toolbar,\n.side ::slotted(*) {\n flex: 1;\n}\n.side.left {\n grid-area: left;\n}\n.side.right {\n grid-area: right;\n}\n\n/* Hiding the interface (Tab key) leaves only the canvas */\n:host([ui-hidden]) header,\n:host([ui-hidden]) .top,\n:host([ui-hidden]) .bottom,\n:host([ui-hidden]) footer,\n:host([ui-hidden]) .side {\n display: none;\n}\n\n/* The canvas fills the middle; things drawn over it go in the overlay */\n.center ::slotted([slot=\"center\"]),\n.center pc-canvas {\n position: absolute;\n inset: 0;\n}\n.overlay {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n.overlay > * {\n pointer-events: auto;\n}\npc-canvas-map {\n position: absolute;\n right: 20px;\n bottom: 20px;\n}\n\n/* Menus opened from the toolbar float over the canvas, beside the toolbar */\n.panel {\n position: absolute;\n z-index: 4;\n left: 0;\n bottom: 0;\n max-height: 100%;\n overflow: auto;\n}\n.panel.top-panel {\n top: 0;\n bottom: auto;\n}\n/* The app menu: the implementer's content in a panel */\n.menu-panel:not([open]) {\n display: none;\n}\n\n/* Floating: the side's panes float over the canvas (see pc-pane), so the side takes no space */\n.side[data-mode=\"floating\"] {\n /* Beside the canvas only, so it floats over the canvas and not the tool settings */\n grid-row: 3;\n width: 0;\n}\n/* While another window is drawing, its message covers only the layout (not the whole page) */\npc-dialog.elsewhere {\n position: absolute;\n}\n";
2
+ var style_default = "/* The layout: header across the top, footer across the bottom, sides left and right, and between them the tool\n settings, the canvas and the bottom bar. Empty areas take no space. */\n:host {\n position: relative;\n display: grid;\n grid-template:\n \"header header header\" auto\n \"left top right\" auto\n \"left center right\" 1fr\n \"left bottom right\" auto\n \"footer footer footer\" auto / auto 1fr auto;\n overflow: hidden;\n background: var(--pc-bar);\n font-family: var(--pc-font);\n font-size: var(--pc-font-size);\n}\nheader {\n grid-area: header;\n}\n.top {\n grid-area: top;\n min-width: 0;\n}\n/* The tool settings fill the top pane */\n.top pc-tool-settings {\n flex: 1;\n}\n.center {\n position: relative;\n grid-area: center;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n.bottom {\n grid-area: bottom;\n min-width: 0;\n}\nfooter {\n grid-area: footer;\n}\n.side {\n position: relative;\n z-index: 3;\n display: flex;\n min-height: 0;\n}\n/* A side's panes fill it */\n.side pc-pane,\n.side pc-toolbar,\n.side ::slotted(*) {\n flex: 1;\n}\n.side.left {\n grid-area: left;\n}\n.side.right {\n grid-area: right;\n}\n\n/* Hiding the interface (Tab key) leaves only the canvas */\n:host([ui-hidden]) header,\n:host([ui-hidden]) .top,\n:host([ui-hidden]) .bottom,\n:host([ui-hidden]) footer,\n:host([ui-hidden]) .side {\n display: none;\n}\n\n/* The canvas fills the middle; things drawn over it go in the overlay */\n.center ::slotted([slot=\"center\"]),\n.center pc-canvas {\n position: absolute;\n inset: 0;\n}\n.overlay {\n position: absolute;\n inset: 0;\n pointer-events: none;\n}\n.overlay > * {\n pointer-events: auto;\n}\npc-canvas-map {\n position: absolute;\n right: 20px;\n bottom: 20px;\n}\n\n/* Menus opened from the toolbar float over the canvas, beside the toolbar */\n.panel {\n position: absolute;\n z-index: 4;\n left: 0;\n bottom: 0;\n max-height: 100%;\n overflow: auto;\n}\n.panel.top-panel {\n top: 0;\n bottom: auto;\n}\n/* The app menu: the implementer's content in a panel */\n.menu-panel:not([open]) {\n display: none;\n}\n\n/* Floating: the side's panes float over the canvas (see pc-pane), so the side takes no space */\n.side[data-mode=\"floating\"] {\n /* Beside the canvas only, so it floats over the canvas and not the tool settings */\n grid-row: 3;\n width: 0;\n}\n/* Overlay: the side's rail sits over the canvas (beside it only, not the tool settings), so the canvas fills the\n width behind it; presses between its panes' buttons (which take presses themselves) reach the canvas */\n.side[data-mode=\"overlay\"] {\n grid-row: 3;\n grid-column: 1 / -1;\n pointer-events: none;\n}\n.side.left[data-mode=\"overlay\"] {\n justify-self: start;\n}\n.side.right[data-mode=\"overlay\"] {\n justify-self: end;\n}\n/* The toolbar's panels open beside a left overlay rail, not under it */\n:host([left-mode=\"overlay\"]) .panel {\n left: var(--pc-left-inset);\n}\n";
3
3
  export { style_default as default };
@@ -1,14 +1,15 @@
1
- import { nothing, type PropertyValues } from "lit";
1
+ import { nothing } from "lit";
2
2
  import { PcElement } from "../../base";
3
3
  import "../PcShortcutSettings";
4
+ import "../PcDialogWindow";
4
5
  import type PaintCanvas from "../../../lib/classes/PaintCanvas";
5
6
  import { type SaveMethod } from "../../../lib/rendering/screenshot";
6
7
  /**
7
8
  * Buttons for the user's app settings: "Keyboard shortcuts", which opens a window to change them (see
8
9
  * `pc-shortcut-settings`), and "Import settings" and "Export settings", which read and write a settings JSON file (input
9
- * settings, keyboard shortcuts, colour palette and colours). The window is a modal `<dialog>` above the whole page; it
10
- * closes with its Close button, Escape, or a press on the backdrop, and the browser gives focus back to the button. Fires `pc-toast` after importing, or when importing or
11
- * exporting fails.
10
+ * settings, keyboard shortcuts, colour palette, colours, profile graphs, theme and language). The window is a shaded
11
+ * `<pc-dialog-window>` over the whole page; it closes with its ⨉ button, Escape or a press outside it, and focus goes
12
+ * back to the button. Fires `pc-toast` after importing, or when importing or exporting fails.
12
13
  *
13
14
  * @example
14
15
  * html`<pc-app-settings .app=${canvas}></pc-app-settings>`
@@ -40,7 +41,6 @@ export declare class PcAppSettings extends PcElement {
40
41
  /** Saves exported files (replaceable for tests) */
41
42
  saveFile: (blob: Blob, name: string) => Promise<SaveMethod | undefined>;
42
43
  constructor();
43
- protected updated(changed: PropertyValues<this>): void;
44
44
  /** Close the keyboard shortcuts window */
45
45
  closeShortcuts(): void;
46
46
  /**
@@ -53,7 +53,7 @@ export declare class PcAppSettings extends PcElement {
53
53
  exportFile(): Promise<void>;
54
54
  /** Show a settings file error (one of `SETTINGS_FILE_ERRORS`) in the chosen language */
55
55
  private toastError;
56
- /** The keyboard shortcuts window: a modal dialog, with its contents only while open */
56
+ /** The keyboard shortcuts window, with its contents only while open */
57
57
  private renderShortcuts;
58
58
  render(): import("lit").TemplateResult<1> | typeof nothing;
59
59
  }
@@ -2,6 +2,7 @@ import { SETTINGS_FILE_FORMAT } from "../../../lib/settings/schema.js";
2
2
  import { ICON_CONTROLS_CSS, PILLS_CSS, WINDOWS_CSS } from "../../styles/index.js";
3
3
  import { PcElement, defineElement, emit } from "../../base/index.js";
4
4
  import "../PcShortcutSettings/index.js";
5
+ import "../PcDialogWindow/index.js";
5
6
  import { SETTINGS_FILE_ERRORS, SettingsFileError, applySettings, collectSettings, exportSettingsFile, parseSettingsFile, settingsFileName } from "../../../lib/settings/index.js";
6
7
  import { JSON_FILE_TYPE, saveFile } from "../../../lib/rendering/screenshot/index.js";
7
8
  import { css, html, nothing, unsafeCSS } from "lit";
@@ -14,9 +15,9 @@ var SETTINGS_FILE_ERROR_KEYS = {
14
15
  /**
15
16
  * Buttons for the user's app settings: "Keyboard shortcuts", which opens a window to change them (see
16
17
  * `pc-shortcut-settings`), and "Import settings" and "Export settings", which read and write a settings JSON file (input
17
- * settings, keyboard shortcuts, colour palette and colours). The window is a modal `<dialog>` above the whole page; it
18
- * closes with its Close button, Escape, or a press on the backdrop, and the browser gives focus back to the button. Fires `pc-toast` after importing, or when importing or
19
- * exporting fails.
18
+ * settings, keyboard shortcuts, colour palette, colours, profile graphs, theme and language). The window is a shaded
19
+ * `<pc-dialog-window>` over the whole page; it closes with its ⨉ button, Escape or a press outside it, and focus goes
20
+ * back to the button. Fires `pc-toast` after importing, or when importing or exporting fails.
20
21
  *
21
22
  * @example
22
23
  * html`<pc-app-settings .app=${canvas}></pc-app-settings>`
@@ -48,32 +49,8 @@ var PcAppSettings = class extends PcElement {
48
49
  flex-wrap: wrap;
49
50
  gap: var(--pc-space-2);
50
51
  }
51
- /* A modal window in the browser's top layer, above everything on the page */
52
- dialog {
53
- box-sizing: border-box;
54
- width: min(480px, calc(100vw - 2 * var(--pc-space-3)));
55
- max-height: calc(100vh - 2 * var(--pc-space-3));
56
- padding: 0;
57
- border: 0;
58
- border-radius: var(--pc-radius);
59
- background: var(--pc-surface-raised);
60
- color: var(--pc-text);
61
- box-shadow: var(--pc-shadow);
62
- }
63
- dialog::backdrop {
64
- background: var(--pc-backdrop);
65
- }
66
- .window {
67
- display: flex;
68
- flex-direction: column;
69
- gap: var(--pc-space-3);
70
- box-shadow: none;
71
- }
72
- .header {
73
- display: flex;
74
- gap: var(--pc-space-2);
75
- align-items: center;
76
- justify-content: space-between;
52
+ pc-dialog-window {
53
+ --pc-dialog-width: 480px;
77
54
  }
78
55
  h2 {
79
56
  margin: 0;
@@ -87,13 +64,6 @@ var PcAppSettings = class extends PcElement {
87
64
  super();
88
65
  this.shortcutsOpen = false;
89
66
  }
90
- updated(changed) {
91
- if (!changed.has("shortcutsOpen")) return;
92
- const dialog = this.renderRoot.querySelector("dialog");
93
- if (!dialog) return;
94
- if (this.shortcutsOpen && !dialog.open) dialog.showModal();
95
- else if (!this.shortcutsOpen && dialog.open) dialog.close();
96
- }
97
67
  /** Close the keyboard shortcuts window */
98
68
  closeShortcuts() {
99
69
  this.shortcutsOpen = false;
@@ -143,34 +113,20 @@ var PcAppSettings = class extends PcElement {
143
113
  kind: "error"
144
114
  });
145
115
  }
146
- /** The keyboard shortcuts window: a modal dialog, with its contents only while open */
116
+ /** The keyboard shortcuts window, with its contents only while open */
147
117
  renderShortcuts(app) {
148
- return html`<dialog
149
- aria-labelledby="shortcuts-title"
150
- @close=${() => this.closeShortcuts()}
151
- @click=${(e) => {
152
- if (e.target === e.currentTarget) this.closeShortcuts();
153
- }}
118
+ return html`<pc-dialog-window
119
+ class="shortcuts-window"
120
+ shaded
121
+ ?open=${this.shortcutsOpen}
122
+ @pc-dismiss=${() => this.closeShortcuts()}
154
123
  >
155
- ${this.shortcutsOpen ? html`<div class="window">
156
- <div class="header">
157
- <h2 id="shortcuts-title">
158
- ${this.t("paintCanvas.shortcuts.title")}
159
- </h2>
160
- <button
161
- type="button"
162
- class="close dismiss"
163
- autofocus
164
- @click=${() => this.closeShortcuts()}
165
- >
166
- ${this.t("paintCanvas.common.close")}
167
- </button>
168
- </div>
169
- <pc-shortcut-settings
170
- .settings=${app.shortcuts}
171
- ></pc-shortcut-settings>
172
- </div>` : nothing}
173
- </dialog>`;
124
+ <h2 slot="header-middle">${this.t("paintCanvas.shortcuts.title")}</h2>
125
+ ${this.shortcutsOpen ? html`<pc-shortcut-settings
126
+ slot="body"
127
+ .settings=${app.shortcuts}
128
+ ></pc-shortcut-settings>` : nothing}
129
+ </pc-dialog-window>`;
174
130
  }
175
131
  render() {
176
132
  const app = this.app;
@@ -178,7 +134,7 @@ var PcAppSettings = class extends PcElement {
178
134
  return html`<div class="actions">
179
135
  <button
180
136
  type="button"
181
- class="pill shortcuts"
137
+ class="pill-s shortcuts"
182
138
  aria-haspopup="dialog"
183
139
  @click=${() => this.shortcutsOpen = true}
184
140
  >
@@ -186,14 +142,14 @@ var PcAppSettings = class extends PcElement {
186
142
  </button>
187
143
  <button
188
144
  type="button"
189
- class="pill import"
145
+ class="pill-s import"
190
146
  @click=${() => this.renderRoot.querySelector(".import-file")?.click()}
191
147
  >
192
148
  ${this.t("paintCanvas.settings.import")}
193
149
  </button>
194
150
  <button
195
151
  type="button"
196
- class="pill export"
152
+ class="pill-s export"
197
153
  @click=${() => void this.exportFile()}
198
154
  >
199
155
  ${this.t("paintCanvas.settings.export")}
@@ -1,13 +1,15 @@
1
1
  import { nothing } from "lit";
2
+ import { type ConfirmFn, type PromptFn } from "../../ask";
2
3
  import { PcElement } from "../../base";
3
4
  import "../PcBrushTest";
5
+ import "../PcDialogWindow";
6
+ import "../PcSliderRange";
7
+ import "../PcProfileEditor";
4
8
  import type PaintCanvas from "../../../lib/classes/PaintCanvas";
5
9
  import { SmoothingType, type BrushConfig } from "../../../lib/brushes/types";
10
+ import { type VaryingParam } from "../../../lib/brushes/configRanges";
6
11
  import { type ShapeImage } from "../../../lib/brushes/shapeImage";
7
- /** Asks the user to confirm; replaceable for tests */
8
- export type ConfirmFn = (message: string) => boolean;
9
- /** Asks the user for text; replaceable for tests */
10
- export type PromptFn = (message: string, value: string) => string | null;
12
+ export type { ConfirmFn, PromptFn } from "../../ask";
11
13
  /** The smoothing choices, in the order shown: value, translation key of the name, and icon name */
12
14
  export declare const SMOOTHING_CHOICES: readonly [{
13
15
  readonly value: SmoothingType.Linear;
@@ -23,14 +25,16 @@ export declare const SMOOTHING_CHOICES: readonly [{
23
25
  readonly icon: "smoothingBezierCubic";
24
26
  }];
25
27
  /**
26
- * The brush (or eraser) configuration window: a testing area, the shape (upload or paste), smoothing, width, height,
28
+ * The brush (or eraser) configuration window: a testing area, the shape (pressing it picks a built-in shape from the
29
+ * device's own list, which says "Custom" for an uploaded or pasted one; or upload or paste one), smoothing, width, height,
27
30
  * opacity, rotation, offsets, sample rate, spacing and snapping to the pixel grid. Width, height, opacity, rotation and the offsets can vary with
28
- * pressure, tilt and randomness; when any is on, the setting has a min and max.
31
+ * pressure, tilt and randomness; when any is on, the setting has a min and max, set with a `<pc-slider-range>`.
29
32
  *
30
33
  * Changes stay in the window until "Save" (fires `pc-save` with the settings, to apply to the current tool) or "Add to
31
34
  * presets" (saves them as one of the user's presets, asking before replacing one with the same name, and selects it).
32
- * "Delete preset…" shows when editing one of the user's presets. Fires `pc-close` when closed, and `pc-toast` with a
33
- * message after adding or deleting a preset, or when a shape can't be used. Styling is structural only.
35
+ * "Delete preset…" shows when editing one of the user's presets. It's a shaded `<pc-dialog-window>`, closed with its ⨉
36
+ * button or Escape (not a press outside it, which would lose the changes). Fires `pc-close` when closed, and `pc-toast`
37
+ * with a message after adding or deleting a preset, or when a shape can't be used.
34
38
  *
35
39
  * @example
36
40
  * html`<pc-brush-config .app=${app} kind="brush" .config=${app.brush.preset} @pc-save=${apply}></pc-brush-config>`
@@ -55,6 +59,9 @@ export declare class PcBrushConfig extends PcElement {
55
59
  busy: {
56
60
  state: boolean;
57
61
  };
62
+ editingProfile: {
63
+ state: boolean;
64
+ };
58
65
  translations: {
59
66
  attribute: boolean;
60
67
  };
@@ -78,16 +85,19 @@ export declare class PcBrushConfig extends PcElement {
78
85
  draft?: BrushConfig;
79
86
  /** Whether a preset is being saved or deleted */
80
87
  busy: boolean;
88
+ /** The setting whose profile graph is being edited, if any */
89
+ editingProfile?: VaryingParam;
90
+ /** Asks the user to confirm, in a dialog (replaceable for tests) */
81
91
  confirm: ConfirmFn;
92
+ /** Asks the user for text, in a dialog (replaceable for tests) */
82
93
  prompt: PromptFn;
83
94
  /** Turns files into brush shapes (replaceable for tests) */
84
95
  readShape: (file: File) => Promise<ShapeImage>;
85
- /** Reads a brush shape from the clipboard (replaceable for tests) */
96
+ /**
97
+ * Reads a brush shape from the clipboard, or else from image data copied on the canvas (replaceable for tests)
98
+ */
86
99
  readClipboard: () => Promise<ShapeImage>;
87
- private readonly onKeyDown;
88
100
  constructor();
89
- connectedCallback(): void;
90
- disconnectedCallback(): void;
91
101
  protected willUpdate(changed: Map<PropertyKey, unknown>): void;
92
102
  /** Fire an event that crosses shadow DOM boundaries */
93
103
  private emit;
@@ -118,13 +128,21 @@ export declare class PcBrushConfig extends PcElement {
118
128
  * Delete the preset being edited, after confirming.
119
129
  */
120
130
  deletePreset(): Promise<void>;
121
- /** Render a number input */
122
- private number;
123
- /** Render a range slider */
124
- private slider;
131
+ /**
132
+ * Render a slider for one value (a single `<pc-slider-range>`), the same as the ranges of settings that vary.
133
+ */
134
+ private single;
125
135
  /** Render a setting that can vary: its value (or min and max), and its pressure, tilt and randomise icon toggles */
126
136
  private renderParam;
137
+ /**
138
+ * Use a built-in shape (see `BUILT_IN_SHAPES`), keeping the width; they're all square, so the height is the same.
139
+ */
140
+ private useBuiltInShape;
127
141
  /** Render the shape and smoothing row */
128
142
  private renderShape;
129
143
  render(): import("lit").TemplateResult<1> | typeof nothing;
144
+ /** The profile graph editor for the setting being edited, while open */
145
+ private renderProfileEditor;
146
+ /** Profile graphs, when there's no canvas to keep them */
147
+ private readonly profiles;
130
148
  }