@lvl99dotcom/paintcanvas 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +131 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/lib/brushes/BrushTipCache/index.d.ts +32 -0
- package/dist/lib/brushes/BrushTipCache/index.js +60 -0
- package/dist/lib/brushes/StrokeEngine/index.d.ts +171 -0
- package/dist/lib/brushes/StrokeEngine/index.js +324 -0
- package/dist/lib/brushes/StrokePath/index.d.ts +53 -0
- package/dist/lib/brushes/StrokePath/index.js +161 -0
- package/dist/lib/brushes/StrokeSampler/index.d.ts +55 -0
- package/dist/lib/brushes/StrokeSampler/index.js +75 -0
- package/dist/lib/brushes/authors/index.d.ts +55 -0
- package/dist/lib/brushes/authors/index.js +60 -0
- package/dist/lib/brushes/configRanges/index.d.ts +52 -0
- package/dist/lib/brushes/configRanges/index.js +206 -0
- package/dist/lib/brushes/index.d.ts +5 -0
- package/dist/lib/brushes/index.js +19 -0
- package/dist/lib/brushes/params/index.d.ts +108 -0
- package/dist/lib/brushes/params/index.js +139 -0
- package/dist/lib/brushes/presetFile/index.d.ts +32 -0
- package/dist/lib/brushes/presetFile/index.js +55 -0
- package/dist/lib/brushes/presets/drawing/brush-pen.js +3 -0
- package/dist/lib/brushes/presets/drawing/felt-pen.js +3 -0
- package/dist/lib/brushes/presets/drawing/index.d.ts +13 -0
- package/dist/lib/brushes/presets/drawing/index.js +88 -0
- package/dist/lib/brushes/presets/drawing/pencil-2b.js +3 -0
- package/dist/lib/brushes/presets/drawing/pencil-hb.js +3 -0
- package/dist/lib/brushes/presets/painting/grass.js +3 -0
- package/dist/lib/brushes/presets/painting/hair.js +3 -0
- package/dist/lib/brushes/presets/painting/index.d.ts +18 -0
- package/dist/lib/brushes/presets/painting/index.js +118 -0
- package/dist/lib/brushes/presets/painting/splatter.js +3 -0
- package/dist/lib/brushes/presets/painting/textured-paint.js +3 -0
- package/dist/lib/brushes/presets/painting/watery-paint.js +3 -0
- package/dist/lib/brushes/presets/round/index.d.ts +9 -0
- package/dist/lib/brushes/presets/round/index.js +44 -0
- package/dist/lib/brushes/presets/round/round.js +3 -0
- package/dist/lib/brushes/presets/round/soft-round.js +3 -0
- package/dist/lib/brushes/presets/sized/index.d.ts +20 -0
- package/dist/lib/brushes/presets/sized/index.js +30 -0
- package/dist/lib/brushes/presets/sketching/index.d.ts +14 -0
- package/dist/lib/brushes/presets/sketching/index.js +107 -0
- package/dist/lib/brushes/presets/square/index.d.ts +7 -0
- package/dist/lib/brushes/presets/square/index.js +22 -0
- package/dist/lib/brushes/presets/square/square.js +3 -0
- package/dist/lib/brushes/shapeImage/index.d.ts +40 -0
- package/dist/lib/brushes/shapeImage/index.js +61 -0
- package/dist/lib/brushes/types/index.d.ts +243 -0
- package/dist/lib/brushes/types/index.js +20 -0
- package/dist/lib/classes/BackgroundWork/index.d.ts +55 -0
- package/dist/lib/classes/BackgroundWork/index.js +97 -0
- package/dist/lib/classes/BrushSettings/index.d.ts +91 -0
- package/dist/lib/classes/BrushSettings/index.js +152 -0
- package/dist/lib/classes/CustomPresets/index.d.ts +53 -0
- package/dist/lib/classes/CustomPresets/index.js +71 -0
- package/dist/lib/classes/ExternalSheets/index.d.ts +64 -0
- package/dist/lib/classes/ExternalSheets/index.js +112 -0
- package/dist/lib/classes/GestureTracker/index.d.ts +62 -0
- package/dist/lib/classes/GestureTracker/index.js +122 -0
- package/dist/lib/classes/History/index.d.ts +83 -0
- package/dist/lib/classes/History/index.js +126 -0
- package/dist/lib/classes/HistoryGuard/index.d.ts +58 -0
- package/dist/lib/classes/HistoryGuard/index.js +97 -0
- package/dist/lib/classes/InputSettings/index.d.ts +74 -0
- package/dist/lib/classes/InputSettings/index.js +101 -0
- package/dist/lib/classes/KeyboardShortcuts/index.d.ts +48 -0
- package/dist/lib/classes/KeyboardShortcuts/index.js +137 -0
- package/dist/lib/classes/Layer/index.d.ts +86 -0
- package/dist/lib/classes/Layer/index.js +111 -0
- package/dist/lib/classes/LayerAutosave/index.d.ts +180 -0
- package/dist/lib/classes/LayerAutosave/index.js +346 -0
- package/dist/lib/classes/LayerStack/index.d.ts +177 -0
- package/dist/lib/classes/LayerStack/index.js +394 -0
- package/dist/lib/classes/PaintCanvas/index.d.ts +537 -0
- package/dist/lib/classes/PaintCanvas/index.js +965 -0
- package/dist/lib/classes/StrokeLog/index.d.ts +149 -0
- package/dist/lib/classes/StrokeLog/index.js +257 -0
- package/dist/lib/classes/Viewport/index.d.ts +108 -0
- package/dist/lib/classes/Viewport/index.js +194 -0
- package/dist/lib/document/index.d.ts +17 -0
- package/dist/lib/document/index.js +25 -0
- package/dist/lib/document/schema.d.ts +132 -0
- package/dist/lib/document/schema.js +110 -0
- package/dist/lib/i18n/index.d.ts +94 -0
- package/dist/lib/i18n/index.js +182 -0
- package/dist/lib/image/index.d.ts +90 -0
- package/dist/lib/image/index.js +147 -0
- package/dist/lib/messages/PatchSender/index.d.ts +75 -0
- package/dist/lib/messages/PatchSender/index.js +125 -0
- package/dist/lib/messages/index.d.ts +26 -0
- package/dist/lib/messages/index.js +59 -0
- package/dist/lib/messages/schema.d.ts +1775 -0
- package/dist/lib/messages/schema.js +192 -0
- package/dist/lib/presets/index.d.ts +32 -0
- package/dist/lib/presets/index.js +35 -0
- package/dist/lib/presets/schema.d.ts +753 -0
- package/dist/lib/presets/schema.js +181 -0
- package/dist/lib/rendering/BrushTip/index.d.ts +63 -0
- package/dist/lib/rendering/BrushTip/index.js +112 -0
- package/dist/lib/rendering/checkerboard/index.d.ts +22 -0
- package/dist/lib/rendering/checkerboard/index.js +31 -0
- package/dist/lib/rendering/compositing/index.d.ts +64 -0
- package/dist/lib/rendering/compositing/index.js +124 -0
- package/dist/lib/rendering/cursor/index.d.ts +14 -0
- package/dist/lib/rendering/cursor/index.js +39 -0
- package/dist/lib/rendering/cursors/index.d.ts +18 -0
- package/dist/lib/rendering/cursors/index.js +23 -0
- package/dist/lib/rendering/maskOutline/index.d.ts +22 -0
- package/dist/lib/rendering/maskOutline/index.js +78 -0
- package/dist/lib/rendering/outline/index.d.ts +36 -0
- package/dist/lib/rendering/outline/index.js +120 -0
- package/dist/lib/rendering/sample/index.d.ts +55 -0
- package/dist/lib/rendering/sample/index.js +83 -0
- package/dist/lib/rendering/screenshot/index.d.ts +67 -0
- package/dist/lib/rendering/screenshot/index.js +96 -0
- package/dist/lib/rendering/transformBox/index.d.ts +10 -0
- package/dist/lib/rendering/transformBox/index.js +57 -0
- package/dist/lib/selection/Lasso/index.d.ts +70 -0
- package/dist/lib/selection/Lasso/index.js +156 -0
- package/dist/lib/selection/Selection/index.d.ts +86 -0
- package/dist/lib/selection/Selection/index.js +228 -0
- package/dist/lib/selection/geometry/index.d.ts +37 -0
- package/dist/lib/selection/geometry/index.js +57 -0
- package/dist/lib/storage/index.d.ts +63 -0
- package/dist/lib/storage/index.js +114 -0
- package/dist/lib/transform/Transformer/index.d.ts +124 -0
- package/dist/lib/transform/Transformer/index.js +286 -0
- package/dist/lib/transform/geometry/index.d.ts +95 -0
- package/dist/lib/transform/geometry/index.js +258 -0
- package/dist/lib/utils/array/index.d.ts +10 -0
- package/dist/lib/utils/array/index.js +21 -0
- package/dist/lib/utils/gestures/index.d.ts +35 -0
- package/dist/lib/utils/gestures/index.js +81 -0
- package/dist/lib/utils/navigation/index.d.ts +51 -0
- package/dist/lib/utils/navigation/index.js +59 -0
- package/dist/lib/utils/random/index.d.ts +18 -0
- package/dist/lib/utils/random/index.js +27 -0
- package/dist/lib/utils/shortcuts/index.d.ts +74 -0
- package/dist/lib/utils/shortcuts/index.js +189 -0
- package/dist/lib/validation/validators.generated.d.ts +27 -0
- package/dist/lib/validation/validators.generated.js +19826 -0
- package/dist/locales/en-GB.js +188 -0
- package/dist/locales/en-US.js +188 -0
- package/dist/locales/fr.js +188 -0
- package/dist/locales/ja.js +188 -0
- package/dist/locales/ko.js +188 -0
- package/dist/locales/zh-Hans.js +188 -0
- package/dist/locales/zh-Hant.js +188 -0
- package/dist/package.js +3 -0
- package/dist/testing/app.d.ts +7 -0
- package/dist/testing/app.js +16 -0
- package/dist/testing/elements.d.ts +42 -0
- package/dist/testing/elements.js +58 -0
- package/dist/testing/fakeCanvas.d.ts +21 -0
- package/dist/testing/fakeCanvas.js +26 -0
- package/dist/testing/layerStore.d.ts +26 -0
- package/dist/testing/layerStore.js +43 -0
- package/dist/testing/locks.d.ts +15 -0
- package/dist/testing/locks.js +41 -0
- package/dist/testing/recordingCanvas.d.ts +14 -0
- package/dist/testing/recordingCanvas.js +28 -0
- package/dist/testing/recordingContext.d.ts +10 -0
- package/dist/testing/recordingContext.js +19 -0
- package/dist/ui/ChangeController/index.d.ts +40 -0
- package/dist/ui/ChangeController/index.js +62 -0
- package/dist/ui/base/index.d.ts +69 -0
- package/dist/ui/base/index.js +94 -0
- package/dist/ui/elements/PaintCanvas/index.d.ts +249 -0
- package/dist/ui/elements/PaintCanvas/index.js +584 -0
- package/dist/ui/elements/PaintCanvas/style.js +3 -0
- package/dist/ui/elements/PcBrushConfig/index.d.ts +130 -0
- package/dist/ui/elements/PcBrushConfig/index.js +463 -0
- package/dist/ui/elements/PcBrushConfig/style.js +3 -0
- package/dist/ui/elements/PcBrushMenu/index.d.ts +121 -0
- package/dist/ui/elements/PcBrushMenu/index.js +362 -0
- package/dist/ui/elements/PcBrushMenu/style.js +3 -0
- package/dist/ui/elements/PcBrushTest/index.d.ts +71 -0
- package/dist/ui/elements/PcBrushTest/index.js +136 -0
- package/dist/ui/elements/PcBrushTest/style.js +3 -0
- package/dist/ui/elements/PcButton/index.d.ts +57 -0
- package/dist/ui/elements/PcButton/index.js +124 -0
- package/dist/ui/elements/PcButtonGroup/index.d.ts +44 -0
- package/dist/ui/elements/PcButtonGroup/index.js +93 -0
- package/dist/ui/elements/PcCanvas/index.d.ts +356 -0
- package/dist/ui/elements/PcCanvas/index.js +1004 -0
- package/dist/ui/elements/PcCanvas/style.js +3 -0
- package/dist/ui/elements/PcCanvasMap/index.d.ts +96 -0
- package/dist/ui/elements/PcCanvasMap/index.js +187 -0
- package/dist/ui/elements/PcCanvasMap/style.js +3 -0
- package/dist/ui/elements/PcContextMenu/index.d.ts +72 -0
- package/dist/ui/elements/PcContextMenu/index.js +148 -0
- package/dist/ui/elements/PcDialog/index.d.ts +63 -0
- package/dist/ui/elements/PcDialog/index.js +114 -0
- package/dist/ui/elements/PcIcon/index.d.ts +36 -0
- package/dist/ui/elements/PcIcon/index.js +43 -0
- package/dist/ui/elements/PcIconToggle/index.d.ts +46 -0
- package/dist/ui/elements/PcIconToggle/index.js +87 -0
- package/dist/ui/elements/PcInfoTip/index.d.ts +40 -0
- package/dist/ui/elements/PcInfoTip/index.js +95 -0
- package/dist/ui/elements/PcInputSettings/index.d.ts +69 -0
- package/dist/ui/elements/PcInputSettings/index.js +150 -0
- package/dist/ui/elements/PcLayerItem/index.d.ts +221 -0
- package/dist/ui/elements/PcLayerItem/index.js +561 -0
- package/dist/ui/elements/PcLayerItem/style.js +3 -0
- package/dist/ui/elements/PcLayersMenu/index.d.ts +108 -0
- package/dist/ui/elements/PcLayersMenu/index.js +208 -0
- package/dist/ui/elements/PcLayersMenu/style.js +3 -0
- package/dist/ui/elements/PcMatch/index.d.ts +31 -0
- package/dist/ui/elements/PcMatch/index.js +58 -0
- package/dist/ui/elements/PcPanel/index.d.ts +43 -0
- package/dist/ui/elements/PcPanel/index.js +51 -0
- package/dist/ui/elements/PcPopover/index.d.ts +48 -0
- package/dist/ui/elements/PcPopover/index.js +86 -0
- package/dist/ui/elements/PcSlider/index.d.ts +57 -0
- package/dist/ui/elements/PcSlider/index.js +88 -0
- package/dist/ui/elements/PcStats/index.d.ts +54 -0
- package/dist/ui/elements/PcStats/index.js +141 -0
- package/dist/ui/elements/PcThemePicker/index.d.ts +56 -0
- package/dist/ui/elements/PcThemePicker/index.js +134 -0
- package/dist/ui/elements/PcToast/index.d.ts +58 -0
- package/dist/ui/elements/PcToast/index.js +110 -0
- package/dist/ui/elements/PcToggleCheckbox/index.d.ts +37 -0
- package/dist/ui/elements/PcToggleCheckbox/index.js +105 -0
- package/dist/ui/elements/PcToolSettings/index.d.ts +128 -0
- package/dist/ui/elements/PcToolSettings/index.js +543 -0
- package/dist/ui/elements/PcToolSettings/style.js +3 -0
- package/dist/ui/elements/PcToolbar/index.d.ts +71 -0
- package/dist/ui/elements/PcToolbar/index.js +190 -0
- package/dist/ui/elements/PcToolbar/style.js +3 -0
- package/dist/ui/icons/images/brush.js +3 -0
- package/dist/ui/icons/images/circle-mask.js +3 -0
- package/dist/ui/icons/images/clipboard.js +3 -0
- package/dist/ui/icons/images/cursor.js +3 -0
- package/dist/ui/icons/images/eraser.js +3 -0
- package/dist/ui/icons/images/eyedropper.js +3 -0
- package/dist/ui/icons/images/flip-horizontal.js +3 -0
- package/dist/ui/icons/images/flip-vertical.js +3 -0
- package/dist/ui/icons/images/focus-pen.js +3 -0
- package/dist/ui/icons/images/freehand-mask.js +3 -0
- package/dist/ui/icons/images/hidden.js +3 -0
- package/dist/ui/icons/images/layers.js +3 -0
- package/dist/ui/icons/images/linked.js +3 -0
- package/dist/ui/icons/images/locked.js +3 -0
- package/dist/ui/icons/images/moon.js +3 -0
- package/dist/ui/icons/images/pan.js +3 -0
- package/dist/ui/icons/images/polygon-mask.js +3 -0
- package/dist/ui/icons/images/pressure.js +3 -0
- package/dist/ui/icons/images/randomise.js +3 -0
- package/dist/ui/icons/images/rectangle-mask.js +3 -0
- package/dist/ui/icons/images/redo.js +3 -0
- package/dist/ui/icons/images/rotate-90-left.js +3 -0
- package/dist/ui/icons/images/rotate-90-right.js +3 -0
- package/dist/ui/icons/images/smoothing-bezier-cubic.js +3 -0
- package/dist/ui/icons/images/smoothing-bezier-quad.js +3 -0
- package/dist/ui/icons/images/smoothing-linear.js +3 -0
- package/dist/ui/icons/images/star.js +3 -0
- package/dist/ui/icons/images/sun.js +3 -0
- package/dist/ui/icons/images/tilt.js +3 -0
- package/dist/ui/icons/images/undo.js +3 -0
- package/dist/ui/icons/images/unlinked.js +3 -0
- package/dist/ui/icons/images/unlocked.js +3 -0
- package/dist/ui/icons/images/visible.js +3 -0
- package/dist/ui/icons/images/zoom-in.js +3 -0
- package/dist/ui/icons/images/zoom-out.js +3 -0
- package/dist/ui/icons/images/zoom.js +3 -0
- package/dist/ui/icons/index.d.ts +42 -0
- package/dist/ui/icons/index.js +130 -0
- package/dist/ui/index.d.ts +21 -0
- package/dist/ui/index.js +22 -0
- package/dist/ui/layout/index.d.ts +88 -0
- package/dist/ui/layout/index.js +96 -0
- package/dist/ui/styles/index.d.ts +13 -0
- package/dist/ui/styles/index.js +195 -0
- package/dist/ui/tokens/index.d.ts +29 -0
- package/dist/ui/tokens/index.js +114 -0
- package/locales/en-GB.json +186 -0
- package/locales/en-US.json +186 -0
- package/locales/fr.json +186 -0
- package/locales/ja.json +186 -0
- package/locales/ko.json +186 -0
- package/locales/zh-Hans.json +186 -0
- package/locales/zh-Hant.json +186 -0
- package/package.json +97 -3
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import style_default from "./style.js";
|
|
2
|
+
import { NO_TEXT_SELECTION_CSS, PILLS_CSS, WINDOWS_CSS } from "../../styles/index.js";
|
|
3
|
+
import { PcElement, defineElement } from "../../base/index.js";
|
|
4
|
+
import ChangeController from "../../ChangeController/index.js";
|
|
5
|
+
import { maskModeFor } from "../../../lib/selection/geometry/index.js";
|
|
6
|
+
import { LAYER_ALPHA_MASK_EVENT, LAYER_DRAG_EVENT, LAYER_MENU_OPEN_EVENT } from "../PcLayerItem/index.js";
|
|
7
|
+
import { html, nothing, unsafeCSS } from "lit";
|
|
8
|
+
import { styleMap } from "lit/directives/style-map.js";
|
|
9
|
+
import { repeat } from "lit/directives/repeat.js";
|
|
10
|
+
// src/ui/elements/PcLayersMenu/index.ts
|
|
11
|
+
/**
|
|
12
|
+
* Whether a point is inside a rectangle (edges included).
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* isInside(element.getBoundingClientRect(), event.clientX, event.clientY);
|
|
16
|
+
*/
|
|
17
|
+
var isInside = (rect, x, y) => x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
|
18
|
+
/**
|
|
19
|
+
* Where a dragged layer would land among the other rows: before the first row whose middle is below the pointer, or
|
|
20
|
+
* after the last. The ghost showing the place is left out, so the place doesn't jump when the ghost moves.
|
|
21
|
+
*
|
|
22
|
+
* @param rows - the other rows' top and height, in list order
|
|
23
|
+
* @param ghost - the ghost's top and height, if shown
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* dropSlot([{ top: 0, height: 30 }, { top: 30, height: 30 }], 40); // 1
|
|
27
|
+
*/
|
|
28
|
+
var dropSlot = (rows, y, ghost) => {
|
|
29
|
+
const index = rows.findIndex((row) => {
|
|
30
|
+
const below = ghost && row.top >= ghost.top ? ghost.height : 0;
|
|
31
|
+
return y < row.top - below + row.height / 2;
|
|
32
|
+
});
|
|
33
|
+
return index < 0 ? rows.length : index;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Layers menu: the user's layers from top to bottom and a "New Layer" button.
|
|
37
|
+
*
|
|
38
|
+
* Dragging a layer's reorder handle lifts its row out of the list to float with the pointer, and leaves a ghost with the
|
|
39
|
+
* layer's name in the list where it would land: where it was, until it is moved somewhere else. Dropping it moves it
|
|
40
|
+
* there, and dropping it on "New Layer" duplicates it (the cursor shows "+", and the button is
|
|
41
|
+
* highlighted for touch). Escape cancels the drag. Moves and duplicates are announced to screen readers.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* html`<pc-layers-menu .app=${app}></pc-layers-menu>`
|
|
45
|
+
*/
|
|
46
|
+
var PcLayersMenu = class extends PcElement {
|
|
47
|
+
static properties = {
|
|
48
|
+
...PcElement.properties,
|
|
49
|
+
app: { attribute: false },
|
|
50
|
+
drag: { state: true },
|
|
51
|
+
announcement: { state: true }
|
|
52
|
+
};
|
|
53
|
+
static styles = [
|
|
54
|
+
PcElement.styles,
|
|
55
|
+
unsafeCSS(NO_TEXT_SELECTION_CSS),
|
|
56
|
+
unsafeCSS(style_default),
|
|
57
|
+
unsafeCSS(WINDOWS_CSS),
|
|
58
|
+
unsafeCSS(PILLS_CSS)
|
|
59
|
+
];
|
|
60
|
+
changes = new ChangeController(this, () => [this.app, this.app?.layers]);
|
|
61
|
+
constructor() {
|
|
62
|
+
super();
|
|
63
|
+
this.announcement = "";
|
|
64
|
+
this.addEventListener(LAYER_DRAG_EVENT, (event) => this.onLayerDrag(event.detail, event.composedPath()[0]));
|
|
65
|
+
this.addEventListener(LAYER_MENU_OPEN_EVENT, (event) => {
|
|
66
|
+
const opened = event.composedPath()[0];
|
|
67
|
+
for (const item of this.renderRoot.querySelectorAll("pc-layer-item")) if (item !== opened) item.menuOpen = false;
|
|
68
|
+
});
|
|
69
|
+
this.addEventListener(LAYER_ALPHA_MASK_EVENT, (event) => {
|
|
70
|
+
const { layer, shiftKey, altKey } = event.detail;
|
|
71
|
+
this.app?.selection.fromAlpha(layer, maskModeFor({
|
|
72
|
+
shiftKey,
|
|
73
|
+
altKey
|
|
74
|
+
}));
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Follow a layer dragged by its reorder handle: show where it would land, then move or duplicate it when dropped.
|
|
79
|
+
*/
|
|
80
|
+
onLayerDrag({ layer, phase, x, y }, row) {
|
|
81
|
+
if (phase === "start") {
|
|
82
|
+
const rect = row.getBoundingClientRect();
|
|
83
|
+
this.drag = {
|
|
84
|
+
id: layer.id,
|
|
85
|
+
name: layer.name,
|
|
86
|
+
action: "none",
|
|
87
|
+
x,
|
|
88
|
+
y,
|
|
89
|
+
offsetX: x - rect.left,
|
|
90
|
+
offsetY: y - rect.top,
|
|
91
|
+
width: rect.width,
|
|
92
|
+
height: rect.height
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const drag = this.drag;
|
|
96
|
+
if (!drag) return;
|
|
97
|
+
if (phase === "cancel") {
|
|
98
|
+
this.drag = void 0;
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
this.drag = {
|
|
102
|
+
...drag,
|
|
103
|
+
x,
|
|
104
|
+
y,
|
|
105
|
+
...this.dropTarget(drag.id, x, y)
|
|
106
|
+
};
|
|
107
|
+
if (phase === "end") this.drop(this.drag);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* What dropping the dragged layer at a point would do: nothing outside the menu, duplicate it on "New Layer" (if
|
|
111
|
+
* another layer can be made), otherwise move it to the place among the other rows nearest the pointer.
|
|
112
|
+
*/
|
|
113
|
+
dropTarget(id, x, y) {
|
|
114
|
+
if (!isInside(this.getBoundingClientRect(), x, y)) return {
|
|
115
|
+
action: "none",
|
|
116
|
+
slot: void 0
|
|
117
|
+
};
|
|
118
|
+
const root = this.renderRoot;
|
|
119
|
+
if (isInside(root.querySelector("button.new").getBoundingClientRect(), x, y)) return {
|
|
120
|
+
action: this.app?.layers.canCreate ? "duplicate" : "none",
|
|
121
|
+
slot: void 0
|
|
122
|
+
};
|
|
123
|
+
const rows = [...root.querySelectorAll("pc-layer-item")].filter((item) => item.layer?.id !== id).map((item) => item.getBoundingClientRect());
|
|
124
|
+
const ghost = root.querySelector(".ghost")?.getBoundingClientRect();
|
|
125
|
+
return {
|
|
126
|
+
action: "move",
|
|
127
|
+
slot: dropSlot(rows, y, ghost)
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Move or duplicate the dropped layer, and tell screen readers what happened.
|
|
132
|
+
*/
|
|
133
|
+
drop(drag) {
|
|
134
|
+
this.drag = void 0;
|
|
135
|
+
const layers = this.app?.layers;
|
|
136
|
+
if (!layers) return;
|
|
137
|
+
if (drag.action === "duplicate") {
|
|
138
|
+
layers.duplicate(drag.id);
|
|
139
|
+
this.announcement = `${drag.name} duplicated`;
|
|
140
|
+
} else if (drag.action === "move" && drag.slot !== void 0) {
|
|
141
|
+
const from = layers.indexOf(drag.id);
|
|
142
|
+
layers.move(drag.id, drag.slot);
|
|
143
|
+
if (layers.indexOf(drag.id) !== from) this.announcement = `${drag.name} moved to position ${drag.slot + 1} of ${layers.layers.length}`;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The rows, with a ghost (the dragged layer's name) where it would land, counting only the other rows: where it was,
|
|
148
|
+
* unless it would move. The dragged row floats with the pointer, out of the list. Rows are keyed by layer, so each
|
|
149
|
+
* layer keeps its row (and a drag its handle) as the ghost moves.
|
|
150
|
+
*/
|
|
151
|
+
renderRows(layers) {
|
|
152
|
+
const drag = this.drag;
|
|
153
|
+
const slot = drag ? drag.action === "move" ? drag.slot : layers.indexOf(drag.id) : void 0;
|
|
154
|
+
const ghost = {
|
|
155
|
+
key: "ghost",
|
|
156
|
+
view: html`<div
|
|
157
|
+
class="ghost"
|
|
158
|
+
aria-hidden="true"
|
|
159
|
+
style=${styleMap({ height: `${drag?.height}px` })}
|
|
160
|
+
>
|
|
161
|
+
${drag?.name}
|
|
162
|
+
</div>`
|
|
163
|
+
};
|
|
164
|
+
const entries = [];
|
|
165
|
+
let others = 0;
|
|
166
|
+
for (const layer of layers.layers) {
|
|
167
|
+
const dragged = layer.id === drag?.id;
|
|
168
|
+
if (!dragged && slot === others++) entries.push(ghost);
|
|
169
|
+
entries.push({
|
|
170
|
+
key: layer.id,
|
|
171
|
+
view: html`<pc-layer-item
|
|
172
|
+
.stack=${layers}
|
|
173
|
+
.background=${this.app?.background}
|
|
174
|
+
.layer=${layer}
|
|
175
|
+
?dragging=${dragged}
|
|
176
|
+
.dropAction=${dragged ? drag?.action : void 0}
|
|
177
|
+
style=${styleMap(dragged && drag ? {
|
|
178
|
+
left: `${drag.x - drag.offsetX}px`,
|
|
179
|
+
top: `${drag.y - drag.offsetY}px`,
|
|
180
|
+
width: `${drag.width}px`
|
|
181
|
+
} : {})}
|
|
182
|
+
></pc-layer-item>`
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
if (slot === others) entries.push(ghost);
|
|
186
|
+
return repeat(entries, (entry) => entry.key, (entry) => entry.view);
|
|
187
|
+
}
|
|
188
|
+
render() {
|
|
189
|
+
const layers = this.app?.layers;
|
|
190
|
+
if (!layers) return html``;
|
|
191
|
+
return html`
|
|
192
|
+
${this.renderRows(layers)}
|
|
193
|
+
<button
|
|
194
|
+
type="button"
|
|
195
|
+
class="pill new ${this.drag?.action === "duplicate" ? "drop-target" : ""}"
|
|
196
|
+
?disabled=${!layers.canCreate}
|
|
197
|
+
@click=${() => layers.create()}
|
|
198
|
+
>
|
|
199
|
+
${this.t("layers.new")}
|
|
200
|
+
</button>
|
|
201
|
+
<p class="announcement" role="status" aria-live="polite">
|
|
202
|
+
${this.announcement || nothing}
|
|
203
|
+
</p>
|
|
204
|
+
`;
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
defineElement("pc-layers-menu", PcLayersMenu);
|
|
208
|
+
export { PcLayersMenu, dropSlot, isInside };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// src/ui/elements/PcLayersMenu/style.css?inline
|
|
2
|
+
var style_default = ":host {\n display: flex;\n flex-direction: column;\n gap: 8px;\n box-sizing: border-box;\n /* The layout makes it fill its panel when narrow */\n width: var(--pc-layers-menu-width, 290px);\n padding: 8px;\n /* Light grey, like the bars */\n background: var(--pc-bar);\n box-shadow: var(--pc-shadow);\n}\n/* \"New Layer\": a full-width purple pill */\nbutton.new {\n width: 100%;\n min-height: 40px;\n}\n/* Where a dragged layer would land: a full-width block with its name, as tall as the row (set by the menu) */\n.ghost {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n padding: 0 8px;\n border: 2px dashed;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n/* Dropping a dragged layer here duplicates it (highlighted for touch, where there is no \"+\" cursor) */\nbutton.new.drop-target {\n outline: var(--pc-focus-width) solid var(--pc-focus);\n outline-offset: 2px;\n}\n/* For screen readers only */\n.announcement {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n";
|
|
3
|
+
export { style_default as default };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
/**
|
|
3
|
+
* Creates the contents of its `<template>` only while the `<paint-canvas>` layout it's in meets a condition (see
|
|
4
|
+
* `matchesState`), e.g. to show a different element on narrow layouts or while using touch. The contents are added
|
|
5
|
+
* beside the template, in the page (not a shadow root), so the page's styles apply. Outside a layout, nothing shows.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* html`<pc-match when="narrow"><template><my-compact-thing></my-compact-thing></template></pc-match>`
|
|
9
|
+
* html`<pc-match when="!narrow input:pen"><template>…</template></pc-match>`
|
|
10
|
+
*/
|
|
11
|
+
export declare class PcMatch extends LitElement {
|
|
12
|
+
static properties: {
|
|
13
|
+
when: {
|
|
14
|
+
type: StringConstructor;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
/** The condition (see `matchesState`) */
|
|
18
|
+
when: string;
|
|
19
|
+
private readonly layout;
|
|
20
|
+
/** The contents created from the template, while shown */
|
|
21
|
+
private created;
|
|
22
|
+
constructor();
|
|
23
|
+
protected createRenderRoot(): HTMLElement;
|
|
24
|
+
/** Whether the condition holds now */
|
|
25
|
+
get active(): boolean;
|
|
26
|
+
disconnectedCallback(): void;
|
|
27
|
+
/** Remove the created contents */
|
|
28
|
+
private clear;
|
|
29
|
+
protected updated(): void;
|
|
30
|
+
protected render(): null;
|
|
31
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { defineElement } from "../../base/index.js";
|
|
2
|
+
import { LayoutStateController, matchesState } from "../../layout/index.js";
|
|
3
|
+
import { LitElement } from "lit";
|
|
4
|
+
// src/ui/elements/PcMatch/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* Creates the contents of its `<template>` only while the `<paint-canvas>` layout it's in meets a condition (see
|
|
7
|
+
* `matchesState`), e.g. to show a different element on narrow layouts or while using touch. The contents are added
|
|
8
|
+
* beside the template, in the page (not a shadow root), so the page's styles apply. Outside a layout, nothing shows.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* html`<pc-match when="narrow"><template><my-compact-thing></my-compact-thing></template></pc-match>`
|
|
12
|
+
* html`<pc-match when="!narrow input:pen"><template>…</template></pc-match>`
|
|
13
|
+
*/
|
|
14
|
+
var PcMatch = class extends LitElement {
|
|
15
|
+
static properties = { when: { type: String } };
|
|
16
|
+
layout = new LayoutStateController(this);
|
|
17
|
+
/** The contents created from the template, while shown */
|
|
18
|
+
created = [];
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this.when = "";
|
|
22
|
+
}
|
|
23
|
+
createRenderRoot() {
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
/** Whether the condition holds now */
|
|
27
|
+
get active() {
|
|
28
|
+
const state = this.layout.state;
|
|
29
|
+
return state !== void 0 && matchesState(this.when, state);
|
|
30
|
+
}
|
|
31
|
+
disconnectedCallback() {
|
|
32
|
+
super.disconnectedCallback();
|
|
33
|
+
this.clear();
|
|
34
|
+
}
|
|
35
|
+
/** Remove the created contents */
|
|
36
|
+
clear() {
|
|
37
|
+
for (const node of this.created) node.parentNode?.removeChild(node);
|
|
38
|
+
this.created = [];
|
|
39
|
+
}
|
|
40
|
+
updated() {
|
|
41
|
+
const shown = this.created.length > 0;
|
|
42
|
+
if (this.active === shown) return;
|
|
43
|
+
if (shown) {
|
|
44
|
+
this.clear();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const template = this.querySelector(":scope > template");
|
|
48
|
+
if (!(template instanceof HTMLTemplateElement)) return;
|
|
49
|
+
const content = template.content.cloneNode(true);
|
|
50
|
+
this.created = [...content.childNodes];
|
|
51
|
+
this.append(content);
|
|
52
|
+
}
|
|
53
|
+
render() {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
defineElement("pc-match", PcMatch);
|
|
58
|
+
export { PcMatch };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { PcElement } from "../../base";
|
|
2
|
+
/**
|
|
3
|
+
* Wraps content docked at a side of the `<paint-canvas>` layout (e.g. the layers menu or a chat window). Its `icon`,
|
|
4
|
+
* `label` and `badge` are what the layout shows for it when the side narrows to a rail of buttons; the badge is a dot
|
|
5
|
+
* meaning something new (e.g. unread messages). It names its region for screen readers. It's at most 290px wide
|
|
6
|
+
* (`--pc-panel-max-width`).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* html`<pc-panel slot="right" icon="layers" label="Layers"><my-layers></my-layers></pc-panel>`
|
|
10
|
+
*/
|
|
11
|
+
export declare class PcPanel extends PcElement {
|
|
12
|
+
static properties: {
|
|
13
|
+
icon: {
|
|
14
|
+
type: StringConstructor;
|
|
15
|
+
};
|
|
16
|
+
label: {
|
|
17
|
+
type: StringConstructor;
|
|
18
|
+
};
|
|
19
|
+
badge: {
|
|
20
|
+
type: BooleanConstructor;
|
|
21
|
+
reflect: boolean;
|
|
22
|
+
};
|
|
23
|
+
translations: {
|
|
24
|
+
attribute: boolean;
|
|
25
|
+
};
|
|
26
|
+
icons: {
|
|
27
|
+
attribute: boolean;
|
|
28
|
+
};
|
|
29
|
+
theme: {
|
|
30
|
+
type: StringConstructor;
|
|
31
|
+
reflect: boolean;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
static styles: import("lit").CSSResultGroup[];
|
|
35
|
+
/** Name of the icon for its rail button */
|
|
36
|
+
icon: string;
|
|
37
|
+
/** Names the panel (its rail button and region) */
|
|
38
|
+
label: string;
|
|
39
|
+
/** Whether there's something new in it */
|
|
40
|
+
badge: boolean;
|
|
41
|
+
constructor();
|
|
42
|
+
render(): import("lit").TemplateResult<1>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { PcElement, defineElement } from "../../base/index.js";
|
|
2
|
+
import { css, html, nothing } from "lit";
|
|
3
|
+
// src/ui/elements/PcPanel/index.ts
|
|
4
|
+
/**
|
|
5
|
+
* Wraps content docked at a side of the `<paint-canvas>` layout (e.g. the layers menu or a chat window). Its `icon`,
|
|
6
|
+
* `label` and `badge` are what the layout shows for it when the side narrows to a rail of buttons; the badge is a dot
|
|
7
|
+
* meaning something new (e.g. unread messages). It names its region for screen readers. It's at most 290px wide
|
|
8
|
+
* (`--pc-panel-max-width`).
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* html`<pc-panel slot="right" icon="layers" label="Layers"><my-layers></my-layers></pc-panel>`
|
|
12
|
+
*/
|
|
13
|
+
var PcPanel = class extends PcElement {
|
|
14
|
+
static properties = {
|
|
15
|
+
...PcElement.properties,
|
|
16
|
+
icon: { type: String },
|
|
17
|
+
label: { type: String },
|
|
18
|
+
badge: {
|
|
19
|
+
type: Boolean,
|
|
20
|
+
reflect: true
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
static styles = [PcElement.styles, css`
|
|
24
|
+
:host {
|
|
25
|
+
display: flex;
|
|
26
|
+
min-width: 0;
|
|
27
|
+
max-width: var(--pc-panel-max-width, 290px);
|
|
28
|
+
min-height: 0;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
}
|
|
31
|
+
section {
|
|
32
|
+
display: flex;
|
|
33
|
+
flex: 1;
|
|
34
|
+
min-height: 0;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
}
|
|
37
|
+
`];
|
|
38
|
+
constructor() {
|
|
39
|
+
super();
|
|
40
|
+
this.icon = "";
|
|
41
|
+
this.label = "";
|
|
42
|
+
this.badge = false;
|
|
43
|
+
}
|
|
44
|
+
render() {
|
|
45
|
+
return html`<section part="panel" aria-label=${this.label || nothing}>
|
|
46
|
+
<slot></slot>
|
|
47
|
+
</section>`;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
defineElement("pc-panel", PcPanel);
|
|
51
|
+
export { PcPanel };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type PropertyValues } from "lit";
|
|
2
|
+
import { PcElement } from "../../base";
|
|
3
|
+
/**
|
|
4
|
+
* A floating box for a menu or settings (e.g. the brush presets), shown while `open`. The implementer places it (e.g.
|
|
5
|
+
* next to the button that opens it). It isn't modal: Escape, or a press outside it and outside its `anchor`, fires
|
|
6
|
+
* `pc-close`, and the implementer sets `open` to false in response. Focus moves into it when it opens.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* html`<pc-popover ?open=${shown} label="Brush presets" .anchor=${button} @pc-close=${hide}>…</pc-popover>`
|
|
10
|
+
*/
|
|
11
|
+
export declare class PcPopover extends PcElement {
|
|
12
|
+
static properties: {
|
|
13
|
+
open: {
|
|
14
|
+
type: BooleanConstructor;
|
|
15
|
+
reflect: boolean;
|
|
16
|
+
};
|
|
17
|
+
label: {
|
|
18
|
+
type: StringConstructor;
|
|
19
|
+
};
|
|
20
|
+
anchor: {
|
|
21
|
+
attribute: boolean;
|
|
22
|
+
};
|
|
23
|
+
translations: {
|
|
24
|
+
attribute: boolean;
|
|
25
|
+
};
|
|
26
|
+
icons: {
|
|
27
|
+
attribute: boolean;
|
|
28
|
+
};
|
|
29
|
+
theme: {
|
|
30
|
+
type: StringConstructor;
|
|
31
|
+
reflect: boolean;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
static styles: import("lit").CSSResultGroup[];
|
|
35
|
+
open: boolean;
|
|
36
|
+
/** Names the popover for screen readers */
|
|
37
|
+
label: string;
|
|
38
|
+
/** The element that opens it (pressing it doesn't count as pressing outside) */
|
|
39
|
+
anchor?: Element;
|
|
40
|
+
private readonly onPointerDown;
|
|
41
|
+
constructor();
|
|
42
|
+
connectedCallback(): void;
|
|
43
|
+
disconnectedCallback(): void;
|
|
44
|
+
updated(changed: PropertyValues<this>): void;
|
|
45
|
+
/** Escape closes */
|
|
46
|
+
private onKeyDown;
|
|
47
|
+
render(): import("lit").TemplateResult<1>;
|
|
48
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { PcElement, defineElement, emit } from "../../base/index.js";
|
|
2
|
+
import { css, html } from "lit";
|
|
3
|
+
// src/ui/elements/PcPopover/index.ts
|
|
4
|
+
/**
|
|
5
|
+
* A floating box for a menu or settings (e.g. the brush presets), shown while `open`. The implementer places it (e.g.
|
|
6
|
+
* next to the button that opens it). It isn't modal: Escape, or a press outside it and outside its `anchor`, fires
|
|
7
|
+
* `pc-close`, and the implementer sets `open` to false in response. Focus moves into it when it opens.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* html`<pc-popover ?open=${shown} label="Brush presets" .anchor=${button} @pc-close=${hide}>…</pc-popover>`
|
|
11
|
+
*/
|
|
12
|
+
var PcPopover = class extends PcElement {
|
|
13
|
+
static properties = {
|
|
14
|
+
...PcElement.properties,
|
|
15
|
+
open: {
|
|
16
|
+
type: Boolean,
|
|
17
|
+
reflect: true
|
|
18
|
+
},
|
|
19
|
+
label: { type: String },
|
|
20
|
+
anchor: { attribute: false }
|
|
21
|
+
};
|
|
22
|
+
static styles = [PcElement.styles, css`
|
|
23
|
+
:host {
|
|
24
|
+
position: absolute;
|
|
25
|
+
z-index: 10;
|
|
26
|
+
display: none;
|
|
27
|
+
}
|
|
28
|
+
:host([open]) {
|
|
29
|
+
display: block;
|
|
30
|
+
}
|
|
31
|
+
[role="dialog"] {
|
|
32
|
+
max-height: inherit;
|
|
33
|
+
overflow: auto;
|
|
34
|
+
padding: var(--pc-space-2);
|
|
35
|
+
border-radius: var(--pc-radius);
|
|
36
|
+
background: var(--pc-surface-raised);
|
|
37
|
+
color: var(--pc-text);
|
|
38
|
+
box-shadow: var(--pc-shadow);
|
|
39
|
+
font-family: var(--pc-font);
|
|
40
|
+
font-size: var(--pc-font-size);
|
|
41
|
+
}
|
|
42
|
+
[role="dialog"]:focus-visible {
|
|
43
|
+
outline: var(--pc-focus-width) solid var(--pc-focus);
|
|
44
|
+
}
|
|
45
|
+
`];
|
|
46
|
+
onPointerDown = (event) => {
|
|
47
|
+
if (!this.open) return;
|
|
48
|
+
const path = event.composedPath();
|
|
49
|
+
if (!path.includes(this) && !(this.anchor && path.includes(this.anchor))) emit(this, "pc-close");
|
|
50
|
+
};
|
|
51
|
+
constructor() {
|
|
52
|
+
super();
|
|
53
|
+
this.open = false;
|
|
54
|
+
this.label = "";
|
|
55
|
+
}
|
|
56
|
+
connectedCallback() {
|
|
57
|
+
super.connectedCallback();
|
|
58
|
+
document.addEventListener("pointerdown", this.onPointerDown, true);
|
|
59
|
+
}
|
|
60
|
+
disconnectedCallback() {
|
|
61
|
+
super.disconnectedCallback();
|
|
62
|
+
document.removeEventListener("pointerdown", this.onPointerDown, true);
|
|
63
|
+
}
|
|
64
|
+
updated(changed) {
|
|
65
|
+
if (changed.has("open") && this.open) this.renderRoot.querySelector("[role=dialog]")?.focus();
|
|
66
|
+
}
|
|
67
|
+
/** Escape closes */
|
|
68
|
+
onKeyDown(event) {
|
|
69
|
+
if (event.key !== "Escape") return;
|
|
70
|
+
event.preventDefault();
|
|
71
|
+
emit(this, "pc-close");
|
|
72
|
+
}
|
|
73
|
+
render() {
|
|
74
|
+
return html`<div
|
|
75
|
+
part="popover"
|
|
76
|
+
role="dialog"
|
|
77
|
+
aria-label=${this.label}
|
|
78
|
+
tabindex="-1"
|
|
79
|
+
@keydown=${this.onKeyDown}
|
|
80
|
+
>
|
|
81
|
+
<slot></slot>
|
|
82
|
+
</div>`;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
defineElement("pc-popover", PcPopover);
|
|
86
|
+
export { PcPopover };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { PcElement } from "../../base";
|
|
2
|
+
/**
|
|
3
|
+
* A slider with its label and value, e.g. opacity or volume. Fires `input` while dragging and `change` once let go,
|
|
4
|
+
* each with the new `value`.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* html`<pc-slider label="Opacity" min="0" max="100" unit="%" .value=${50} @change=${setOpacity}></pc-slider>`
|
|
8
|
+
*/
|
|
9
|
+
export declare class PcSlider extends PcElement {
|
|
10
|
+
static properties: {
|
|
11
|
+
label: {
|
|
12
|
+
type: StringConstructor;
|
|
13
|
+
};
|
|
14
|
+
min: {
|
|
15
|
+
type: NumberConstructor;
|
|
16
|
+
};
|
|
17
|
+
max: {
|
|
18
|
+
type: NumberConstructor;
|
|
19
|
+
};
|
|
20
|
+
step: {
|
|
21
|
+
type: NumberConstructor;
|
|
22
|
+
};
|
|
23
|
+
value: {
|
|
24
|
+
type: NumberConstructor;
|
|
25
|
+
};
|
|
26
|
+
unit: {
|
|
27
|
+
type: StringConstructor;
|
|
28
|
+
};
|
|
29
|
+
disabled: {
|
|
30
|
+
type: BooleanConstructor;
|
|
31
|
+
reflect: boolean;
|
|
32
|
+
};
|
|
33
|
+
translations: {
|
|
34
|
+
attribute: boolean;
|
|
35
|
+
};
|
|
36
|
+
icons: {
|
|
37
|
+
attribute: boolean;
|
|
38
|
+
};
|
|
39
|
+
theme: {
|
|
40
|
+
type: StringConstructor;
|
|
41
|
+
reflect: boolean;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
static styles: import("lit").CSSResultGroup[];
|
|
45
|
+
label: string;
|
|
46
|
+
min: number;
|
|
47
|
+
max: number;
|
|
48
|
+
step: number;
|
|
49
|
+
value: number;
|
|
50
|
+
/** Shown after the value, e.g. "%" */
|
|
51
|
+
unit: string;
|
|
52
|
+
disabled: boolean;
|
|
53
|
+
constructor();
|
|
54
|
+
/** Follow the slider, and tell listeners (`input` while dragging, `change` once let go) */
|
|
55
|
+
private onSlide;
|
|
56
|
+
render(): import("lit").TemplateResult<1>;
|
|
57
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { PcElement, defineElement, emit } from "../../base/index.js";
|
|
2
|
+
import { css, html, nothing } from "lit";
|
|
3
|
+
import { live } from "lit/directives/live.js";
|
|
4
|
+
// src/ui/elements/PcSlider/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* A slider with its label and value, e.g. opacity or volume. Fires `input` while dragging and `change` once let go,
|
|
7
|
+
* each with the new `value`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* html`<pc-slider label="Opacity" min="0" max="100" unit="%" .value=${50} @change=${setOpacity}></pc-slider>`
|
|
11
|
+
*/
|
|
12
|
+
var PcSlider = class extends PcElement {
|
|
13
|
+
static properties = {
|
|
14
|
+
...PcElement.properties,
|
|
15
|
+
label: { type: String },
|
|
16
|
+
min: { type: Number },
|
|
17
|
+
max: { type: Number },
|
|
18
|
+
step: { type: Number },
|
|
19
|
+
value: { type: Number },
|
|
20
|
+
unit: { type: String },
|
|
21
|
+
disabled: {
|
|
22
|
+
type: Boolean,
|
|
23
|
+
reflect: true
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
static styles = [PcElement.styles, css`
|
|
27
|
+
:host {
|
|
28
|
+
display: block;
|
|
29
|
+
}
|
|
30
|
+
label {
|
|
31
|
+
display: grid;
|
|
32
|
+
grid-template-columns: 1fr auto;
|
|
33
|
+
gap: var(--pc-space-1) var(--pc-space-2);
|
|
34
|
+
align-items: center;
|
|
35
|
+
color: var(--pc-text);
|
|
36
|
+
font-family: var(--pc-font);
|
|
37
|
+
font-size: var(--pc-font-size);
|
|
38
|
+
}
|
|
39
|
+
input {
|
|
40
|
+
grid-column: 1 / -1;
|
|
41
|
+
width: 100%;
|
|
42
|
+
margin: 0;
|
|
43
|
+
accent-color: var(--pc-accent);
|
|
44
|
+
}
|
|
45
|
+
input:focus-visible {
|
|
46
|
+
outline: var(--pc-focus-width) solid var(--pc-focus);
|
|
47
|
+
outline-offset: 2px;
|
|
48
|
+
}
|
|
49
|
+
output {
|
|
50
|
+
color: var(--pc-text-muted);
|
|
51
|
+
font-variant-numeric: tabular-nums;
|
|
52
|
+
}
|
|
53
|
+
`];
|
|
54
|
+
constructor() {
|
|
55
|
+
super();
|
|
56
|
+
this.label = "";
|
|
57
|
+
this.min = 0;
|
|
58
|
+
this.max = 100;
|
|
59
|
+
this.step = 1;
|
|
60
|
+
this.value = 0;
|
|
61
|
+
this.unit = "";
|
|
62
|
+
this.disabled = false;
|
|
63
|
+
}
|
|
64
|
+
/** Follow the slider, and tell listeners (`input` while dragging, `change` once let go) */
|
|
65
|
+
onSlide(event) {
|
|
66
|
+
this.value = Number(event.target.value);
|
|
67
|
+
emit(this, event.type, { value: this.value });
|
|
68
|
+
}
|
|
69
|
+
render() {
|
|
70
|
+
return html`<label part="label">
|
|
71
|
+
<span>${this.label}</span>
|
|
72
|
+
<output part="value">${this.value}${this.unit || nothing}</output>
|
|
73
|
+
<input
|
|
74
|
+
part="slider"
|
|
75
|
+
type="range"
|
|
76
|
+
min=${this.min}
|
|
77
|
+
max=${this.max}
|
|
78
|
+
step=${this.step}
|
|
79
|
+
.value=${live(String(this.value))}
|
|
80
|
+
?disabled=${this.disabled}
|
|
81
|
+
@input=${this.onSlide}
|
|
82
|
+
@change=${this.onSlide}
|
|
83
|
+
/>
|
|
84
|
+
</label>`;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
defineElement("pc-slider", PcSlider);
|
|
88
|
+
export { PcSlider };
|