@lvl99dotcom/paintcanvas 0.0.0-stage → 0.3.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 (284) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +131 -2
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +5 -0
  5. package/dist/lib/brushes/BrushTipCache/index.d.ts +32 -0
  6. package/dist/lib/brushes/BrushTipCache/index.js +60 -0
  7. package/dist/lib/brushes/StrokeEngine/index.d.ts +171 -0
  8. package/dist/lib/brushes/StrokeEngine/index.js +324 -0
  9. package/dist/lib/brushes/StrokePath/index.d.ts +53 -0
  10. package/dist/lib/brushes/StrokePath/index.js +161 -0
  11. package/dist/lib/brushes/StrokeSampler/index.d.ts +55 -0
  12. package/dist/lib/brushes/StrokeSampler/index.js +75 -0
  13. package/dist/lib/brushes/authors/index.d.ts +55 -0
  14. package/dist/lib/brushes/authors/index.js +60 -0
  15. package/dist/lib/brushes/configRanges/index.d.ts +52 -0
  16. package/dist/lib/brushes/configRanges/index.js +206 -0
  17. package/dist/lib/brushes/index.d.ts +5 -0
  18. package/dist/lib/brushes/index.js +19 -0
  19. package/dist/lib/brushes/params/index.d.ts +108 -0
  20. package/dist/lib/brushes/params/index.js +139 -0
  21. package/dist/lib/brushes/presetFile/index.d.ts +32 -0
  22. package/dist/lib/brushes/presetFile/index.js +55 -0
  23. package/dist/lib/brushes/presets/drawing/brush-pen.js +3 -0
  24. package/dist/lib/brushes/presets/drawing/felt-pen.js +3 -0
  25. package/dist/lib/brushes/presets/drawing/index.d.ts +13 -0
  26. package/dist/lib/brushes/presets/drawing/index.js +88 -0
  27. package/dist/lib/brushes/presets/drawing/pencil-2b.js +3 -0
  28. package/dist/lib/brushes/presets/drawing/pencil-hb.js +3 -0
  29. package/dist/lib/brushes/presets/painting/grass.js +3 -0
  30. package/dist/lib/brushes/presets/painting/hair.js +3 -0
  31. package/dist/lib/brushes/presets/painting/index.d.ts +18 -0
  32. package/dist/lib/brushes/presets/painting/index.js +118 -0
  33. package/dist/lib/brushes/presets/painting/splatter.js +3 -0
  34. package/dist/lib/brushes/presets/painting/textured-paint.js +3 -0
  35. package/dist/lib/brushes/presets/painting/watery-paint.js +3 -0
  36. package/dist/lib/brushes/presets/round/index.d.ts +9 -0
  37. package/dist/lib/brushes/presets/round/index.js +44 -0
  38. package/dist/lib/brushes/presets/round/round.js +3 -0
  39. package/dist/lib/brushes/presets/round/soft-round.js +3 -0
  40. package/dist/lib/brushes/presets/sized/index.d.ts +20 -0
  41. package/dist/lib/brushes/presets/sized/index.js +30 -0
  42. package/dist/lib/brushes/presets/sketching/index.d.ts +14 -0
  43. package/dist/lib/brushes/presets/sketching/index.js +107 -0
  44. package/dist/lib/brushes/presets/square/index.d.ts +7 -0
  45. package/dist/lib/brushes/presets/square/index.js +22 -0
  46. package/dist/lib/brushes/presets/square/square.js +3 -0
  47. package/dist/lib/brushes/shapeImage/index.d.ts +40 -0
  48. package/dist/lib/brushes/shapeImage/index.js +61 -0
  49. package/dist/lib/brushes/types/index.d.ts +243 -0
  50. package/dist/lib/brushes/types/index.js +20 -0
  51. package/dist/lib/classes/BackgroundWork/index.d.ts +55 -0
  52. package/dist/lib/classes/BackgroundWork/index.js +97 -0
  53. package/dist/lib/classes/BrushSettings/index.d.ts +91 -0
  54. package/dist/lib/classes/BrushSettings/index.js +152 -0
  55. package/dist/lib/classes/CustomPresets/index.d.ts +53 -0
  56. package/dist/lib/classes/CustomPresets/index.js +71 -0
  57. package/dist/lib/classes/ExternalSheets/index.d.ts +64 -0
  58. package/dist/lib/classes/ExternalSheets/index.js +112 -0
  59. package/dist/lib/classes/GestureTracker/index.d.ts +62 -0
  60. package/dist/lib/classes/GestureTracker/index.js +122 -0
  61. package/dist/lib/classes/History/index.d.ts +83 -0
  62. package/dist/lib/classes/History/index.js +126 -0
  63. package/dist/lib/classes/HistoryGuard/index.d.ts +58 -0
  64. package/dist/lib/classes/HistoryGuard/index.js +97 -0
  65. package/dist/lib/classes/InputSettings/index.d.ts +74 -0
  66. package/dist/lib/classes/InputSettings/index.js +101 -0
  67. package/dist/lib/classes/KeyboardShortcuts/index.d.ts +48 -0
  68. package/dist/lib/classes/KeyboardShortcuts/index.js +137 -0
  69. package/dist/lib/classes/Layer/index.d.ts +86 -0
  70. package/dist/lib/classes/Layer/index.js +111 -0
  71. package/dist/lib/classes/LayerAutosave/index.d.ts +180 -0
  72. package/dist/lib/classes/LayerAutosave/index.js +346 -0
  73. package/dist/lib/classes/LayerStack/index.d.ts +177 -0
  74. package/dist/lib/classes/LayerStack/index.js +394 -0
  75. package/dist/lib/classes/PaintCanvas/index.d.ts +537 -0
  76. package/dist/lib/classes/PaintCanvas/index.js +965 -0
  77. package/dist/lib/classes/StrokeLog/index.d.ts +149 -0
  78. package/dist/lib/classes/StrokeLog/index.js +257 -0
  79. package/dist/lib/classes/Viewport/index.d.ts +108 -0
  80. package/dist/lib/classes/Viewport/index.js +194 -0
  81. package/dist/lib/document/index.d.ts +17 -0
  82. package/dist/lib/document/index.js +25 -0
  83. package/dist/lib/document/schema.d.ts +132 -0
  84. package/dist/lib/document/schema.js +110 -0
  85. package/dist/lib/i18n/index.d.ts +131 -0
  86. package/dist/lib/i18n/index.js +277 -0
  87. package/dist/lib/image/index.d.ts +90 -0
  88. package/dist/lib/image/index.js +147 -0
  89. package/dist/lib/messages/PatchSender/index.d.ts +75 -0
  90. package/dist/lib/messages/PatchSender/index.js +125 -0
  91. package/dist/lib/messages/index.d.ts +26 -0
  92. package/dist/lib/messages/index.js +59 -0
  93. package/dist/lib/messages/schema.d.ts +1775 -0
  94. package/dist/lib/messages/schema.js +192 -0
  95. package/dist/lib/presets/index.d.ts +32 -0
  96. package/dist/lib/presets/index.js +35 -0
  97. package/dist/lib/presets/schema.d.ts +753 -0
  98. package/dist/lib/presets/schema.js +181 -0
  99. package/dist/lib/rendering/BrushTip/index.d.ts +63 -0
  100. package/dist/lib/rendering/BrushTip/index.js +112 -0
  101. package/dist/lib/rendering/checkerboard/index.d.ts +22 -0
  102. package/dist/lib/rendering/checkerboard/index.js +31 -0
  103. package/dist/lib/rendering/compositing/index.d.ts +64 -0
  104. package/dist/lib/rendering/compositing/index.js +124 -0
  105. package/dist/lib/rendering/cursor/index.d.ts +14 -0
  106. package/dist/lib/rendering/cursor/index.js +39 -0
  107. package/dist/lib/rendering/cursors/index.d.ts +18 -0
  108. package/dist/lib/rendering/cursors/index.js +23 -0
  109. package/dist/lib/rendering/maskOutline/index.d.ts +22 -0
  110. package/dist/lib/rendering/maskOutline/index.js +78 -0
  111. package/dist/lib/rendering/outline/index.d.ts +36 -0
  112. package/dist/lib/rendering/outline/index.js +120 -0
  113. package/dist/lib/rendering/sample/index.d.ts +55 -0
  114. package/dist/lib/rendering/sample/index.js +83 -0
  115. package/dist/lib/rendering/screenshot/index.d.ts +67 -0
  116. package/dist/lib/rendering/screenshot/index.js +96 -0
  117. package/dist/lib/rendering/transformBox/index.d.ts +10 -0
  118. package/dist/lib/rendering/transformBox/index.js +57 -0
  119. package/dist/lib/selection/Lasso/index.d.ts +70 -0
  120. package/dist/lib/selection/Lasso/index.js +156 -0
  121. package/dist/lib/selection/Selection/index.d.ts +86 -0
  122. package/dist/lib/selection/Selection/index.js +228 -0
  123. package/dist/lib/selection/geometry/index.d.ts +37 -0
  124. package/dist/lib/selection/geometry/index.js +57 -0
  125. package/dist/lib/storage/index.d.ts +63 -0
  126. package/dist/lib/storage/index.js +114 -0
  127. package/dist/lib/transform/Transformer/index.d.ts +124 -0
  128. package/dist/lib/transform/Transformer/index.js +286 -0
  129. package/dist/lib/transform/geometry/index.d.ts +95 -0
  130. package/dist/lib/transform/geometry/index.js +258 -0
  131. package/dist/lib/utils/array/index.d.ts +10 -0
  132. package/dist/lib/utils/array/index.js +21 -0
  133. package/dist/lib/utils/gestures/index.d.ts +35 -0
  134. package/dist/lib/utils/gestures/index.js +81 -0
  135. package/dist/lib/utils/navigation/index.d.ts +51 -0
  136. package/dist/lib/utils/navigation/index.js +59 -0
  137. package/dist/lib/utils/random/index.d.ts +18 -0
  138. package/dist/lib/utils/random/index.js +27 -0
  139. package/dist/lib/utils/shortcuts/index.d.ts +74 -0
  140. package/dist/lib/utils/shortcuts/index.js +189 -0
  141. package/dist/lib/validation/validators.generated.d.ts +27 -0
  142. package/dist/lib/validation/validators.generated.js +19826 -0
  143. package/dist/locales/en-GB.js +181 -0
  144. package/dist/locales/en-US.js +181 -0
  145. package/dist/locales/fr.js +181 -0
  146. package/dist/locales/ja.js +181 -0
  147. package/dist/locales/ko.js +181 -0
  148. package/dist/locales/zh-Hans.js +181 -0
  149. package/dist/locales/zh-Hant.js +181 -0
  150. package/dist/package.js +3 -0
  151. package/dist/testing/app.d.ts +7 -0
  152. package/dist/testing/app.js +16 -0
  153. package/dist/testing/elements.d.ts +42 -0
  154. package/dist/testing/elements.js +58 -0
  155. package/dist/testing/fakeCanvas.d.ts +21 -0
  156. package/dist/testing/fakeCanvas.js +26 -0
  157. package/dist/testing/layerStore.d.ts +26 -0
  158. package/dist/testing/layerStore.js +43 -0
  159. package/dist/testing/locks.d.ts +15 -0
  160. package/dist/testing/locks.js +41 -0
  161. package/dist/testing/recordingCanvas.d.ts +14 -0
  162. package/dist/testing/recordingCanvas.js +28 -0
  163. package/dist/testing/recordingContext.d.ts +10 -0
  164. package/dist/testing/recordingContext.js +19 -0
  165. package/dist/ui/ChangeController/index.d.ts +40 -0
  166. package/dist/ui/ChangeController/index.js +62 -0
  167. package/dist/ui/base/index.d.ts +69 -0
  168. package/dist/ui/base/index.js +94 -0
  169. package/dist/ui/elements/PaintCanvas/index.d.ts +249 -0
  170. package/dist/ui/elements/PaintCanvas/index.js +584 -0
  171. package/dist/ui/elements/PaintCanvas/style.js +3 -0
  172. package/dist/ui/elements/PcBrushConfig/index.d.ts +130 -0
  173. package/dist/ui/elements/PcBrushConfig/index.js +465 -0
  174. package/dist/ui/elements/PcBrushConfig/style.js +3 -0
  175. package/dist/ui/elements/PcBrushMenu/index.d.ts +121 -0
  176. package/dist/ui/elements/PcBrushMenu/index.js +362 -0
  177. package/dist/ui/elements/PcBrushMenu/style.js +3 -0
  178. package/dist/ui/elements/PcBrushTest/index.d.ts +71 -0
  179. package/dist/ui/elements/PcBrushTest/index.js +136 -0
  180. package/dist/ui/elements/PcBrushTest/style.js +3 -0
  181. package/dist/ui/elements/PcButton/index.d.ts +57 -0
  182. package/dist/ui/elements/PcButton/index.js +124 -0
  183. package/dist/ui/elements/PcButtonGroup/index.d.ts +44 -0
  184. package/dist/ui/elements/PcButtonGroup/index.js +93 -0
  185. package/dist/ui/elements/PcCanvas/index.d.ts +356 -0
  186. package/dist/ui/elements/PcCanvas/index.js +1004 -0
  187. package/dist/ui/elements/PcCanvas/style.js +3 -0
  188. package/dist/ui/elements/PcCanvasMap/index.d.ts +96 -0
  189. package/dist/ui/elements/PcCanvasMap/index.js +187 -0
  190. package/dist/ui/elements/PcCanvasMap/style.js +3 -0
  191. package/dist/ui/elements/PcContextMenu/index.d.ts +72 -0
  192. package/dist/ui/elements/PcContextMenu/index.js +148 -0
  193. package/dist/ui/elements/PcDialog/index.d.ts +63 -0
  194. package/dist/ui/elements/PcDialog/index.js +114 -0
  195. package/dist/ui/elements/PcIcon/index.d.ts +36 -0
  196. package/dist/ui/elements/PcIcon/index.js +43 -0
  197. package/dist/ui/elements/PcIconToggle/index.d.ts +46 -0
  198. package/dist/ui/elements/PcIconToggle/index.js +87 -0
  199. package/dist/ui/elements/PcInfoTip/index.d.ts +40 -0
  200. package/dist/ui/elements/PcInfoTip/index.js +95 -0
  201. package/dist/ui/elements/PcInputSettings/index.d.ts +69 -0
  202. package/dist/ui/elements/PcInputSettings/index.js +154 -0
  203. package/dist/ui/elements/PcLayerItem/index.d.ts +221 -0
  204. package/dist/ui/elements/PcLayerItem/index.js +561 -0
  205. package/dist/ui/elements/PcLayerItem/style.js +3 -0
  206. package/dist/ui/elements/PcLayersMenu/index.d.ts +108 -0
  207. package/dist/ui/elements/PcLayersMenu/index.js +208 -0
  208. package/dist/ui/elements/PcLayersMenu/style.js +3 -0
  209. package/dist/ui/elements/PcMatch/index.d.ts +31 -0
  210. package/dist/ui/elements/PcMatch/index.js +58 -0
  211. package/dist/ui/elements/PcPanel/index.d.ts +43 -0
  212. package/dist/ui/elements/PcPanel/index.js +51 -0
  213. package/dist/ui/elements/PcPopover/index.d.ts +48 -0
  214. package/dist/ui/elements/PcPopover/index.js +86 -0
  215. package/dist/ui/elements/PcSlider/index.d.ts +57 -0
  216. package/dist/ui/elements/PcSlider/index.js +88 -0
  217. package/dist/ui/elements/PcStats/index.d.ts +54 -0
  218. package/dist/ui/elements/PcStats/index.js +144 -0
  219. package/dist/ui/elements/PcThemePicker/index.d.ts +56 -0
  220. package/dist/ui/elements/PcThemePicker/index.js +134 -0
  221. package/dist/ui/elements/PcToast/index.d.ts +58 -0
  222. package/dist/ui/elements/PcToast/index.js +110 -0
  223. package/dist/ui/elements/PcToggleCheckbox/index.d.ts +37 -0
  224. package/dist/ui/elements/PcToggleCheckbox/index.js +105 -0
  225. package/dist/ui/elements/PcToolSettings/index.d.ts +128 -0
  226. package/dist/ui/elements/PcToolSettings/index.js +549 -0
  227. package/dist/ui/elements/PcToolSettings/style.js +3 -0
  228. package/dist/ui/elements/PcToolbar/index.d.ts +71 -0
  229. package/dist/ui/elements/PcToolbar/index.js +190 -0
  230. package/dist/ui/elements/PcToolbar/style.js +3 -0
  231. package/dist/ui/icons/images/brush.js +3 -0
  232. package/dist/ui/icons/images/circle-mask.js +3 -0
  233. package/dist/ui/icons/images/clipboard.js +3 -0
  234. package/dist/ui/icons/images/cursor.js +3 -0
  235. package/dist/ui/icons/images/eraser.js +3 -0
  236. package/dist/ui/icons/images/eyedropper.js +3 -0
  237. package/dist/ui/icons/images/flip-horizontal.js +3 -0
  238. package/dist/ui/icons/images/flip-vertical.js +3 -0
  239. package/dist/ui/icons/images/focus-pen.js +3 -0
  240. package/dist/ui/icons/images/freehand-mask.js +3 -0
  241. package/dist/ui/icons/images/hidden.js +3 -0
  242. package/dist/ui/icons/images/layers.js +3 -0
  243. package/dist/ui/icons/images/linked.js +3 -0
  244. package/dist/ui/icons/images/locked.js +3 -0
  245. package/dist/ui/icons/images/moon.js +3 -0
  246. package/dist/ui/icons/images/pan.js +3 -0
  247. package/dist/ui/icons/images/polygon-mask.js +3 -0
  248. package/dist/ui/icons/images/pressure.js +3 -0
  249. package/dist/ui/icons/images/randomise.js +3 -0
  250. package/dist/ui/icons/images/rectangle-mask.js +3 -0
  251. package/dist/ui/icons/images/redo.js +3 -0
  252. package/dist/ui/icons/images/rotate-90-left.js +3 -0
  253. package/dist/ui/icons/images/rotate-90-right.js +3 -0
  254. package/dist/ui/icons/images/smoothing-bezier-cubic.js +3 -0
  255. package/dist/ui/icons/images/smoothing-bezier-quad.js +3 -0
  256. package/dist/ui/icons/images/smoothing-linear.js +3 -0
  257. package/dist/ui/icons/images/star.js +3 -0
  258. package/dist/ui/icons/images/sun.js +3 -0
  259. package/dist/ui/icons/images/tilt.js +3 -0
  260. package/dist/ui/icons/images/undo.js +3 -0
  261. package/dist/ui/icons/images/unlinked.js +3 -0
  262. package/dist/ui/icons/images/unlocked.js +3 -0
  263. package/dist/ui/icons/images/visible.js +3 -0
  264. package/dist/ui/icons/images/zoom-in.js +3 -0
  265. package/dist/ui/icons/images/zoom-out.js +3 -0
  266. package/dist/ui/icons/images/zoom.js +3 -0
  267. package/dist/ui/icons/index.d.ts +42 -0
  268. package/dist/ui/icons/index.js +130 -0
  269. package/dist/ui/index.d.ts +21 -0
  270. package/dist/ui/index.js +22 -0
  271. package/dist/ui/layout/index.d.ts +88 -0
  272. package/dist/ui/layout/index.js +96 -0
  273. package/dist/ui/styles/index.d.ts +13 -0
  274. package/dist/ui/styles/index.js +195 -0
  275. package/dist/ui/tokens/index.d.ts +29 -0
  276. package/dist/ui/tokens/index.js +114 -0
  277. package/locales/en-GB.json +179 -0
  278. package/locales/en-US.json +179 -0
  279. package/locales/fr.json +179 -0
  280. package/locales/ja.json +179 -0
  281. package/locales/ko.json +179 -0
  282. package/locales/zh-Hans.json +179 -0
  283. package/locales/zh-Hant.json +179 -0
  284. package/package.json +97 -3
@@ -0,0 +1,54 @@
1
+ import { nothing, type PropertyValues } from "lit";
2
+ import { PcElement } from "../../base";
3
+ import type PaintCanvas from "../../../lib/classes/PaintCanvas";
4
+ /**
5
+ * A size in bytes in the largest unit it has at least one of, to one decimal place (whole bytes), for a locale.
6
+ *
7
+ * @example
8
+ * formatBytes(84_560, "en-GB"); // "84.6 kB"
9
+ * formatBytes(512, "en-GB"); // "512 byte"
10
+ */
11
+ export declare const formatBytes: (bytes: number, locale?: string) => string;
12
+ /**
13
+ * A line of small text about the canvas: its size; while the drawing is kept in the browser, how much its layer
14
+ * 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.
17
+ *
18
+ * @example
19
+ * html`<pc-stats .app=${app}></pc-stats>`
20
+ */
21
+ export declare class PcStats extends PcElement {
22
+ static properties: {
23
+ app: {
24
+ attribute: boolean;
25
+ };
26
+ translations: {
27
+ attribute: boolean;
28
+ };
29
+ icons: {
30
+ attribute: boolean;
31
+ };
32
+ theme: {
33
+ type: StringConstructor;
34
+ reflect: boolean;
35
+ };
36
+ };
37
+ static styles: import("lit").CSSResultGroup[];
38
+ /** The canvas described */
39
+ app?: PaintCanvas;
40
+ private changes;
41
+ /** The canvas whose pointer is followed */
42
+ private followed?;
43
+ /** The animation frame the next update waits for, if any */
44
+ private frame?;
45
+ private readonly onPointer;
46
+ connectedCallback(): void;
47
+ disconnectedCallback(): void;
48
+ protected willUpdate(changed: PropertyValues<this>): void;
49
+ /**
50
+ * Follow a canvas's pointer (or none), instead of the one followed before.
51
+ */
52
+ private follow;
53
+ render(): import("lit").TemplateResult<1> | typeof nothing;
54
+ }
@@ -0,0 +1,144 @@
1
+ import { PcElement, defineElement } from "../../base/index.js";
2
+ import ChangeController from "../../ChangeController/index.js";
3
+ import { zoomPercent } from "../PcToolSettings/index.js";
4
+ import { css, html, nothing } from "lit";
5
+ import { styleMap } from "lit/directives/style-map.js";
6
+ // src/ui/elements/PcStats/index.ts
7
+ /** Units for sizes in bytes, each 1000 times the one before */
8
+ var BYTE_UNITS = [
9
+ "byte",
10
+ "kilobyte",
11
+ "megabyte",
12
+ "gigabyte"
13
+ ];
14
+ /**
15
+ * A size in bytes in the largest unit it has at least one of, to one decimal place (whole bytes), for a locale.
16
+ *
17
+ * @example
18
+ * formatBytes(84_560, "en-GB"); // "84.6 kB"
19
+ * formatBytes(512, "en-GB"); // "512 byte"
20
+ */
21
+ var formatBytes = (bytes, locale) => {
22
+ const step = Math.min(Math.max(Math.floor(Math.log10(bytes) / 3), 0), BYTE_UNITS.length - 1);
23
+ return new Intl.NumberFormat(locale, {
24
+ style: "unit",
25
+ unit: BYTE_UNITS[step],
26
+ unitDisplay: "short",
27
+ maximumFractionDigits: step === 0 ? 0 : 1
28
+ }).format(bytes / 1e3 ** step);
29
+ };
30
+ /**
31
+ * A line of small text about the canvas: its size; while the drawing is kept in the browser, how much its layer
32
+ * 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.
35
+ *
36
+ * @example
37
+ * html`<pc-stats .app=${app}></pc-stats>`
38
+ */
39
+ var PcStats = class extends PcElement {
40
+ static properties = {
41
+ ...PcElement.properties,
42
+ app: { attribute: false }
43
+ };
44
+ static styles = [PcElement.styles, css`
45
+ :host {
46
+ display: block;
47
+ padding: 2px var(--pc-space-2);
48
+ border-top: 1px solid var(--pc-border);
49
+ background: var(--pc-bar);
50
+ color: var(--pc-text);
51
+ font-family: var(--pc-font);
52
+ font-size: var(--pc-font-size-small);
53
+ }
54
+ ul {
55
+ display: flex;
56
+ flex-wrap: wrap;
57
+ gap: 2px var(--pc-space-3);
58
+ margin: 0;
59
+ padding: 0;
60
+ list-style: none;
61
+ }
62
+ li {
63
+ display: flex;
64
+ align-items: center;
65
+ gap: 4px;
66
+ white-space: nowrap;
67
+ font-variant-numeric: tabular-nums;
68
+ }
69
+ .swatch {
70
+ width: 10px;
71
+ height: 10px;
72
+ border: 1px solid var(--pc-border);
73
+ }
74
+ `];
75
+ changes = new ChangeController(this, () => [
76
+ this.app,
77
+ this.app?.viewport,
78
+ this.app?.autosave
79
+ ]);
80
+ /** The canvas whose pointer is followed */
81
+ followed;
82
+ /** The animation frame the next update waits for, if any */
83
+ frame;
84
+ onPointer = () => {
85
+ this.frame ??= requestAnimationFrame(() => {
86
+ this.frame = void 0;
87
+ this.requestUpdate();
88
+ });
89
+ };
90
+ connectedCallback() {
91
+ super.connectedCallback();
92
+ this.follow(this.app);
93
+ }
94
+ disconnectedCallback() {
95
+ super.disconnectedCallback();
96
+ this.follow(void 0);
97
+ if (this.frame !== void 0) cancelAnimationFrame(this.frame);
98
+ this.frame = void 0;
99
+ }
100
+ willUpdate(changed) {
101
+ super.willUpdate(changed);
102
+ if (changed.has("app") && this.isConnected) this.follow(this.app);
103
+ }
104
+ /**
105
+ * Follow a canvas's pointer (or none), instead of the one followed before.
106
+ */
107
+ follow(app) {
108
+ this.followed?.removeEventListener("pointer", this.onPointer);
109
+ this.followed = app;
110
+ app?.addEventListener("pointer", this.onPointer);
111
+ }
112
+ render() {
113
+ const app = this.app;
114
+ if (!app) return nothing;
115
+ const colour = app.pointer && app.sampleColour(app.pointer);
116
+ const autosave = app.autosave;
117
+ return html`<ul
118
+ part="stats"
119
+ aria-label=${this.t("paintCanvas.stats.label")}
120
+ >
121
+ <li class="size">
122
+ ${this.t("paintCanvas.stats.size", {
123
+ width: app.width,
124
+ height: app.height
125
+ })}
126
+ </li>
127
+ ${autosave ? html`<li class="stored">
128
+ ${this.t("paintCanvas.stats.stored", { size: formatBytes(autosave.storedBytes, this.translations.locale) })}
129
+ </li>` : nothing}
130
+ <li class="zoom">
131
+ ${this.t("paintCanvas.stats.zoom", { zoom: zoomPercent(app.viewport.zoom) })}
132
+ </li>
133
+ <li class="colour">
134
+ ${this.t("paintCanvas.stats.colour", { colour: colour ?? "—" })}
135
+ ${colour ? html`<span
136
+ class="swatch"
137
+ style=${styleMap({ background: colour })}
138
+ ></span>` : nothing}
139
+ </li>
140
+ </ul>`;
141
+ }
142
+ };
143
+ defineElement("pc-stats", PcStats);
144
+ export { PcStats, formatBytes };
@@ -0,0 +1,56 @@
1
+ import { PcElement } from "../../base";
2
+ import type { IconName } from "../../icons";
3
+ import "../PcButtonGroup";
4
+ /** The themes to pick from: light, dark, or following the device (auto) */
5
+ export declare const THEMES: readonly ["light", "dark", "auto"];
6
+ export type Theme = (typeof THEMES)[number];
7
+ /** Each theme's icon */
8
+ export declare const THEME_ICONS: Readonly<Record<Theme, IconName>>;
9
+ /**
10
+ * Whether a value is one of the themes.
11
+ *
12
+ * @example
13
+ * isTheme("dark"); // true
14
+ * isTheme(undefined); // false
15
+ */
16
+ export declare const isTheme: (value: unknown) => value is Theme;
17
+ /**
18
+ * Picks the light, dark or automatic theme (which follows the device), as a labelled group of three radios joined into
19
+ * one pill (a joined `<pc-button-group>`), each with its icon (sun, moon and star) and name; the picked one is purple.
20
+ * Shows the theme of its `target` (the page's root element by default; light unless it has another), and sets the
21
+ * target's `data-pc-theme` when the user picks one, firing `change` (detail: the theme).
22
+ *
23
+ * @example
24
+ * html`<pc-theme-picker @change=${(e) => save(e.detail)}></pc-theme-picker>`
25
+ */
26
+ export declare class PcThemePicker extends PcElement {
27
+ static properties: {
28
+ theme: {
29
+ type: StringConstructor;
30
+ reflect: boolean;
31
+ };
32
+ translations: {
33
+ attribute: boolean;
34
+ };
35
+ icons: {
36
+ attribute: boolean;
37
+ };
38
+ };
39
+ static styles: import("lit").CSSResultGroup[];
40
+ /** The theme shown as picked */
41
+ theme: Theme;
42
+ /** The element whose `data-pc-theme` is shown and set (the page's root element by default) */
43
+ target?: HTMLElement;
44
+ constructor();
45
+ connectedCallback(): void;
46
+ /** The element whose theme is shown and set */
47
+ private get themeTarget();
48
+ /**
49
+ * Pick a theme: show it, set it on the target and tell listeners.
50
+ *
51
+ * @example
52
+ * picker.pick("auto");
53
+ */
54
+ pick(theme: Theme): void;
55
+ render(): import("lit").TemplateResult<1>;
56
+ }
@@ -0,0 +1,134 @@
1
+ import { ICON_CONTROLS_CSS } from "../../styles/index.js";
2
+ import { PcElement, defineElement, emit } from "../../base/index.js";
3
+ import { css, html, unsafeCSS } from "lit";
4
+ // src/ui/elements/PcThemePicker/index.ts
5
+ /** The themes to pick from: light, dark, or following the device (auto) */
6
+ var THEMES = [
7
+ "light",
8
+ "dark",
9
+ "auto"
10
+ ];
11
+ /** Each theme's icon */
12
+ var THEME_ICONS = {
13
+ light: "sun",
14
+ dark: "moon",
15
+ auto: "star"
16
+ };
17
+ /**
18
+ * Whether a value is one of the themes.
19
+ *
20
+ * @example
21
+ * isTheme("dark"); // true
22
+ * isTheme(undefined); // false
23
+ */
24
+ var isTheme = (value) => THEMES.includes(value);
25
+ /**
26
+ * Picks the light, dark or automatic theme (which follows the device), as a labelled group of three radios joined into
27
+ * one pill (a joined `<pc-button-group>`), each with its icon (sun, moon and star) and name; the picked one is purple.
28
+ * Shows the theme of its `target` (the page's root element by default; light unless it has another), and sets the
29
+ * target's `data-pc-theme` when the user picks one, firing `change` (detail: the theme).
30
+ *
31
+ * @example
32
+ * html`<pc-theme-picker @change=${(e) => save(e.detail)}></pc-theme-picker>`
33
+ */
34
+ var PcThemePicker = class extends PcElement {
35
+ static properties = {
36
+ ...PcElement.properties,
37
+ theme: {
38
+ type: String,
39
+ reflect: true
40
+ }
41
+ };
42
+ static styles = [
43
+ PcElement.styles,
44
+ unsafeCSS(ICON_CONTROLS_CSS),
45
+ css`
46
+ :host {
47
+ display: block;
48
+ }
49
+ fieldset {
50
+ margin: 0;
51
+ padding: 0;
52
+ border: 0;
53
+ min-width: 0;
54
+ color: var(--pc-text);
55
+ font-family: var(--pc-font);
56
+ font-size: var(--pc-font-size);
57
+ }
58
+ legend {
59
+ margin-bottom: var(--pc-space-1);
60
+ padding: 0;
61
+ }
62
+ /* As wide as the picker, with the options sharing the width */
63
+ pc-button-group {
64
+ display: flex;
65
+ }
66
+ pc-button-group::part(group) {
67
+ flex: 1;
68
+ }
69
+ /* One pill: the button group gives each option its corners */
70
+ .icon-toggle {
71
+ flex: 1;
72
+ align-items: center;
73
+ justify-content: center;
74
+ gap: 4px;
75
+ padding: 2px var(--pc-space-2);
76
+ border-radius: var(--pc-group-radius, var(--pc-radius-small));
77
+ }
78
+ /* The picked option's border shows over its neighbours' */
79
+ .icon-toggle:has(input:checked) {
80
+ z-index: 1;
81
+ color: var(--pc-accent-text);
82
+ }
83
+ .icon-toggle:has(input:focus-visible) {
84
+ z-index: 2;
85
+ }
86
+ `
87
+ ];
88
+ /** The element whose `data-pc-theme` is shown and set (the page's root element by default) */
89
+ target;
90
+ constructor() {
91
+ super();
92
+ this.theme = "light";
93
+ }
94
+ connectedCallback() {
95
+ super.connectedCallback();
96
+ const current = this.themeTarget.dataset.pcTheme;
97
+ if (isTheme(current)) this.theme = current;
98
+ }
99
+ /** The element whose theme is shown and set */
100
+ get themeTarget() {
101
+ return this.target ?? document.documentElement;
102
+ }
103
+ /**
104
+ * Pick a theme: show it, set it on the target and tell listeners.
105
+ *
106
+ * @example
107
+ * picker.pick("auto");
108
+ */
109
+ pick(theme) {
110
+ this.theme = theme;
111
+ this.themeTarget.dataset.pcTheme = theme;
112
+ emit(this, "change", theme);
113
+ }
114
+ render() {
115
+ return html`<fieldset>
116
+ <legend>${this.t("paintCanvas.theme.label")}</legend>
117
+ <pc-button-group joined>
118
+ ${THEMES.map((theme) => html`<label class="icon-toggle" data-theme=${theme}>
119
+ <input
120
+ type="radio"
121
+ name="theme"
122
+ value=${theme}
123
+ .checked=${this.theme === theme}
124
+ @change=${() => this.pick(theme)}
125
+ />
126
+ <img src=${this.iconUrl(THEME_ICONS[theme])} alt="" />
127
+ <span>${this.t(`paintCanvas.theme.${theme}`)}</span>
128
+ </label>`)}
129
+ </pc-button-group>
130
+ </fieldset>`;
131
+ }
132
+ };
133
+ defineElement("pc-theme-picker", PcThemePicker);
134
+ export { PcThemePicker, THEMES, THEME_ICONS, isTheme };
@@ -0,0 +1,58 @@
1
+ import { type PropertyValues } from "lit";
2
+ import { PcElement } from "../../base";
3
+ import "../PcButton";
4
+ /** What a toast tells: a notice, an error or a success (each has its own colour) */
5
+ export type ToastKind = "info" | "error" | "success";
6
+ /** How long a toast shows before dismissing itself, unless told otherwise (milliseconds) */
7
+ export declare const TOAST_DURATION_MS = 5000;
8
+ /**
9
+ * A short message, e.g. "Saved", coloured by its kind: a notice (`info`), an `error` (red) or a `success` (green). An
10
+ * error is announced at once; others politely. It dismisses itself after `duration` milliseconds (0 keeps it), or with
11
+ * its dismiss button. With an `action`, it shows that button too. Fires `pc-action` and `pc-dismiss`. The buttons move
12
+ * under the message when there isn't room beside it. The implementer places it (e.g. near the bottom of the screen).
13
+ *
14
+ * @example
15
+ * html`<pc-toast message="Preset deleted" action="Undo" @pc-action=${restore} @pc-dismiss=${hide}></pc-toast>`
16
+ */
17
+ export declare class PcToast extends PcElement {
18
+ static properties: {
19
+ message: {
20
+ type: StringConstructor;
21
+ };
22
+ kind: {
23
+ type: StringConstructor;
24
+ reflect: boolean;
25
+ };
26
+ action: {
27
+ type: StringConstructor;
28
+ };
29
+ duration: {
30
+ type: NumberConstructor;
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
+ message: string;
45
+ /** "info" (default), "error" or "success" */
46
+ kind: ToastKind;
47
+ /** Label of an extra button (e.g. "Undo"), if any */
48
+ action?: string;
49
+ /** Milliseconds before it dismisses itself (0 keeps it until dismissed) */
50
+ duration: number;
51
+ private timer?;
52
+ constructor();
53
+ updated(changed: PropertyValues<this>): void;
54
+ disconnectedCallback(): void;
55
+ /** Tell listeners it should go */
56
+ dismiss(): void;
57
+ render(): import("lit").TemplateResult<1>;
58
+ }
@@ -0,0 +1,110 @@
1
+ import { PcElement, defineElement, emit } from "../../base/index.js";
2
+ import { css, html, nothing } from "lit";
3
+ // src/ui/elements/PcToast/index.ts
4
+ /** How long a toast shows before dismissing itself, unless told otherwise (milliseconds) */
5
+ var TOAST_DURATION_MS = 5e3;
6
+ /**
7
+ * A short message, e.g. "Saved", coloured by its kind: a notice (`info`), an `error` (red) or a `success` (green). An
8
+ * error is announced at once; others politely. It dismisses itself after `duration` milliseconds (0 keeps it), or with
9
+ * its dismiss button. With an `action`, it shows that button too. Fires `pc-action` and `pc-dismiss`. The buttons move
10
+ * under the message when there isn't room beside it. The implementer places it (e.g. near the bottom of the screen).
11
+ *
12
+ * @example
13
+ * html`<pc-toast message="Preset deleted" action="Undo" @pc-action=${restore} @pc-dismiss=${hide}></pc-toast>`
14
+ */
15
+ var PcToast = class extends PcElement {
16
+ static properties = {
17
+ ...PcElement.properties,
18
+ message: { type: String },
19
+ kind: {
20
+ type: String,
21
+ reflect: true
22
+ },
23
+ action: { type: String },
24
+ duration: { type: Number }
25
+ };
26
+ static styles = [PcElement.styles, css`
27
+ :host {
28
+ display: block;
29
+ }
30
+ .toast {
31
+ display: flex;
32
+ flex-wrap: wrap;
33
+ gap: var(--pc-space-2);
34
+ align-items: center;
35
+ padding: var(--pc-space-2) var(--pc-space-3);
36
+ border-radius: var(--pc-radius);
37
+ background: var(--pc-text);
38
+ color: var(--pc-surface);
39
+ box-shadow: var(--pc-shadow);
40
+ font-family: var(--pc-font);
41
+ font-size: var(--pc-font-size);
42
+ }
43
+ :host([kind="error"]) .toast {
44
+ background: var(--pc-red);
45
+ color: #ffffff;
46
+ }
47
+ :host([kind="success"]) .toast {
48
+ background: var(--pc-green);
49
+ color: #ffffff;
50
+ }
51
+ p {
52
+ /* Wide enough to read; the buttons wrap under it when there isn't room */
53
+ flex: 1 1 16em;
54
+ margin: 0;
55
+ }
56
+ .buttons {
57
+ display: flex;
58
+ gap: var(--pc-space-1);
59
+ }
60
+ /* The dismiss button's text is the toast's colour */
61
+ .buttons pc-button[variant="dismiss"] {
62
+ color: inherit;
63
+ }
64
+ pc-button[variant="dismiss"]::part(button) {
65
+ color: inherit;
66
+ }
67
+ `];
68
+ timer;
69
+ constructor() {
70
+ super();
71
+ this.message = "";
72
+ this.kind = "info";
73
+ this.duration = TOAST_DURATION_MS;
74
+ }
75
+ updated(changed) {
76
+ if (!changed.has("message") && !changed.has("duration")) return;
77
+ clearTimeout(this.timer);
78
+ if (this.duration > 0) this.timer = setTimeout(() => this.dismiss(), this.duration);
79
+ }
80
+ disconnectedCallback() {
81
+ super.disconnectedCallback();
82
+ clearTimeout(this.timer);
83
+ }
84
+ /** Tell listeners it should go */
85
+ dismiss() {
86
+ clearTimeout(this.timer);
87
+ emit(this, "pc-dismiss");
88
+ }
89
+ render() {
90
+ return html`<div
91
+ class="toast"
92
+ part="toast"
93
+ role=${this.kind === "error" ? "alert" : "status"}
94
+ >
95
+ <p part="message">${this.message}</p>
96
+ <div class="buttons">
97
+ ${this.action ? html`<pc-button
98
+ variant="pill"
99
+ @click=${() => emit(this, "pc-action")}
100
+ >${this.action}</pc-button
101
+ >` : nothing}
102
+ <pc-button variant="dismiss" @click=${() => this.dismiss()}
103
+ >${this.t("paintCanvas.common.dismiss")}</pc-button
104
+ >
105
+ </div>
106
+ </div>`;
107
+ }
108
+ };
109
+ defineElement("pc-toast", PcToast);
110
+ export { PcToast, TOAST_DURATION_MS };
@@ -0,0 +1,37 @@
1
+ import { PcElement } from "../../base";
2
+ /**
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.
5
+ *
6
+ * @example
7
+ * html`<pc-toggle-checkbox .checked=${pinchZoom} @change=${toggle}>Pinch to zoom</pc-toggle-checkbox>`
8
+ */
9
+ export declare class PcToggleCheckbox extends PcElement {
10
+ static properties: {
11
+ checked: {
12
+ type: BooleanConstructor;
13
+ reflect: boolean;
14
+ };
15
+ disabled: {
16
+ type: BooleanConstructor;
17
+ reflect: boolean;
18
+ };
19
+ translations: {
20
+ attribute: boolean;
21
+ };
22
+ icons: {
23
+ attribute: boolean;
24
+ };
25
+ theme: {
26
+ type: StringConstructor;
27
+ reflect: boolean;
28
+ };
29
+ };
30
+ static styles: import("lit").CSSResultGroup[];
31
+ checked: boolean;
32
+ disabled: boolean;
33
+ constructor();
34
+ /** Follow the user's change, and tell listeners */
35
+ private onChange;
36
+ render(): import("lit").TemplateResult<1>;
37
+ }
@@ -0,0 +1,105 @@
1
+ import { PcElement, defineElement, emit } from "../../base/index.js";
2
+ import { css, html } from "lit";
3
+ import { live } from "lit/directives/live.js";
4
+ // src/ui/elements/PcToggleCheckbox/index.ts
5
+ /**
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
+ *
9
+ * @example
10
+ * html`<pc-toggle-checkbox .checked=${pinchZoom} @change=${toggle}>Pinch to zoom</pc-toggle-checkbox>`
11
+ */
12
+ var PcToggleCheckbox = class extends PcElement {
13
+ static properties = {
14
+ ...PcElement.properties,
15
+ checked: {
16
+ type: Boolean,
17
+ reflect: true
18
+ },
19
+ disabled: {
20
+ type: Boolean,
21
+ reflect: true
22
+ }
23
+ };
24
+ static styles = [PcElement.styles, css`
25
+ :host {
26
+ display: flex;
27
+ }
28
+ label {
29
+ display: flex;
30
+ flex: 1;
31
+ gap: var(--pc-space-2);
32
+ align-items: center;
33
+ color: var(--pc-text);
34
+ font-family: var(--pc-font);
35
+ font-size: var(--pc-font-size);
36
+ cursor: pointer;
37
+ }
38
+ :host([disabled]) label {
39
+ opacity: 0.5;
40
+ cursor: default;
41
+ }
42
+ input {
43
+ position: relative;
44
+ flex: none;
45
+ width: 36px;
46
+ height: 20px;
47
+ margin: 0;
48
+ border-radius: var(--pc-radius-pill);
49
+ background: var(--pc-disabled);
50
+ appearance: none;
51
+ cursor: inherit;
52
+ }
53
+ input::before {
54
+ position: absolute;
55
+ top: 2px;
56
+ left: 2px;
57
+ width: 16px;
58
+ height: 16px;
59
+ border-radius: 50%;
60
+ background: #ffffff;
61
+ content: "";
62
+ transition: transform 0.15s;
63
+ }
64
+ input:checked {
65
+ background: var(--pc-accent);
66
+ }
67
+ input:checked::before {
68
+ transform: translateX(16px);
69
+ }
70
+ input:focus-visible {
71
+ outline: var(--pc-focus-width) solid var(--pc-focus);
72
+ outline-offset: 2px;
73
+ }
74
+ @media (prefers-reduced-motion: reduce) {
75
+ input::before {
76
+ transition: none;
77
+ }
78
+ }
79
+ `];
80
+ constructor() {
81
+ super();
82
+ this.checked = false;
83
+ this.disabled = false;
84
+ }
85
+ /** Follow the user's change, and tell listeners */
86
+ onChange(event) {
87
+ this.checked = event.target.checked;
88
+ emit(this, "change", { checked: this.checked });
89
+ }
90
+ render() {
91
+ return html`<label part="label">
92
+ <input
93
+ part="switch"
94
+ type="checkbox"
95
+ role="switch"
96
+ .checked=${live(this.checked)}
97
+ ?disabled=${this.disabled}
98
+ @change=${this.onChange}
99
+ />
100
+ <span><slot></slot></span>
101
+ </label>`;
102
+ }
103
+ };
104
+ defineElement("pc-toggle-checkbox", PcToggleCheckbox);
105
+ export { PcToggleCheckbox };