diff --git a/examples/counter/app.js b/examples/counter/app.js index ba96ea8..385a309 100644 --- a/examples/counter/app.js +++ b/examples/counter/app.js @@ -1,12 +1,17 @@ -import { getInputId, refocus, reset, focusBlurListeners } from '../../src/gui.js'; -import { buildApp, div, p } from '../../src/html.js'; +import { + getInputId, + refocus, + reset, + focusBlurListeners, +} from "../../src/gui.js"; +import { buildApp, div, p } from "../../src/html.js"; -import { logger } from '../helpers/logger.js'; +import { logger } from "../helpers/logger.js"; -import { counterButtonBuilder } from './components/counter-button.js'; -import { resetButtonBuilder } from './components/reset-button.js'; -import { incrementTextInputBuilder } from './components/increment-text.js'; -import { debugCheckboxBuilder } from './components/debug-checkbox.js'; +import { counterButtonBuilder } from "./components/counter-button.js"; +import { resetButtonBuilder } from "./components/reset-button.js"; +import { incrementTextInputBuilder } from "./components/increment-text.js"; +import { debugCheckboxBuilder } from "./components/debug-checkbox.js"; const appId = "counter-app"; @@ -28,15 +33,15 @@ focusBlurListeners({ state, log }); async function loop() { log("loop", state.loopCounter++); - const app = buildApp({ + const app = buildApp({ appId, - classList: "w-52 mx-auto py-6" + classList: "w-52 mx-auto py-6", }); const resetFn = () => reset({ app, state, log }); - + const appContext = { loop, resetFn, getInputIdFn, log }; - + const counterButton = counterButtonBuilder(appContext); const resetButton = resetButtonBuilder(appContext); const incrementTextInput = incrementTextInputBuilder(appContext); @@ -47,27 +52,34 @@ async function loop() { if (!isCounterDisabled(state.counterValue)) { state.counterValue = state.counterValue + state.incrementValue; } - + return state.counterValue; - } + }; const htmlElements = [ div({ description: "Container for counter and reset buttons", - classList: "flex justify-between items-center mb-4", + classList: "flex justify-between items-center mb-4", children: [ - counterButton(state.counterValue, counterUpdate, isCounterDisabled(state.counterValue)), - resetButton(() => { + counterButton( + state.counterValue, + counterUpdate, + isCounterDisabled(state.counterValue), + ), + resetButton(() => { state.counterValue = 0; return state.counterValue; - }) - ] + }), + ], }), div({ description: "Container for increment number input and its label", classList: "flex items-center justify-between mb-4", - children: incrementTextInput(state.incrementValue, (newVal) => state.incrementValue = newVal) + children: incrementTextInput( + state.incrementValue, + (newVal) => (state.incrementValue = newVal), + ), }), div({ description: "Container for debug checkbox and its label", @@ -76,25 +88,26 @@ async function loop() { state.debug = newChecked; return state.debug; - }) + }), }), div({ description: "Container for counter limit warning text", classList: "flex items-center mb-4", - children: state.counterValue >= 5 - ? [ - state.counterValue === 8 - ? p({ - classList: "text-blue-500 text-xl", - text: "Congrats, you reached the maximum count possible!" - }) - : p({ - classList: "text-red-500 text-xl", - text: "You reached your counter limit. Please reset" - }) - ] - : [] - }) + children: + state.counterValue >= 5 + ? [ + state.counterValue === 8 + ? p({ + classList: "text-blue-500 text-xl", + text: "Congrats, you reached the maximum count possible!", + }) + : p({ + classList: "text-red-500 text-xl", + text: "You reached your counter limit. Please reset", + }), + ] + : [], + }), ]; htmlElements.forEach((el) => app.appendChild(el)); diff --git a/examples/counter/components/counter-button.js b/examples/counter/components/counter-button.js index 4af7601..99e9828 100644 --- a/examples/counter/components/counter-button.js +++ b/examples/counter/components/counter-button.js @@ -1,24 +1,24 @@ - export const counterButtonBuilder = ({ loop, resetFn, log, getInputIdFn }) => { return (val, updateFn, disabled) => { const button = document.createElement("button"); - + button.id = getInputIdFn(); - button.classList = "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"; + button.classList = + "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"; button.disabled = disabled; button.textContent = val; - + button.addEventListener("click", () => { const newVal = updateFn(); log("new counter", newVal); - + resetFn(); - + requestAnimationFrame(loop); }); - + return button; - } -} + }; +}; diff --git a/examples/counter/components/debug-checkbox.js b/examples/counter/components/debug-checkbox.js index f8a889b..f3d7c7d 100644 --- a/examples/counter/components/debug-checkbox.js +++ b/examples/counter/components/debug-checkbox.js @@ -2,28 +2,28 @@ import { labelFor } from "../../../src/html.js"; export const debugCheckboxBuilder = ({ loop, log, resetFn, getInputIdFn }) => { return (checked, updateFn) => { - const checkbox = document.createElement('input'); + const checkbox = document.createElement("input"); - checkbox.type = 'checkbox'; + checkbox.type = "checkbox"; checkbox.id = getInputIdFn(); checkbox.classList = "h-5 w-5 text-blue-600"; checkbox.checked = checked; - checkbox.addEventListener("change", (event) => { + checkbox.addEventListener("change", (event) => { const newVal = updateFn(event.target.checked); log("debug is", newVal); - + resetFn(); - + requestAnimationFrame(loop); }); - return labelFor({ - input: checkbox, - classList: "text-sm font-medium text-gray-900 mr-2", - text: "Debug Logs" + return labelFor({ + input: checkbox, + classList: "text-sm font-medium text-gray-900 mr-2", + text: "Debug Logs", }); - } -} \ No newline at end of file + }; +}; diff --git a/examples/counter/components/increment-text.js b/examples/counter/components/increment-text.js index 4a735c9..5f7c4ea 100644 --- a/examples/counter/components/increment-text.js +++ b/examples/counter/components/increment-text.js @@ -1,33 +1,39 @@ import { labelFor } from "../../../src/html.js"; -export const incrementTextInputBuilder = ({ loop, log, resetFn, getInputIdFn }) => { +export const incrementTextInputBuilder = ({ + loop, + log, + resetFn, + getInputIdFn, +}) => { return (initVal, updateFn) => { - const numberInput = document.createElement('input'); - + const numberInput = document.createElement("input"); + numberInput.id = getInputIdFn(); - numberInput.type = 'number'; - - numberInput.min = '1'; - numberInput.max = '5'; - - numberInput.classList = "px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"; - numberInput.style = "width: auto;" + numberInput.type = "number"; + + numberInput.min = "1"; + numberInput.max = "5"; + + numberInput.classList = + "px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"; + numberInput.style = "width: auto;"; numberInput.value = initVal; numberInput.addEventListener("change", (event) => { const currentVal = event.target.value; - const newVal = updateFn(parseInt(currentVal)) + const newVal = updateFn(parseInt(currentVal)); log("increment set to", newVal); - - resetFn(); + + resetFn(); requestAnimationFrame(loop); }); - return labelFor({ - input: numberInput, - classList: "text-sm font-medium text-gray-700 mr-3", - text: "Increment Value" + return labelFor({ + input: numberInput, + classList: "text-sm font-medium text-gray-700 mr-3", + text: "Increment Value", }); - } -} + }; +}; diff --git a/examples/counter/components/reset-button.js b/examples/counter/components/reset-button.js index 27e91d4..b42d4ca 100644 --- a/examples/counter/components/reset-button.js +++ b/examples/counter/components/reset-button.js @@ -1,22 +1,22 @@ - export const resetButtonBuilder = ({ loop, log, resetFn, getInputIdFn }) => { return (updateFn) => { let button = document.createElement("button"); button.id = getInputIdFn(); - button.classList = "bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-1 px-3 rounded"; + button.classList = + "bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-1 px-3 rounded"; button.textContent = "Reset Counter"; - + button.addEventListener("click", () => { const newVal = updateFn(); - + log("reset counter to", newVal); - + resetFn(); - + requestAnimationFrame(loop); }); - + return button; - } -} + }; +}; diff --git a/examples/helpers/logger.js b/examples/helpers/logger.js index 9132a2a..6047008 100644 --- a/examples/helpers/logger.js +++ b/examples/helpers/logger.js @@ -3,5 +3,5 @@ export function logger({ state }) { if (state.debug) { console.log(...text); } - } + }; } diff --git a/examples/todo/app.js b/examples/todo/app.js index 37cdba3..71c8c14 100644 --- a/examples/todo/app.js +++ b/examples/todo/app.js @@ -1,13 +1,18 @@ -import { getInputId, refocus, reset, focusBlurListeners } from '../../src/gui.js'; -import { buildApp, div, h1, p } from '../../src/html.js'; +import { + getInputId, + refocus, + reset, + focusBlurListeners, +} from "../../src/gui.js"; +import { buildApp, div, h1, p } from "../../src/html.js"; -import { logger } from '../helpers/logger.js'; +import { logger } from "../helpers/logger.js"; -import { inputTextBuilder } from './components/input-text.js'; -import { addButtonBuilder } from './components/add-button.js'; -import { doneToggleButtonBuilder } from './components/done-button.js'; -import { removeButtonBuilder } from './components/remove-button.js'; -import { debugCheckboxBuilder } from './components/debug-checkbox.js'; +import { inputTextBuilder } from "./components/input-text.js"; +import { addButtonBuilder } from "./components/add-button.js"; +import { doneToggleButtonBuilder } from "./components/done-button.js"; +import { removeButtonBuilder } from "./components/remove-button.js"; +import { debugCheckboxBuilder } from "./components/debug-checkbox.js"; const appId = "todo-app"; @@ -18,12 +23,13 @@ const state = { focusedElementId: null, isResetting: false, inputText: "", - todoItems: [] + todoItems: [], }; const log = logger({ state }); const getInputIdFn = () => getInputId({ state, appId }); -const buttonClassList = "py-2 px-3 mr-3 bg-cyan-500 hover:bg-cyan-600 text-white text-sm font-semibold rounded-md shadow focus:outline-none"; +const buttonClassList = + "py-2 px-3 mr-3 bg-cyan-500 hover:bg-cyan-600 text-white text-sm font-semibold rounded-md shadow focus:outline-none"; focusBlurListeners({ state, log }); @@ -33,10 +39,11 @@ async function loop() { } log("loop", state.loopCounter++); - - const app = buildApp({ + + const app = buildApp({ appId, - classList: "h-100 w-full flex items-center justify-center bg-teal-lightest font-sans" + classList: + "h-100 w-full flex items-center justify-center bg-teal-lightest font-sans", }); const resetFn = () => reset({ app, state, log }); @@ -58,55 +65,60 @@ async function loop() { children: [ h1({ classList: "text-grey-darkest", - text: "Todo List" + text: "Todo List", }), div({ classList: "flex mt-4", children: [ inputText({ description: "Add Todo Textbox", - value: state.inputText, - updateFn: (newVal) => state.inputText = newVal, + value: state.inputText, + updateFn: (newVal) => (state.inputText = newVal), addTodoFn: (newVal) => { state.todoItems.push({ title: newVal, done: false }); - + state.inputText = ""; - } + }, }), addButton({ updateFn: () => { if (state.inputText) { - state.todoItems.push({ title: state.inputText, done: false }) - + state.todoItems.push({ + title: state.inputText, + done: false, + }); + state.inputText = ""; } - } - }) - ] - }) - ] + }, + }), + ], + }), + ], }), - div({ - children: state.todoItems.map((item, i) => + div({ + children: state.todoItems.map((item, i) => div({ classList: "flex mb-4 items-center", children: [ p({ - classList: "w-full text-grey-darkest" + (item.done ? " line-through" : ""), - text: item.title + classList: + "w-full text-grey-darkest" + + (item.done ? " line-through" : ""), + text: item.title, }), - doneToggleButton(item.done, () => item.done = !item.done), - removeButton(() => state.todoItems.splice(i, 1)) - ] - }) - ) + doneToggleButton(item.done, () => (item.done = !item.done)), + removeButton(() => state.todoItems.splice(i, 1)), + ], + }), + ), }), div({ classList: "flex items-center pt-8", - children: debugCheckbox(state.debug, (val) => state.debug = val) - }) - ] - }) + children: debugCheckbox(state.debug, (val) => (state.debug = val)), + }), + ], + }), ]; htmlElements.forEach((el) => app.appendChild(el)); @@ -114,4 +126,4 @@ async function loop() { refocus({ app, state, log }); } -requestAnimationFrame(loop); \ No newline at end of file +requestAnimationFrame(loop); diff --git a/examples/todo/components/add-button.js b/examples/todo/components/add-button.js index d9e8561..1cdc64d 100644 --- a/examples/todo/components/add-button.js +++ b/examples/todo/components/add-button.js @@ -1,6 +1,9 @@ -export const addButtonBuilder = ({ loop, resetFn, log, getInputIdFn }, classList) => { - return ({ updateFn, desciption }) => { - const button = document.createElement('button'); +export const addButtonBuilder = ( + { loop, resetFn, log, getInputIdFn }, + classList, +) => { + return ({ updateFn }) => { + const button = document.createElement("button"); button.id = getInputIdFn(); button.classList = classList; button.textContent = "Add"; @@ -9,12 +12,12 @@ export const addButtonBuilder = ({ loop, resetFn, log, getInputIdFn }, classList updateFn(); log("Add button clicked"); - + resetFn(); - + requestAnimationFrame(loop); }); return button; - } + }; }; diff --git a/examples/todo/components/debug-checkbox.js b/examples/todo/components/debug-checkbox.js index f8a889b..f3d7c7d 100644 --- a/examples/todo/components/debug-checkbox.js +++ b/examples/todo/components/debug-checkbox.js @@ -2,28 +2,28 @@ import { labelFor } from "../../../src/html.js"; export const debugCheckboxBuilder = ({ loop, log, resetFn, getInputIdFn }) => { return (checked, updateFn) => { - const checkbox = document.createElement('input'); + const checkbox = document.createElement("input"); - checkbox.type = 'checkbox'; + checkbox.type = "checkbox"; checkbox.id = getInputIdFn(); checkbox.classList = "h-5 w-5 text-blue-600"; checkbox.checked = checked; - checkbox.addEventListener("change", (event) => { + checkbox.addEventListener("change", (event) => { const newVal = updateFn(event.target.checked); log("debug is", newVal); - + resetFn(); - + requestAnimationFrame(loop); }); - return labelFor({ - input: checkbox, - classList: "text-sm font-medium text-gray-900 mr-2", - text: "Debug Logs" + return labelFor({ + input: checkbox, + classList: "text-sm font-medium text-gray-900 mr-2", + text: "Debug Logs", }); - } -} \ No newline at end of file + }; +}; diff --git a/examples/todo/components/done-button.js b/examples/todo/components/done-button.js index fbc39f5..d2d46a4 100644 --- a/examples/todo/components/done-button.js +++ b/examples/todo/components/done-button.js @@ -1,6 +1,9 @@ -export const doneToggleButtonBuilder = ({ loop, resetFn, log, getInputIdFn }, classList) => { +export const doneToggleButtonBuilder = ( + { loop, resetFn, log, getInputIdFn }, + classList, +) => { return (alreadyDone, updateFn) => { - const button = document.createElement('button'); + const button = document.createElement("button"); button.id = getInputIdFn(); button.classList = classList; button.textContent = alreadyDone ? "Undone" : "Done"; @@ -9,12 +12,12 @@ export const doneToggleButtonBuilder = ({ loop, resetFn, log, getInputIdFn }, cl updateFn(); log(`${button.textContent} button clicked`); - + resetFn(); - + requestAnimationFrame(loop); }); return button; - } + }; }; diff --git a/examples/todo/components/input-text.js b/examples/todo/components/input-text.js index 0147082..96d1cdd 100644 --- a/examples/todo/components/input-text.js +++ b/examples/todo/components/input-text.js @@ -1,10 +1,17 @@ -export const inputTextBuilder = ({ log, getInputIdFn, resetFn, loop, state }) => { - return ({ value, updateFn, addTodoFn, description }) => { - const input = document.createElement('input'); +export const inputTextBuilder = ({ + log, + getInputIdFn, + resetFn, + loop, + state, +}) => { + return ({ value, updateFn, addTodoFn }) => { + const input = document.createElement("input"); input.type = "text"; input.id = getInputIdFn(); input.placeholder = "Add Todo"; - input.classList = "shadow appearance-none border rounded w-full py-2 px-3 mr-4 text-grey-darker"; + input.classList = + "shadow appearance-none border rounded w-full py-2 px-3 mr-4 text-grey-darker"; input.value = value; input.addEventListener("change", (event) => { @@ -12,14 +19,13 @@ export const inputTextBuilder = ({ log, getInputIdFn, resetFn, loop, state }) => const newVal = updateFn(event.target.value); log("updated todo input to", newVal); - } - else { + } else { log("skipped updating text input because of reset"); } }); input.addEventListener("keydown", (event) => { - if (event.key === 'Enter') { + if (event.key === "Enter") { if (event.target.value) { addTodoFn(event.target.value); @@ -33,5 +39,5 @@ export const inputTextBuilder = ({ log, getInputIdFn, resetFn, loop, state }) => }); return input; - } + }; }; diff --git a/examples/todo/components/remove-button.js b/examples/todo/components/remove-button.js index 063586b..b587fc3 100644 --- a/examples/todo/components/remove-button.js +++ b/examples/todo/components/remove-button.js @@ -1,6 +1,9 @@ -export const removeButtonBuilder = ({ loop, resetFn, log, getInputIdFn }, classList) => { +export const removeButtonBuilder = ( + { loop, resetFn, log, getInputIdFn }, + classList, +) => { return (updateFn) => { - const button = document.createElement('button'); + const button = document.createElement("button"); button.id = getInputIdFn(); button.classList = classList; button.textContent = "Remove"; @@ -9,12 +12,12 @@ export const removeButtonBuilder = ({ loop, resetFn, log, getInputIdFn }, classL updateFn(); log("Remove button clicked"); - + resetFn(); - + requestAnimationFrame(loop); }); return button; - } + }; }; diff --git a/src/gui.js b/src/gui.js index 3e52fe3..df49ffd 100644 --- a/src/gui.js +++ b/src/gui.js @@ -1,8 +1,8 @@ export function reset({ app, state, log }) { - log('reset is called'); - + log("reset is called"); + state.isResetting = true; - + let clonedApp = app.cloneNode(); app.parentNode.replaceChild(clonedApp, app); @@ -13,7 +13,7 @@ export function reset({ app, state, log }) { export function refocus({ app, state, log }) { if (state.focusedElementId) { - log('refocus to', state.focusedElementId); + log("refocus to", state.focusedElementId); app.querySelector(`#${state.focusedElementId}`).focus(); } @@ -22,23 +22,31 @@ export function refocus({ app, state, log }) { export function getInputId({ appId, state }) { state.htmlElementOrderId++; - return '__' + appId + '_' + state.htmlElementOrderId; + return "__" + appId + "_" + state.htmlElementOrderId; } export function focusBlurListeners({ state, log }) { - document.addEventListener('focus', function(event) { - if (!state.isResetting) { - log('focused element', event.target); - - state.focusedElementId = event.target.id; - } - }, true); - - document.addEventListener('blur', function(event) { - if (!state.isResetting) { - log('blur element', event.target); - - state.focusedElementId = null; - } - }, true); -} \ No newline at end of file + document.addEventListener( + "focus", + function (event) { + if (!state.isResetting) { + log("focused element", event.target); + + state.focusedElementId = event.target.id; + } + }, + true, + ); + + document.addEventListener( + "blur", + function (event) { + if (!state.isResetting) { + log("blur element", event.target); + + state.focusedElementId = null; + } + }, + true, + ); +} diff --git a/src/html.js b/src/html.js index 7fc9cc4..f84ab28 100644 --- a/src/html.js +++ b/src/html.js @@ -1,19 +1,19 @@ -export function div({ classList, children, description }) { - const containerDiv = document.createElement('div'); +export function div({ classList, children }) { + const containerDiv = document.createElement("div"); if (classList) { containerDiv.classList = classList; } - children.forEach(element => { + children.forEach((element) => { containerDiv.appendChild(element); }); return containerDiv; } -export function p({ classList, text, description }) { - const pElement = document.createElement('p'); +export function p({ classList, text }) { + const pElement = document.createElement("p"); pElement.classList = classList; pElement.textContent = text; @@ -21,8 +21,8 @@ export function p({ classList, text, description }) { return pElement; } -export function h1({ classList, text, description }) { - const h1Element = document.createElement('h1'); +export function h1({ classList, text }) { + const h1Element = document.createElement("h1"); h1Element.classList = classList; h1Element.textContent = text; @@ -31,23 +31,23 @@ export function h1({ classList, text, description }) { } export function labelFor({ input, classList, text }) { - const label = document.createElement('label'); + const label = document.createElement("label"); label.classList = classList; - label.setAttribute('for', input.id); + label.setAttribute("for", input.id); label.textContent = text; return [label, input]; } -export function buildApp({ appId, classList, children = [], description }) { +export function buildApp({ appId, classList, children = [] }) { const appDiv = document.getElementById(appId); appDiv.classList = classList; - children.forEach(element => { + children.forEach((element) => { appDiv.appendChild(element); }); return appDiv; -} \ No newline at end of file +}