Skip to content

Commit

Permalink
Added drag area component
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-harding committed Oct 6, 2024
1 parent 5a3e752 commit fcab9b3
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 59 deletions.
35 changes: 19 additions & 16 deletions demo/assets/css/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,30 @@ body {
align-items: stretch;
}

.th-squircle {
th-squircle {
contain: strict;
}

.tester {
}

.tester__squircle {
}

.tester__controls {
}

.tester-corner {
}

.tester-control {
th-tester {
background-color: lightgray;
display: grid;
grid-template-rows: 1fr min-content;
grid-template-areas: "drag-area" "controls";
}

.tester-control__label {
th-drag-area {
position: relative;
grid-area: "drag-area";
background-color: gray;
}

.tester-control__input {
th-corner {
position: absolute;
display: grid;
width: 1.5rem;
height: 1.5rem;
background-color: blue;
opacity: 20%;
border-radius: 50%;
transform: translateX(-50%) translateY(-50%);
}
7 changes: 4 additions & 3 deletions demo/assets/js/demo.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Tester, Corner, Control } from "./tester.js";
import { Tester, Corner, Control, DragArea } from "./tester.js";

const IS_PAINT_SUPPORTED = CSS.supports("background", "paint(id)");

function main() {
loadSquircleComponent();
loadPaintWorklet();
customElements.define("th-tester", Tester);
customElements.define("th-tester-corner", Corner);
customElements.define("th-tester-control", Control);
customElements.define("th-drag-area", DragArea);
customElements.define("th-corner", Corner);
customElements.define("th-control", Control);
}

async function loadPaintWorklet() {
Expand Down
91 changes: 78 additions & 13 deletions demo/assets/js/tester.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* @typedef {"top-left" | "bottom-right"} Position
* @typedef {{ x: number, y: number, position: Position }} CornerEventProps
* @typedef {"top-left" | "bottom-right"} Side
* @typedef {{ x: number, y: number, side: Side }} CornerEventProps
* @typedef {CustomEvent<CornerEventProps>} CornerEvent
*
* @typedef {{ value: string, aspect: string }} ControlEventProps
Expand All @@ -11,38 +11,91 @@ export class Tester extends HTMLElement {
/** @type {HTMLElement?} */
_squircle = null;

constructor() {
super();
}

connectedCallback() {
this._squircle = this.querySelector("th-squircle");
}
}

const SIDE_OFFSET = 32;

export class DragArea extends HTMLElement {
_l = SIDE_OFFSET;
_r = 0;
_t = SIDE_OFFSET;
_b = 0;
/** @type {HTMLElement?} */
_squircle = null;

constructor() {
super();
const listen = listenPassive.bind(this);
listen("th-tester-corner", this._handleCorner);
listen("th-tester-control", this._handleControl);
listen("th-corner__update", this._handleCornerUpdate);
listen("th-corner__register", this._handleCornerRegister);
listen("th-control__change", this._handleControlChange);
}

connectedCallback() {
this._squircle = this.querySelector("th-squircle");
}

/**
* @param {CustomEvent} event
*/
_handleCornerRegister(event) {
const corner = event.target;
if (!(corner instanceof Corner)) {
console.warn("Expected a corner element");
return;
}

switch (corner._side) {
case "top-left": {
corner.setAttribute("y", `${this._t}px`);
corner.setAttribute("x", `${this._l}px`);
break;
}

case "bottom-right": {
const { clientWidth: w, clientHeight: h } = this;
this._r = w - SIDE_OFFSET;
this._b = h - SIDE_OFFSET;
corner.setAttribute("y", `${this._b}px`);
corner.setAttribute("x", `${this._r}px`);
break;
}

default: {
console.warn(`Unexpected corner side: ${corner._side}`);
break;
}
}
}

/**
* @param {CornerEvent} event
*/
_handleCorner(event) {
_handleCornerUpdate(event) {
console.log(event);
}

/**
* @param {ControlEvent} event
*/
_handleControl(event) {
_handleControlChange(event) {
console.log(event);
}
}

export class Corner extends HTMLElement {
_isPressed = false;
_position = "";
_side = "";

static get observedAttributes() {
return ["position"];
return ["side", "x", "y"];
}

constructor() {
Expand All @@ -60,8 +113,20 @@ export class Corner extends HTMLElement {
*/
attributeChangedCallback(name, _, newValue) {
switch (name) {
case "position": {
this._position = newValue;
case "side": {
this._side = newValue;
const event = new CustomEvent("th-corner__register", { bubbles: true });
this.dispatchEvent(event);
break;
}

case "x": {
this.style.left = newValue;
break;
}

case "y": {
this.style.top = newValue;
break;
}
}
Expand All @@ -81,8 +146,8 @@ export class Corner extends HTMLElement {
_handleMouseMove(mouseEvent) {
if (!this._isPressed) return;
const { movementX: x, movementY: y } = mouseEvent;
const event = new CustomEvent("th-tester-corner", {
detail: { x, y, position: this._position },
const event = new CustomEvent("th-corner__update", {
detail: { x, y, side: this._side },
bubbles: true,
});
this.dispatchEvent(event);
Expand Down Expand Up @@ -132,7 +197,7 @@ export class Control extends HTMLElement {
const target = inputEvent.target;
if (!(target instanceof HTMLInputElement)) return;
const value = target.value;
const event = new CustomEvent("th-tester-control", {
const event = new CustomEvent("th-control__change", {
detail: { value, aspect: this._aspect },
bubbles: true,
});
Expand Down
44 changes: 17 additions & 27 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,33 +33,23 @@
</head>

<body class="poppins-regular">
<th-tester class="tester">
<th-tester-corner class="tester__corner"></th-tester-corner>
<th-tester-corner class="tester__corner"></th-tester-corner>
<th-squircle class="tester__squircle"></th-squircle>

<form class="tester__controls">
<th-tester-control class="tester-control">
<label class="tester-control__label" for="tester-input-radius"
>Radius</label
>
<input
class="tester-control__input"
id="tester-input-radius"
type="range"
/>
</th-tester-control>

<th-tester-control class="tester-control">
<label class="tester-control__label" for="tester-input-fill"
>Fill</label
>
<input
class="tester-control__input"
id="tester-input-fill"
type="color"
/>
</th-tester-control>
<th-tester>
<th-drag-area>
<th-corner side="top-left"></th-corner>
<th-corner side="bottom-right"></th-corner>
<th-squircle></th-squircle>
</th-drag-area>

<form>
<th-control aspect="radius">
<label for="tester-input-radius">Radius</label>
<input id="tester-input-radius" type="range" />
</th-control>

<th-control aspect="fill">
<label for="tester-input-fill">Fill</label>
<input id="tester-input-fill" type="color" />
</th-control>
</form>
</th-tester>
</body>
Expand Down

0 comments on commit fcab9b3

Please sign in to comment.