diff --git a/README.md b/README.md
index b1fc940..d2e4df2 100644
--- a/README.md
+++ b/README.md
@@ -1,87 +1,11 @@
# zulip
-A modern, no-build web application using Lit web components with Zustand state management.
+A minimal, no-build web app kit using only Lit-based web components via importmaps.
-## Architecture Overview
-* **Lit-based web components** - Standards-based, framework-agnostic UI
-* **No-build tooling** - Import maps only, no bundler required
-* **Zustand state management** - Lightweight, vanilla JS store
-* **StoreController** - Reactive controller that bridges Zustand and Lit
+## Quick Start Example
-## Project Structure
-
-```
-components/ -> standard lit components, including top-level "app-root"
-controllers/ -> lit reactive controllers (such as Zustand<->Lit bridge)
-store/ -> defines specific accessor sets
-index.html -> entry point with inline importmap and app-root
-README.md
-```
-
-## Data Flow Diagram
-
-```mermaid
-sequenceDiagram
- participant User
- participant LitComponent
- participant StoreController
- participant ZustandStore
-
- User->>LitComponent: Click button
- LitComponent->>ZustandStore: Call action (e.g., addItem)
- ZustandStore->>ZustandStore: Update state
- ZustandStore->>StoreController: Notify subscribers
- StoreController->>LitComponent: requestUpdate()
- LitComponent->>LitComponent: Re-render
- LitComponent->>User: Show updated UI
-```
-
-## Example
-
-### 1. Define Store (Zustand Vanilla)
-
-```javascript
-// store/index.js
-import { createStore } from 'zustand/vanilla'
-
-export const store = createStore((set, get) => ({
- count: 0,
- increment: () => set(s => ({ count: s.count + 1 })),
- decrement: () => set(s => ({ count: s.count - 1 })),
-}))
-```
-
-### 2. Create StoreController (Bridge)
-
-```javascript
-// controllers/store.js
-export class StoreController {
- constructor(host, store, selector) {
- this.host = host
- this.store = store
- this.selector = selector
- host.addController(this)
- }
-
- hostConnected() {
- this._unsub = this.store.subscribe((state) => {
- const next = this.selector(state)
- if (next !== this.value) {
- this.value = next
- this.host.requestUpdate()
- }
- })
- this.value = this.selector(this.store.getState())
- }
-
- hostDisconnected() {
- this._unsub?.()
- }
-}
-```
-
-### 3. Create Component (Lit + StoreController)
+### 1. Define a Component
```javascript
// components/counter.js
@@ -98,15 +22,16 @@ class Counter extends LitElement {
}
static styles = css`
- button { padding: 1rem; font-size: 1.2rem; margin: 0.5rem; }
+ button { padding: 1rem; font-size: 1.2rem; }
`
render() {
return html`
-
Count: ${this.#count.value}
-
-
+
Count: ${this.count}
+
`
}
@@ -115,24 +40,53 @@ class Counter extends LitElement {
customElements.define('my-counter', Counter)
```
-### 4. Instantiate in parent (such as app-root)
+### 2. Use in App root (or other composition node)
```js
-import counter from "./counter.js":
+import "./my-counter.js";
class AppRoot extends LitElement {
+ ...
render() {
- return html`
-
- `;
+ return html``;
}
}
```
+### 3. Define Data Flows
+
+#### Parent-to-Child (Props)
+
+```javascript
+// Parent passes data down
+html``
+
+// Child receives via properties
+static properties = {
+ items: { type: Array }
+}
+```
+
+#### Child-to-Parent (Events)
+
+```javascript
+// Child emits event
+this.dispatchEvent(new CustomEvent('add-item', {
+ detail: { item: newItem },
+ bubbles: true,
+ composed: true
+}))
+
+// Parent listens
+html` this.handleAdd(e.detail.item)}>`
+```
+
## Benefits Over TSX
1. **No build step** - Edit and refresh, instant feedback
+1. **Minimal dependencies** - Just Lit, nothing else
+
1. **Smaller bundle** - No framework runtime, just standards
1. **Better encapsulation** - Shadow DOM, scoped styles
@@ -141,6 +95,4 @@ class AppRoot extends LitElement {
1. **Future-proof** - Built on web standards
-1. **Familiar patterns** - Zustand works like Redux/Context
-
-1. **Type-safe** - Can add JSDoc or TypeScript without build step
+1. **Easy to learn** - Simple mental model for state, with natural evolution into Zustand/IndexedDB or similar extensions
diff --git a/components/app-root.js b/components/app-root.js
index c5226f9..88f59a6 100644
--- a/components/app-root.js
+++ b/components/app-root.js
@@ -4,8 +4,18 @@ import "./page-home.js";
import "./page-items.js";
class AppRoot extends LitElement {
- #user = new StoreController(this, store, s => s.user);
- #route = new StoreController(this, store, s => s.route);
+ static properties = {
+ user: { type: Object, state: true },
+ route: { type: String, state: true },
+ items: { type: Array, state: true }
+ };
+
+ constructor() {
+ super();
+ this.user = null;
+ this.route = 'home';
+ this.items = [];
+ }
static styles = css`
:host {
diff --git a/index.html b/index.html
index 91255c2..879175b 100644
--- a/index.html
+++ b/index.html
@@ -8,8 +8,7 @@
{
"imports": {
"lit": "https://esm.sh/lit@3",
- "lit/decorators.js": "https://esm.sh/lit@3/decorators.js",
- "zustand/vanilla": "https://esm.sh/zustand@5/vanilla"
+ "lit/decorators.js": "https://esm.sh/lit@3/decorators.js"
}
}
diff --git a/store/index.js b/store/index.js
deleted file mode 100644
index 3328f31..0000000
--- a/store/index.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { createStore } from 'zustand/vanilla'
-
-export const store = createStore((set, get) => ({
- user: null,
- items: [],
- route: 'home',
-
- // Actions
- setUser: (user) => set({ user }),
- addItem: (item) => set(s => ({ items: [...s.items, item] })),
- removeItem: (id) => set(s => ({ items: s.items.filter(i => i.id !== id) })),
- navigate: (route) => set({ route }),
-}))