@lvl99dotcom/paintcanvas 0.4.0 → 0.5.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/README.md +30 -15
- package/dist/lib/brushes/presets/round/index.d.ts +1 -1
- package/dist/lib/brushes/presets/round/index.js +12 -7
- package/dist/lib/brushes/presets/square/index.d.ts +1 -1
- package/dist/lib/brushes/presets/square/index.js +7 -3
- package/dist/lib/brushes/shapeImage/index.d.ts +7 -3
- package/dist/lib/brushes/shapeImage/index.js +15 -9
- package/dist/lib/brushes/shapes/index.d.ts +18 -0
- package/dist/lib/brushes/shapes/index.js +86 -0
- package/dist/lib/classes/BrushSettings/index.d.ts +29 -2
- package/dist/lib/classes/BrushSettings/index.js +51 -14
- package/dist/lib/classes/KeyboardShortcuts/index.d.ts +31 -2
- package/dist/lib/classes/KeyboardShortcuts/index.js +66 -4
- package/dist/lib/classes/PaintCanvas/index.d.ts +46 -0
- package/dist/lib/classes/PaintCanvas/index.js +67 -0
- package/dist/lib/classes/SettingsAutosave/index.d.ts +3 -2
- package/dist/lib/classes/SettingsAutosave/index.js +5 -3
- package/dist/lib/classes/UiSettings/index.d.ts +68 -0
- package/dist/lib/classes/UiSettings/index.js +82 -0
- package/dist/lib/settings/index.d.ts +1 -1
- package/dist/lib/settings/index.js +4 -2
- package/dist/lib/settings/schema.d.ts +18 -0
- package/dist/lib/settings/schema.js +14 -0
- package/dist/lib/validation/validators.generated.js +169 -1
- package/dist/locales/en-GB.js +9 -2
- package/dist/locales/en-US.js +9 -2
- package/dist/locales/fr.js +9 -2
- package/dist/locales/ja.js +9 -2
- package/dist/locales/ko.js +9 -2
- package/dist/locales/zh-Hans.js +9 -2
- package/dist/locales/zh-Hant.js +9 -2
- package/dist/package.js +1 -1
- package/dist/testing/recordingCanvas.js +2 -1
- package/dist/ui/base/index.d.ts +2 -2
- package/dist/ui/dismiss/index.d.ts +21 -0
- package/dist/ui/dismiss/index.js +27 -0
- package/dist/ui/drag/index.d.ts +51 -0
- package/dist/ui/drag/index.js +81 -0
- package/dist/ui/elements/PaintCanvas/index.d.ts +17 -12
- package/dist/ui/elements/PaintCanvas/index.js +34 -17
- package/dist/ui/elements/PaintCanvas/style.js +1 -1
- package/dist/ui/elements/PcAppSettings/index.d.ts +1 -1
- package/dist/ui/elements/PcAppSettings/index.js +1 -1
- package/dist/ui/elements/PcBrushConfig/index.d.ts +9 -2
- package/dist/ui/elements/PcBrushConfig/index.js +47 -7
- package/dist/ui/elements/PcBrushConfig/style.js +1 -1
- package/dist/ui/elements/PcBrushSize/index.d.ts +53 -0
- package/dist/ui/elements/PcBrushSize/index.js +66 -0
- package/dist/ui/elements/PcBrushTest/index.d.ts +26 -0
- package/dist/ui/elements/PcBrushTest/index.js +73 -5
- package/dist/ui/elements/PcBrushTest/style.js +1 -1
- package/dist/ui/elements/PcCanvas/index.d.ts +21 -1
- package/dist/ui/elements/PcCanvas/index.js +53 -10
- package/dist/ui/elements/PcCanvasMap/style.js +1 -1
- package/dist/ui/elements/PcClipboardTools/index.d.ts +48 -0
- package/dist/ui/elements/PcClipboardTools/index.js +118 -0
- package/dist/ui/elements/PcContextMenu/index.d.ts +2 -2
- package/dist/ui/elements/PcInputSettings/index.d.ts +13 -0
- package/dist/ui/elements/PcInputSettings/index.js +16 -1
- package/dist/ui/elements/PcMenu/index.d.ts +48 -3
- package/dist/ui/elements/PcMenu/index.js +111 -19
- package/dist/ui/elements/PcNumberSlider/index.d.ts +137 -0
- package/dist/ui/elements/PcNumberSlider/index.js +247 -0
- package/dist/ui/elements/PcPane/index.d.ts +3 -1
- package/dist/ui/elements/PcPane/index.js +44 -7
- package/dist/ui/elements/PcPanel/index.d.ts +2 -2
- package/dist/ui/elements/PcPanel/index.js +8 -8
- package/dist/ui/elements/PcPanelBrushes/index.d.ts +2 -15
- package/dist/ui/elements/PcPanelBrushes/index.js +6 -43
- package/dist/ui/elements/PcPanelBrushes/style.js +1 -1
- package/dist/ui/elements/PcPopover/index.d.ts +39 -1
- package/dist/ui/elements/PcPopover/index.js +72 -4
- package/dist/ui/elements/PcThemePicker/index.d.ts +17 -15
- package/dist/ui/elements/PcThemePicker/index.js +22 -21
- package/dist/ui/elements/PcToolSettings/index.d.ts +48 -9
- package/dist/ui/elements/PcToolSettings/index.js +382 -318
- package/dist/ui/elements/PcToolSettings/style.js +1 -1
- package/dist/ui/elements/PcToolbar/index.d.ts +15 -0
- package/dist/ui/elements/PcToolbar/index.js +55 -14
- package/dist/ui/elements/PcToolbar/style.js +1 -1
- package/dist/ui/icons/images/icon-brush@2x.js +3 -0
- package/dist/ui/icons/images/icon-circle-mask@2x.js +3 -0
- package/dist/ui/icons/images/icon-clipboard@2x.js +3 -0
- package/dist/ui/icons/images/icon-cog@2x.js +3 -0
- package/dist/ui/icons/images/icon-cursor@2x.js +3 -0
- package/dist/ui/icons/images/icon-diagonal-tlbr-size@2x.js +3 -0
- package/dist/ui/icons/images/icon-diagonal-trbl-size@2x.js +3 -0
- package/dist/ui/icons/images/icon-eraser@2x.js +3 -0
- package/dist/ui/icons/images/icon-eyedropper@2x.js +3 -0
- package/dist/ui/icons/images/icon-flip-horizontal@2x.js +3 -0
- package/dist/ui/icons/images/icon-flip-vertical@2x.js +3 -0
- package/dist/ui/icons/images/icon-focus-pen@2x.js +3 -0
- package/dist/ui/icons/images/icon-freehand-mask@2x.js +3 -0
- package/dist/ui/icons/images/icon-hidden@2x.js +3 -0
- package/dist/ui/icons/images/icon-horizontal-size@2x.js +3 -0
- package/dist/ui/icons/images/icon-layers@2x.js +3 -0
- package/dist/ui/icons/images/icon-linked@2x.js +3 -0
- package/dist/ui/icons/images/icon-locked@2x.js +3 -0
- package/dist/ui/icons/images/icon-moon@2x.js +3 -0
- package/dist/ui/icons/images/icon-pan@2x.js +3 -0
- package/dist/ui/icons/images/icon-polygon-mask@2x.js +3 -0
- package/dist/ui/icons/images/icon-pressure@2x.js +3 -0
- package/dist/ui/icons/images/icon-randomise@2x.js +3 -0
- package/dist/ui/icons/images/icon-rectangle-mask@2x.js +3 -0
- package/dist/ui/icons/images/icon-redo@2x.js +3 -0
- package/dist/ui/icons/images/icon-rotate-90-left@2x.js +3 -0
- package/dist/ui/icons/images/icon-rotate-90-right@2x.js +3 -0
- package/dist/ui/icons/images/icon-rotate@2x.js +3 -0
- package/dist/ui/icons/images/icon-smoothing-bezier-cubic@2x.js +3 -0
- package/dist/ui/icons/images/icon-smoothing-bezier-quad@2x.js +3 -0
- package/dist/ui/icons/images/icon-smoothing-linear@2x.js +3 -0
- package/dist/ui/icons/images/icon-star@2x.js +3 -0
- package/dist/ui/icons/images/icon-sun@2x.js +3 -0
- package/dist/ui/icons/images/icon-tilt@2x.js +3 -0
- package/dist/ui/icons/images/icon-undo@2x.js +3 -0
- package/dist/ui/icons/images/icon-unlinked@2x.js +3 -0
- package/dist/ui/icons/images/icon-unlocked@2x.js +3 -0
- package/dist/ui/icons/images/icon-vertical-size@2x.js +3 -0
- package/dist/ui/icons/images/icon-visible@2x.js +3 -0
- package/dist/ui/icons/images/icon-zoom-in@2x.js +3 -0
- package/dist/ui/icons/images/icon-zoom-out@2x.js +3 -0
- package/dist/ui/icons/images/icon-zoom@2x.js +3 -0
- package/dist/ui/icons/index.d.ts +1 -1
- package/dist/ui/icons/index.js +84 -72
- package/dist/ui/index.d.ts +7 -2
- package/dist/ui/index.js +10 -4
- package/dist/ui/layout/index.d.ts +9 -1
- package/dist/ui/layout/index.js +11 -2
- package/dist/ui/tokens/index.d.ts +5 -4
- package/dist/ui/tokens/index.js +12 -7
- package/locales/en-GB.json +9 -2
- package/locales/en-US.json +9 -2
- package/locales/fr.json +9 -2
- package/locales/ja.json +9 -2
- package/locales/ko.json +9 -2
- package/locales/zh-Hans.json +9 -2
- package/locales/zh-Hant.json +9 -2
- package/package.json +11 -4
- package/dist/ui/icons/images/brush.js +0 -3
- package/dist/ui/icons/images/circle-mask.js +0 -3
- package/dist/ui/icons/images/clipboard.js +0 -3
- package/dist/ui/icons/images/cursor.js +0 -3
- package/dist/ui/icons/images/eraser.js +0 -3
- package/dist/ui/icons/images/eyedropper.js +0 -3
- package/dist/ui/icons/images/flip-horizontal.js +0 -3
- package/dist/ui/icons/images/flip-vertical.js +0 -3
- package/dist/ui/icons/images/focus-pen.js +0 -3
- package/dist/ui/icons/images/freehand-mask.js +0 -3
- package/dist/ui/icons/images/hidden.js +0 -3
- package/dist/ui/icons/images/layers.js +0 -3
- package/dist/ui/icons/images/linked.js +0 -3
- package/dist/ui/icons/images/locked.js +0 -3
- package/dist/ui/icons/images/moon.js +0 -3
- package/dist/ui/icons/images/pan.js +0 -3
- package/dist/ui/icons/images/polygon-mask.js +0 -3
- package/dist/ui/icons/images/pressure.js +0 -3
- package/dist/ui/icons/images/randomise.js +0 -3
- package/dist/ui/icons/images/rectangle-mask.js +0 -3
- package/dist/ui/icons/images/redo.js +0 -3
- package/dist/ui/icons/images/rotate-90-left.js +0 -3
- package/dist/ui/icons/images/rotate-90-right.js +0 -3
- package/dist/ui/icons/images/smoothing-bezier-cubic.js +0 -3
- package/dist/ui/icons/images/smoothing-bezier-quad.js +0 -3
- package/dist/ui/icons/images/smoothing-linear.js +0 -3
- package/dist/ui/icons/images/star.js +0 -3
- package/dist/ui/icons/images/sun.js +0 -3
- package/dist/ui/icons/images/tilt.js +0 -3
- package/dist/ui/icons/images/undo.js +0 -3
- package/dist/ui/icons/images/unlinked.js +0 -3
- package/dist/ui/icons/images/unlocked.js +0 -3
- package/dist/ui/icons/images/visible.js +0 -3
- package/dist/ui/icons/images/zoom-in.js +0 -3
- package/dist/ui/icons/images/zoom-out.js +0 -3
- package/dist/ui/icons/images/zoom.js +0 -3
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { PcElement, defineElement, emit } from "../../base/index.js";
|
|
2
|
+
import { PointerDrag } from "../../drag/index.js";
|
|
3
|
+
import { css, html, nothing } from "lit";
|
|
4
|
+
// src/ui/elements/PcNumberSlider/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* A number kept within `min` and `max` and rounded to a multiple of `step` (from `min`).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* fitNumber(300, 1, 256, 1); // 256
|
|
10
|
+
* fitNumber(12.4, 0, 100, 5); // 10
|
|
11
|
+
* fitNumber(45.678, -360, 360, 0.01); // 45.68
|
|
12
|
+
*/
|
|
13
|
+
var fitNumber = (value, min, max, step) => {
|
|
14
|
+
const decimals = String(step).split(".")[1]?.length ?? 0;
|
|
15
|
+
const stepped = Number((min + Math.round((value - min) / step) * step).toFixed(decimals));
|
|
16
|
+
return Math.min(max, Math.max(min, stepped));
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* A number shown as text that changes when pressed and dragged: right or up raises it, left or down lowers it, a step
|
|
20
|
+
* per pixel (or `drag-step`), within `min` and `max`. A press that barely moves (a tap or click) turns it into a field to type a value
|
|
21
|
+
* in: Enter or leaving the field keeps the value, Escape cancels.
|
|
22
|
+
*
|
|
23
|
+
* With keyboard focus, the arrow keys change it by `step`, Page Up and Page Down by `pageStep`, Home and End go to
|
|
24
|
+
* `min` and `max`, and Enter or F2 starts typing.
|
|
25
|
+
*
|
|
26
|
+
* Fires `pc-change` (detail: `{ value }`) when the value changes, after changing `value` itself. Bind a value that
|
|
27
|
+
* may be changed by others with `live()`, e.g. `.value=${live(brush.width)}`, so it's shown again if a listener keeps
|
|
28
|
+
* it the same.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* html`<pc-number-slider label="Opacity" min="0" max="100" unit="%" .value=${live(50)}
|
|
32
|
+
* @pc-change=${(e) => setOpacity(e.detail.value)}></pc-number-slider>`
|
|
33
|
+
*/
|
|
34
|
+
var PcNumberSlider = class extends PcElement {
|
|
35
|
+
static properties = {
|
|
36
|
+
...PcElement.properties,
|
|
37
|
+
value: { type: Number },
|
|
38
|
+
min: { type: Number },
|
|
39
|
+
max: { type: Number },
|
|
40
|
+
step: { type: Number },
|
|
41
|
+
pageStep: {
|
|
42
|
+
type: Number,
|
|
43
|
+
attribute: "page-step"
|
|
44
|
+
},
|
|
45
|
+
dragStep: {
|
|
46
|
+
type: Number,
|
|
47
|
+
attribute: "drag-step"
|
|
48
|
+
},
|
|
49
|
+
unit: { type: String },
|
|
50
|
+
text: { type: String },
|
|
51
|
+
label: { type: String },
|
|
52
|
+
disabled: {
|
|
53
|
+
type: Boolean,
|
|
54
|
+
reflect: true
|
|
55
|
+
},
|
|
56
|
+
editing: {
|
|
57
|
+
type: Boolean,
|
|
58
|
+
reflect: true
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
static styles = [PcElement.styles, css`
|
|
62
|
+
:host {
|
|
63
|
+
display: inline-flex;
|
|
64
|
+
min-width: 44px;
|
|
65
|
+
user-select: none;
|
|
66
|
+
-webkit-user-select: none;
|
|
67
|
+
}
|
|
68
|
+
[role="slider"],
|
|
69
|
+
input {
|
|
70
|
+
display: flex;
|
|
71
|
+
flex: 1;
|
|
72
|
+
align-items: center;
|
|
73
|
+
justify-content: center;
|
|
74
|
+
width: 100%;
|
|
75
|
+
min-width: 0;
|
|
76
|
+
min-height: 30px;
|
|
77
|
+
margin: 0;
|
|
78
|
+
padding: 0 var(--pc-space-2);
|
|
79
|
+
border: 1px solid var(--pc-border);
|
|
80
|
+
border-radius: var(--pc-radius-small);
|
|
81
|
+
background: var(--pc-surface);
|
|
82
|
+
color: var(--pc-text);
|
|
83
|
+
font-family: var(--pc-font);
|
|
84
|
+
font-size: var(--pc-font-size);
|
|
85
|
+
font-variant-numeric: tabular-nums;
|
|
86
|
+
text-align: center;
|
|
87
|
+
white-space: nowrap;
|
|
88
|
+
}
|
|
89
|
+
[role="slider"] {
|
|
90
|
+
cursor: ew-resize;
|
|
91
|
+
touch-action: none;
|
|
92
|
+
}
|
|
93
|
+
[role="slider"]:hover {
|
|
94
|
+
background: var(--pc-surface-hover);
|
|
95
|
+
}
|
|
96
|
+
[role="slider"]:focus-visible,
|
|
97
|
+
input:focus-visible {
|
|
98
|
+
outline: var(--pc-focus-width) solid var(--pc-focus);
|
|
99
|
+
outline-offset: -2px;
|
|
100
|
+
}
|
|
101
|
+
input {
|
|
102
|
+
user-select: text;
|
|
103
|
+
-webkit-user-select: text;
|
|
104
|
+
}
|
|
105
|
+
:host([disabled]) [role="slider"] {
|
|
106
|
+
opacity: 0.4;
|
|
107
|
+
cursor: default;
|
|
108
|
+
}
|
|
109
|
+
`];
|
|
110
|
+
/** Whether focus goes back to the slider when typing ends (it doesn't when the field lost focus) */
|
|
111
|
+
refocus = false;
|
|
112
|
+
drag = new PointerDrag((delta) => this.change(this.value + delta * (this.dragStep ?? this.step)), 4);
|
|
113
|
+
constructor() {
|
|
114
|
+
super();
|
|
115
|
+
this.value = 0;
|
|
116
|
+
this.min = 0;
|
|
117
|
+
this.max = 100;
|
|
118
|
+
this.step = 1;
|
|
119
|
+
this.unit = "";
|
|
120
|
+
this.text = "";
|
|
121
|
+
this.label = "";
|
|
122
|
+
this.disabled = false;
|
|
123
|
+
this.editing = false;
|
|
124
|
+
}
|
|
125
|
+
/** The value as shown: `text`, or the value and unit */
|
|
126
|
+
get displayText() {
|
|
127
|
+
return this.text || `${this.value}${this.unit}`;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Set the value (fitted within `min` and `max`, to a multiple of `step`) and tell listeners if it changed.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* slider.change(40); // fires pc-change with { value: 40 }
|
|
134
|
+
*/
|
|
135
|
+
change(value) {
|
|
136
|
+
const next = fitNumber(value, this.min, this.max, this.step);
|
|
137
|
+
if (next === this.value) return;
|
|
138
|
+
this.value = next;
|
|
139
|
+
emit(this, "pc-change", { value: next });
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Turn into a field to type a value in, with its text selected.
|
|
143
|
+
*/
|
|
144
|
+
startEditing() {
|
|
145
|
+
if (this.disabled) return;
|
|
146
|
+
this.refocus = true;
|
|
147
|
+
this.editing = true;
|
|
148
|
+
this.performUpdate();
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Stop typing, keeping the typed value (if it's a number) unless cancelled.
|
|
152
|
+
*/
|
|
153
|
+
stopEditing(keep) {
|
|
154
|
+
const typed = this.renderRoot.querySelector("input").value.trim();
|
|
155
|
+
this.editing = false;
|
|
156
|
+
if (keep && typed !== "" && Number.isFinite(Number(typed))) this.change(Number(typed));
|
|
157
|
+
}
|
|
158
|
+
/** Start a press, unless disabled */
|
|
159
|
+
onPointerDown(event) {
|
|
160
|
+
if (!this.disabled) this.drag.start(event);
|
|
161
|
+
}
|
|
162
|
+
/** End a press: one that didn't become a drag starts typing */
|
|
163
|
+
onPointerUp() {
|
|
164
|
+
if (this.disabled) return;
|
|
165
|
+
if (!this.drag.end()) this.startEditing();
|
|
166
|
+
}
|
|
167
|
+
/** Change the value with the arrow keys, Page Up and Page Down, Home and End, or start typing (Enter, F2) */
|
|
168
|
+
onSliderKeyDown(event) {
|
|
169
|
+
if (this.disabled) return;
|
|
170
|
+
const page = this.pageStep ?? this.step * 10;
|
|
171
|
+
const action = {
|
|
172
|
+
ArrowUp: () => this.change(this.value + this.step),
|
|
173
|
+
ArrowRight: () => this.change(this.value + this.step),
|
|
174
|
+
ArrowDown: () => this.change(this.value - this.step),
|
|
175
|
+
ArrowLeft: () => this.change(this.value - this.step),
|
|
176
|
+
PageUp: () => this.change(this.value + page),
|
|
177
|
+
PageDown: () => this.change(this.value - page),
|
|
178
|
+
Home: () => this.change(this.min),
|
|
179
|
+
End: () => this.change(this.max),
|
|
180
|
+
Enter: () => this.startEditing(),
|
|
181
|
+
F2: () => this.startEditing()
|
|
182
|
+
}[event.key];
|
|
183
|
+
if (!action) return;
|
|
184
|
+
event.preventDefault();
|
|
185
|
+
action();
|
|
186
|
+
}
|
|
187
|
+
/** Keep the typed value with Enter, or cancel with Escape (neither reaches the rest of the page) */
|
|
188
|
+
onInputKeyDown(event) {
|
|
189
|
+
if (event.key !== "Enter" && event.key !== "Escape") return;
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
event.stopPropagation();
|
|
192
|
+
this.stopEditing(event.key === "Enter");
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Keep the typed value when the field loses focus, leaving focus where it went. Ignored once typing has ended (some
|
|
196
|
+
* browsers blur the field as it's removed).
|
|
197
|
+
*/
|
|
198
|
+
onInputBlur() {
|
|
199
|
+
if (!this.editing) return;
|
|
200
|
+
this.refocus = false;
|
|
201
|
+
this.stopEditing(true);
|
|
202
|
+
}
|
|
203
|
+
willUpdate(changed) {
|
|
204
|
+
if (changed.has("disabled") && this.disabled) this.editing = false;
|
|
205
|
+
}
|
|
206
|
+
updated(changed) {
|
|
207
|
+
if (!changed.has("editing")) return;
|
|
208
|
+
if (this.editing) {
|
|
209
|
+
const input = this.renderRoot.querySelector("input");
|
|
210
|
+
input.focus();
|
|
211
|
+
input.select();
|
|
212
|
+
} else if (changed.get("editing") && this.refocus) this.renderRoot.querySelector("[role=slider]").focus();
|
|
213
|
+
}
|
|
214
|
+
render() {
|
|
215
|
+
const text = this.displayText;
|
|
216
|
+
if (this.editing) return html`<input
|
|
217
|
+
part="field"
|
|
218
|
+
type="text"
|
|
219
|
+
inputmode="decimal"
|
|
220
|
+
aria-label=${this.label || nothing}
|
|
221
|
+
.value=${String(this.value)}
|
|
222
|
+
@keydown=${this.onInputKeyDown}
|
|
223
|
+
@blur=${this.onInputBlur}
|
|
224
|
+
/>`;
|
|
225
|
+
return html`<div
|
|
226
|
+
part="control"
|
|
227
|
+
role="slider"
|
|
228
|
+
tabindex=${this.disabled ? -1 : 0}
|
|
229
|
+
aria-label=${this.label || nothing}
|
|
230
|
+
aria-valuemin=${this.min}
|
|
231
|
+
aria-valuemax=${this.max}
|
|
232
|
+
aria-valuenow=${this.value}
|
|
233
|
+
aria-valuetext=${text}
|
|
234
|
+
aria-disabled=${this.disabled ? "true" : nothing}
|
|
235
|
+
title=${this.t("paintCanvas.numberSlider.hint")}
|
|
236
|
+
@pointerdown=${this.onPointerDown}
|
|
237
|
+
@pointermove=${this.drag.move}
|
|
238
|
+
@pointerup=${this.onPointerUp}
|
|
239
|
+
@pointercancel=${this.drag.end}
|
|
240
|
+
@keydown=${this.onSliderKeyDown}
|
|
241
|
+
>
|
|
242
|
+
${text}
|
|
243
|
+
</div>`;
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
defineElement("pc-number-slider", PcNumberSlider);
|
|
247
|
+
export { PcNumberSlider, fitNumber };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { nothing, type PropertyValues, type TemplateResult } from "lit";
|
|
2
2
|
import { PcElement } from "../../base";
|
|
3
3
|
import { PcPanel } from "../PcPanel";
|
|
4
|
-
import type
|
|
4
|
+
import { type SideMode } from "../../layout";
|
|
5
5
|
/** Which way a pane's start, middle and end run */
|
|
6
6
|
export type PaneOrientation = "vertical" | "horizontal";
|
|
7
7
|
/** Which edge of the layout a pane is on: panels opened from its rail, and its floating box, go the other way */
|
|
@@ -20,6 +20,8 @@ export declare const PANE_COLLAPSE_EVENT = "pc-collapse";
|
|
|
20
20
|
* button again closes it, and focus goes back to the button.
|
|
21
21
|
* - `floating`: the pane floats over the canvas as a box that collapses to a button (`collapsed`, named with its
|
|
22
22
|
* `label`), firing `pc-collapse` when it's shown or collapsed.
|
|
23
|
+
* - `overlay`: a rail over the canvas, without a background: each button has its own, and presses between them reach
|
|
24
|
+
* the canvas. Its panels stay solid.
|
|
23
25
|
*
|
|
24
26
|
* Panes made for one purpose extend it and put their own content in its regions (see `renderStart`, `renderMiddle`
|
|
25
27
|
* and `renderEnd`), e.g. `<pc-toolbar>`.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { PcElement, defineElement, emit } from "../../base/index.js";
|
|
2
|
+
import { markDismissingPress } from "../../dismiss/index.js";
|
|
2
3
|
import { PcPanel } from "../PcPanel/index.js";
|
|
4
|
+
import { showsRail } from "../../layout/index.js";
|
|
3
5
|
import { css, html, nothing } from "lit";
|
|
4
6
|
// src/ui/elements/PcPane/index.ts
|
|
5
7
|
/** Event fired when a floating pane is shown or collapsed (detail: `{ collapsed }`) */
|
|
@@ -18,6 +20,8 @@ var FOCUSABLE = "button, [href], input, select, textarea, [tabindex]:not([tabind
|
|
|
18
20
|
* button again closes it, and focus goes back to the button.
|
|
19
21
|
* - `floating`: the pane floats over the canvas as a box that collapses to a button (`collapsed`, named with its
|
|
20
22
|
* `label`), firing `pc-collapse` when it's shown or collapsed.
|
|
23
|
+
* - `overlay`: a rail over the canvas, without a background: each button has its own, and presses between them reach
|
|
24
|
+
* the canvas. Its panels stay solid.
|
|
21
25
|
*
|
|
22
26
|
* Panes made for one purpose extend it and put their own content in its regions (see `renderStart`, `renderMiddle`
|
|
23
27
|
* and `renderEnd`), e.g. `<pc-toolbar>`.
|
|
@@ -95,10 +99,16 @@ var PcPane = class extends PcElement {
|
|
|
95
99
|
border-inline: 1px solid var(--pc-border);
|
|
96
100
|
background: var(--pc-bar);
|
|
97
101
|
}
|
|
102
|
+
/* The same size as the toolbars' buttons (borders included) */
|
|
98
103
|
.rail button {
|
|
99
104
|
position: relative;
|
|
100
105
|
display: inline-flex;
|
|
101
|
-
|
|
106
|
+
align-items: center;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
box-sizing: border-box;
|
|
109
|
+
width: var(--pc-side-button-size);
|
|
110
|
+
height: var(--pc-side-button-size);
|
|
111
|
+
padding: 0;
|
|
102
112
|
border: 1px solid transparent;
|
|
103
113
|
border-radius: var(--pc-radius-small);
|
|
104
114
|
background: transparent;
|
|
@@ -115,8 +125,8 @@ var PcPane = class extends PcElement {
|
|
|
115
125
|
outline: var(--pc-focus-width) solid var(--pc-focus);
|
|
116
126
|
}
|
|
117
127
|
.rail img {
|
|
118
|
-
width: var(--pc-icon-size);
|
|
119
|
-
height: var(--pc-icon-size);
|
|
128
|
+
width: var(--pc-side-icon-size);
|
|
129
|
+
height: var(--pc-side-icon-size);
|
|
120
130
|
filter: var(--pc-icon-filter);
|
|
121
131
|
}
|
|
122
132
|
.rail .badge {
|
|
@@ -130,6 +140,31 @@ var PcPane = class extends PcElement {
|
|
|
130
140
|
background: var(--pc-red);
|
|
131
141
|
}
|
|
132
142
|
|
|
143
|
+
/* Overlay: the rail over the canvas without a background, so only its buttons (each with its own) take presses */
|
|
144
|
+
:host([mode="overlay"]) {
|
|
145
|
+
pointer-events: none;
|
|
146
|
+
}
|
|
147
|
+
:host([mode="overlay"]) .rail {
|
|
148
|
+
border-inline: 0;
|
|
149
|
+
background: transparent;
|
|
150
|
+
}
|
|
151
|
+
:host([mode="overlay"]) .rail button,
|
|
152
|
+
:host([mode="overlay"]) ::slotted(*) {
|
|
153
|
+
pointer-events: auto;
|
|
154
|
+
}
|
|
155
|
+
:host([mode="overlay"]) .rail button {
|
|
156
|
+
border-color: var(--pc-border);
|
|
157
|
+
background: var(--pc-surface-raised);
|
|
158
|
+
box-shadow: var(--pc-shadow);
|
|
159
|
+
}
|
|
160
|
+
:host([mode="overlay"]) .rail button:hover {
|
|
161
|
+
background: var(--pc-surface-hover);
|
|
162
|
+
}
|
|
163
|
+
:host([mode="overlay"]) .rail button[aria-expanded="true"] {
|
|
164
|
+
border-color: var(--pc-accent);
|
|
165
|
+
background: var(--pc-accent);
|
|
166
|
+
}
|
|
167
|
+
|
|
133
168
|
/* Floating: the pane floats over the canvas as a box, and collapses to a button */
|
|
134
169
|
:host([mode="floating"]) {
|
|
135
170
|
position: absolute;
|
|
@@ -176,7 +211,9 @@ var PcPane = class extends PcElement {
|
|
|
176
211
|
const panel = this.openPanel;
|
|
177
212
|
if (!panel) return;
|
|
178
213
|
const path = event.composedPath();
|
|
179
|
-
if (
|
|
214
|
+
if (path.includes(panel) || this.opener && path.includes(this.opener)) return;
|
|
215
|
+
markDismissingPress(event);
|
|
216
|
+
this.closePanel(false);
|
|
180
217
|
};
|
|
181
218
|
onKeyDown = (event) => {
|
|
182
219
|
if (event.key !== "Escape" || !this.openPanel) return;
|
|
@@ -258,7 +295,7 @@ var PcPane = class extends PcElement {
|
|
|
258
295
|
}
|
|
259
296
|
/** Show the panels for the mode: hidden behind the rail (except the open one, beside the pane) or as they are */
|
|
260
297
|
syncPanels() {
|
|
261
|
-
const rail = this.mode
|
|
298
|
+
const rail = showsRail(this.mode);
|
|
262
299
|
for (const panel of this.panels) {
|
|
263
300
|
panel.toggleAttribute("data-pc-rail", rail);
|
|
264
301
|
if (rail && panel === this.openPanel) panel.setAttribute("data-pc-open", this.edge);
|
|
@@ -267,7 +304,7 @@ var PcPane = class extends PcElement {
|
|
|
267
304
|
}
|
|
268
305
|
updated(changed) {
|
|
269
306
|
if (!changed.has("mode") && !changed.has("edge")) return;
|
|
270
|
-
if (this.mode
|
|
307
|
+
if (!showsRail(this.mode)) this.closePanel(false);
|
|
271
308
|
this.syncPanels();
|
|
272
309
|
}
|
|
273
310
|
/** Content of its own at its start, before what's slotted there */
|
|
@@ -284,7 +321,7 @@ var PcPane = class extends PcElement {
|
|
|
284
321
|
}
|
|
285
322
|
/** The rail: a button per panel */
|
|
286
323
|
renderRail() {
|
|
287
|
-
if (this.mode
|
|
324
|
+
if (!showsRail(this.mode) || this.panels.length === 0) return nothing;
|
|
288
325
|
return html`<div
|
|
289
326
|
class="rail"
|
|
290
327
|
part="rail"
|
|
@@ -6,8 +6,8 @@ import { PcElement } from "../../base";
|
|
|
6
6
|
* for screen readers.
|
|
7
7
|
*
|
|
8
8
|
* Its `icon`, `label` and `badge` are what a pane shows for it when the pane narrows to a rail of buttons; the badge is
|
|
9
|
-
* a dot meaning something new (e.g. unread messages). It's 290px wide (`--pc-panel-width`) and
|
|
10
|
-
* it has.
|
|
9
|
+
* a dot meaning something new (e.g. unread messages). It's 290px wide (`--pc-panel-width`), and in every layout it's
|
|
10
|
+
* never wider than 290px (`--pc-panel-max-width`) or the space it has.
|
|
11
11
|
*
|
|
12
12
|
* Panels made for one purpose extend `PcPanel`, so they share its look: e.g. `<pc-panel-layers>`,
|
|
13
13
|
* `<pc-panel-brushes>` and `<pc-panel-colours>`. They put their own content in the body (see `renderBody`), and give
|
|
@@ -7,8 +7,8 @@ import { css, html, nothing } from "lit";
|
|
|
7
7
|
* for screen readers.
|
|
8
8
|
*
|
|
9
9
|
* Its `icon`, `label` and `badge` are what a pane shows for it when the pane narrows to a rail of buttons; the badge is
|
|
10
|
-
* a dot meaning something new (e.g. unread messages). It's 290px wide (`--pc-panel-width`) and
|
|
11
|
-
* it has.
|
|
10
|
+
* a dot meaning something new (e.g. unread messages). It's 290px wide (`--pc-panel-width`), and in every layout it's
|
|
11
|
+
* never wider than 290px (`--pc-panel-max-width`) or the space it has.
|
|
12
12
|
*
|
|
13
13
|
* Panels made for one purpose extend `PcPanel`, so they share its look: e.g. `<pc-panel-layers>`,
|
|
14
14
|
* `<pc-panel-brushes>` and `<pc-panel-colours>`. They put their own content in the body (see `renderBody`), and give
|
|
@@ -33,7 +33,7 @@ var PcPanel = class extends PcElement {
|
|
|
33
33
|
box-sizing: border-box;
|
|
34
34
|
width: var(--pc-panel-width, var(--pc-panel-default-width, 290px));
|
|
35
35
|
min-width: 0;
|
|
36
|
-
max-width: 100
|
|
36
|
+
max-width: min(100%, var(--pc-panel-max-width, 290px));
|
|
37
37
|
min-height: 0;
|
|
38
38
|
max-height: 100%;
|
|
39
39
|
flex-direction: column;
|
|
@@ -44,7 +44,8 @@ var PcPanel = class extends PcElement {
|
|
|
44
44
|
font-family: var(--pc-font);
|
|
45
45
|
font-size: var(--pc-font-size);
|
|
46
46
|
}
|
|
47
|
-
/* In a pane's rail (set by the pane): hidden until opened from its button, then over the canvas beside the pane
|
|
47
|
+
/* In a pane's rail (set by the pane): hidden until opened from its button, then over the canvas beside the pane,
|
|
48
|
+
as tall as its content needs (at most 90% of the window's height, and never taller than the pane) */
|
|
48
49
|
:host([data-pc-rail]:not([data-pc-open])) {
|
|
49
50
|
display: none;
|
|
50
51
|
}
|
|
@@ -52,10 +53,9 @@ var PcPanel = class extends PcElement {
|
|
|
52
53
|
position: absolute;
|
|
53
54
|
z-index: 5;
|
|
54
55
|
top: 0;
|
|
55
|
-
|
|
56
|
-
width: var(--pc-
|
|
57
|
-
max-
|
|
58
|
-
max-height: none;
|
|
56
|
+
/* Its usual width, kept within the window (the pane it opens from is narrower than it) */
|
|
57
|
+
max-width: min(var(--pc-panel-max-width, 290px), 85vw);
|
|
58
|
+
max-height: min(90vh, 100%);
|
|
59
59
|
}
|
|
60
60
|
:host([data-pc-open="left"]) {
|
|
61
61
|
left: 100%;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { nothing } from "lit";
|
|
2
2
|
import { PcPanel } from "../PcPanel";
|
|
3
|
+
import "../PcBrushSize";
|
|
3
4
|
import type PaintCanvas from "../../../lib/classes/PaintCanvas";
|
|
4
5
|
import type BrushSettings from "../../../lib/classes/BrushSettings";
|
|
5
6
|
import type { BrushConfig } from "../../../lib/brushes/types";
|
|
@@ -31,7 +32,7 @@ export declare const previewSizes: (presets: BrushConfig[]) => Map<string, {
|
|
|
31
32
|
* tile showing its shape at its size relative to the rest of its family, five to a row. Picking a preset closes the
|
|
32
33
|
* menu; holding Alt/Option shows an "X" over custom presets, and clicking one asks before deleting it.
|
|
33
34
|
*
|
|
34
|
-
* Dragging the size control up or right makes the brush bigger; down or left makes it smaller.
|
|
35
|
+
* Dragging the size control (`pc-brush-size`) up or right makes the brush bigger; down or left makes it smaller.
|
|
35
36
|
*
|
|
36
37
|
* Fires `pc-new-preset` (detail: "brush" or "eraser") for "New preset", and `pc-toast` (detail: the message) after
|
|
37
38
|
* importing, exporting or deleting presets, or when that fails.
|
|
@@ -75,8 +76,6 @@ export declare class PcPanelBrushes extends PcPanel {
|
|
|
75
76
|
confirm: ConfirmFn;
|
|
76
77
|
/** Saves exported presets (replaceable for tests) */
|
|
77
78
|
saveFile: (blob: Blob, name: string) => Promise<SaveMethod | undefined>;
|
|
78
|
-
/** Last pointer position while dragging the size control */
|
|
79
|
-
private dragPoint;
|
|
80
79
|
private changes;
|
|
81
80
|
private readonly onKey;
|
|
82
81
|
private readonly onBlur;
|
|
@@ -115,18 +114,6 @@ export declare class PcPanelBrushes extends PcPanel {
|
|
|
115
114
|
* Select a preset and close the menu.
|
|
116
115
|
*/
|
|
117
116
|
selectPreset(id: string): void;
|
|
118
|
-
/**
|
|
119
|
-
* Start dragging the size control.
|
|
120
|
-
*/
|
|
121
|
-
private onPointerDown;
|
|
122
|
-
/**
|
|
123
|
-
* Resize while dragging: right and up are positive, left and down are negative.
|
|
124
|
-
*/
|
|
125
|
-
private onPointerMove;
|
|
126
|
-
/**
|
|
127
|
-
* Stop dragging the size control.
|
|
128
|
-
*/
|
|
129
|
-
private onPointerUp;
|
|
130
117
|
/** Render a preset's tile */
|
|
131
118
|
private renderTile;
|
|
132
119
|
protected get defaultIcon(): string;
|
|
@@ -3,6 +3,7 @@ import { BRUSH_PRESET_FILE_FORMAT } from "../../../lib/presets/schema.js";
|
|
|
3
3
|
import { NO_TEXT_SELECTION_CSS, PILLS_CSS, WINDOWS_CSS } from "../../styles/index.js";
|
|
4
4
|
import { defineElement } from "../../base/index.js";
|
|
5
5
|
import { PcPanel } from "../PcPanel/index.js";
|
|
6
|
+
import "../PcBrushSize/index.js";
|
|
6
7
|
import ChangeController from "../../ChangeController/index.js";
|
|
7
8
|
import { groupPresetsByAuthor } from "../../../lib/brushes/authors/index.js";
|
|
8
9
|
import "../../../lib/presets/index.js";
|
|
@@ -55,7 +56,7 @@ var previewSizes = (presets) => {
|
|
|
55
56
|
* tile showing its shape at its size relative to the rest of its family, five to a row. Picking a preset closes the
|
|
56
57
|
* menu; holding Alt/Option shows an "X" over custom presets, and clicking one asks before deleting it.
|
|
57
58
|
*
|
|
58
|
-
* Dragging the size control up or right makes the brush bigger; down or left makes it smaller.
|
|
59
|
+
* Dragging the size control (`pc-brush-size`) up or right makes the brush bigger; down or left makes it smaller.
|
|
59
60
|
*
|
|
60
61
|
* Fires `pc-new-preset` (detail: "brush" or "eraser") for "New preset", and `pc-toast` (detail: the message) after
|
|
61
62
|
* importing, exporting or deleting presets, or when that fails.
|
|
@@ -79,8 +80,6 @@ var PcPanelBrushes = class extends PcPanel {
|
|
|
79
80
|
confirm = (message) => window.confirm(message);
|
|
80
81
|
/** Saves exported presets (replaceable for tests) */
|
|
81
82
|
saveFile = (blob, name) => saveFile(blob, name, void 0, JSON_FILE_TYPE);
|
|
82
|
-
/** Last pointer position while dragging the size control */
|
|
83
|
-
dragPoint = null;
|
|
84
83
|
changes = new ChangeController(this, () => [this.app, this.settings]);
|
|
85
84
|
onKey = (event) => {
|
|
86
85
|
if (event.key === "Alt") this.toggleAttribute("deleting", event.type === "keydown");
|
|
@@ -215,34 +214,6 @@ var PcPanelBrushes = class extends PcPanel {
|
|
|
215
214
|
this.settings?.select(id);
|
|
216
215
|
this.app?.closePanel();
|
|
217
216
|
}
|
|
218
|
-
/**
|
|
219
|
-
* Start dragging the size control.
|
|
220
|
-
*/
|
|
221
|
-
onPointerDown(event) {
|
|
222
|
-
this.dragPoint = {
|
|
223
|
-
x: event.clientX,
|
|
224
|
-
y: event.clientY
|
|
225
|
-
};
|
|
226
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Resize while dragging: right and up are positive, left and down are negative.
|
|
230
|
-
*/
|
|
231
|
-
onPointerMove(event) {
|
|
232
|
-
if (!this.dragPoint || !this.settings) return;
|
|
233
|
-
const delta = event.clientX - this.dragPoint.x + (this.dragPoint.y - event.clientY);
|
|
234
|
-
this.dragPoint = {
|
|
235
|
-
x: event.clientX,
|
|
236
|
-
y: event.clientY
|
|
237
|
-
};
|
|
238
|
-
if (delta !== 0) this.settings.resize(delta);
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Stop dragging the size control.
|
|
242
|
-
*/
|
|
243
|
-
onPointerUp() {
|
|
244
|
-
this.dragPoint = null;
|
|
245
|
-
}
|
|
246
217
|
/** Render a preset's tile */
|
|
247
218
|
renderTile(settings, preset, sizes) {
|
|
248
219
|
const size = sizes.get(preset.id);
|
|
@@ -296,19 +267,11 @@ var PcPanelBrushes = class extends PcPanel {
|
|
|
296
267
|
style=${styleMap({ maskImage: typeof preset.image === "string" ? `url("${preset.image}")` : void 0 })}
|
|
297
268
|
></span>
|
|
298
269
|
<span class="name">${preset.name ?? preset.id}</span>
|
|
299
|
-
<
|
|
270
|
+
<pc-brush-size
|
|
300
271
|
class="size"
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
title=${this.t("paintCanvas.brushMenu.dragToResize")}
|
|
305
|
-
@pointerdown=${this.onPointerDown}
|
|
306
|
-
@pointermove=${this.onPointerMove}
|
|
307
|
-
@pointerup=${this.onPointerUp}
|
|
308
|
-
@pointercancel=${this.onPointerUp}
|
|
309
|
-
>
|
|
310
|
-
${settings.width === settings.height ? settings.width : `${settings.width} × ${settings.height}`}
|
|
311
|
-
</div>
|
|
272
|
+
.settings=${settings}
|
|
273
|
+
label=${this.t("paintCanvas.brushMenu.size", { tool: title })}
|
|
274
|
+
></pc-brush-size>
|
|
312
275
|
</div>
|
|
313
276
|
<div
|
|
314
277
|
class="presets"
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// src/ui/elements/PcPanelBrushes/style.css?inline
|
|
2
|
-
var style_default = "/* Narrower than other panels by default (set --pc-panel-width to change it) */\n:host {\n --pc-panel-default-width: 240px;\n}\n/* The current preset on one row: its shape, name and size */\n.current {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 44px;\n padding: 4px 8px;\n border: 1px solid var(--pc-border);\n background: var(--pc-surface);\n}\n.current-shape {\n flex: none;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n background: var(--pc-text);\n}\n.current-shape.image {\n border-radius: 0;\n mask-repeat: no-repeat;\n mask-size: contain;\n mask-position: center;\n}\n.name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.size {\n flex: none;\n align-self: stretch;\n
|
|
2
|
+
var style_default = "/* Narrower than other panels by default (set --pc-panel-width to change it) */\n:host {\n --pc-panel-default-width: 240px;\n}\n/* The current preset on one row: its shape, name and size */\n.current {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 44px;\n padding: 4px 8px;\n border: 1px solid var(--pc-border);\n background: var(--pc-surface);\n}\n.current-shape {\n flex: none;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n background: var(--pc-text);\n}\n.current-shape.image {\n border-radius: 0;\n mask-repeat: no-repeat;\n mask-size: contain;\n mask-position: center;\n}\n.name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.size {\n flex: none;\n align-self: stretch;\n margin: -4px -8px -4px 0;\n border-left: 1px solid var(--pc-border);\n}\n/* The presets scroll, at most 400px tall, or less so the whole menu fits under the settings bar in a shorter window */\n.presets {\n flex: 1 1 auto;\n min-height: 0;\n max-height: min(400px, calc(100vh - 180px));\n overflow-y: auto;\n}\nh3 {\n margin: 4px 0;\n font-size: 14px;\n}\nul {\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n align-content: start;\n margin: 0;\n padding: 0;\n list-style: none;\n border: 1px solid var(--pc-border);\n background: var(--pc-bar);\n}\n:host([deleting]) li button.custom {\n cursor: var(--pc-delete-cursor);\n}\n/* Create, Import and Export side by side */\n.actions {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 6px;\n}\n.actions button.pill {\n padding: 4px 8px;\n}\n.visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n}\nli button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n aspect-ratio: 1;\n padding: 0;\n border: none;\n border-right: 1px solid var(--pc-border);\n border-bottom: 1px solid var(--pc-border);\n background: var(--pc-bar);\n cursor: pointer;\n}\nli button:hover {\n background: var(--pc-surface-hover);\n}\nli button[aria-pressed=\"true\"] {\n background: var(--pc-surface-active);\n}\n.shape {\n background: var(--pc-text);\n border-radius: 50%;\n}\n.shape.image {\n border-radius: 0;\n mask-repeat: no-repeat;\n mask-size: 100% 100%;\n}\n";
|
|
3
3
|
export { style_default as default };
|
|
@@ -1,8 +1,30 @@
|
|
|
1
1
|
import { type PropertyValues } from "lit";
|
|
2
2
|
import { PcElement } from "../../base";
|
|
3
|
+
/** Height of a popover's arrow (pixels) */
|
|
4
|
+
export declare const POPOVER_ARROW_SIZE = 8;
|
|
5
|
+
/** Space kept between a placed popover and the window's edges (pixels) */
|
|
6
|
+
export declare const POPOVER_MARGIN = 8;
|
|
7
|
+
/**
|
|
8
|
+
* Where a popover goes under its anchor: centred below it (leaving room for the arrow), moved sideways as far as needed
|
|
9
|
+
* to stay in the window, with its arrow still pointing at the anchor's centre (`arrowX`, from the popover's left).
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* popoverBelow({ left: 100, bottom: 40, width: 40 }, 200, 1000); // { left: 20, top: 48, arrowX: 100 }
|
|
13
|
+
* popoverBelow({ left: 0, bottom: 40, width: 40 }, 200, 1000); // { left: 8, top: 48, arrowX: 12 }
|
|
14
|
+
*/
|
|
15
|
+
export declare const popoverBelow: (anchor: {
|
|
16
|
+
left: number;
|
|
17
|
+
bottom: number;
|
|
18
|
+
width: number;
|
|
19
|
+
}, popoverWidth: number, viewportWidth: number, margin?: number) => {
|
|
20
|
+
left: number;
|
|
21
|
+
top: number;
|
|
22
|
+
arrowX: number;
|
|
23
|
+
};
|
|
3
24
|
/**
|
|
4
25
|
* 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)
|
|
26
|
+
* next to the button that opens it), or `placeBelow` puts it under its `anchor`. With `arrow`, an arrow on its top edge
|
|
27
|
+
* points up at the anchor (at `--pc-popover-arrow-x` from its left, the middle by default). It isn't modal: Escape, or a press outside it and outside its `anchor`, fires
|
|
6
28
|
* `pc-close`, and the implementer sets `open` to false in response. Focus moves into it when it opens.
|
|
7
29
|
*
|
|
8
30
|
* @example
|
|
@@ -20,6 +42,10 @@ export declare class PcPopover extends PcElement {
|
|
|
20
42
|
anchor: {
|
|
21
43
|
attribute: boolean;
|
|
22
44
|
};
|
|
45
|
+
arrow: {
|
|
46
|
+
type: BooleanConstructor;
|
|
47
|
+
reflect: boolean;
|
|
48
|
+
};
|
|
23
49
|
translations: {
|
|
24
50
|
attribute: boolean;
|
|
25
51
|
};
|
|
@@ -37,8 +63,20 @@ export declare class PcPopover extends PcElement {
|
|
|
37
63
|
label: string;
|
|
38
64
|
/** The element that opens it (pressing it doesn't count as pressing outside) */
|
|
39
65
|
anchor?: Element;
|
|
66
|
+
/** Whether an arrow on its top edge points up at the anchor */
|
|
67
|
+
arrow: boolean;
|
|
40
68
|
private readonly onPointerDown;
|
|
41
69
|
constructor();
|
|
70
|
+
/**
|
|
71
|
+
* Put the popover under its anchor, in the window (see `popoverBelow`), with its arrow pointing at the anchor. Call it
|
|
72
|
+
* once open, so it can be measured.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* popover.open = true;
|
|
76
|
+
* await popover.updateComplete;
|
|
77
|
+
* popover.placeBelow();
|
|
78
|
+
*/
|
|
79
|
+
placeBelow(): void;
|
|
42
80
|
connectedCallback(): void;
|
|
43
81
|
disconnectedCallback(): void;
|
|
44
82
|
updated(changed: PropertyValues<this>): void;
|