From d7e273aa4a3bf9a7fd4beb5fc954480558357c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20L=2E=20K=2E=20S=C3=B8rensen?= Date: Sun, 2 Jun 2024 12:43:29 +0200 Subject: [PATCH] fix(Component): require `state` if `S` is defined (#45) --- CHANGELOG.md | 6 ++++++ src/__tests__/component.test.ts | 29 +++++++++++++++++++++++++++++ src/main.ts | 21 ++++++++------------- src/types.ts | 4 ++-- src/walker.ts | 8 ++------ 5 files changed, 47 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b563e406..1c7812d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Fixed + +- `Component` now requires `state` if `S` is defined ([#43](https://github.com/tentjs/tent/issues/43)) + ## [0.0.33-0] - 2024-05-27 ### Added diff --git a/src/__tests__/component.test.ts b/src/__tests__/component.test.ts index 44cae560..40a05f25 100644 --- a/src/__tests__/component.test.ts +++ b/src/__tests__/component.test.ts @@ -5,6 +5,10 @@ import { getByText, getByTestId, fireEvent } from '@testing-library/dom'; const { div, p, button } = tags; +beforeEach(() => { + document.body.innerHTML = ''; +}); + const Counter: Component<{ count: number }> = { state: { count: 0 }, view: ({ state }) => @@ -47,4 +51,29 @@ describe('components', () => { expect(mounted).toHaveBeenCalledTimes(1); }); + + test('with state', () => { + const WithState: Component<{ count: number }> = { + state: { count: 0 }, + view: ({ state }) => div(p(`Count: ${state.count}`)), + }; + + mount(document.body, WithState); + + const el = getByText(document.body, /Count: 0/); + + expect(el).toBeDefined(); + }); + + test('without state', () => { + const WithoutState: Component = { + view: () => div(p(`No state`)), + }; + + mount(document.body, WithoutState); + + const el = getByText(document.body, /No state/); + + expect(el).toBeDefined(); + }); }); diff --git a/src/main.ts b/src/main.ts index 6800700b..6e825f89 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,17 +6,14 @@ function mount( element: HTMLElement | Element | TentNode | null, component: Component, ) { - if (element == null) { - return; - } + if (element == null) return; let node: TentNode; - const { state = {} as S, view, mounted } = component; + const { view, mounted } = component; + const state = 'state' in component ? component.state : ({} as S); const el = element as TentNode; - el.$tent = { - attributes: {}, - }; + el.$tent = { attributes: {} }; const handler = { get(obj: S, key: string) { @@ -45,9 +42,7 @@ function mount( const proxy = new Proxy({ ...state }, handler); node = view({ state: proxy, el }); - node.$tent = { - attributes: {}, - }; + node.$tent = { attributes: {} }; el.append(node); @@ -55,11 +50,11 @@ function mount( } export { - mount, tags, + mount, createTag, - type Component, - type Children, type Context, type TentNode, + type Children, + type Component, }; diff --git a/src/types.ts b/src/types.ts index e9120acb..23f2b9db 100644 --- a/src/types.ts +++ b/src/types.ts @@ -6,9 +6,9 @@ type ComponentContext = { export type Attrs = {} | undefined; export type Component = { view: (context: ComponentContext) => TentNode; - state?: S; mounted?: (context: ComponentContext) => void; -}; +} & State; +type State = {} extends S ? {} : { state: S }; export type TentNode = Node & Element & diff --git a/src/walker.ts b/src/walker.ts index c76ec332..07181ac6 100644 --- a/src/walker.ts +++ b/src/walker.ts @@ -45,9 +45,7 @@ function walker(oldNode: TentNode, newNode: TentNode) { addAttribute(oldNode, key, attrs[key]); } - if (oc.length === 0 && nc.length === 0) { - return; - } + if (oc.length === 0 && nc.length === 0) return; if (oc.length < nc.length) { for (let i = 0; i < nc.length; i++) { @@ -69,9 +67,7 @@ function walker(oldNode: TentNode, newNode: TentNode) { const oChild = oc[i]; const nChild = nc[i]; - if (nChild == null) { - continue; - } + if (nChild == null) continue; if (oChild.tagName !== nChild.tagName) { oChild.replaceWith(nChild);