mirror of
https://github.com/PR0M3TH3AN/Artstr-Studio.git
synced 2026-11-04 12:40:40 +00:00
eyedropper tool (I) — sample colors via the native picker
A new ⊙ button in the tool palette and the I keyboard shortcut open the browser's window.EyeDropper picker so the user can sample any pixel anywhere on screen (not just our canvas) and apply the sampled hex to a smart target: - Selected shape layer → fill color (Shift = stroke color). - Selected text layer → text color. - No layer selected → pen / shape tool's default fill (or stroke), so the next thing drawn picks up the sampled hue. The eyedropper is a transient action rather than a persistent tool — invoking it doesn't change the active tool, so users can sample mid-edit without losing their cursor. Falls back to a hint toast in browsers that don't yet support window.EyeDropper (Safari).
This commit is contained in:
1 parent
0cb028c3f1
commit
cb130b82cd
1 file changed
+51
@@ -4042,6 +4042,7 @@
|
||||
<button type="button" class="toolPaletteBtn" id="tool-pencil" data-tool="pencil" title="Pencil tool (B)" aria-label="Pencil tool">✎</button>
|
||||
<button type="button" class="toolPaletteBtn" id="tool-shape" data-tool="shape" title="Shape tool (S)" aria-label="Shape tool">▢</button>
|
||||
<button type="button" class="toolPaletteBtn" id="tool-text" data-tool="text" title="Text tool (T)" aria-label="Text tool">T</button>
|
||||
<button type="button" class="toolPaletteBtn" id="tool-eyedropper" data-tool="eyedropper" title="Eyedropper (I) — sample a color from anywhere on screen" aria-label="Eyedropper tool">⊙</button>
|
||||
<div class="pixelToolWrap">
|
||||
<button type="button" class="toolPaletteBtn" id="tool-pixel" title="Pixel art layer" aria-haspopup="true" aria-expanded="false" aria-label="Pixel art layer">▦</button>
|
||||
<div id="pixelToolMenu" class="pixelToolMenu">
|
||||
@@ -9534,6 +9535,50 @@
|
||||
render();
|
||||
}
|
||||
|
||||
// Eyedropper: invoke the browser's native EyeDropper picker so
|
||||
// the user can sample any pixel anywhere on screen (not just our
|
||||
// canvas). Applies the picked hex to the most-relevant target:
|
||||
// shape layer → fill (or stroke if Shift was held)
|
||||
// text layer → text color
|
||||
// nothing → the pen / shape tool's default fill colour so
|
||||
// the next thing drawn picks up the sampled hue.
|
||||
// Not supported in Safari yet — show a hint toast there.
|
||||
async function invokeEyedropper(toStroke) {
|
||||
if (typeof window.EyeDropper !== 'function') {
|
||||
toastError?.('Eyedropper needs Chrome, Edge, or Firefox 124+. Safari support is still pending.');
|
||||
return;
|
||||
}
|
||||
let hex = '';
|
||||
try {
|
||||
const res = await new window.EyeDropper().open();
|
||||
hex = (res && res.sRGBHex) || '';
|
||||
} catch (err) {
|
||||
// User pressed Escape — silent abort.
|
||||
return;
|
||||
}
|
||||
if (!hex) return;
|
||||
const layer = selectedLayer?.();
|
||||
if (layer && layer.type === 'shape') {
|
||||
pushHistory('eyedropper');
|
||||
if (toStroke) layer.stroke = { type: 'none', color: '#000000', width: 2, dash: 'solid', ...(layer.stroke || {}), type: 'solid', color: hex };
|
||||
else layer.fill = { ...(layer.fill || {}), type: 'solid', color: hex };
|
||||
render();
|
||||
} else if (layer && layer.type === 'text') {
|
||||
pushHistory('eyedropper');
|
||||
layer.color = hex;
|
||||
render();
|
||||
} else {
|
||||
// No layer selected — stash the color on the active drawing
|
||||
// tool's defaults so the next stroke / fill uses it.
|
||||
if (toStroke) _penToolOpts.penStrokeColor = hex;
|
||||
else _penToolOpts.penFillColor = hex;
|
||||
_shapeToolOpts.fillColor = toStroke ? _shapeToolOpts.fillColor : hex;
|
||||
_shapeToolOpts.strokeColor = toStroke ? hex : _shapeToolOpts.strokeColor;
|
||||
syncToolOptionInputs?.();
|
||||
toast?.(`Sampled ${hex} — applied to current ${toStroke ? 'stroke' : 'fill'} color.`);
|
||||
}
|
||||
}
|
||||
|
||||
function syncPenOverlay() {
|
||||
if (_penOverlay && _penOverlay.parentNode) _penOverlay.parentNode.removeChild(_penOverlay);
|
||||
_penOverlay = null;
|
||||
@@ -30053,6 +30098,11 @@
|
||||
for (const t of EDITOR_TOOLS) {
|
||||
on(`tool-${t}`, 'click', () => setEditorTool(t));
|
||||
}
|
||||
// Eyedropper is a transient action, not a persistent tool — its
|
||||
// button immediately opens the native picker and the previous
|
||||
// tool stays active. Shift-click samples into the stroke color
|
||||
// instead of the fill.
|
||||
on('tool-eyedropper', 'click', (e) => invokeEyedropper(!!e.shiftKey));
|
||||
on('penFinishBtn', 'click', () => { finishPenPath(false); setEditorTool('select'); });
|
||||
on('penCancelBtn', 'click', () => setEditorTool('select'));
|
||||
// Path actions side-panel buttons. Each grabs the currently
|
||||
@@ -30191,6 +30241,7 @@
|
||||
if (k === 'b') { setEditorTool('pencil'); return; }
|
||||
if (k === 's') { setEditorTool('shape'); return; }
|
||||
if (k === 't') { setEditorTool('text'); return; }
|
||||
if (k === 'i') { invokeEyedropper(e.shiftKey); return; }
|
||||
if (k === 'enter' && _penDraft && _penDraft.tool === 'pen') { e.preventDefault(); finishPenPath(false); return; }
|
||||
if (!_penDraft) {
|
||||
if (k === 'delete' || k === 'backspace') {
|
||||
|
||||
Reference in new issue
Block a user