@threadlabs/looma 0.35.1 → 0.36.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/components/ui-button/ui-button.html +11 -4
- package/components/ui-color-picker/ui-color-picker.html +1 -1
- package/components/ui-combobox/ui-combobox.html +1 -1
- package/components/ui-curve-editor/ui-curve-editor.html +1 -0
- package/components/ui-curve-editor/ui-curve-editor.js +15 -6
- package/components/ui-input/ui-input.html +4 -1
- package/components/ui-light-editor/ui-light-editor.html +143 -19
- package/components/ui-light-editor/ui-light-editor.js +26 -9
- package/components/ui-select/ui-select.html +10 -6
- package/dist/index.js +1 -1
- package/docs/README.md +33 -7
- package/docs/card.js +1 -0
- package/docs/catalog.json +37 -3
- package/docs/customizer-render.mjs +26 -8
- package/docs/customizer.js +122 -18
- package/docs/fonts.mjs +45 -0
- package/docs/index.d.ts +2 -2
- package/docs/palette.mjs +67 -0
- package/docs/site.mjs +1 -1
- package/docs/theme-session.mjs +28 -9
- package/docs/theme.mjs +67 -27
- package/docs/value-editors.mjs +6 -4
- package/package.json +2 -2
- package/styles/ui-button.css +11 -4
- package/styles/ui-color-picker.css +1 -1
- package/styles/ui-combobox.css +2 -2
- package/styles/ui-input.css +4 -1
- package/styles/ui-light-editor.css +111 -16
- package/styles/ui-select.css +10 -6
- package/theme-system.css +14 -2
- package/tokens.css +10 -0
- package/vanilla/UiCurveEditor.d.ts +1 -0
- package/vanilla/UiCurveEditor.js +1 -1
- package/vanilla/UiLightEditor.d.ts +1 -0
- package/vanilla/UiLightEditor.js +2 -2
- package/vue/UiButton.vue +4 -2
- package/vue/UiColorPicker.vue +1 -1
- package/vue/UiCombobox.vue +2 -2
- package/vue/UiCurveEditor.d.ts +6 -0
- package/vue/UiCurveEditor.vue +2 -0
- package/vue/UiInput.vue +4 -1
- package/vue/UiLightEditor.d.ts +8 -0
- package/vue/UiLightEditor.vue +22 -3
- package/vue/UiSelect.vue +1 -1
- package/vue/chunks/UiButton.js +1 -1
- package/vue/chunks/UiColorPicker.js +1 -1
- package/vue/chunks/UiCombobox.js +1 -1
- package/vue/chunks/UiCurveEditor.js +5 -3
- package/vue/chunks/UiInput.js +1 -1
- package/vue/chunks/UiLightEditor.js +16 -6
- package/vue/chunks/UiSelect.js +1 -1
- package/vue/components.css +41 -14
|
@@ -249,7 +249,9 @@
|
|
|
249
249
|
line-height: var(--ui-line-height-tight);
|
|
250
250
|
padding: var(--ui-control-inset-block-md, var(--ui-space-2)) var(--ui-action-inset-md, var(--ui-space-3)) !important;
|
|
251
251
|
background-image: var(--ui-surface-highlight, none);
|
|
252
|
-
box-shadow:
|
|
252
|
+
box-shadow:
|
|
253
|
+
var(--ui-button-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
|
|
254
|
+
var(--_tone-glow);
|
|
253
255
|
cursor: pointer;
|
|
254
256
|
transition:
|
|
255
257
|
scale var(--ui-motion-press, var(--ui-motion-fast)) var(--ui-motion-ease),
|
|
@@ -382,7 +384,9 @@
|
|
|
382
384
|
background-color: var(--_tone);
|
|
383
385
|
color: var(--_on-tone);
|
|
384
386
|
background-image: var(--_tone-highlight);
|
|
385
|
-
box-shadow:
|
|
387
|
+
box-shadow:
|
|
388
|
+
var(--ui-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
|
|
389
|
+
var(--_tone-glow);
|
|
386
390
|
}
|
|
387
391
|
|
|
388
392
|
:is(:host[data-appearance="solid"], :host[data-appearance="danger"]):hover:not(:disabled, [aria-disabled="true"]) {
|
|
@@ -552,8 +556,11 @@
|
|
|
552
556
|
|
|
553
557
|
/* The size states outrank :host, so sm is named too, or a small button would stay small. */
|
|
554
558
|
@media (pointer: coarse) {
|
|
555
|
-
:host
|
|
556
|
-
min-block-size: var(--ui-control-min-block-size);
|
|
559
|
+
:host {
|
|
560
|
+
min-block-size: max(var(--ui-control-size-md), var(--ui-control-min-block-size));
|
|
561
|
+
}
|
|
562
|
+
:host([size="sm"]) {
|
|
563
|
+
min-block-size: max(var(--ui-control-size-sm), var(--ui-control-min-block-size));
|
|
557
564
|
}
|
|
558
565
|
}
|
|
559
566
|
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
--_size: max(var(--ui-control-size-md), var(--ui-control-min-block-size));
|
|
128
128
|
}
|
|
129
129
|
:host([size="sm"]) {
|
|
130
|
-
--_size: var(--ui-control-min-block-size);
|
|
130
|
+
--_size: max(var(--ui-control-size-sm), var(--ui-control-min-block-size));
|
|
131
131
|
--_font: var(--ui-font-size-md);
|
|
132
132
|
}
|
|
133
133
|
}
|
|
@@ -882,7 +882,7 @@
|
|
|
882
882
|
/* Under touch a small field is still a touch-sized target, as a small button is, and keeps
|
|
883
883
|
body-size text: below 16px, iOS zooms the page into the focused field. */
|
|
884
884
|
:host([size="sm"]) {
|
|
885
|
-
--_row: var(--ui-control-min-block-size);
|
|
885
|
+
--_row: max(var(--ui-control-size-sm), var(--ui-control-min-block-size));
|
|
886
886
|
}
|
|
887
887
|
:host([size="sm"]) input {
|
|
888
888
|
font-size: inherit;
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
<prop name="disabled" type="boolean" default="false">Prevents typing, stepping and pointer or keyboard changes while keeping the value visible.</prop>
|
|
14
14
|
<event name="input" type="object"><prop name="value" type="string" required></prop></event>
|
|
15
15
|
<event name="change" type="object"><prop name="value" type="string" required></prop></event>
|
|
16
|
+
<event name="cancel" type="object"><prop name="value" type="string" required></prop></event>
|
|
16
17
|
</defs>
|
|
17
18
|
<span>
|
|
18
19
|
<span class="plot-frame" from:aria-label="$label" role="group"><span class="plot" $ref="plot">
|
|
@@ -24,21 +24,30 @@ export function connect(host) {
|
|
|
24
24
|
if (!drag || event.pointerId !== drag.id || host.props.disabled.value) return;
|
|
25
25
|
const rect = plot.getBoundingClientRect();
|
|
26
26
|
if (!rect.width || !rect.height) return;
|
|
27
|
-
points[drag.index] = (event.clientX - rect.left) / rect.width;
|
|
28
|
-
points[drag.index + 1] = 2 - (event.clientY - rect.top) / rect.height * 3;
|
|
27
|
+
points[drag.index] = (event.clientX - rect.left - drag.offsetX) / rect.width;
|
|
28
|
+
points[drag.index + 1] = 2 - (event.clientY - rect.top - drag.offsetY) / rect.height * 3;
|
|
29
29
|
paint(); emit("input");
|
|
30
30
|
};
|
|
31
|
-
const finish = event => {
|
|
31
|
+
const finish = event => {
|
|
32
|
+
if (drag?.id !== event.pointerId) return;
|
|
33
|
+
const start = drag; drag = undefined;
|
|
34
|
+
if (start.handle.hasPointerCapture(start.id)) start.handle.releasePointerCapture(start.id);
|
|
35
|
+
if (event.type !== 'pointerup' || host.props.disabled.value) { points = start.points; paint(); emit('input'); emit('cancel'); }
|
|
36
|
+
else emit('change');
|
|
37
|
+
};
|
|
32
38
|
const cleanups = [];
|
|
33
39
|
for (const [index, handle] of [[0, first], [2, second]]) {
|
|
34
|
-
const down = event => { if (host.props.disabled.value || event.button !== 0) return; event.preventDefault(); handle.focus();
|
|
40
|
+
const down = event => { if (host.props.disabled.value || event.button !== 0) return; event.preventDefault(); handle.focus(); const rect = plot.getBoundingClientRect();
|
|
41
|
+
drag = { id: event.pointerId, index, handle, points: [...points], offsetX: event.clientX - rect.left - points[index] * rect.width, offsetY: event.clientY - rect.top - (2 - points[index + 1]) / 3 * rect.height };
|
|
42
|
+
handle.setPointerCapture(event.pointerId); };
|
|
35
43
|
const key = event => {
|
|
44
|
+
if (event.key === 'Escape' && drag) { event.preventDefault(); finish({ pointerId: drag.id, type: 'cancel' }); return; }
|
|
36
45
|
if (host.props.disabled.value || !["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(event.key)) return;
|
|
37
46
|
event.preventDefault(); const step = event.shiftKey ? .1 : .01;
|
|
38
47
|
points[index + (event.key === "ArrowUp" || event.key === "ArrowDown" ? 1 : 0)] += (event.key === "ArrowLeft" || event.key === "ArrowDown" ? -step : step);
|
|
39
48
|
paint(); emit("input"); emit("change");
|
|
40
49
|
};
|
|
41
|
-
for (const [type, callback] of [["pointerdown", down], ["pointermove", move], ["pointerup", finish], ["pointercancel", finish], ["keydown", key]]) {
|
|
50
|
+
for (const [type, callback] of [["pointerdown", down], ["pointermove", move], ["pointerup", finish], ["pointercancel", finish], ["lostpointercapture", finish], ["keydown", key]]) {
|
|
42
51
|
handle.addEventListener(type, callback); cleanups.push(() => handle.removeEventListener(type, callback));
|
|
43
52
|
}
|
|
44
53
|
}
|
|
@@ -47,5 +56,5 @@ export function connect(host) {
|
|
|
47
56
|
for (const type of ["input", "change"]) { field.addEventListener(type, edit); cleanups.push(() => field.removeEventListener(type, edit)); }
|
|
48
57
|
});
|
|
49
58
|
const stop = host.effect(() => { const value = host.props.value.value; if (value === external) return; external = value; try { points = curvePoints(value); } catch { /* Keep the last valid curve. */ } paint(); });
|
|
50
|
-
return () => { stop(); cleanups.forEach(cleanup => cleanup()); };
|
|
59
|
+
return () => { stop(); cleanups.forEach(cleanup => cleanup()); if (drag?.handle.hasPointerCapture(drag.id)) drag.handle.releasePointerCapture(drag.id); };
|
|
51
60
|
}
|
|
@@ -150,7 +150,10 @@
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
:host([size="sm"]) {
|
|
153
|
-
min-block-size: var(
|
|
153
|
+
min-block-size: var(
|
|
154
|
+
--ui-input-min-block-size,
|
|
155
|
+
var(--_ui-default-input-min-block-size, max(var(--ui-control-size-sm), var(--ui-control-min-block-size)))
|
|
156
|
+
);
|
|
154
157
|
}
|
|
155
158
|
}
|
|
156
159
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<link rel="component" href="../ui-icon/ui-icon.html">
|
|
1
2
|
<link rel="component" href="../ui-number-input/ui-number-input.html">
|
|
2
3
|
<template component="ui-light-editor" module="./ui-light-editor.js">
|
|
3
4
|
<defs>
|
|
@@ -10,36 +11,159 @@
|
|
|
10
11
|
<prop name="disabled" type="boolean" default="false">Prevents pointer, keyboard and exact edits.</prop>
|
|
11
12
|
<event name="input" type="object"><prop name="x" type="number" required></prop><prop name="y" type="number" required></prop></event>
|
|
12
13
|
<event name="change" type="object"><prop name="x" type="number" required></prop><prop name="y" type="number" required></prop></event>
|
|
14
|
+
<event name="cancel" type="object"><prop name="x" type="number" required></prop><prop name="y" type="number" required></prop></event>
|
|
13
15
|
</defs>
|
|
14
16
|
<span>
|
|
15
17
|
<span class="stage" from:aria-label="$label" role="group">
|
|
16
18
|
<span class="plane" $ref="plane">
|
|
17
19
|
<svg viewBox="0 0 100 60" preserveAspectRatio="none" aria-hidden="true"><path d="M0 30 H100 M50 0 V60"></path></svg>
|
|
18
20
|
<span class="specimen"><slot></slot></span>
|
|
19
|
-
<button
|
|
21
|
+
<button
|
|
22
|
+
type="button"
|
|
23
|
+
class="source"
|
|
24
|
+
$ref="source"
|
|
25
|
+
from:disabled="$disabled"
|
|
26
|
+
from:aria-label="concat($label, '. Arrow keys move the source; Shift moves faster.')"
|
|
27
|
+
>
|
|
28
|
+
<span class="source-glyph"><ui-icon name="lightbulb"></ui-icon></span>
|
|
29
|
+
</button>
|
|
20
30
|
</span>
|
|
21
31
|
</span>
|
|
22
32
|
<span class="coordinates">
|
|
23
|
-
<ui-number-input
|
|
24
|
-
|
|
33
|
+
<ui-number-input
|
|
34
|
+
data-coordinate="x"
|
|
35
|
+
from:value="$horizontal"
|
|
36
|
+
min="0"
|
|
37
|
+
max="100"
|
|
38
|
+
step="1"
|
|
39
|
+
unit="%"
|
|
40
|
+
label="Light horizontal position"
|
|
41
|
+
from:size="$size"
|
|
42
|
+
from:disabled="$disabled"
|
|
43
|
+
></ui-number-input>
|
|
44
|
+
<ui-number-input
|
|
45
|
+
data-coordinate="y"
|
|
46
|
+
from:value="$vertical"
|
|
47
|
+
min="0"
|
|
48
|
+
max="100"
|
|
49
|
+
step="1"
|
|
50
|
+
unit="%"
|
|
51
|
+
label="Light vertical position"
|
|
52
|
+
from:size="$size"
|
|
53
|
+
from:disabled="$disabled"
|
|
54
|
+
></ui-number-input>
|
|
25
55
|
</span>
|
|
26
|
-
<span class="hint">Drag the light, use arrow keys, or enter its position. Top centre is 50%, 0%.</span>
|
|
56
|
+
<span class="hint">Drag the light, tap the background, use arrow keys, or enter its position. Escape cancels a drag. Top centre is 50%, 0%.</span>
|
|
27
57
|
</span>
|
|
28
58
|
<style>
|
|
29
|
-
:host {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
59
|
+
:host {
|
|
60
|
+
display: grid !important;
|
|
61
|
+
gap: var(--ui-space-3) !important;
|
|
62
|
+
min-inline-size: 0;
|
|
63
|
+
padding: 0 !important;
|
|
64
|
+
margin: 0 !important;
|
|
65
|
+
}
|
|
66
|
+
.stage {
|
|
67
|
+
box-sizing: border-box !important;
|
|
68
|
+
display: block !important;
|
|
69
|
+
block-size: 13rem;
|
|
70
|
+
padding: calc(var(--ui-control-min-block-size) / 2) !important;
|
|
71
|
+
border: var(--ui-border-width) solid var(--ui-control-border);
|
|
72
|
+
border-radius: var(--ui-field-radius, var(--ui-radius-md));
|
|
73
|
+
background: var(--ui-neutral-surface, var(--ui-surface));
|
|
74
|
+
}
|
|
75
|
+
.plane {
|
|
76
|
+
position: relative;
|
|
77
|
+
display: block !important;
|
|
78
|
+
inline-size: 100%;
|
|
79
|
+
block-size: 100%;
|
|
80
|
+
}
|
|
81
|
+
svg {
|
|
82
|
+
inline-size: 100%;
|
|
83
|
+
block-size: 100%;
|
|
84
|
+
overflow: visible;
|
|
85
|
+
}
|
|
86
|
+
path {
|
|
87
|
+
fill: none;
|
|
88
|
+
stroke: var(--ui-border);
|
|
89
|
+
stroke-width: 1;
|
|
90
|
+
vector-effect: non-scaling-stroke;
|
|
91
|
+
}
|
|
92
|
+
.specimen {
|
|
93
|
+
position: absolute;
|
|
94
|
+
inset: 0;
|
|
95
|
+
display: grid !important;
|
|
96
|
+
place-items: center !important;
|
|
97
|
+
}
|
|
98
|
+
.source {
|
|
99
|
+
position: absolute;
|
|
100
|
+
left: 50%;
|
|
101
|
+
top: 0;
|
|
102
|
+
translate: -50% -50%;
|
|
103
|
+
display: grid !important;
|
|
104
|
+
place-items: center !important;
|
|
105
|
+
inline-size: max(2rem, var(--ui-control-min-block-size));
|
|
106
|
+
block-size: max(2rem, var(--ui-control-min-block-size));
|
|
107
|
+
padding: 0 !important;
|
|
108
|
+
margin: 0 !important;
|
|
109
|
+
border: 0;
|
|
110
|
+
border-radius: 50%;
|
|
111
|
+
background: transparent;
|
|
112
|
+
cursor: grab;
|
|
113
|
+
touch-action: none;
|
|
114
|
+
}
|
|
115
|
+
.source-glyph {
|
|
116
|
+
position: relative;
|
|
117
|
+
z-index: 1;
|
|
118
|
+
display: inline-flex !important;
|
|
119
|
+
color: var(--ui-accent);
|
|
120
|
+
font-size: var(--ui-font-size-lg);
|
|
121
|
+
}
|
|
122
|
+
.source::after {
|
|
123
|
+
content: "";
|
|
124
|
+
position: absolute;
|
|
125
|
+
inline-size: 2rem;
|
|
126
|
+
block-size: 2rem;
|
|
127
|
+
border: var(--ui-border-width) solid var(--ui-accent);
|
|
128
|
+
border-radius: 50%;
|
|
129
|
+
background: var(--ui-surface-raised);
|
|
130
|
+
box-shadow: 0 0 0 var(--ui-space-2) color-mix(in srgb, var(--ui-accent) 12%, transparent), var(--ui-shadow-sm);
|
|
131
|
+
}
|
|
132
|
+
.source:active {
|
|
133
|
+
cursor: grabbing;
|
|
134
|
+
}
|
|
135
|
+
.source:focus-visible {
|
|
136
|
+
outline: var(--ui-focus-width) solid var(--ui-focus-ring);
|
|
137
|
+
outline-offset: var(--ui-space-1);
|
|
138
|
+
}
|
|
139
|
+
.source:disabled {
|
|
140
|
+
cursor: not-allowed;
|
|
141
|
+
}
|
|
142
|
+
.source:disabled::after {
|
|
143
|
+
background: var(--ui-disabled-surface);
|
|
144
|
+
border-color: var(--ui-disabled-border);
|
|
145
|
+
box-shadow: none;
|
|
146
|
+
}
|
|
147
|
+
.coordinates {
|
|
148
|
+
display: grid !important;
|
|
149
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
150
|
+
gap: var(--ui-space-2) !important;
|
|
151
|
+
}
|
|
152
|
+
.hint {
|
|
153
|
+
font-size: var(--ui-font-size-sm);
|
|
154
|
+
color: var(--ui-text-secondary);
|
|
155
|
+
}
|
|
156
|
+
@media (forced-colors: active) {
|
|
157
|
+
.source-glyph {
|
|
158
|
+
color: CanvasText;
|
|
159
|
+
}
|
|
160
|
+
.source::after {
|
|
161
|
+
background: Canvas;
|
|
162
|
+
border-color: CanvasText;
|
|
163
|
+
}
|
|
164
|
+
.source:focus-visible {
|
|
165
|
+
outline-color: Highlight;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
44
168
|
</style>
|
|
45
169
|
</template>
|
|
@@ -2,7 +2,7 @@ const coordinate = value => Number.isFinite(Number(value)) ? Math.round(Math.max
|
|
|
2
2
|
|
|
3
3
|
export function connect(host) {
|
|
4
4
|
const { plane, source } = host.refs;
|
|
5
|
-
let x = coordinate(host.props.x.value), y = coordinate(host.props.y.value), drag;
|
|
5
|
+
let x = coordinate(host.props.x.value), y = coordinate(host.props.y.value), drag, suppressClick = false;
|
|
6
6
|
const listeners = [];
|
|
7
7
|
const listen = (element, type, fn) => { element.addEventListener(type, fn); listeners.push(() => element.removeEventListener(type, fn)); };
|
|
8
8
|
const paint = () => {
|
|
@@ -14,21 +14,38 @@ export function connect(host) {
|
|
|
14
14
|
const emit = type => host.dispatch(type, { x, y });
|
|
15
15
|
listen(source, 'pointerdown', event => {
|
|
16
16
|
if (host.props.disabled.value || event.button !== 0) return;
|
|
17
|
-
event.preventDefault(); source.focus();
|
|
17
|
+
event.preventDefault(); source.focus();
|
|
18
|
+
const rect = plane.getBoundingClientRect();
|
|
19
|
+
drag = { id: event.pointerId, x, y, offsetX: event.clientX - rect.left - x * rect.width, offsetY: event.clientY - rect.top - y * rect.height };
|
|
20
|
+
source.setPointerCapture(drag.id);
|
|
18
21
|
});
|
|
19
22
|
listen(source, 'pointermove', event => {
|
|
20
|
-
if (drag !== event.pointerId || host.props.disabled.value) return;
|
|
23
|
+
if (drag?.id !== event.pointerId || host.props.disabled.value) return;
|
|
21
24
|
const rect = plane.getBoundingClientRect(); if (!rect.width || !rect.height) return;
|
|
22
|
-
x = (event.clientX - rect.left) / rect.width; y = (event.clientY - rect.top) / rect.height;
|
|
25
|
+
x = (event.clientX - rect.left - drag.offsetX) / rect.width; y = (event.clientY - rect.top - drag.offsetY) / rect.height;
|
|
23
26
|
paint(); emit('input');
|
|
24
27
|
});
|
|
25
28
|
const end = event => {
|
|
26
|
-
if (drag !== event.pointerId) return;
|
|
27
|
-
drag = undefined;
|
|
28
|
-
if (source.hasPointerCapture(
|
|
29
|
-
if (
|
|
29
|
+
if (drag?.id !== event.pointerId) return;
|
|
30
|
+
const start = drag; drag = undefined; suppressClick = true;
|
|
31
|
+
if (source.hasPointerCapture(start.id)) source.releasePointerCapture(start.id);
|
|
32
|
+
if (event.type !== 'pointerup' || host.props.disabled.value) {
|
|
33
|
+
x = start.x; y = start.y; paint(); emit('input'); emit('cancel');
|
|
34
|
+
} else if (!host.props.disabled.value) emit('change');
|
|
30
35
|
};
|
|
31
36
|
listen(source, 'pointerup', end); listen(source, 'pointercancel', end); listen(source, 'lostpointercapture', end);
|
|
37
|
+
listen(source, 'keydown', event => {
|
|
38
|
+
if (event.key === 'Escape' && drag) { event.preventDefault(); end({ pointerId: drag.id, type: 'cancel' }); }
|
|
39
|
+
});
|
|
40
|
+
// A background tap is deliberate placement; scrolling and specimen controls keep native gestures.
|
|
41
|
+
listen(plane, 'pointerdown', () => { suppressClick = false; });
|
|
42
|
+
listen(plane, 'click', event => {
|
|
43
|
+
if (suppressClick) { suppressClick = false; return; }
|
|
44
|
+
if (host.props.disabled.value || event.target.closest('button,input,select,textarea,a,[role="button"]')) return;
|
|
45
|
+
const rect = plane.getBoundingClientRect(); if (!rect.width || !rect.height) return;
|
|
46
|
+
x = (event.clientX - rect.left) / rect.width; y = (event.clientY - rect.top) / rect.height;
|
|
47
|
+
paint(); emit('input'); emit('change');
|
|
48
|
+
});
|
|
32
49
|
listen(source, 'keydown', event => {
|
|
33
50
|
if (host.props.disabled.value || !['ArrowLeft','ArrowRight','ArrowUp','ArrowDown','Home','End'].includes(event.key)) return;
|
|
34
51
|
event.preventDefault(); const step = event.shiftKey ? .1 : .01;
|
|
@@ -49,5 +66,5 @@ export function connect(host) {
|
|
|
49
66
|
});
|
|
50
67
|
}
|
|
51
68
|
const stop = host.effect(() => { x = coordinate(host.props.x.value); y = coordinate(host.props.y.value); paint(); });
|
|
52
|
-
return () => { stop(); listeners.forEach(cleanup => cleanup()); if (drag
|
|
69
|
+
return () => { stop(); listeners.forEach(cleanup => cleanup()); if (drag && source.hasPointerCapture(drag.id)) source.releasePointerCapture(drag.id); };
|
|
53
70
|
}
|
|
@@ -84,10 +84,12 @@
|
|
|
84
84
|
--_ui-select-highlight: var(--ui-surface-highlight, linear-gradient(transparent, transparent));
|
|
85
85
|
appearance: none;
|
|
86
86
|
padding-inline-end: calc(var(--ui-space-3) + 1.5rem) !important;
|
|
87
|
-
background-image:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
background-image:
|
|
88
|
+
var(
|
|
89
|
+
--ui-select-chevron,
|
|
90
|
+
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235c5c58' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")
|
|
91
|
+
),
|
|
92
|
+
var(--_ui-select-highlight);
|
|
91
93
|
background-repeat: no-repeat;
|
|
92
94
|
background-position: right var(--ui-space-3) center, center;
|
|
93
95
|
background-size: 1.125rem 1.125rem, 100% 100%;
|
|
@@ -134,7 +136,9 @@
|
|
|
134
136
|
padding: var(--ui-control-inset-block-sm, var(--ui-space-1)) var(--ui-space-2) !important;
|
|
135
137
|
padding-inline-end: calc(var(--ui-space-2) + var(--ui-icon-size-sm) + var(--ui-space-1)) !important;
|
|
136
138
|
background-position: right var(--ui-space-2) center, center;
|
|
137
|
-
background-size:
|
|
139
|
+
background-size:
|
|
140
|
+
var(--ui-icon-size-sm) var(--ui-icon-size-sm),
|
|
141
|
+
100% 100%;
|
|
138
142
|
font-size: var(--ui-font-size-sm);
|
|
139
143
|
}
|
|
140
144
|
|
|
@@ -154,7 +158,7 @@
|
|
|
154
158
|
}
|
|
155
159
|
|
|
156
160
|
:host([size="sm"]) {
|
|
157
|
-
min-block-size: var(--ui-control-min-block-size);
|
|
161
|
+
min-block-size: max(var(--ui-control-size-sm), var(--ui-control-min-block-size));
|
|
158
162
|
font-size: inherit;
|
|
159
163
|
}
|
|
160
164
|
}
|