diff --git a/README.md b/README.md index 4908a77..7f7b77f 100644 --- a/README.md +++ b/README.md @@ -231,11 +231,9 @@ Here's a "Hello, World!" example of mount functions: // Loosely mapped to ".hello-world" export function HelloWorld(el) { // Define initial state - const state = { - title: 'Hello, World!', - description: 'An example vanilla component', - counter: 0, - }; + let title = 'Hello, World!'; + let description = 'An example vanilla component'; + let counter = 0; // Set rigid base HTML el.innerHTML = ` @@ -248,27 +246,24 @@ export function HelloWorld(el) { el.querySelectorAll('.my-counter').forEach(MyCounter); // Attach event listeners - el.addEventListener('modifyCounter', (e) => - update({ counter: state.counter + e.detail }), - ); + el.addEventListener('modifyCounter', (e) => { + counter += e.detail; + update(); + }); // Initial update update(); // Define idempotent update function - function update(next) { - // Update state - // Optionally optimize, e.g. bail out if state hasn't changed - Object.assign(state, next); - + function update() { // Update own HTML - el.querySelector('.title').innerText = state.title; - el.querySelector('.description').innerText = state.description; + el.querySelector('.title').innerText = title; + el.querySelector('.description').innerText = description; - // Pass data to sub-scomponents + // Pass data to sub-components el.querySelector('.my-counter').dispatchEvent( new CustomEvent('updateMyCounter', { - detail: { value: state.counter }, + detail: { value: counter }, }), ); } @@ -278,9 +273,7 @@ export function HelloWorld(el) { // Loosely mapped to ".my-counter" export function MyCounter(el) { // Define initial state - const state = { - value: 0, - }; + let value = 0; // Set rigid base HTML el.innerHTML = ` @@ -314,13 +307,14 @@ export function MyCounter(el) { ); }); - el.addEventListener('updateMyCounter', (e) => update(e.detail)); + el.addEventListener('updateMyCounter', (e) => { + value = e.detail; + update(); + }); // Define idempotent update function - function update(next) { - Object.assign(state, next); - - el.querySelector('.value').innerText = state.value; + function update() { + el.querySelector('.value').innerText = value; } } @@ -416,17 +410,16 @@ from the implementation outlining the reconciliation algorithm: ```js export function TodoList(el) { - const state = { - items: [], - }; + let items = []; el.innerHTML = `
`; - el.addEventListener('updateTodoList', (e) => update(e.detail)); - - function update(next) { - Object.assign(state, next); + el.addEventListener('updateTodoList', (e) => { + items = e.detail; + update(); + }); + function update() { const container = el.querySelector('.items'); // Mark current children for removal @@ -440,7 +433,7 @@ export function TodoList(el) { ); // Build new list of child elements from data - const children = state.items.map((item) => { + const children = items.map((item) => { // Find existing child by data-key let child = childrenByKey.get(item.id); diff --git a/public/scripts/AppCollapsible.js b/public/scripts/AppCollapsible.js index 67e963f..6001435 100644 --- a/public/scripts/AppCollapsible.js +++ b/public/scripts/AppCollapsible.js @@ -2,32 +2,33 @@ * @param {HTMLElement} el */ export function AppCollapsible(el) { - const state = { - show: true, - }; + let show = true; setTimeout(() => el.classList.add('-animated'), 200); el.addEventListener('collapse', (e) => { - update({ show: typeof e.detail === 'boolean' ? !e.detail : state.show }); + if (typeof e.detail === 'boolean') { + show = e.detail; + } + + update(); }); el.querySelector('.bar > .toggle').addEventListener('click', () => { - update({ show: !state.show }); + show = !show; + update(); }); update(); - function update(next) { - Object.assign(state, next); - + function update() { el.querySelector('.bar > .toggle > .app-icon').classList.toggle( '-r180', - state.show, + show, ); el.querySelectorAll('.body').forEach((el) => { - el.style.height = state.show ? `${el.children[0].offsetHeight}px` : '0'; + el.style.height = show ? `${el.children[0].offsetHeight}px` : '0'; }); } } diff --git a/public/scripts/AppDatePicker.js b/public/scripts/AppDatePicker.js index 5dad4af..e40efeb 100644 --- a/public/scripts/AppDatePicker.js +++ b/public/scripts/AppDatePicker.js @@ -22,11 +22,11 @@ const datesRow = ` */ export function AppDatePicker(el) { const now = new Date(); - const state = { + let at = { year: now.getFullYear(), month: now.getMonth() + 1, - show: false, }; + let show = false; el.innerHTML = `

@@ -62,11 +62,10 @@ export function AppDatePicker(el) { el.querySelectorAll('.app-icon').forEach(AppIcon); - el.addEventListener('toggleDatePicker', (e) => - update({ show: e.detail ?? !state.show }), - ); - - el.addEventListener('setMonth', (e) => update(e.detail)); + el.addEventListener('toggleDatePicker', (e) => { + show = e.detail ?? !show; + update(); + }); el.querySelector('.previousmonth').addEventListener('click', previousMonth); el.querySelector('.nextmonth').addEventListener('click', nextMonth); @@ -74,7 +73,8 @@ export function AppDatePicker(el) { el.addEventListener('click', (e) => { if (!e.target.matches('.app-button')) return; - update({ show: false }); + show = false; + update(); el.dispatchEvent( new CustomEvent('pickDate', { @@ -89,40 +89,42 @@ export function AppDatePicker(el) { }); function previousMonth() { - update( - state.month > 1 - ? { - year: state.year, - month: state.month - 1, - } - : { - year: state.year - 1, - month: 12, - }, - ); + if (at.month > 1) { + at = { + year: at.year, + month: at.month - 1, + }; + } else { + at = { + year: at.year - 1, + month: 12, + }; + } + + update(); } function nextMonth() { - update( - state.month < 12 - ? { - year: state.year, - month: state.month + 1, - } - : { - year: state.year + 1, - month: 1, - }, - ); + if (at.month < 12) { + at = { + year: at.year, + month: at.month + 1, + }; + } else { + at = { + year: at.year + 1, + month: 1, + }; + } + + update(); } - function update(next) { - Object.assign(state, next); - - el.classList.toggle('-show', state.show); + function update() { + el.classList.toggle('-show', show); const now = new Date(); - const first = new Date(state.year, state.month - 1, 1); + const first = new Date(at.year, at.month - 1, 1); el.querySelector('.month').innerHTML = `${formatMonth( first, diff --git a/public/scripts/AppSortable.js b/public/scripts/AppSortable.js index d86da53..cc3a60e 100644 --- a/public/scripts/AppSortable.js +++ b/public/scripts/AppSortable.js @@ -7,9 +7,10 @@ export function AppSortable(el, options) { let placeholder; let placeholderSource; - const horizontal = options.direction === 'horizontal'; let currentIndex = -1; + const isBefore = options.direction === 'horizontal' ? isLeft : isAbove; + el.addEventListener('draggableStart', (e) => e.detail.image.addEventListener('draggableCancel', cleanUp), ); @@ -115,7 +116,6 @@ export function AppSortable(el, options) { function calculateIndex(image) { if (el.children.length === 0) return 0; - const isBefore = horizontal ? isLeft : isAbove; const rect = image.getBoundingClientRect(); let p = 0; diff --git a/public/scripts/TodoApp.js b/public/scripts/TodoApp.js index b4b971e..da98969 100644 --- a/public/scripts/TodoApp.js +++ b/public/scripts/TodoApp.js @@ -11,7 +11,7 @@ import { formatDateId } from './util.js'; * @param {HTMLElement} el */ export function TodoApp(el) { - const state = { + let todoData = { items: [], customLists: [], at: formatDateId(new Date()), @@ -83,7 +83,7 @@ export function TodoApp(el) { e.detail.placeholder.classList.add('_noflip'); }); - // dispatch "focusOther" on .use-focus-other inputs if they are not active + // dispatch "focusOther" on .use-focus-other inputs if they are not active // ensures only one edit input is active el.addEventListener('focusin', (e) => { if (!e.target.classList.contains('use-focus-other')) return; @@ -97,7 +97,10 @@ export function TodoApp(el) { // listen to the TodoStore's data // this is the main update // everything else is related to drag & drop or FLIP animations - el.addEventListener('todoData', (e) => update(e.detail)); + el.addEventListener('todoData', (e) => { + todoData = e.detail; + update(); + }); // dispatch "flip" after HTML changes from these events // this plays the FLIP animations @@ -108,11 +111,9 @@ export function TodoApp(el) { el.dispatchEvent(new CustomEvent('loadTodoStore')); - function update(next) { - Object.assign(state, next); - + function update() { el.querySelectorAll('.todo-frame').forEach((el) => - el.dispatchEvent(new CustomEvent('todoData', { detail: state })), + el.dispatchEvent(new CustomEvent('todoData', { detail: todoData })), ); el.querySelectorAll('.app-collapsible').forEach((el) => diff --git a/public/scripts/TodoCustomList.js b/public/scripts/TodoCustomList.js index 71458eb..96b2cc4 100644 --- a/public/scripts/TodoCustomList.js +++ b/public/scripts/TodoCustomList.js @@ -6,10 +6,8 @@ import { TodoList } from './TodoList.js'; * @param {HTMLElement} el */ export function TodoCustomList(el) { - const state = { - list: null, - editing: false, - }; + let list; + let editing = false; let startEditing = false; let saveOnBlur = true; @@ -36,7 +34,8 @@ export function TodoCustomList(el) { titleEl.addEventListener('click', () => { startEditing = true; - update({ editing: true }); + editing = true; + update(); }); deleteEl.addEventListener('touchstart', () => { @@ -53,7 +52,7 @@ export function TodoCustomList(el) { }); inputEl.addEventListener('focusOther', () => { - if (state.editing) save(); + if (editing) save(); }); inputEl.addEventListener('keyup', (e) => { @@ -68,7 +67,7 @@ export function TodoCustomList(el) { }); deleteEl.addEventListener('click', () => { - if (state.list.items.length > 0) { + if (list.items.length > 0) { if ( !confirm( 'Deleting this list will delete its items as well. Are you sure?', @@ -80,7 +79,7 @@ export function TodoCustomList(el) { el.dispatchEvent( new CustomEvent('deleteTodoList', { - detail: state.list, + detail: list, bubbles: true, }), ); @@ -89,8 +88,8 @@ export function TodoCustomList(el) { el.addEventListener('draggableStart', (e) => { if (e.target !== titleEl) return; - e.detail.data.list = state.list; - e.detail.data.key = state.list.id; + e.detail.data.list = list; + e.detail.data.key = list.id; // update image (default would only be title element) e.detail.setImage(el); @@ -104,47 +103,50 @@ export function TodoCustomList(el) { }); el.addEventListener('addTodoItem', (e) => { - e.detail.listId = state.list.id; + e.detail.listId = list.id; }); el.addEventListener('moveTodoItem', (e) => { - e.detail.listId = state.list.id; + e.detail.listId = list.id; e.detail.index = e.detail.index ?? 0; }); - el.addEventListener('todoCustomList', (e) => update({ list: e.detail })); + el.addEventListener('todoCustomList', (e) => { + list = e.detail; + update(); + }); function save() { el.dispatchEvent( new CustomEvent('saveTodoList', { - detail: { list: state.list, title: inputEl.value.trim() }, + detail: { list, title: inputEl.value.trim() }, bubbles: true, }), ); - update({ editing: false }); + editing = false; + update(); } function cancelEdit() { saveOnBlur = false; - update({ editing: false }); + editing = false; + update(); } - function update(next) { - Object.assign(state, next); - - titleEl.innerText = state.list.title || '...'; + function update() { + titleEl.innerText = list.title || '...'; el.querySelector('.todo-list').dispatchEvent( - new CustomEvent('todoItems', { detail: state.list.items }), + new CustomEvent('todoItems', { detail: list.items }), ); el.querySelector('.todo-list > .todo-item-input').dataset.key = - `todo-item-input${state.list.id}`; + `todo-item-input${list.id}`; - el.classList.toggle('-editing', state.editing); + el.classList.toggle('-editing', editing); - if (state.editing && startEditing) { - inputEl.value = state.list.title; + if (editing && startEditing) { + inputEl.value = list.title; inputEl.focus(); inputEl.select(); startEditing = false; diff --git a/public/scripts/TodoDay.js b/public/scripts/TodoDay.js index c4d45ac..83b8df5 100644 --- a/public/scripts/TodoDay.js +++ b/public/scripts/TodoDay.js @@ -5,10 +5,8 @@ import { formatDate, formatDayOfWeek } from './util.js'; * @param {HTMLElement} el */ export function TodoDay(el) { - const state = { - dateId: el.dataset.key, - items: [], - }; + const dateId = el.dataset.key; + let items = []; el.innerHTML = `
@@ -21,20 +19,21 @@ export function TodoDay(el) { TodoList(el.querySelector('.todo-list')); el.addEventListener('addTodoItem', (e) => { - e.detail.listId = state.dateId; + e.detail.listId = dateId; }); el.addEventListener('moveTodoItem', (e) => { - e.detail.listId = state.dateId; + e.detail.listId = dateId; e.detail.index = e.detail.index ?? 0; }); - el.addEventListener('todoDay', (e) => update(e.detail)); + el.addEventListener('todoDay', (e) => { + items = e.detail.items; + update(); + }); - function update(next) { - Object.assign(state, next); - - const date = new Date(state.dateId); + function update() { + const date = new Date(dateId); const today = new Date(); today.setHours(0, 0, 0, 0); const tomorrow = new Date(today); @@ -46,7 +45,7 @@ export function TodoDay(el) { el.querySelector('.header > .dayofweek').innerText = formatDayOfWeek(date); el.querySelector('.header > .date').innerText = formatDate(date); el.querySelector('.todo-list').dispatchEvent( - new CustomEvent('todoItems', { detail: state.items }), + new CustomEvent('todoItems', { detail: items }), ); } } diff --git a/public/scripts/TodoFrameCustom.js b/public/scripts/TodoFrameCustom.js index bc8d5aa..6006c59 100644 --- a/public/scripts/TodoFrameCustom.js +++ b/public/scripts/TodoFrameCustom.js @@ -6,11 +6,10 @@ import { TodoCustomList } from './TodoCustomList.js'; * @param {HTMLElement} el */ export function TodoFrameCustom(el) { - const state = { + let todoData = { customLists: [], items: [], customAt: 0, - show: true, }; el.innerHTML = ` @@ -69,11 +68,12 @@ export function TodoFrameCustom(el) { updatePositions(); }); - el.addEventListener('todoData', (e) => update(e.detail)); - - function update(next) { - Object.assign(state, next); + el.addEventListener('todoData', (e) => { + todoData = e.detail; + update(); + }); + function update() { const lists = getLists(); const container = el.querySelector('.container'); const obsolete = new Set(container.children); @@ -112,7 +112,9 @@ export function TodoFrameCustom(el) { function updatePositions() { el.querySelectorAll('.container > *').forEach((child, index) => { - child.style.transform = `translateX(${(index - state.customAt) * 100}%)`; + child.style.transform = `translateX(${ + (index - todoData.customAt) * 100 + }%)`; }); } @@ -136,7 +138,7 @@ export function TodoFrameCustom(el) { } function getLists() { - return state.customLists + return todoData.customLists .map((list) => ({ id: list.id, index: list.index, @@ -147,7 +149,7 @@ export function TodoFrameCustom(el) { } function getItemsForList(listId) { - return state.items + return todoData.items .filter((item) => item.listId === listId) .sort((a, b) => a.index - b.index); } diff --git a/public/scripts/TodoFrameDays.js b/public/scripts/TodoFrameDays.js index 62a4b3c..96e3099 100644 --- a/public/scripts/TodoFrameDays.js +++ b/public/scripts/TodoFrameDays.js @@ -8,7 +8,7 @@ import { formatDateId } from './util.js'; */ export function TodoFrameDays(el) { const RANGE = 14; - const state = { + let todoData = { items: [], at: formatDateId(new Date()), }; @@ -93,11 +93,12 @@ export function TodoFrameDays(el) { ), ); - el.addEventListener('todoData', (e) => update(e.detail)); - - function update(next) { - Object.assign(state, next); + el.addEventListener('todoData', (e) => { + todoData = e.detail; + update(); + }); + function update() { const days = getDays(); const container = el.querySelector('.container'); @@ -150,7 +151,7 @@ export function TodoFrameDays(el) { const days = []; for (let i = 0; i < 2 * RANGE; ++i) { - const t = new Date(state.at); + const t = new Date(todoData.at); t.setDate(t.getDate() - RANGE + i); const id = formatDateId(t); @@ -165,7 +166,7 @@ export function TodoFrameDays(el) { } function getItemsForDay(dateId) { - return state.items + return todoData.items .filter((item) => item.listId === dateId) .sort((a, b) => a.index - b.index); } diff --git a/public/scripts/TodoItem.js b/public/scripts/TodoItem.js index b92ca20..f25b83a 100644 --- a/public/scripts/TodoItem.js +++ b/public/scripts/TodoItem.js @@ -5,11 +5,8 @@ import { AppIcon } from './AppIcon.js'; * @param {HTMLElement} el */ export function TodoItem(el) { - const state = { - item: null, - editing: false, - }; - + let item; + let editing = false; let startEditing = false; let saveOnBlur = true; @@ -44,13 +41,13 @@ export function TodoItem(el) { }); checkboxEl.addEventListener('click', () => { - if (state.editing) save(); + if (editing) save(); el.dispatchEvent( new CustomEvent('checkTodoItem', { detail: { - item: state.item, - done: !state.item.done, + item, + done: !item.done, }, bubbles: true, }), @@ -59,7 +56,8 @@ export function TodoItem(el) { labelEl.addEventListener('click', () => { startEditing = true; - update({ editing: true }); + editing = true; + update(); }); inputEl.addEventListener('keyup', (e) => { @@ -79,7 +77,7 @@ export function TodoItem(el) { }); inputEl.addEventListener('focusOther', () => { - if (state.editing) save(); + if (editing) save(); }); saveEl.addEventListener('mousedown', () => { @@ -89,11 +87,14 @@ export function TodoItem(el) { saveEl.addEventListener('click', save); el.addEventListener('draggableStart', (e) => { - e.detail.data.item = state.item; - e.detail.data.key = state.item.id; + e.detail.data.item = item; + e.detail.data.key = item.id; }); - el.addEventListener('todoItem', (e) => update({ item: e.detail })); + el.addEventListener('todoItem', (e) => { + item = e.detail; + update(); + }); function save() { const label = inputEl.value.trim(); @@ -106,7 +107,7 @@ export function TodoItem(el) { requestAnimationFrame(() => { el.dispatchEvent( new CustomEvent('deleteTodoItem', { - detail: state.item, + detail: item, bubbles: true, }), ); @@ -118,34 +119,35 @@ export function TodoItem(el) { el.dispatchEvent( new CustomEvent('saveTodoItem', { detail: { - item: state.item, + item, label, }, bubbles: true, }), ); - update({ editing: false }); + editing = false; + update(); } function cancelEdit() { saveOnBlur = false; - update({ editing: false }); + editing = false; + update(); } - function update(next) { + function update() { // TODO optimize - Object.assign(state, next); - el.classList.toggle('-done', state.item.done); - checkboxEl.querySelector('input').checked = state.item.done; - labelEl.innerText = state.item.label; + el.classList.toggle('-done', item.done); + checkboxEl.querySelector('input').checked = item.done; + labelEl.innerText = item.label; - el.classList.toggle('-editing', state.editing); - el.classList.toggle('_nodrag', state.editing); + el.classList.toggle('-editing', editing); + el.classList.toggle('_nodrag', editing); - if (state.editing && startEditing) { - inputEl.value = state.item.label; + if (editing && startEditing) { + inputEl.value = item.label; inputEl.focus(); inputEl.select(); startEditing = false; diff --git a/public/scripts/TodoList.js b/public/scripts/TodoList.js index 489ce8f..2e856ce 100644 --- a/public/scripts/TodoList.js +++ b/public/scripts/TodoList.js @@ -6,9 +6,7 @@ import { TodoItemInput } from './TodoItemInput.js'; * @param {HTMLElement} el */ export function TodoList(el) { - const state = { - items: [], - }; + let items = []; el.innerHTML = `
@@ -30,18 +28,19 @@ export function TodoList(el) { ), ); - el.addEventListener('todoItems', (e) => update({ items: e.detail })); - - function update(next) { - Object.assign(state, next); + el.addEventListener('todoItems', (e) => { + items = e.detail; + update(); + }); + function update() { const container = el.querySelector('.items'); const obsolete = new Set(container.children); const childrenByKey = new Map(); obsolete.forEach((child) => childrenByKey.set(child.dataset.key, child)); - const children = state.items.map((item) => { + const children = items.map((item) => { let child = childrenByKey.get(item.id); if (child) { diff --git a/public/scripts/TodoStore.js b/public/scripts/TodoStore.js index c8e07dd..c044016 100644 --- a/public/scripts/TodoStore.js +++ b/public/scripts/TodoStore.js @@ -4,7 +4,7 @@ import { formatDateId, uuid } from './util.js'; * @param {HTMLElement} el */ export function TodoStore(el) { - const state = { + const todoData = { items: [], customLists: [], at: formatDateId(new Date()), @@ -18,13 +18,13 @@ export function TodoStore(el) { el.addEventListener('addTodoItem', (e) => { let index = 0; - for (const item of state.items) { + for (const item of todoData.items) { if (item.listId === e.detail.listId) { index = Math.max(index, item.index + 1); } } - state.items.push({ + todoData.items.push({ id: uuid(), listId: e.detail.listId, index, @@ -32,27 +32,29 @@ export function TodoStore(el) { done: false, }); - dispatch({ items: state.items }); + dispatch({ items: todoData.items }); }); el.addEventListener('checkTodoItem', (e) => { if (e.detail.item.done === e.detail.done) return; e.detail.item.done = e.detail.done; - dispatch({ items: state.items }); + dispatch({ items: todoData.items }); }); el.addEventListener('saveTodoItem', (e) => { if (e.detail.item.label === e.detail.label) return; e.detail.item.label = e.detail.label; - dispatch({ items: state.items }); + dispatch({ items: todoData.items }); }); el.addEventListener('moveTodoItem', (e) => { - const movedItem = state.items.find((item) => item.id === e.detail.item.id); + const movedItem = todoData.items.find( + (item) => item.id === e.detail.item.id, + ); - const listItems = state.items.filter( + const listItems = todoData.items.filter( (item) => item.listId === e.detail.listId && item !== movedItem, ); @@ -65,66 +67,68 @@ export function TodoStore(el) { item.index = index; }); - dispatch({ items: state.items }); + dispatch({ items: todoData.items }); }); el.addEventListener('deleteTodoItem', (e) => - dispatch({ items: state.items.filter((item) => item.id !== e.detail.id) }), + dispatch({ + items: todoData.items.filter((item) => item.id !== e.detail.id), + }), ); el.addEventListener('addTodoList', (e) => { let index = 0; - for (const customList of state.customLists) { + for (const customList of todoData.customLists) { index = Math.max(index, customList.index + 1); } - state.customLists.push({ + todoData.customLists.push({ id: uuid(), index, title: e.detail.title || '', }); - dispatch({ customLists: state.customLists }); + dispatch({ customLists: todoData.customLists }); }); el.addEventListener('saveTodoList', (e) => { - const list = state.customLists.find((l) => l.id === e.detail.list.id); + const list = todoData.customLists.find((l) => l.id === e.detail.list.id); if (list.title === e.detail.title) return; list.title = e.detail.title; - dispatch({ customLists: state.customLists }); + dispatch({ customLists: todoData.customLists }); }); el.addEventListener('moveTodoList', (e) => { - const movedListIndex = state.customLists.findIndex( + const movedListIndex = todoData.customLists.findIndex( (list) => list.id === e.detail.list.id, ); - const movedList = state.customLists[movedListIndex]; + const movedList = todoData.customLists[movedListIndex]; - state.customLists.splice(movedListIndex, 1); - state.customLists.sort((a, b) => a.index - b.index); - state.customLists.splice(e.detail.index, 0, movedList); + todoData.customLists.splice(movedListIndex, 1); + todoData.customLists.sort((a, b) => a.index - b.index); + todoData.customLists.splice(e.detail.index, 0, movedList); - state.customLists.forEach((item, index) => { + todoData.customLists.forEach((item, index) => { item.index = index; }); - dispatch({ customLists: state.customLists }); + dispatch({ customLists: todoData.customLists }); }); el.addEventListener('deleteTodoList', (e) => dispatch({ - customLists: state.customLists.filter( + customLists: todoData.customLists.filter( (customList) => customList.id !== e.detail.id, ), }), ); el.addEventListener('seekDays', (e) => { - const t = new Date(`${state.at}T00:00:00`); + const t = new Date(`${todoData.at}T00:00:00`); t.setDate(t.getDate() + e.detail); dispatch({ at: formatDateId(t) }); @@ -142,18 +146,18 @@ export function TodoStore(el) { dispatch({ customAt: Math.max( 0, - Math.min(state.customLists.length - 1, state.customAt + e.detail), + Math.min(todoData.customLists.length - 1, todoData.customAt + e.detail), ), }), ); function dispatch(next) { - Object.assign(state, next); + Object.assign(todoData, next); save(); el.dispatchEvent( new CustomEvent('todoData', { - detail: state, + detail: todoData, bubbles: false, }), ); @@ -161,7 +165,7 @@ export function TodoStore(el) { function load() { if (!localStorage || !localStorage.todo) { - dispatch(state); + dispatch(todoData); return; } @@ -178,7 +182,7 @@ export function TodoStore(el) { storeTimeout = setTimeout(() => { try { - localStorage.todo = JSON.stringify(state); + localStorage.todo = JSON.stringify(todoData); } catch (err) { // eslint-disable-next-line no-console console.warn(err);