ranui
Version:
A framework-agnostic Web Components UI library built on native custom elements, with TypeScript types, light/dark theming, SSR and PWA support.
106 lines (105 loc) • 5.95 kB
JavaScript
import { _ as n, i as r, p as o } from "./factory-WDxu11V0.js";
import { t as d } from "./events-Cqz3ramM.js";
import "./builder-EH76YCFS.js";
import { i as l, l as u, n as b, o as p, t as k } from "./utils-U-9uH7EX.js";
import { a as v, n as g } from "./ssr-BzykYefm.js";
var w = ":host{position:relative;display:block;--ran-scratch-cover-background: var(--ran-color-text-secondary, #6b6b6b)}:host([hidden]){display:none}:host([disabled]){cursor:var(--ran-scratch-disabled-cursor, not-allowed);opacity:var(--ran-scratch-disabled-opacity, .6)}:host([disabled]) .ran-scratch-ticket-canvas{pointer-events:none}.ran-scratch-ticket{position:relative;display:block;width:100%;height:100%}.ran-scratch-ticket-award{position:absolute;top:0;left:0;display:block;width:100%;height:100%;background:var(--ran-scratch-award-background, var(--ran-color-bg-elevated, #fff));z-index:1}.ran-scratch-ticket-canvas{position:absolute;top:0;left:0;display:block;width:100%;height:100%;z-index:2;cursor:var(--ran-scratch-cursor, pointer);touch-action:none;-webkit-tap-highlight-color:transparent}", T = 0.35, f = class extends g {
scratchTicketContainer;
scratchTicket;
state;
scratchAward;
_shadowDom;
_events = new d();
static get observedAttributes() {
return ["disabled", "sheet"];
}
constructor() {
super(), this._shadowDom = k(this, w);
const t = n("canvas").class("ran-scratch-ticket-canvas").style("width", "100%").style("height", "100%").build(), e = r().class("ran-scratch-ticket-award").part("award").children(o()).build(), i = r().class("ran-scratch-ticket").children(t, e).build();
this._shadowDom.appendChild(i), this.scratchTicketContainer = i, this.scratchAward = e, this.scratchTicket = t, this.state = {
isScratching: !1,
scratchedArea: 0,
lastX: 0,
lastY: 0,
activePointerId: void 0
};
}
get disabled() {
return u(this);
}
set disabled(t) {
t ? this.setAttribute("disabled", "") : this.removeAttribute("disabled");
}
get sheet() {
return b(this, "sheet");
}
set sheet(t) {
l(this, "sheet", t);
}
handlerExternalCss = () => {
p(this, this._shadowDom, "sheet", null, this.sheet);
};
syncDisabled = () => {
this.setAttribute("aria-disabled", this.disabled ? "true" : "false");
};
brushRadius = () => Math.max(14, Math.min(this.scratchTicket.width, this.scratchTicket.height) * 0.09);
toCanvasPoint = (t, e) => {
const i = this.scratchTicket.getBoundingClientRect(), s = i.width > 0 ? this.scratchTicket.width / i.width : 1, a = i.height > 0 ? this.scratchTicket.height / i.height : 1;
return {
x: (t - i.left) * s,
y: (e - i.top) * a
};
};
scratchStroke = (t, e, i, s) => {
const a = this.scratchTicket.getContext("2d");
if (!a) return;
const c = this.brushRadius();
a.globalCompositeOperation = "destination-out", a.lineCap = "round", a.lineJoin = "round", a.lineWidth = c * 2, a.beginPath(), a.moveTo(t, e), a.lineTo(i, s), a.stroke();
const h = Math.max(Math.hypot(i - t, s - e), 1);
this.state.scratchedArea += h * c * 2;
};
onScratchPointerDown = (t) => {
if (this.disabled || this.state.isScratching || t.pointerType === "mouse" && t.button !== 0) return;
t.preventDefault(), this.state.isScratching = !0, this.state.activePointerId = t.pointerId, this.scratchTicket.setPointerCapture?.(t.pointerId);
const { x: e, y: i } = this.toCanvasPoint(t.clientX, t.clientY);
this.state.lastX = e, this.state.lastY = i, this.scratchStroke(e, i, e, i);
};
onScratchPointerMove = (t) => {
if (this.disabled || !this.state.isScratching || t.pointerId !== this.state.activePointerId) return;
const { x: e, y: i } = this.toCanvasPoint(t.clientX, t.clientY);
this.scratchStroke(this.state.lastX, this.state.lastY, e, i), this.state.lastX = e, this.state.lastY = i;
};
onScratchPointerUp = (t) => {
if (t.pointerId !== this.state.activePointerId || (this.state.isScratching = !1, this.state.activePointerId = void 0, this.disabled)) return;
const { width: e, height: i } = this.scratchTicket, s = this.scratchTicket.getContext("2d");
s && this.state.scratchedArea > e * i * T && (this.state.scratchedArea = 0, s.clearRect(0, 0, e, i));
};
drawScratchTicket = () => {
const t = this.scratchTicket.getContext("2d");
if (!this.scratchTicketContainer || !t) return;
const { width: e, height: i } = this.scratchTicket, s = getComputedStyle(this).getPropertyValue("--ran-scratch-cover-background").trim();
t.globalCompositeOperation = "source-over", t.fillStyle = s || "#6b6b6b", t.fillRect(0, 0, e, i);
};
syncCanvasResolution = () => {
const t = this.scratchTicketContainer.getBoundingClientRect();
if (t.width <= 0 || t.height <= 0) return;
const e = window.devicePixelRatio || 1, i = Math.max(1, Math.round(t.width * e)), s = Math.max(1, Math.round(t.height * e));
this.scratchTicket.width === i && this.scratchTicket.height === s || (this.scratchTicket.width = i, this.scratchTicket.height = s, this.state.scratchedArea = 0, this.drawScratchTicket());
};
onWindowResize = () => {
this.syncCanvasResolution();
};
connectedCallback() {
this.handlerExternalCss(), this.syncDisabled(), this._events.on(this.scratchTicket, "pointerdown", this.onScratchPointerDown, { passive: !1 }).on(this.scratchTicket, "pointermove", this.onScratchPointerMove).on(this.scratchTicket, "pointerup", this.onScratchPointerUp).on(this.scratchTicket, "pointercancel", this.onScratchPointerUp).on(this.scratchTicket, "lostpointercapture", this.onScratchPointerUp).on(window, "resize", this.onWindowResize), this.syncCanvasResolution();
}
disconnectedCallback() {
this._events.abort();
}
attributeChangedCallback(t, e, i) {
e !== i && (t === "disabled" && this.syncDisabled(), t === "sheet" && this.handlerExternalCss(), this.drawScratchTicket());
}
};
v("r-scratch", f);
export {
f as t
};