Skip to content

Commit e74728c

Browse files
committed
enclose click handlers to variant button
this reduces the code which handles variants panel and co-locates the functionality inside of the class
1 parent 48f9621 commit e74728c

File tree

8 files changed

+172
-130
lines changed

8 files changed

+172
-130
lines changed

css/panel.css

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,16 @@
4040
.panel-row ui-button,
4141
.panel-row color-button,
4242
.panel-row tool-button,
43-
.panel-row variant-button {
43+
.panel-row variant-button,
44+
.panel-row variant-stamp-button {
4445
margin-right: var(--button-space);
4546
}
4647

4748
.panel-row ui-button:last-child,
4849
.panel-row color-button:last-child,
4950
.panel-row tool-button:last-child,
50-
.panel-row variant-button:last-child {
51+
.panel-row variant-button:last-child,
52+
.panel-row variant-stamp-button:last-child {
5153
margin-right: 0px;
5254
}
5355

js/boot.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ import { initializeCursor } from "./cursor.mjs";
2525
import { ColorButton } from "./ui/color.mjs";
2626
import { ToolButton } from "./ui/tool.mjs";
2727
import { VariantButton } from "./ui/variant.mjs";
28+
import { VariantStampButton } from "./ui/variant-stamp.mjs";
2829
import { UiButton } from "./ui/button.mjs";
2930

3031
function registerComponents() {
3132
customElements.define("ui-button", UiButton);
3233
customElements.define("color-button", ColorButton);
3334
customElements.define("tool-button", ToolButton);
3435
customElements.define("variant-button", VariantButton);
36+
customElements.define("variant-stamp-button", VariantStampButton);
3537
}
3638

3739
function attachResizeListeners() {

js/dom.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ export function getPanelToolVariants() {
2525
}
2626

2727
export function getVariantButtons() {
28-
return getPanelToolVariants().querySelectorAll("variant-button");
28+
return getPanelToolVariants().querySelectorAll(
29+
"variant-button,variant-stamp-button",
30+
);
2931
}
3032

3133
export function getVariantButtonById(id) {

js/ui/button.mjs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ export class UiButton extends HTMLElement {
3535

3636
#isActive = false;
3737
#id = "";
38+
#iconUrl = null;
3839
#ariaLabel = "";
3940
#dataset = {};
40-
#iconUrl = "";
4141
#backgroundColor = "#000000";
4242
#onClick = () => {};
4343
#signal = null;
@@ -74,8 +74,19 @@ export class UiButton extends HTMLElement {
7474
if (this.#onClick) {
7575
this.addClickListener(this.#onClick);
7676
}
77+
this.iconUrl = this.#iconUrl || this.getAttribute("icon-url");
7778
this.isActive = false;
78-
this.#setContents();
79+
}
80+
81+
attributeChangedCallback(name, oldValue, newValue) {
82+
switch (name) {
83+
case "icon-url":
84+
if (oldValue === newValue) {
85+
break;
86+
}
87+
this.iconUrl = newValue;
88+
break;
89+
}
7990
}
8091

8192
click(e) {
@@ -105,18 +116,17 @@ export class UiButton extends HTMLElement {
105116
return this.#isActive;
106117
}
107118

108-
#setContents() {
109-
const iconUrl = this.#iconUrl ?? this.getAttribute("icon-url");
110-
const dataset = this.#dataset ?? this.dataset;
111-
112-
if (!iconUrl) {
119+
set iconUrl(value) {
120+
if (!value) {
113121
return;
114122
}
115123

116-
if (isDataUri(iconUrl)) {
117-
this.button.innerHTML = serializeSvg(deserializeSvgFromDataURI(iconUrl));
124+
const dataset = this.#dataset ?? this.dataset;
125+
126+
if (isDataUri(value)) {
127+
this.button.innerHTML = serializeSvg(deserializeSvgFromDataURI(value));
118128
} else {
119-
loadIcon(iconUrl)
129+
loadIcon(value)
120130
.then((icon) => {
121131
this.button.innerHTML = icon;
122132
})
@@ -127,6 +137,8 @@ export class UiButton extends HTMLElement {
127137
}
128138
}
129139

140+
static observedAttributes = ["icon-url"];
141+
130142
static #createDataSetAttributesString(dataset) {
131143
return Object.entries(dataset ?? {})
132144
.map(([key, value]) => `data-${key}="${value}"`)

js/ui/panel.mjs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import { isCursorWithinPanelBounds } from "./utils.mjs";
77
import { ColorButton } from "./color.mjs";
88
import { ToolButton } from "./tool.mjs";
99
import { VariantButton } from "./variant.mjs";
10+
import { VariantStampButton } from "./variant-stamp.mjs";
1011
import { UiButton } from "./button.mjs";
1112

1213
function getPanelButtonByCoordinates(x, y, panel) {
1314
const buttons = panel.querySelectorAll(
14-
"ui-button,color-button,tool-button,variant-button",
15+
"ui-button,color-button,tool-button,variant-button,variant-stamp-button",
1516
);
1617

1718
for (let i = 0; i < buttons.length; i++) {
@@ -53,7 +54,9 @@ function activatePanelButtonOnCoordinates(x, y) {
5354
button instanceof UiButton ||
5455
button instanceof ColorButton ||
5556
button instanceof ToolButton ||
56-
button instanceof VariantButton
57+
button instanceof VariantButton ||
58+
// TODO should be enough to inherit from VariantButton or even UiButton
59+
button instanceof VariantStampButton
5760
) {
5861
button.click(clickEvent);
5962

js/ui/variant-stamp.mjs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { setCustomVariant, setTool } from "../state/actions/tool.mjs";
2+
import { VariantButton } from "./variant.mjs";
3+
4+
import {
5+
createSvgDataUri,
6+
serializeSvg,
7+
deserializeSvgFromDataURI,
8+
normalizeSvgSize,
9+
} from "../svg-utils.mjs";
10+
11+
export class VariantStampButton extends VariantButton {
12+
constructor(options) {
13+
super(options);
14+
15+
const { variant, tool, state } = options;
16+
this.#variant = variant;
17+
this.#tool = tool;
18+
this.#state = state;
19+
}
20+
21+
#variant = null;
22+
#tool = null;
23+
#state = null;
24+
25+
connectedCallback() {
26+
super.connectedCallback();
27+
}
28+
29+
click = () => {
30+
if (this.#variant.value) {
31+
setTool(this.#tool, { state: this.#state, variant: this.#variant });
32+
return;
33+
}
34+
35+
const fileInput = document.createElement("input");
36+
fileInput.type = "file";
37+
fileInput.accept = "image/svg+xml";
38+
fileInput.style.display = "none";
39+
40+
const handleFileUpload = (event) => {
41+
this.#readUploadedSVG(event, fileInput);
42+
};
43+
44+
fileInput.addEventListener("stamp-custom-slot-success", (event) => {
45+
fileInput.removeEventListener("change", handleFileUpload);
46+
fileInput.remove();
47+
48+
const updatedVariant = {
49+
...this.#variant,
50+
iconUrl: event.detail.iconDataUri,
51+
value: event.detail.dataUri,
52+
};
53+
setTool(this.#tool, { state: this.#state, variant: updatedVariant });
54+
setCustomVariant(this.#tool, updatedVariant, { state: this.#state });
55+
this.#variant = updatedVariant;
56+
super.uiButton.setAttribute("icon-url", event.detail.iconDataUri);
57+
});
58+
fileInput.addEventListener("stamp-custom-slot-failure", () => {
59+
alert("Something went wrong with uploading the image!");
60+
});
61+
fileInput.addEventListener("change", handleFileUpload);
62+
63+
fileInput.click();
64+
};
65+
66+
#readUploadedSVG = (event, fileInput) => {
67+
const file = event.target.files[0];
68+
const failureEvent = new CustomEvent("stamp-custom-slot-failure");
69+
70+
if (!file) {
71+
fileInput.dispatchEvent(failureEvent);
72+
throw new Error("No file selected!");
73+
}
74+
75+
const fileReader = new FileReader();
76+
fileReader.addEventListener("load", (fileEvent) => {
77+
const parsedSvgElement = deserializeSvgFromDataURI(
78+
fileEvent.srcElement.result,
79+
);
80+
const iconSvgDocument = parsedSvgElement.documentElement.cloneNode(true);
81+
const stampSvgDocument = parsedSvgElement.documentElement.cloneNode(true);
82+
const iconSvgElement = normalizeSvgSize(iconSvgDocument);
83+
const stampSvgElement = normalizeSvgSize(stampSvgDocument, 50);
84+
85+
fileInput.dispatchEvent(
86+
new CustomEvent("stamp-custom-slot-success", {
87+
detail: {
88+
iconDataUri: createSvgDataUri(serializeSvg(iconSvgElement)),
89+
dataUri: createSvgDataUri(serializeSvg(stampSvgElement)),
90+
},
91+
}),
92+
);
93+
});
94+
fileReader.addEventListener("error", () => {
95+
fileInput.dispatchEvent(failureEvent);
96+
});
97+
98+
fileReader.readAsDataURL(file);
99+
};
100+
101+
static compare(id, value) {
102+
return VariantButton.compare(id, value);
103+
}
104+
}

js/ui/variant.mjs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import { UiButton } from "./button.mjs";
2+
import { setTool } from "../state/actions/tool.mjs";
23

34
export class VariantButton extends HTMLElement {
4-
constructor({ id, onClick, iconUrl, signal, isActive }) {
5+
constructor({ id, iconUrl, signal, isActive, tool, state, variant }) {
56
super();
67

78
this.#isActive = isActive;
89
this.id = id;
9-
this.#onClick = onClick;
10+
this.#tool = tool;
11+
this.#state = state;
12+
this.#variant = variant;
1013
this.#iconUrl = iconUrl;
1114
this.#signal = signal;
1215

@@ -15,9 +18,11 @@ export class VariantButton extends HTMLElement {
1518

1619
#isActive = false;
1720
id = "";
18-
#onClick = () => {};
1921
#iconUrl = "";
2022
#signal = null;
23+
#tool = null;
24+
#state = null;
25+
#variant = null;
2126

2227
connectedCallback() {
2328
const button = new UiButton({
@@ -26,24 +31,24 @@ export class VariantButton extends HTMLElement {
2631
value: this.id.description,
2732
},
2833
iconUrl: this.#iconUrl,
29-
onClick: this.#onClick,
34+
onClick: this.click,
3035
signal: this.#signal,
3136
});
3237

3338
this.shadowRoot.appendChild(button);
3439
this.isActive = this.#isActive;
3540
}
3641

37-
click(e) {
38-
this.#button.click(e);
39-
}
42+
click = () => {
43+
setTool(this.#tool, { state: this.#state, variant: this.#variant });
44+
};
4045

41-
get #button() {
46+
get button() {
4247
return this.shadowRoot.querySelector("ui-button").button;
4348
}
4449

45-
get button() {
46-
return this.#button;
50+
get uiButton() {
51+
return this.shadowRoot.querySelector("ui-button");
4752
}
4853

4954
set isActive(value) {

0 commit comments

Comments
 (0)