kopia lustrzana https://github.com/shoelace-style/shoelace
use HSB grid for color picker; fixes #762
rodzic
139073dc3e
commit
79306e0618
|
|
@ -20,6 +20,8 @@ _During the beta period, these restrictions may be relaxed in the event of a mis
|
|||
- Improved behavior of clearable and password toggle buttons in `<sl-input>` and `<sl-select>` [#745](https://github.com/shoelace-style/shoelace/issues/745)
|
||||
- Improved performance of `<sl-select>` by caching menu items instead of traversing for them each time
|
||||
- Improved drag utility so initial click/touch events can be accepted [#758](https://github.com/shoelace-style/shoelace/issues/758)
|
||||
- Improved `<sl-color-picker>` to use an HSB grid instead of HSL to be more consistent with existing color picker implementations [#762](https://github.com/shoelace-style/shoelace/issues/762)
|
||||
- Improved `<sl-color-picker>` so the cursor is hidden and the preview is larger when dragging the grid
|
||||
- Refactored `<sl-menu>` to be more performant by caching menu items on slot change
|
||||
- Reverted form submit logic [#718](https://github.com/shoelace-style/shoelace/issues/718)
|
||||
- Updated the `disabled` attribute so it reflects in `<sl-dropdown>` [#741](https://github.com/shoelace-style/shoelace/discussions/741)
|
||||
|
|
|
|||
|
|
@ -39,14 +39,8 @@ export default css`
|
|||
.color-picker__grid {
|
||||
position: relative;
|
||||
height: var(--grid-height);
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
hsl(0, 0%, 100%) 0%,
|
||||
hsla(0, 0%, 100%, 0) 50%,
|
||||
hsla(0, 0%, 0%, 0) 50%,
|
||||
hsl(0, 0%, 0%) 100%
|
||||
),
|
||||
linear-gradient(to right, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%),
|
||||
linear-gradient(to right, #fff 0%, rgba(255, 255, 255, 0) 100%);
|
||||
border-top-left-radius: var(--sl-border-radius-medium);
|
||||
border-top-right-radius: var(--sl-border-radius-medium);
|
||||
cursor: crosshair;
|
||||
|
|
@ -61,6 +55,12 @@ export default css`
|
|||
border: solid 2px white;
|
||||
margin-top: calc(var(--grid-handle-size) / -2);
|
||||
margin-left: calc(var(--grid-handle-size) / -2);
|
||||
transition: var(--sl-transition-fast) transform;
|
||||
}
|
||||
|
||||
.color-picker__grid-handle--dragging {
|
||||
cursor: none;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
|
||||
.color-picker__grid-handle${focusVisibleSelector} {
|
||||
|
|
@ -133,10 +133,10 @@ export default css`
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
width: 3.25rem;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
border: none;
|
||||
border-radius: var(--sl-input-border-radius-medium);
|
||||
border-radius: var(--sl-border-radius-circle);
|
||||
background: none;
|
||||
margin-left: var(--sl-spacing-small);
|
||||
cursor: copy;
|
||||
|
|
|
|||
|
|
@ -93,10 +93,12 @@ export default class SlColorPicker extends LitElement {
|
|||
private lastValueEmitted: string;
|
||||
private readonly localize = new LocalizeController(this);
|
||||
|
||||
@state() private isDraggingGridHandle = false;
|
||||
@state() private inputValue = '';
|
||||
@state() private hue = 0;
|
||||
@state() private saturation = 100;
|
||||
@state() private lightness = 100;
|
||||
@state() private brightness = 100;
|
||||
@state() private alpha = 100;
|
||||
|
||||
/** The current color. */
|
||||
|
|
@ -211,6 +213,14 @@ export default class SlColorPicker extends LitElement {
|
|||
}
|
||||
}
|
||||
|
||||
getBrightness(lightness: number) {
|
||||
return clamp(-1 * ((200 * lightness) / (this.saturation - 200)), 0, 100);
|
||||
}
|
||||
|
||||
getLightness(brightness: number) {
|
||||
return clamp(((((200 - this.saturation) * brightness) / 100) * 5) / 10, 0, 100);
|
||||
}
|
||||
|
||||
/** Checks for validity and shows the browser's validation message if the control is invalid. */
|
||||
reportValidity() {
|
||||
// If the input is invalid, show the dropdown so the browser can focus on it
|
||||
|
|
@ -262,14 +272,13 @@ export default class SlColorPicker extends LitElement {
|
|||
handle.focus();
|
||||
event.preventDefault();
|
||||
|
||||
drag(
|
||||
container,
|
||||
x => {
|
||||
drag(container, {
|
||||
onMove: x => {
|
||||
this.alpha = clamp((x / width) * 100, 0, 100);
|
||||
this.syncValues();
|
||||
},
|
||||
{ initialEvent: event }
|
||||
);
|
||||
initialEvent: event
|
||||
});
|
||||
}
|
||||
|
||||
handleHueDrag(event: PointerEvent) {
|
||||
|
|
@ -280,14 +289,13 @@ export default class SlColorPicker extends LitElement {
|
|||
handle.focus();
|
||||
event.preventDefault();
|
||||
|
||||
drag(
|
||||
container,
|
||||
x => {
|
||||
drag(container, {
|
||||
onMove: x => {
|
||||
this.hue = clamp((x / width) * 360, 0, 360);
|
||||
this.syncValues();
|
||||
},
|
||||
{ initialEvent: event }
|
||||
);
|
||||
initialEvent: event
|
||||
});
|
||||
}
|
||||
|
||||
handleGridDrag(event: PointerEvent) {
|
||||
|
|
@ -298,17 +306,19 @@ export default class SlColorPicker extends LitElement {
|
|||
handle.focus();
|
||||
event.preventDefault();
|
||||
|
||||
drag(
|
||||
grid,
|
||||
(x, y) => {
|
||||
this.isDraggingGridHandle = true;
|
||||
|
||||
drag(grid, {
|
||||
onMove: (x, y) => {
|
||||
this.saturation = clamp((x / width) * 100, 0, 100);
|
||||
this.lightness = clamp(100 - (y / height) * 100, 0, 100);
|
||||
this.brightness = clamp(100 - (y / height) * 100, 0, 100);
|
||||
this.lightness = this.getLightness(this.brightness);
|
||||
|
||||
this.syncValues();
|
||||
},
|
||||
{
|
||||
initialEvent: event
|
||||
}
|
||||
);
|
||||
onStop: () => (this.isDraggingGridHandle = false),
|
||||
initialEvent: event
|
||||
});
|
||||
}
|
||||
|
||||
handleAlphaKeyDown(event: KeyboardEvent) {
|
||||
|
|
@ -384,13 +394,17 @@ export default class SlColorPicker extends LitElement {
|
|||
|
||||
if (event.key === 'ArrowUp') {
|
||||
event.preventDefault();
|
||||
this.lightness = clamp(this.lightness + increment, 0, 100);
|
||||
this.brightness = clamp(this.brightness + increment, 0, 100);
|
||||
this.lightness = this.getLightness(this.brightness);
|
||||
console.log(this.lightness, this.brightness);
|
||||
this.syncValues();
|
||||
}
|
||||
|
||||
if (event.key === 'ArrowDown') {
|
||||
event.preventDefault();
|
||||
this.lightness = clamp(this.lightness - increment, 0, 100);
|
||||
this.brightness = clamp(this.brightness - increment, 0, 100);
|
||||
this.lightness = this.getLightness(this.brightness);
|
||||
console.log(this.lightness, this.brightness);
|
||||
this.syncValues();
|
||||
}
|
||||
}
|
||||
|
|
@ -543,6 +557,7 @@ export default class SlColorPicker extends LitElement {
|
|||
this.hue = newColor.hsla.h;
|
||||
this.saturation = newColor.hsla.s;
|
||||
this.lightness = newColor.hsla.l;
|
||||
this.brightness = this.getBrightness(newColor.hsla.l);
|
||||
this.alpha = this.opacity ? newColor.hsla.a * 100 : 100;
|
||||
|
||||
this.syncValues();
|
||||
|
|
@ -623,6 +638,7 @@ export default class SlColorPicker extends LitElement {
|
|||
this.hue = newColor.hsla.h;
|
||||
this.saturation = newColor.hsla.s;
|
||||
this.lightness = newColor.hsla.l;
|
||||
this.brightness = this.getBrightness(newColor.hsla.l);
|
||||
this.alpha = newColor.hsla.a * 100;
|
||||
} else {
|
||||
this.inputValue = oldValue;
|
||||
|
|
@ -636,8 +652,8 @@ export default class SlColorPicker extends LitElement {
|
|||
}
|
||||
|
||||
render() {
|
||||
const x = this.saturation;
|
||||
const y = 100 - this.lightness;
|
||||
const gridHandleX = this.saturation;
|
||||
const gridHandleY = 100 - this.brightness;
|
||||
|
||||
const colorPicker = html`
|
||||
<div
|
||||
|
|
@ -668,10 +684,13 @@ export default class SlColorPicker extends LitElement {
|
|||
>
|
||||
<span
|
||||
part="grid-handle"
|
||||
class="color-picker__grid-handle"
|
||||
class=${classMap({
|
||||
'color-picker__grid-handle': true,
|
||||
'color-picker__grid-handle--dragging': this.isDraggingGridHandle
|
||||
})}
|
||||
style=${styleMap({
|
||||
top: `${y}%`,
|
||||
left: `${x}%`,
|
||||
top: `${gridHandleY}%`,
|
||||
left: `${gridHandleX}%`,
|
||||
backgroundColor: `hsla(${this.hue}deg, ${this.saturation}%, ${this.lightness}%)`
|
||||
})}
|
||||
role="application"
|
||||
|
|
|
|||
|
|
@ -44,15 +44,12 @@ export default class SlImageComparer extends LitElement {
|
|||
|
||||
event.preventDefault();
|
||||
|
||||
drag(
|
||||
this.base,
|
||||
x => {
|
||||
drag(this.base, {
|
||||
onMove: x => {
|
||||
this.position = parseFloat(clamp((x / width) * 100, 0, 100).toFixed(2));
|
||||
},
|
||||
{
|
||||
initialEvent: event
|
||||
}
|
||||
);
|
||||
initialEvent: event
|
||||
});
|
||||
}
|
||||
|
||||
handleKeyDown(event: KeyboardEvent) {
|
||||
|
|
|
|||
|
|
@ -108,9 +108,8 @@ export default class SlSplitPanel extends LitElement {
|
|||
// Prevent text selection when dragging
|
||||
event.preventDefault();
|
||||
|
||||
drag(
|
||||
this,
|
||||
(x, y) => {
|
||||
drag(this, {
|
||||
onMove: (x, y) => {
|
||||
let newPositionInPixels = this.vertical ? y : x;
|
||||
|
||||
// Flip for end panels
|
||||
|
|
@ -142,10 +141,8 @@ export default class SlSplitPanel extends LitElement {
|
|||
|
||||
this.position = clamp(this.pixelsToPercentage(newPositionInPixels), 0, 100);
|
||||
},
|
||||
{
|
||||
initialEvent: event
|
||||
}
|
||||
);
|
||||
initialEvent: event
|
||||
});
|
||||
}
|
||||
|
||||
handleKeyDown(event: KeyboardEvent) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
interface DragOptions {
|
||||
/** Callback that runs as dragging occurs. */
|
||||
onMove: (x: number, y: number) => void;
|
||||
/** Callback that runs when dragging stops. */
|
||||
onStop: () => void;
|
||||
/**
|
||||
* When an initial event is passed, the first drag will be triggered immediately using the coordinates therein. This
|
||||
* is useful when the drag is initiated by a mousedown/touchstart event but you want the initial "click" to activate
|
||||
|
|
@ -7,7 +11,7 @@ interface DragOptions {
|
|||
initialEvent: PointerEvent;
|
||||
}
|
||||
|
||||
export function drag(container: HTMLElement, onMove: (x: number, y: number) => void, options?: Partial<DragOptions>) {
|
||||
export function drag(container: HTMLElement, options?: Partial<DragOptions>) {
|
||||
function move(pointerEvent: PointerEvent) {
|
||||
const dims = container.getBoundingClientRect();
|
||||
const defaultView = container.ownerDocument.defaultView!;
|
||||
|
|
@ -16,12 +20,18 @@ export function drag(container: HTMLElement, onMove: (x: number, y: number) => v
|
|||
const x = pointerEvent.pageX - offsetX;
|
||||
const y = pointerEvent.pageY - offsetY;
|
||||
|
||||
onMove(x, y);
|
||||
if (options?.onMove) {
|
||||
options.onMove(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
document.removeEventListener('pointermove', move);
|
||||
document.removeEventListener('pointerup', stop);
|
||||
|
||||
if (options?.onStop) {
|
||||
options.onStop();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('pointermove', move, { passive: true });
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue