{const t=this._window();this._closeTimer&&t?.clearTimeout(this._closeTimer),this._closeTimer=0},this._surfacePointerLeave=()=>{this._scheduleClose()},this._outsidePointerDown=t=>{if(!this._open)return;const e=t.composedPath();this._floating.containsPath(e)||this._closeHelp(!1,"outside")},this._dialogScroll=t=>{const e=this._floating.containsPath(t.composedPath()),i=t.target,s=this._dialog(),n=i instanceof Node&&(i===s||i instanceof Element&&i.contains(this));var o;this._open&&(o=n,!e&&o)&&this._closeHelp(!1,"scroll")},this._keyDown=t=>{if(!this._open||t.defaultPrevented)return;if("Escape"===t.key)return t.preventDefault(),t.stopImmediatePropagation(),void this._closeHelp(this._floating.ownsActiveElement(),"escape");const e=this.renderRoot.querySelector(".trigger");if(!e||!t.composedPath().includes(e))return;const i=this._surface();if(!i||i.scrollHeight<=i.clientHeight)return;const s=Math.max(40,.8*i.clientHeight),n={ArrowDown:40,ArrowUp:-40,PageDown:s,PageUp:-s};if("Home"===t.key)i.scrollTop=0;else if("End"===t.key)i.scrollTop=i.scrollHeight;else{if(!(t.key in n))return;i.scrollBy({top:n[t.key],behavior:"auto"})}t.preventDefault(),t.stopImmediatePropagation()},this._floating=new Wt(this,"help",this._keyDown),this._queuePosition=()=>{if(!this._open||this._positionRaf)return;const t=this._window();t&&(this._positionRaf=t.requestAnimationFrame(()=>{this._positionRaf=0,this._position()||this._closeHelp()}))}}connectedCallback(){super.connectedCallback(),this.addEventListener("keydown",this._keyDown,!0)}willUpdate(){this.toggleAttribute("data-has-content",this._hasContent())}disconnectedCallback(){const t=this.ownerDocument.defaultView;this._unsubscribeOpenListeners(),this.removeEventListener("keydown",this._keyDown,!0),this._clearTimers(),this._positionRaf&&t?.cancelAnimationFrame(this._positionRaf),this._positionRaf=0,this._closeHelp(!1,"disconnect"),super.disconnectedCallback()}updated(t){this._hasContent()||!this._open?this._open&&t.has("text")&&(this._usesPopover()||this._renderFallback(),this._queuePosition()):this._closeHelp()}_window(){return this._floating.window()}_dialog(){return this._floating.dialog()}_usesPopover(){return this._floating.usesPopover(this._forceFallback)}_hasContent(){return t=this.text,e=this.ariaLabel,"string"==typeof t&&t.trim().length>0&&"string"==typeof e&&e.trim().length>0;var t,e}_clearTimers(){const t=this._window();this._openTimer&&t?.clearTimeout(this._openTimer),this._closeTimer&&t?.clearTimeout(this._closeTimer),this._openTimer=0,this._closeTimer=0}_scheduleOpen(){const t=this._window();!t||this._open||this._openTimer||(this._closeTimer&&t.clearTimeout(this._closeTimer),this._closeTimer=0,this._openTimer=t.setTimeout(()=>{this._openTimer=0,this.isConnected&&this._openHelp()},300))}_scheduleClose(){const t=this._window(),e=this.renderRoot.querySelector(".trigger");t&&!e?.matches(":focus-visible")&&(this._openTimer&&t.clearTimeout(this._openTimer),this._closeTimer&&t.clearTimeout(this._closeTimer),this._openTimer=0,this._closeTimer=t.setTimeout(()=>{this._closeTimer=0,this.isConnected&&this._closeHelp()},150))}_triggerPointerEnter(t){"mouse"===t.pointerType&&this._scheduleOpen()}_triggerPointerLeave(t){"mouse"===t.pointerType&&this._scheduleClose()}_triggerFocus(){queueMicrotask(()=>{const t=this.renderRoot.querySelector(".trigger");t?.matches(":focus-visible")&&this._openHelp()})}_triggerBlur(){this._scheduleClose()}_triggerClick(){this._open?this._closeHelp():this._openHelp()}_subscribeOpenListeners(){this.ownerDocument.addEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.addEventListener("keydown",this._keyDown,!0);const t=this._window();t?.addEventListener("resize",this._queuePosition),t?.addEventListener("orientationchange",this._queuePosition),t?.visualViewport?.addEventListener("resize",this._queuePosition),t?.visualViewport?.addEventListener("scroll",this._queuePosition),this._scrollDialog=this._dialog(),this._scrollDialog?.addEventListener("scroll",this._dialogScroll,!0)}_unsubscribeOpenListeners(){this.ownerDocument.removeEventListener("pointerdown",this._outsidePointerDown,!0),this.ownerDocument.removeEventListener("keydown",this._keyDown,!0);const t=this._window();t?.removeEventListener("resize",this._queuePosition),t?.removeEventListener("orientationchange",this._queuePosition),t?.visualViewport?.removeEventListener("resize",this._queuePosition),t?.visualViewport?.removeEventListener("scroll",this._queuePosition),this._scrollDialog?.removeEventListener("scroll",this._dialogScroll,!0),this._scrollDialog=null}async _openHelp(){!this._open&&this._hasContent()&&(this._clearTimers(),this._forceFallback=!1,this._open=!0,this._subscribeOpenListeners(),await this.updateComplete,this._open&&(this._usesPopover()||this._renderFallback(),this._position()?this._overlayDispose=this._dialog()?.registerOverlay({owner:this,group:"transient",close:t=>this._closeHelp("escape"===t&&this._floating.ownsActiveElement(),t)})||null:this._closeHelp()))}_closeHelp(t=!1,e="exclusive"){if(!this._open&&!this._floating.hasFallback)return;this._clearTimers();const i=this._overlayDispose;this._overlayDispose=null,i?.();const s=this.renderRoot.querySelector(".tooltip");if(s?.hidePopover)try{s.matches(":popover-open")&&s.hidePopover()}catch{}this._open=!1,this._unsubscribeOpenListeners(),this._floating.destroy(),t&&this.updateComplete.then(()=>this.renderRoot.querySelector(".trigger")?.focus())}_tooltipTemplate(t){return W`
diff --git a/docs/USER-GUIDE.ru.md b/docs/USER-GUIDE.ru.md
index 5409238a..a440b483 100644
--- a/docs/USER-GUIDE.ru.md
+++ b/docs/USER-GUIDE.ru.md
@@ -189,8 +189,9 @@ title: План дома
Если редактор показывает образец цвета, один клик открывает палитру House Plan.
Оттенок, насыщенность, яркость, точное значение HEX и прозрачность (если она
поддерживается этой настройкой) доступны вместе, без второго системного диалога
-браузера. Шкала «Оттенок» сразу показывает полный цветовой спектр. Изменения
-остаются черновиком до сохранения родительского диалога свойств.
+браузера. Шкала «Оттенок» сразу показывает полный цветовой спектр, а контрастный
+контур сохраняет видимость ползунка. Изменения остаются черновиком до сохранения
+родительского диалога свойств.
diff --git a/src/hp-color-opacity.ts b/src/hp-color-opacity.ts
index 7b17f02d..0e38dca8 100644
--- a/src/hp-color-opacity.ts
+++ b/src/hp-color-opacity.ts
@@ -236,6 +236,9 @@ export class HpColorOpacity extends LitElement {
--hp-picker-hue-track: linear-gradient(to right,
#f00 0%, #ff0 16.667%, #0f0 33.333%, #0ff 50%,
#00f 66.667%, #f0f 83.333%, #f00 100%);
+ --hp-picker-hue-thumb-shadow:
+ 0 0 0 2px var(--card-background-color, #202126),
+ 0 0 0 3px var(--primary-text-color, #fff);
}
.hue-range::-webkit-slider-runnable-track {
height: 10px;
@@ -257,6 +260,14 @@ export class HpColorOpacity extends LitElement {
border-radius: 999px;
background: transparent;
}
+ .hue-range::-webkit-slider-thumb {
+ border-radius: 50%;
+ box-shadow: var(--hp-picker-hue-thumb-shadow);
+ }
+ .hue-range::-moz-range-thumb {
+ border-radius: 50%;
+ box-shadow: var(--hp-picker-hue-thumb-shadow);
+ }
input[type='text'],
input[type='number'] {
min-height: 40px;
@@ -308,6 +319,12 @@ export class HpColorOpacity extends LitElement {
border-color: ButtonText;
background: Canvas;
}
+ .hue-range::-webkit-slider-thumb {
+ box-shadow: none;
+ }
+ .hue-range::-moz-range-thumb {
+ box-shadow: none;
+ }
}
`;
diff --git a/test/color-picker.test.mjs b/test/color-picker.test.mjs
index 57e928ce..35d1a6cf 100644
--- a/test/color-picker.test.mjs
+++ b/test/color-picker.test.mjs
@@ -58,6 +58,9 @@ test('the hue range exposes one cyclic spectrum without restyling other ranges',
assert.match(component, /\.hue-range::\-webkit-slider-runnable-track\s*\{[\s\S]*?height:\s*10px;[\s\S]*?background:\s*var\(--hp-picker-hue-track\);/);
assert.match(component, /\.hue-range::\-moz-range-track\s*\{[\s\S]*?height:\s*10px;[\s\S]*?background:\s*var\(--hp-picker-hue-track\);/);
assert.match(component, /\.hue-range::\-moz-range-progress\s*\{[\s\S]*?background:\s*transparent;/);
+ assert.match(component, /\.hue-range::\-webkit-slider-thumb\s*\{[\s\S]*?border-radius:\s*50%;[\s\S]*?box-shadow:\s*var\(--hp-picker-hue-thumb-shadow\);/);
+ assert.match(component, /\.hue-range::\-moz-range-thumb\s*\{[\s\S]*?border-radius:\s*50%;[\s\S]*?box-shadow:\s*var\(--hp-picker-hue-thumb-shadow\);/);
+ assert.match(spectrum, /--hp-picker-hue-thumb-shadow:[\s\S]*?card-background-color[\s\S]*?primary-text-color/);
assert.match(component, /@media \(forced-colors:\s*active\)[\s\S]*?background:\s*Canvas;/);
assert.match(component, /class="hue-range" type="range" min="0" max="359" step="1"/);
const commonRange = component.match(/input\[type='range'\]\s*\{[\s\S]*?\n\s*\}/)?.[0] || '';