@dumiflex/wp-kit 0.15.1 → 0.15.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.15.2](https://github.com/DumiFlex/wp-kit/compare/v0.15.1...v0.15.2) (2026-11-09)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * colour picker edges and thumb drift, uncut Segmented descenders, no false more-below hint ([#119](https://github.com/DumiFlex/wp-kit/issues/119)) ([d4728bb](https://github.com/DumiFlex/wp-kit/commit/d4728bb70ae90bedc68fc61a662cc848788b41a0))
9
+
3
10
  ## [0.15.1](https://github.com/DumiFlex/wp-kit/compare/v0.15.0...v0.15.1) (2026-11-09)
4
11
 
5
12
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dumiflex/wp-kit",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
4
4
  "description": "Vue 3 component kit shared by the Wildcard Pipeline manager, canvas and community site.",
5
5
  "keywords": [
6
6
  "vue",
@@ -199,6 +199,9 @@ function pickNone(): void {
199
199
  border-radius: min(3px, var(--wp-radius-cap, 999px));
200
200
  /* Checks show through a see-through colour. */
201
201
  background: repeating-conic-gradient(var(--wp-bg-4) 0 25%, var(--wp-bg-1) 0 50%) 0 0 / 8px 8px;
202
+ /* Not under the see-through border, or the checks show round the colour
203
+ as a jagged edge. */
204
+ background-clip: padding-box;
202
205
  }
203
206
  .wp-color-field--md .wp-color-field__chip { width: 20px; height: 20px; border-radius: min(4px, var(--wp-radius-cap, 999px)); }
204
207
  .wp-color-field--compact { padding: 0 3px; }
package/src/HsvPicker.vue CHANGED
@@ -38,6 +38,10 @@ const emit = defineEmits<{
38
38
  const hsv = ref<Hsv>({ h: 0, s: 1, v: 1 });
39
39
 
40
40
  function syncFromProp(hex: string) {
41
+ // Our own emit coming back: keep the exact position. A hex has only 256
42
+ // steps per channel, so near black (or grey) reading it back moves the
43
+ // thumb away from the pointer, and the hue jumps.
44
+ if (hex.toLowerCase() === hsvToHex(hsv.value).toLowerCase()) return;
41
45
  const parsed = hexToHsv(hex);
42
46
  if (!parsed) return;
43
47
  // Preserve the local hue when incoming RGB is pure black/white —
@@ -58,6 +62,18 @@ const hueBg = computed(() => `hsl(${hsv.value.h}, 100%, 50%)`);
58
62
  const svEl = ref<HTMLDivElement | null>(null);
59
63
  const hueEl = ref<HTMLDivElement | null>(null);
60
64
 
65
+ /** Where `evt` sits inside `el`'s padding box (what the gradient and the
66
+ * thumb are drawn in), as 0..1 fractions; the border is not part of it. */
67
+ function fraction(el: HTMLElement, evt: PointerEvent): { x: number; y: number } {
68
+ const rect = el.getBoundingClientRect();
69
+ const left = rect.left + el.clientLeft;
70
+ const top = rect.top + el.clientTop;
71
+ const w = el.clientWidth || rect.width;
72
+ const h = el.clientHeight || rect.height;
73
+ const clamp = (n: number) => Math.max(0, Math.min(1, n));
74
+ return { x: w ? clamp((evt.clientX - left) / w) : 0, y: h ? clamp((evt.clientY - top) / h) : 0 };
75
+ }
76
+
61
77
  /** Document-level drag state. Only one drag can be active at a time
62
78
  * (one mouse / one finger), so a single `activeDrag` ref tracking
63
79
  * which surface owns the current pointer is sufficient. */
@@ -66,19 +82,16 @@ let activeDrag: "sv" | "hue" | null = null;
66
82
  function handleSvMove(evt: PointerEvent) {
67
83
  const el = svEl.value;
68
84
  if (!el) return;
69
- const rect = el.getBoundingClientRect();
70
- const x = Math.max(0, Math.min(rect.width, evt.clientX - rect.left));
71
- const y = Math.max(0, Math.min(rect.height, evt.clientY - rect.top));
72
- hsv.value = { h: hsv.value.h, s: x / rect.width, v: 1 - (y / rect.height) };
85
+ const { x, y } = fraction(el, evt);
86
+ hsv.value = { h: hsv.value.h, s: x, v: 1 - y };
73
87
  emitHex();
74
88
  }
75
89
 
76
90
  function handleHueMove(evt: PointerEvent) {
77
91
  const el = hueEl.value;
78
92
  if (!el) return;
79
- const rect = el.getBoundingClientRect();
80
- const x = Math.max(0, Math.min(rect.width, evt.clientX - rect.left));
81
- hsv.value = { h: (x / rect.width) * 360, s: hsv.value.s, v: hsv.value.v };
93
+ const { x } = fraction(el, evt);
94
+ hsv.value = { h: x * 360, s: hsv.value.s, v: hsv.value.v };
82
95
  emitHex();
83
96
  }
84
97
 
@@ -162,6 +175,11 @@ const hueCursorStyle = computed(() => ({
162
175
  linear-gradient(to top, #000, transparent),
163
176
  linear-gradient(to right, #fff, transparent),
164
177
  var(--wp-hsv-hue, hsl(0, 100%, 50%));
178
+ /* The gradients are sized to the padding box; without these they repeat
179
+ under the see-through border: a white line down the right edge, the
180
+ hue along the bottom. */
181
+ background-repeat: no-repeat;
182
+ background-clip: padding-box;
165
183
  }
166
184
  .wp-hsv-picker__sv-cursor {
167
185
  position: absolute;
@@ -192,6 +210,8 @@ const hueCursorStyle = computed(() => ({
192
210
  hsl(300, 100%, 50%),
193
211
  hsl(360, 100%, 50%)
194
212
  );
213
+ background-repeat: no-repeat;
214
+ background-clip: padding-box;
195
215
  }
196
216
  .wp-hsv-picker__hue-cursor {
197
217
  position: absolute;
@@ -158,7 +158,9 @@ function onKeydown(ev: KeyboardEvent): void {
158
158
  .wp-segmented[data-size="lg"] .wp-segmented__opt { padding: 0 var(--wp-space-6); font-size: var(--wp-text-base); }
159
159
  .wp-segmented[data-block] { display: flex; width: 100%; align-self: stretch; }
160
160
  .wp-segmented[data-block] .wp-segmented__opt { flex: 1 1 0; }
161
- .wp-segmented__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
161
+ /* The option sets line-height 1; the label clips (for the ellipsis), so it
162
+ needs a taller line or it cuts g, p, q and y. */
163
+ .wp-segmented__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; line-height: 1.3; }
162
164
  .wp-segmented[data-icon-only] .wp-segmented__opt { aspect-ratio: 1; padding: 0; }
163
165
  .wp-segmented__opt:hover:not(:disabled) { color: var(--wp-text); background: var(--wp-bg-3); }
164
166
  .wp-segmented__opt[data-active="true"] {
@@ -74,8 +74,12 @@ export function useGrowableField(
74
74
  function updateOverflowHint(): void {
75
75
  const el = getEl();
76
76
  if (!el) return;
77
- // 2px slack absorbs sub-pixel rounding at the exact bottom.
78
- hasMoreBelow.value = el.scrollHeight - el.scrollTop - el.clientHeight > 2;
77
+ // Only text counts: the bottom padding scrolling out of view hides
78
+ // nothing, so it is allowed for (a box a few px short of its padding
79
+ // showed the hint under a fully visible last line). 2px slack absorbs
80
+ // sub-pixel rounding at the exact bottom.
81
+ const pad = parseFloat(getComputedStyle(el).paddingBottom) || 0;
82
+ hasMoreBelow.value = el.scrollHeight - el.scrollTop - el.clientHeight > pad + 2;
79
83
  }
80
84
 
81
85
  function scheduleOverflowHint(): void {