1.2.12: eyedropper — sample colours from anywhere on the page
Tiny progressive-enhancement feature using the browser's native
EyeDropper API (Chromium 95+). Adds a small pipette button next
to every colour swatch in the properties panel; clicking it opens
the OS picker and applies the chosen sRGBHex to the bound colour
property.
- src/composables/useEyeDropper.ts: returns { supported, pick }.
`supported` re-detects on every call (not a singleton) so a late-
loaded polyfill or a test-time monkey-patch is observed without
juggling Vite's module cache. `pick()` resolves to the chosen
hex string, returns null on cancel / abort / missing API.
- PropertiesPanel: PhEyedropper button on each of the three colour
rows (fill, stroke, shadow). v-if="eyeDropperSupported" hides
the button entirely on Safari + Firefox — clean PE. Fill and
stroke buttons disable when their "Transparent" toggle is on.
Picked colour writes through the same fillColor / strokeColor /
shadowColorValue computeds, so the keyframe path / asset writer
is identical to a color-input drag.
- properties.eyedropper i18n string.
Tests (7 new under "eyedropper — color sampling from anywhere on the page"):
- supported reflects window.EyeDropper presence at call time.
- pick() resolves with the sRGBHex from a stubbed EyeDropper.
- pick() returns null on AbortError.
- pick() returns null when the API is missing.
- PropertiesPanel renders eyedropper buttons when supported.
- PropertiesPanel hides them when EyeDropper is undefined.
- Clicking the fill eyedropper applies the picked colour through
the layer's keyframe / asset writer.
`claude.txt` backlog complete (wiggle / motion-paths / eyedropper
all shipped).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
a2fdd1684a
commit
184842b2e0
6 files changed
+237
-2
No files matched your search
@@ -6,6 +6,7 @@ import {
|
||||
PhDiamond,
|
||||
PhEye,
|
||||
PhEyeSlash,
|
||||
PhEyedropper,
|
||||
PhFlower,
|
||||
PhMaskHappy,
|
||||
PhWaveSine,
|
||||
@@ -23,8 +24,23 @@ import ActionEditor from './ActionEditor.vue'
|
||||
import FontPicker from './FontPicker.vue'
|
||||
import { t } from '@/i18n'
|
||||
import { useTimeFormat } from '@/composables/useTimeFormat'
|
||||
import { useEyeDropper } from '@/composables/useEyeDropper'
|
||||
|
||||
const { formatTime, timeToInputValue, inputValueToSeconds, inputStep, unitLabel } = useTimeFormat()
|
||||
const { supported: eyeDropperSupported, pick: pickColor } = useEyeDropper()
|
||||
|
||||
async function pickFillColor() {
|
||||
const c = await pickColor()
|
||||
if (c) fillColor.value = c
|
||||
}
|
||||
async function pickStrokeColor() {
|
||||
const c = await pickColor()
|
||||
if (c) strokeColor.value = c
|
||||
}
|
||||
async function pickShadowColor() {
|
||||
const c = await pickColor()
|
||||
if (c) shadowColorValue.value = c
|
||||
}
|
||||
|
||||
const SECTION_STORAGE_KEY = 'animatr:propSections'
|
||||
|
||||
@@ -645,6 +661,16 @@ function deleteSelection() {
|
||||
@input="fillColor = ($event.target as HTMLInputElement).value"
|
||||
/>
|
||||
<span class="color-hex">{{ fillTransparent ? '—' : fillColor.toUpperCase() }}</span>
|
||||
<button
|
||||
v-if="eyeDropperSupported"
|
||||
type="button"
|
||||
class="icon-toggle eyedropper-btn"
|
||||
:disabled="fillTransparent"
|
||||
v-tooltip="t('properties.eyedropper')"
|
||||
@click="pickFillColor"
|
||||
>
|
||||
<PhEyedropper :size="13" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="icon-toggle alpha-toggle-btn"
|
||||
@@ -667,6 +693,16 @@ function deleteSelection() {
|
||||
@input="strokeColor = ($event.target as HTMLInputElement).value"
|
||||
/>
|
||||
<span class="color-hex">{{ strokeTransparent ? '—' : strokeColor.toUpperCase() }}</span>
|
||||
<button
|
||||
v-if="eyeDropperSupported"
|
||||
type="button"
|
||||
class="icon-toggle eyedropper-btn"
|
||||
:disabled="strokeTransparent"
|
||||
v-tooltip="t('properties.eyedropper')"
|
||||
@click="pickStrokeColor"
|
||||
>
|
||||
<PhEyedropper :size="13" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="icon-toggle alpha-toggle-btn"
|
||||
@@ -721,6 +757,15 @@ function deleteSelection() {
|
||||
@input="shadowColorValue = ($event.target as HTMLInputElement).value"
|
||||
/>
|
||||
<span class="color-hex">{{ shadowColorValue.toUpperCase() }}</span>
|
||||
<button
|
||||
v-if="eyeDropperSupported"
|
||||
type="button"
|
||||
class="icon-toggle eyedropper-btn"
|
||||
v-tooltip="t('properties.eyedropper')"
|
||||
@click="pickShadowColor"
|
||||
>
|
||||
<PhEyedropper :size="13" />
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
<label class="slider-label">
|
||||
|
||||
Reference in new issue
Block a user