@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,13 +1,21 @@
1
1
  import style_default from "./style.js";
2
2
  import { ICON_CONTROLS_CSS, PILLS_CSS, WINDOWS_CSS } from "../../styles/index.js";
3
3
  import { iconLabel } from "../../icons/index.js";
4
+ import { askConfirm, askText, deletePresetQuestion } from "../../ask/index.js";
4
5
  import { PcElement, defineElement } from "../../base/index.js";
5
6
  import "../PcBrushTest/index.js";
7
+ import "../PcDialogWindow/index.js";
8
+ import "../PcSliderRange/index.js";
9
+ import "../PcProfileEditor/index.js";
10
+ import ProfileGraphs from "../../../lib/classes/ProfileGraphs/index.js";
11
+ import { isLinear } from "../../../lib/profiles/index.js";
6
12
  import { SmoothingType } from "../../../lib/brushes/types/index.js";
7
- import { PARAM_LIMITS, VARIATION_SOURCES, readRange, toggleSource, writeRange } from "../../../lib/brushes/configRanges/index.js";
13
+ import { PARAM_LIMITS, VARIATION_SOURCES, configKey, readRange, selectSource, writeRange } from "../../../lib/brushes/configRanges/index.js";
8
14
  import { SHAPE_ERRORS, ShapeImageError, readClipboardShape, readShapeImage } from "../../../lib/brushes/shapeImage/index.js";
15
+ import { BUILT_IN_SHAPES, builtInShapeId } from "../../../lib/brushes/shapes/index.js";
9
16
  import "../../../lib/brushes/StrokeSampler/index.js";
10
17
  import { html, nothing, unsafeCSS } from "lit";
18
+ import { live } from "lit/directives/live.js";
11
19
  import { styleMap } from "lit/directives/style-map.js";
12
20
  // src/ui/elements/PcBrushConfig/index.ts
13
21
  /** The smoothing choices, in the order shown: value, translation key of the name, and icon name */
@@ -34,12 +42,23 @@ var SOURCE_ICONS = {
34
42
  tilt: "tilt",
35
43
  randomise: "randomise"
36
44
  };
45
+ /** Translation keys of the varying settings' names */
46
+ var PARAM_LABELS = {
47
+ width: "paintCanvas.common.width",
48
+ height: "paintCanvas.common.height",
49
+ alpha: "paintCanvas.common.opacity",
50
+ rotation: "paintCanvas.brushConfig.rotation",
51
+ offsetX: "paintCanvas.brushConfig.offsetX",
52
+ offsetY: "paintCanvas.brushConfig.offsetY"
53
+ };
37
54
  /** Translation keys of the variation sources' names */
38
55
  var SOURCE_LABELS = {
39
56
  pressure: "paintCanvas.toolSettings.pressure",
40
57
  tilt: "paintCanvas.toolSettings.tilt",
41
58
  randomise: "paintCanvas.brushConfig.randomise"
42
59
  };
60
+ /** The shape picker's value for a shape the user uploaded or pasted */
61
+ var CUSTOM_SHAPE = "custom";
43
62
  /** Translation keys of the brush shape error messages */
44
63
  var SHAPE_ERROR_KEYS = {
45
64
  [SHAPE_ERRORS.type]: "paintCanvas.shape.notPng",
@@ -49,20 +68,17 @@ var SHAPE_ERROR_KEYS = {
49
68
  };
50
69
  /** Largest stamp spacing in pixels */
51
70
  var MAX_SPACING = 200;
52
- /** Read a number input, or undefined if it isn't a number */
53
- var numberValue = (event) => {
54
- const value = event.target.valueAsNumber;
55
- return Number.isFinite(value) ? value : void 0;
56
- };
57
71
  /**
58
- * The brush (or eraser) configuration window: a testing area, the shape (upload or paste), smoothing, width, height,
72
+ * The brush (or eraser) configuration window: a testing area, the shape (pressing it picks a built-in shape from the
73
+ * device's own list, which says "Custom" for an uploaded or pasted one; or upload or paste one), smoothing, width, height,
59
74
  * opacity, rotation, offsets, sample rate, spacing and snapping to the pixel grid. Width, height, opacity, rotation and the offsets can vary with
60
- * pressure, tilt and randomness; when any is on, the setting has a min and max.
75
+ * pressure, tilt and randomness; when any is on, the setting has a min and max, set with a `<pc-slider-range>`.
61
76
  *
62
77
  * Changes stay in the window until "Save" (fires `pc-save` with the settings, to apply to the current tool) or "Add to
63
78
  * presets" (saves them as one of the user's presets, asking before replacing one with the same name, and selects it).
64
- * "Delete preset…" shows when editing one of the user's presets. Fires `pc-close` when closed, and `pc-toast` with a
65
- * message after adding or deleting a preset, or when a shape can't be used. Styling is structural only.
79
+ * "Delete preset…" shows when editing one of the user's presets. It's a shaded `<pc-dialog-window>`, closed with its ⨉
80
+ * button or Escape (not a press outside it, which would lose the changes). Fires `pc-close` when closed, and `pc-toast`
81
+ * with a message after adding or deleting a preset, or when a shape can't be used.
66
82
  *
67
83
  * @example
68
84
  * html`<pc-brush-config .app=${app} kind="brush" .config=${app.brush.preset} @pc-save=${apply}></pc-brush-config>`
@@ -75,7 +91,8 @@ var PcBrushConfig = class extends PcElement {
75
91
  config: { attribute: false },
76
92
  editingId: { type: String },
77
93
  draft: { state: true },
78
- busy: { state: true }
94
+ busy: { state: true },
95
+ editingProfile: { state: true }
79
96
  };
80
97
  static styles = [
81
98
  PcElement.styles,
@@ -84,28 +101,21 @@ var PcBrushConfig = class extends PcElement {
84
101
  unsafeCSS(ICON_CONTROLS_CSS),
85
102
  unsafeCSS(PILLS_CSS)
86
103
  ];
87
- confirm = (message) => window.confirm(message);
88
- prompt = (message, value) => window.prompt(message, value);
104
+ /** Asks the user to confirm, in a dialog (replaceable for tests) */
105
+ confirm = (options) => askConfirm(this.renderRoot, options);
106
+ /** Asks the user for text, in a dialog (replaceable for tests) */
107
+ prompt = (options) => askText(this.renderRoot, options);
89
108
  /** Turns files into brush shapes (replaceable for tests) */
90
109
  readShape = readShapeImage;
91
- /** Reads a brush shape from the clipboard (replaceable for tests) */
92
- readClipboard = () => readClipboardShape();
93
- onKeyDown = (event) => {
94
- if (event.key === "Escape") this.close();
95
- };
110
+ /**
111
+ * Reads a brush shape from the clipboard, or else from image data copied on the canvas (replaceable for tests)
112
+ */
113
+ readClipboard = () => readClipboardShape(navigator.clipboard, {}, async () => this.app?.copiedPng());
96
114
  constructor() {
97
115
  super();
98
116
  this.kind = "brush";
99
117
  this.busy = false;
100
118
  }
101
- connectedCallback() {
102
- super.connectedCallback();
103
- window.addEventListener("keydown", this.onKeyDown);
104
- }
105
- disconnectedCallback() {
106
- super.disconnectedCallback();
107
- window.removeEventListener("keydown", this.onKeyDown);
108
- }
109
119
  willUpdate(changed) {
110
120
  super.willUpdate(changed);
111
121
  if (changed.has("config") && this.config) this.draft = structuredClone(this.config);
@@ -183,10 +193,22 @@ var PcBrushConfig = class extends PcElement {
183
193
  const app = this.app;
184
194
  const draft = this.draft;
185
195
  if (!app || !draft) return;
186
- const name = this.prompt(this.t("paintCanvas.brushConfig.presetName"), draft.name ?? "")?.trim();
196
+ const name = (await this.prompt({
197
+ heading: this.t("paintCanvas.brushConfig.addToPresets"),
198
+ label: this.t("paintCanvas.brushConfig.presetName"),
199
+ value: draft.name ?? "",
200
+ confirm: this.t("paintCanvas.common.save"),
201
+ cancel: this.t("paintCanvas.common.cancel")
202
+ }))?.trim();
187
203
  if (!name) return;
188
204
  const existing = app.customPresets.findOwn(name, app.authorHandle, app.names.unknownAuthor);
189
- if (existing && !this.confirm(this.t("paintCanvas.presets.replaceConfirm", { name }))) return;
205
+ if (existing && !await this.confirm({
206
+ heading: this.t("paintCanvas.presets.replaceHeading"),
207
+ message: this.t("paintCanvas.presets.replaceConfirm", { name }),
208
+ confirm: this.t("paintCanvas.presets.replace"),
209
+ cancel: this.t("paintCanvas.common.cancel"),
210
+ cancelling: true
211
+ })) return;
190
212
  const preset = {
191
213
  ...app.newPreset(draft, name),
192
214
  ...existing ? { id: existing.id } : {}
@@ -217,7 +239,7 @@ var PcBrushConfig = class extends PcElement {
217
239
  const id = this.editingId;
218
240
  if (!app || !id) return;
219
241
  const name = app.customPresets.get(id)?.name ?? "this preset";
220
- if (!this.confirm(this.t("paintCanvas.presets.deleteConfirm", { name }))) return;
242
+ if (!await this.confirm(deletePresetQuestion(this.translations, name))) return;
221
243
  this.busy = true;
222
244
  try {
223
245
  await app.customPresets.remove(id);
@@ -235,32 +257,22 @@ var PcBrushConfig = class extends PcElement {
235
257
  this.busy = false;
236
258
  }
237
259
  }
238
- /** Render a number input */
239
- number(className, value, limits, onChange, disabled = false) {
240
- return html`<input
241
- type="number"
242
- class=${className}
243
- min=${limits.min}
244
- max=${limits.max}
245
- ?disabled=${disabled || this.busy}
246
- .value=${String(Math.round(value))}
247
- @change=${(e) => {
248
- const next = numberValue(e);
249
- if (next !== void 0) onChange(next);
250
- }}
251
- />`;
252
- }
253
- /** Render a range slider */
254
- slider(className, value, limits, onChange, disabled = false) {
255
- return html`<input
256
- type="range"
260
+ /**
261
+ * Render a slider for one value (a single `<pc-slider-range>`), the same as the ranges of settings that vary.
262
+ */
263
+ single(className, label, value, limits, onChange, disabled = false) {
264
+ const changed = (event) => onChange(event.detail.value);
265
+ return html`<pc-slider-range
266
+ single
257
267
  class=${className}
268
+ label=${label}
258
269
  min=${limits.min}
259
270
  max=${limits.max}
271
+ .value=${live(Math.round(value))}
260
272
  ?disabled=${disabled || this.busy}
261
- .value=${String(value)}
262
- @input=${(e) => onChange(e.target.valueAsNumber)}
263
- />`;
273
+ @pc-input=${changed}
274
+ @pc-change=${changed}
275
+ ></pc-slider-range>`;
264
276
  }
265
277
  /** Render a setting that can vary: its value (or min and max), and its pressure, tilt and randomise icon toggles */
266
278
  renderParam(draft, param, label, disabled = false) {
@@ -268,42 +280,105 @@ var PcBrushConfig = class extends PcElement {
268
280
  const limits = PARAM_LIMITS[param];
269
281
  const isOffset = param === "offsetX" || param === "offsetY";
270
282
  const write = (values) => this.changeParam(param, writeRange(draft, param, values));
271
- const values = range.varies ? html`${this.number(`${param} min`, range.min, limits, (min) => write({ min }), disabled)}
272
- ${this.slider(`${param} min`, range.min, limits, (min) => write({ min }), disabled)}
273
- ${this.slider(`${param} max`, range.max, limits, (max) => write({ max }), disabled)}
274
- ${this.number(`${param} max`, range.max, limits, (max) => write({ max }), disabled)}` : html`${this.number(param, range.value, limits, (value) => write({ value }), disabled || isOffset)}
275
- ${this.slider(param, range.value, limits, (value) => write({ value }), disabled || isOffset)}`;
283
+ const writeEnds = (event) => write({
284
+ min: event.detail.low,
285
+ max: event.detail.high
286
+ });
287
+ const values = range.varies ? html`<pc-slider-range
288
+ class=${`${param} range`}
289
+ label=${label}
290
+ min=${limits.min}
291
+ max=${limits.max}
292
+ .low=${live(Math.round(range.min))}
293
+ .high=${live(Math.round(range.max))}
294
+ ?disabled=${disabled || this.busy}
295
+ @pc-input=${writeEnds}
296
+ @pc-change=${writeEnds}
297
+ ></pc-slider-range>` : this.single(param, label, range.value, limits, (value) => write({ value }), disabled || isOffset);
298
+ const active = VARIATION_SOURCES.find((source) => range.sources[source]);
299
+ const select = (source) => this.changeParam(param, selectSource(draft, param, source));
276
300
  return html`<div class="row" data-param=${param}>
277
301
  <span class="label">${label}</span>
278
302
  ${values}
279
- ${VARIATION_SOURCES.map((source) => html`<label
280
- class="icon-toggle"
281
- title=${this.t(SOURCE_LABELS[source])}
282
- >
283
- <input
284
- type="checkbox"
285
- class=${`${param} ${source}`}
286
- aria-label=${this.t("paintCanvas.brushConfig.variation", {
303
+ <fieldset class="sources" ?disabled=${disabled || this.busy}>
304
+ <legend class="visually-hidden">
305
+ ${this.t("paintCanvas.brushConfig.varyWith", { param: label })}
306
+ </legend>
307
+ ${VARIATION_SOURCES.map((source) => html`<label
308
+ class="icon-toggle"
309
+ title=${this.t(SOURCE_LABELS[source])}
310
+ >
311
+ <input
312
+ type="radio"
313
+ name=${`${param}-source`}
314
+ class=${`${param} ${source}`}
315
+ aria-label=${this.t("paintCanvas.brushConfig.variation", {
287
316
  param: label,
288
317
  source: this.t(SOURCE_LABELS[source])
289
318
  })}
290
- .checked=${range.sources[source]}
291
- ?disabled=${disabled || this.busy}
292
- @change=${(e) => this.changeParam(param, toggleSource(draft, param, source, e.target.checked))}
293
- />
294
- ${iconLabel(this.iconUrl(SOURCE_ICONS[source]), this.t(SOURCE_LABELS[source]))}
295
- </label>`)}
319
+ .checked=${live(active === source)}
320
+ @change=${() => select(source)}
321
+ @click=${() => {
322
+ if (active === source) select(void 0);
323
+ }}
324
+ />
325
+ ${iconLabel(this.iconUrl(SOURCE_ICONS[source]), this.t(SOURCE_LABELS[source]))}
326
+ </label>`)}
327
+ </fieldset>
328
+ <button
329
+ type="button"
330
+ class=${`icon-button profile ${param} ${draft[configKey(param)]?.profile ? "configured" : ""}`}
331
+ title=${this.t("paintCanvas.profileEditor.button", { param: label })}
332
+ aria-haspopup="dialog"
333
+ ?disabled=${!active || disabled || this.busy}
334
+ @click=${() => this.editingProfile = param}
335
+ >
336
+ ${iconLabel(this.iconUrl("profileGraph"), this.t("paintCanvas.profileEditor.button", { param: label }))}
337
+ </button>
296
338
  </div>`;
297
339
  }
340
+ /**
341
+ * Use a built-in shape (see `BUILT_IN_SHAPES`), keeping the width; they're all square, so the height is the same.
342
+ */
343
+ useBuiltInShape(id) {
344
+ const shape = BUILT_IN_SHAPES.find((built) => built.id === id);
345
+ if (!shape) return;
346
+ const width = this.draft?.width ?? 1;
347
+ this.change({
348
+ image: shape.image,
349
+ height: width
350
+ });
351
+ }
298
352
  /** Render the shape and smoothing row */
299
353
  renderShape(draft) {
354
+ const shapeId = builtInShapeId(draft.image);
300
355
  const smoothing = draft.smoothingType === SmoothingType.None || draft.smoothingType === void 0 ? SmoothingType.Linear : draft.smoothingType;
301
356
  return html`<div class="row shape-row">
302
357
  <span class="label">${this.t("paintCanvas.brushConfig.shape")}</span>
303
- <span
304
- class=${draft.image ? "shape-preview image" : "shape-preview"}
305
- style=${styleMap({ maskImage: typeof draft.image === "string" ? `url("${draft.image}")` : void 0 })}
306
- ></span>
358
+ <span class="shape-picker">
359
+ <span
360
+ class=${draft.image ? "shape-preview image" : "shape-preview"}
361
+ style=${styleMap({ maskImage: typeof draft.image === "string" ? `url("${draft.image}")` : void 0 })}
362
+ ></span>
363
+ <!-- Over the shape, so pressing it opens the device's own list -->
364
+ <select
365
+ class="shape-select"
366
+ aria-label=${this.t("paintCanvas.brushConfig.shape")}
367
+ title=${this.t("paintCanvas.brushConfig.chooseShape")}
368
+ ?disabled=${this.busy}
369
+ @change=${(e) => this.useBuiltInShape(e.target.value)}
370
+ >
371
+ ${shapeId === void 0 ? html`<option value=${CUSTOM_SHAPE} .selected=${true}>
372
+ ${this.t("paintCanvas.brushConfig.customShape")}
373
+ </option>` : nothing}
374
+ ${BUILT_IN_SHAPES.map((shape) => html`<option
375
+ value=${shape.id}
376
+ .selected=${live(shape.id === shapeId)}
377
+ >
378
+ ${shape.name}
379
+ </option>`)}
380
+ </select>
381
+ </span>
307
382
  <button
308
383
  type="button"
309
384
  class="pill upload"
@@ -366,13 +441,17 @@ var PcBrushConfig = class extends PcElement {
366
441
  min: 0,
367
442
  max: MAX_SPACING
368
443
  };
369
- return html`<div
370
- role="dialog"
371
- aria-modal="true"
372
- aria-label=${this.t(this.kind === "eraser" ? "paintCanvas.brushConfig.eraserTitle" : "paintCanvas.brushConfig.brushTitle")}
373
- >
374
- <div class="row header">
375
- <label>
444
+ return html`<pc-dialog-window
445
+ open
446
+ shaded
447
+ dismissible="false"
448
+ label=${this.t(this.kind === "eraser" ? "paintCanvas.brushConfig.eraserTitle" : "paintCanvas.brushConfig.brushTitle")}
449
+ @pc-dismiss=${(event) => {
450
+ event.preventDefault();
451
+ this.close();
452
+ }}
453
+ >
454
+ <label slot="header-start" class="name-field">
376
455
  ${this.t("paintCanvas.brushConfig.name")}
377
456
  <input
378
457
  class="name"
@@ -381,86 +460,117 @@ var PcBrushConfig = class extends PcElement {
381
460
  @input=${(e) => this.change({ name: e.target.value })}
382
461
  />
383
462
  </label>
384
- <button
385
- type="button"
386
- class="close dismiss"
387
- @click=${() => this.close()}
388
- >
389
- ${this.t("paintCanvas.common.dismiss")}
390
- </button>
391
- </div>
392
- <pc-brush-test .config=${draft} .tips=${this.app?.tips}></pc-brush-test>
393
- ${this.renderShape(draft)}
394
- ${this.renderParam(draft, "width", this.t("paintCanvas.common.width"))}
395
- <div class="row">
396
- <span class="label"></span>
397
- <label
398
- class="icon-toggle"
399
- title=${this.t("paintCanvas.toolSettings.constrainProportions")}
400
- >
401
- <input
402
- type="checkbox"
403
- class="constrain"
404
- .checked=${constrained}
405
- ?disabled=${this.busy}
406
- @change=${(e) => this.change({ constrainProportions: e.target.checked })}
407
- />
408
- ${iconLabel(this.iconUrl(constrained ? "linked" : "unlinked"), this.t("paintCanvas.toolSettings.constrainProportions"))}
409
- </label>
410
- </div>
411
- ${this.renderParam(draft, "height", this.t("paintCanvas.common.height"), constrained)}
412
- ${this.renderParam(draft, "alpha", this.t("paintCanvas.common.opacity"))}
413
- ${this.renderParam(draft, "rotation", this.t("paintCanvas.brushConfig.rotation"))}
414
- ${this.renderParam(draft, "offsetX", this.t("paintCanvas.brushConfig.offsetX"))}
415
- ${this.renderParam(draft, "offsetY", this.t("paintCanvas.brushConfig.offsetY"))}
416
- <div class="row">
417
- <span class="label"
418
- >${this.t("paintCanvas.brushConfig.sampleRate")}</span
419
- >
420
- ${this.number("sample-rate", draft.sampleRate ?? 5, sampleLimits, (sampleRate) => this.change({ sampleRate }))}
421
- ${this.slider("sample-rate", draft.sampleRate ?? 5, sampleLimits, (sampleRate) => this.change({ sampleRate }))}
422
- <span class="label">${this.t("paintCanvas.brushConfig.spacing")}</span>
423
- ${this.number("spacing", draft.spacing ?? 5, spacingLimits, (spacing) => this.change({ spacing }))}
424
- ${this.slider("spacing", draft.spacing ?? 5, spacingLimits, (spacing) => this.change({ spacing }))}
425
- </div>
426
- <label>
427
- <input
428
- type="checkbox"
429
- class="snap"
430
- .checked=${draft.snapToPixelGrid ?? false}
431
- ?disabled=${this.busy}
432
- @change=${(e) => this.change({ snapToPixelGrid: e.target.checked })}
433
- />
434
- ${this.t("paintCanvas.brushConfig.snapToPixelGrid")}
435
- </label>
436
- <div class="row">
463
+ <div slot="body" class="settings">
464
+ <pc-brush-test
465
+ .config=${draft}
466
+ .tips=${this.app?.tips}
467
+ ></pc-brush-test>
468
+ ${this.renderShape(draft)}
469
+ ${this.renderParam(draft, "width", this.t(PARAM_LABELS.width))}
470
+ <div class="row">
471
+ <span class="label"></span>
472
+ <label
473
+ class="icon-toggle"
474
+ title=${this.t("paintCanvas.toolSettings.constrainProportions")}
475
+ >
476
+ <input
477
+ type="checkbox"
478
+ class="constrain"
479
+ .checked=${constrained}
480
+ ?disabled=${this.busy}
481
+ @change=${(e) => this.change({ constrainProportions: e.target.checked })}
482
+ />
483
+ ${iconLabel(this.iconUrl(constrained ? "linked" : "unlinked"), this.t("paintCanvas.toolSettings.constrainProportions"))}
484
+ </label>
485
+ </div>
486
+ ${this.renderParam(draft, "height", this.t(PARAM_LABELS.height), constrained)}
487
+ ${this.renderParam(draft, "alpha", this.t(PARAM_LABELS.alpha))}
488
+ ${this.renderParam(draft, "rotation", this.t(PARAM_LABELS.rotation))}
489
+ ${this.renderParam(draft, "offsetX", this.t(PARAM_LABELS.offsetX))}
490
+ ${this.renderParam(draft, "offsetY", this.t(PARAM_LABELS.offsetY))}
491
+ <div class="row">
492
+ <span class="label"
493
+ >${this.t("paintCanvas.brushConfig.sampleRate")}</span
494
+ >
495
+ ${this.single("sample-rate", this.t("paintCanvas.brushConfig.sampleRate"), draft.sampleRate ?? 5, sampleLimits, (sampleRate) => this.change({ sampleRate }))}
496
+ </div>
497
+ <div class="row">
498
+ <span class="label"
499
+ >${this.t("paintCanvas.brushConfig.spacing")}</span
500
+ >
501
+ ${this.single("spacing", this.t("paintCanvas.brushConfig.spacing"), draft.spacing ?? 5, spacingLimits, (spacing) => this.change({ spacing }))}
502
+ </div>
503
+ <label>
504
+ <input
505
+ type="checkbox"
506
+ class="snap"
507
+ .checked=${draft.snapToPixelGrid ?? false}
508
+ ?disabled=${this.busy}
509
+ @change=${(e) => this.change({ snapToPixelGrid: e.target.checked })}
510
+ />
511
+ ${this.t("paintCanvas.brushConfig.snapToPixelGrid")}
512
+ </label>
513
+ </div>
437
514
  ${this.editingId ? html`<button
515
+ slot="footer-start"
438
516
  type="button"
439
- class="delete"
517
+ class="cancel delete"
440
518
  ?disabled=${this.busy}
441
519
  @click=${() => void this.deletePreset()}
442
520
  >
443
521
  ${this.t("paintCanvas.brushConfig.deletePreset")}
444
522
  </button>` : nothing}
445
- <button
446
- type="button"
447
- class="add affirmative"
448
- ?disabled=${this.busy}
449
- @click=${() => void this.addToPresets()}
450
- >
451
- ${this.t("paintCanvas.brushConfig.addToPresets")}
452
- </button>
453
- <button
454
- type="button"
455
- class="save affirmative"
456
- ?disabled=${this.busy}
457
- @click=${() => this.save()}
458
- >
459
- ${this.t("paintCanvas.common.save")}
460
- </button>
461
- </div>
462
- </div>`;
523
+ <div slot="footer-end" class="actions">
524
+ <button
525
+ type="button"
526
+ class="add affirmative"
527
+ ?disabled=${this.busy}
528
+ @click=${() => void this.addToPresets()}
529
+ >
530
+ ${this.t("paintCanvas.brushConfig.addToPresets")}
531
+ </button>
532
+ <button
533
+ type="button"
534
+ class="save affirmative"
535
+ ?disabled=${this.busy}
536
+ @click=${() => this.save()}
537
+ >
538
+ ${this.t("paintCanvas.common.save")}
539
+ </button>
540
+ </div>
541
+ </pc-dialog-window>
542
+ ${this.renderProfileEditor(draft)}`;
543
+ }
544
+ /** The profile graph editor for the setting being edited, while open */
545
+ renderProfileEditor(draft) {
546
+ const param = this.editingProfile;
547
+ if (!param) return nothing;
548
+ const key = configKey(param);
549
+ const variation = draft[key];
550
+ return html`<pc-profile-editor
551
+ .profiles=${this.app?.profiles ?? this.profiles}
552
+ .points=${variation.profile}
553
+ profile-id=${variation.profileId ?? (variation.profile ? nothing : "linear")}
554
+ label=${this.t(PARAM_LABELS[param])}
555
+ @pc-save=${(event) => {
556
+ event.stopPropagation();
557
+ const { points, profileId } = event.detail;
558
+ const linear = isLinear(points);
559
+ this.changeParam(param, { [key]: {
560
+ ...variation,
561
+ profile: linear ? void 0 : points,
562
+ profileId: linear ? void 0 : profileId
563
+ } });
564
+ this.editingProfile = void 0;
565
+ }}
566
+ @pc-close=${(event) => {
567
+ event.stopPropagation();
568
+ this.editingProfile = void 0;
569
+ }}
570
+ ></pc-profile-editor>`;
463
571
  }
572
+ /** Profile graphs, when there's no canvas to keep them */
573
+ profiles = new ProfileGraphs();
464
574
  };
465
575
  defineElement("pc-brush-config", PcBrushConfig);
466
576
  export { PcBrushConfig, SMOOTHING_CHOICES };
@@ -1,3 +1,3 @@
1
1
  // src/ui/elements/PcBrushConfig/style.css?inline
2
- var style_default = ":host {\n position: fixed;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--pc-backdrop);\n}\n[role=\"dialog\"] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n width: min(560px, 95vw);\n max-height: 95vh;\n overflow: auto;\n padding: 8px;\n background: var(--pc-surface);\n}\n.row {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n}\n.row > .label {\n width: 6em;\n}\ninput[type=\"number\"] {\n width: 4.5em;\n}\ninput[type=\"range\"] {\n flex: 1;\n min-width: 60px;\n}\n.shape-preview {\n display: inline-block;\n width: 40px;\n height: 40px;\n background: var(--pc-text);\n border-radius: 50%;\n}\n.shape-preview.image {\n border-radius: 0;\n mask-repeat: no-repeat;\n mask-size: contain;\n mask-position: center;\n}\n/* The name, with \"Close\" on the right */\n.header .close {\n margin-left: auto;\n}\n/* The shape (preview, Upload and Paste) and the smoothing icons on one row */\n.shape-row {\n flex-wrap: nowrap;\n}\n.shape-row .shape-preview {\n flex: none;\n}\nfieldset.smoothing {\n display: flex;\n align-items: center;\n gap: 4px;\n margin: 0 0 0 auto;\n padding: 0;\n border: 0;\n}\nfieldset.smoothing legend {\n float: left;\n margin-right: 4px;\n padding: 0;\n}\n";
2
+ var style_default = ":host {\n display: contents;\n}\npc-dialog-window {\n --pc-dialog-width: 560px;\n}\n.settings {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.name-field {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.actions {\n display: flex;\n gap: 6px;\n}\n.row {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n}\n.row > .label {\n width: 6em;\n}\ninput[type=\"number\"] {\n width: 4.5em;\n}\ninput[type=\"range\"] {\n flex: 1;\n min-width: 60px;\n}\npc-slider-range {\n flex: 1;\n min-width: 200px;\n}\n.shape-preview {\n display: inline-block;\n width: 40px;\n height: 40px;\n background: var(--pc-text);\n border-radius: 50%;\n}\n.shape-preview.image {\n border-radius: 0;\n mask-repeat: no-repeat;\n mask-size: contain;\n mask-position: center;\n}\n/* The shape (preview, Upload and Paste) and the smoothing icons on one row */\n.shape-row {\n flex-wrap: nowrap;\n}\n/* The shape, with an invisible list over it: pressing the shape opens the device's own list of shapes */\n.shape-picker {\n position: relative;\n display: inline-flex;\n flex: none;\n border-radius: var(--pc-radius-small);\n}\n.shape-picker:hover {\n background: var(--pc-surface-hover);\n}\n.shape-picker:focus-within {\n outline: var(--pc-focus-width) solid var(--pc-focus);\n}\n.shape-select {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n opacity: 0;\n cursor: pointer;\n}\nfieldset.smoothing {\n display: flex;\n align-items: center;\n gap: 4px;\n margin: 0 0 0 auto;\n padding: 0;\n border: 0;\n}\nfieldset.smoothing legend {\n float: left;\n margin-right: 4px;\n padding: 0;\n}\n/* Pressure, tilt and randomise: one at a time, side by side */\nfieldset.sources {\n display: flex;\n gap: 4px;\n margin: 0;\n padding: 0;\n border: 0;\n}\n/* A setting with a profile graph: its button is purple */\nbutton.icon-button.profile.configured {\n border-color: var(--pc-accent);\n background: var(--pc-accent);\n}\n";
3
3
  export { style_default as default };
@@ -0,0 +1,53 @@
1
+ import { nothing } from "lit";
2
+ import { PcElement } from "../../base";
3
+ import "../PcNumberSlider";
4
+ import { type default as BrushSettings } from "../../../lib/classes/BrushSettings";
5
+ /**
6
+ * A brush's size as text: one number when the width and height are the same, otherwise "width × height".
7
+ *
8
+ * @example
9
+ * sizeText({ width: 20, height: 20 }); // "20"
10
+ * sizeText({ width: 30, height: 10 }); // "30 × 10"
11
+ */
12
+ export declare const sizeText: ({ width, height, }: {
13
+ width: number;
14
+ height: number;
15
+ }) => string;
16
+ /**
17
+ * A brush or eraser's size, as a `pc-number-slider`: pressed and dragged right or up it gets bigger, left or down
18
+ * smaller, keeping its proportions (see `BrushSettings.resize`). Tapping it lets you type the larger side's size. With
19
+ * keyboard focus, the arrow keys change it by a pixel and Page Up and Page Down by a step (like `]` and `[`).
20
+ *
21
+ * @example
22
+ * html`<pc-brush-size .settings=${app.brush} label="Brush size"></pc-brush-size>`
23
+ */
24
+ export declare class PcBrushSize extends PcElement {
25
+ static properties: {
26
+ settings: {
27
+ attribute: boolean;
28
+ };
29
+ label: {
30
+ type: StringConstructor;
31
+ };
32
+ translations: {
33
+ attribute: boolean;
34
+ };
35
+ icons: {
36
+ attribute: boolean;
37
+ };
38
+ theme: {
39
+ type: StringConstructor;
40
+ reflect: boolean;
41
+ };
42
+ };
43
+ static styles: import("lit").CSSResultGroup[];
44
+ /** The brush or eraser settings it shows and changes */
45
+ settings?: BrushSettings;
46
+ /** Its name for screen readers, e.g. "Brush size" */
47
+ label: string;
48
+ private changes;
49
+ constructor();
50
+ /** Resize to the slider's value (the larger side), keeping the proportions */
51
+ private onChange;
52
+ render(): import("lit").TemplateResult<1> | typeof nothing;
53
+ }