Skip to content

Commit 007cc27

Browse files
committed
refactor: enhance buildComponent function to support copying multiple folders and add FormModule for form data handling
1 parent 707ad21 commit 007cc27

File tree

5 files changed

+196
-9
lines changed

5 files changed

+196
-9
lines changed

_build_scripts/build-component.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ await init();
66
const encoder = new TextEncoder();
77
const decoder = new TextDecoder();
88

9-
export async function buildComponent(componentName: string, folder: string = "") {
9+
export async function buildComponent(componentName: string, folder: string = "", copyFolders: string[] = []) {
1010
console.log(`Building ${componentName}`);
1111

1212
if (folder.length > 0) {
@@ -15,6 +15,12 @@ export async function buildComponent(componentName: string, folder: string = "")
1515

1616
await build_src(componentName, folder);
1717
await copy_files(componentName, folder);
18+
19+
if (copyFolders.length > 0) {
20+
for (const subFolder of copyFolders) {
21+
await copyFilesToFolder(`components/${componentName}/${folder}${subFolder}`, `dist/components/${componentName}/${folder}`);
22+
}
23+
}
1824
}
1925

2026
async function build_src(componentName: string, folder: string = "") {
@@ -87,14 +93,7 @@ async function copyHTMLFiles(srcFolder: string, distFile: string) {
8793
await Deno.writeTextFile(distFile, result);
8894
}
8995

90-
export async function copyFilesToFolder(sourceDir: string, targetDir: string) {
91-
// if the targetDir does not exist, create it
92-
try {
93-
await Deno.stat(targetDir);
94-
} catch (error) {
95-
await Deno.mkdir(targetDir, { recursive: true });
96-
}
97-
96+
async function copyFilesToFolder(sourceDir: string, targetDir: string) {
9897
for await (const entry of Deno.readDir(sourceDir)) {
9998
const srcPath = `${sourceDir}/${entry.name}`;
10099
const distPath = `${targetDir}/${entry.name}`;

app/form/form.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
required>
3030
</div>
3131
<div role="toolbar">
32+
<button type="button" data-action="populate">Populate</button>
33+
<button type="button" data-action="print">Print</button>
3234
<button type="submit">Submit</button>
3335
<button type="reset">Reset</button>
3436
<button type="button" data-action="error">Error</button>

app/form/form.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import "./../../components/toast-notification/toast-notification.js";
2+
import { FormModule } from "./../../src/modules/form.js";
3+
24
export default class FormView extends HTMLElement {
35
static tag = "form-view";
46

@@ -48,6 +50,23 @@ export default class FormView extends HTMLElement {
4850
warning() {
4951
toastNotification.warning("Something not so good happened");
5052
}
53+
54+
populate() {
55+
const form = this.shadowRoot.querySelector("form");
56+
const data = {
57+
personName: "John",
58+
personAge: 20,
59+
personEmail: "[email protected]"
60+
};
61+
62+
FormModule.to({ form, data });
63+
}
64+
65+
print() {
66+
const form = this.shadowRoot.querySelector("form");
67+
const data = FormModule.from({ form });
68+
toastNotification.info(JSON.stringify(data, null, 2));
69+
}
5170
}
5271

5372
customElements.define(FormView.tag, FormView);

src/modules/form.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* FormModule provides utility methods to handle form data.
3+
*/
4+
class FormModule {
5+
static name = Object.freeze("form");
6+
7+
/**
8+
* Create a dictionary from the form elements.
9+
* @param {FormElement} args.form
10+
* @returns {Object} Dictionary of form data.
11+
*/
12+
static from(args) {
13+
const { form } = args;
14+
const data = new FormData(form);
15+
const dict = {};
16+
17+
for (const [key, value] of data.entries()) {
18+
dict[key] = value;
19+
}
20+
21+
return dict;
22+
}
23+
24+
/**
25+
* Populate form elements with data from a dictionary.
26+
* @param {FormElement} args.form
27+
* @param {Object} args.data
28+
*/
29+
static to(args) {
30+
const { form, data } = args;
31+
32+
for (const [key, value] of Object.entries(data)) {
33+
const element = form.querySelector(`[name="${key}"]`);
34+
35+
if (element) {
36+
element.value = value;
37+
}
38+
}
39+
}
40+
41+
/**
42+
* Set a specific form element's value.
43+
* @param {FormElement} args.form
44+
* @param {string} args.property
45+
* @param {string} args.value
46+
*/
47+
static set(args) {
48+
const { form, property, value } = args;
49+
const element = form.querySelector(`[name="${property}"]`);
50+
element.value = value;
51+
}
52+
53+
/**
54+
* Clear the form elements.
55+
* @param {FormElement} args.form
56+
*/
57+
static clear(args) {
58+
const { form } = args;
59+
form.reset();
60+
}
61+
62+
/**
63+
* Submit the form.
64+
* @param {FormElement} args.form
65+
*/
66+
static submit(args) {
67+
const { form } = args;
68+
form.submit();
69+
}
70+
}
71+
72+
export { FormModule };

tests/src/modules/form.test.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { assertEquals, assert } from "jsr:@std/assert";
2+
import { FormModule } from "../../../src/modules/form.js";
3+
4+
// Mocking DOM features
5+
globalThis.document = {
6+
elements: {},
7+
createElement: (tagName) => {
8+
const element = {
9+
tagName,
10+
name: "",
11+
value: "",
12+
appendChild: (child) => {
13+
globalThis.document.elements[child.name] = child;
14+
},
15+
querySelector: (selector) => {
16+
const name = selector.match(/\[name="(.+)"\]/)[1];
17+
return globalThis.document.elements[name] || { name, value: "" };
18+
},
19+
reset: () => {
20+
Object.values(globalThis.document.elements).forEach(element => {
21+
element.value = "";
22+
});
23+
},
24+
submit: () => {
25+
const event = new Event("submit", { bubbles: true, cancelable: true });
26+
form.dispatchEvent(event);
27+
}
28+
};
29+
return element;
30+
}
31+
};
32+
33+
globalThis.FormData = class {
34+
constructor(form) {
35+
this.data = form?.data || {};
36+
}
37+
append(name, value) {
38+
this.data[name] = value;
39+
}
40+
get(name) {
41+
return this.data[name];
42+
}
43+
entries() {
44+
return Object.entries(this.data);
45+
}
46+
};
47+
48+
Deno.test("FormModule.from should create a dictionary from form elements", () => {
49+
const form = new FormData();
50+
form.append("name", "John");
51+
form.append("age", "30");
52+
53+
const result = FormModule.from({ form });
54+
assertEquals(result.name, "John");
55+
assertEquals(result.age, "30");
56+
});
57+
58+
Deno.test("FormModule.to should populate form elements with data from a dictionary", () => {
59+
const form = document.createElement("form");
60+
const inputName = document.createElement("input");
61+
inputName.name = "name";
62+
form.appendChild(inputName);
63+
64+
const inputAge = document.createElement("input");
65+
inputAge.name = "age";
66+
form.appendChild(inputAge);
67+
68+
const data = { name: "John", age: "30" };
69+
FormModule.to({ form, data });
70+
71+
assertEquals(inputName.value, "John");
72+
assertEquals(inputAge.value, "30");
73+
});
74+
75+
Deno.test("FormModule.set should set a specific form element's value", () => {
76+
const form = document.createElement("form");
77+
const inputName = document.createElement("input");
78+
inputName.name = "name";
79+
form.appendChild(inputName);
80+
81+
FormModule.set({ form, property: "name", value: "John" });
82+
assertEquals(inputName.value, "John");
83+
});
84+
85+
Deno.test("FormModule.clear should clear the form elements", () => {
86+
const form = document.createElement("form");
87+
const inputName = document.createElement("input");
88+
inputName.name = "name";
89+
inputName.value = "John";
90+
form.appendChild(inputName);
91+
92+
FormModule.clear({ form });
93+
assertEquals(inputName.value, "");
94+
});
95+

0 commit comments

Comments
 (0)