diff --git a/README.md b/README.md index fb3507d..d2e4df2 100644 --- a/README.md +++ b/README.md @@ -1,95 +1,7 @@ -# Lit-Only Architecture (No Build) +# zulip -A minimal, no-build web application using only Lit web components with local state management. +A minimal, no-build web app kit using only Lit-based web components via importmaps. -> **Note:** This is the `lit-only` branch. For the full-featured version with Zustand state management and IndexedDB persistence, see the `main` branch. - -## For TSX/React Developers - -If you're coming from React/TSX, here's how this minimal architecture maps to familiar concepts: - -| React/TSX Pattern | This Architecture | -|-------------------|-------------------| -| `useState` | Lit's `static properties` with `state: true` | -| Props drilling | Property passing via `.prop=${value}` | -| Custom events | `CustomEvent` with `bubbles: true` | -| JSX | Lit's `html` tagged template literals | -| CSS-in-JS / CSS Modules | Lit's `css` tagged template literals | -| React Router | Simple route state in root component | -| Build step (Vite/Webpack) | Import maps (no build!) | - -### Key Differences - -1. **No Virtual DOM**: Lit uses native Web Components with efficient DOM updates -2. **No Build Step**: Import maps let you use npm packages directly from CDN -3. **Local State Only**: Each component manages its own state, parent manages shared state -4. **Event-Based Communication**: Child components emit events, parent handles them -5. **Tagged Templates**: Instead of JSX, use `html\`
...
\`` - -## Architecture Overview - -* **Lit-based web components** - Standards-based, framework-agnostic UI -* **No-build tooling** - Import maps only, no bundler required -* **Local state management** - Component properties and state -* **Event-driven** - CustomEvents for child-to-parent communication - -## Project Structure - -``` -components/ - app-root.js ← Root component with shared state - nav-bar.js ← Navigation component - page-home.js ← Home page component - page-items.js ← Items page component -index.html ← Entry point with inline importmap -README.md -tasks.md -``` - -## Data Flow Pattern - -### 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)}>` -``` - -## State Management Pattern - -```mermaid -graph TD - A[app-root] -->|.user, .items, .route| B[nav-bar] - A -->|.user, .items| C[page-home] - A -->|.items| D[page-items] - B -->|@navigate event| A - D -->|@add-item event| A - D -->|@remove-item event| A - - style A fill:#f9f,stroke:#333,stroke-width:2px - style B fill:#bbf,stroke:#333,stroke-width:2px - style C fill:#bfb,stroke:#333,stroke-width:2px - style D fill:#bfb,stroke:#333,stroke-width:2px -``` ## Quick Start Example @@ -128,109 +40,59 @@ class Counter extends LitElement { customElements.define('my-counter', Counter) ``` -### 2. Use in HTML (no build step!) +### 2. Use in App root (or other composition node) -```html - - - - - - - - - - -``` +```js +import "./my-counter.js"; -## Component Communication Patterns - -### Pattern 1: Shared State in Root - -```javascript class AppRoot extends LitElement { - static properties = { - items: { type: Array, state: true } - } - - constructor() { - super() - this.items = [] - } - - addItem(item) { - this.items = [...this.items, item] - } - + ... render() { - return html` - this.addItem(e.detail.item)} - > - ` + return html``; } } ``` -### Pattern 2: Local State in Component +### 3. Define Data Flows + +#### Parent-to-Child (Props) ```javascript -class MyComponent extends LitElement { - static properties = { - _draft: { type: String, state: true } - } +// Parent passes data down +html`` - constructor() { - super() - this._draft = '' - } - - render() { - return html` - this._draft = e.target.value} - /> - ` - } +// Child receives via properties +static properties = { + items: { type: Array } } ``` -## Benefits Over React/TSX +#### Child-to-Parent (Events) -✅ **No build step** - Edit and refresh, instant feedback -✅ **Minimal dependencies** - Just Lit, nothing else -✅ **Smaller bundle** - No framework runtime, just standards -✅ **Better encapsulation** - Shadow DOM, scoped styles -✅ **Framework agnostic** - Works anywhere, even in React apps -✅ **Future-proof** - Built on web standards -✅ **Easy to learn** - Simple mental model, no complex state management +```javascript +// Child emits event +this.dispatchEvent(new CustomEvent('add-item', { + detail: { item: newItem }, + bubbles: true, + composed: true +})) -## When to Use This vs. Full Stack +// Parent listens +html` this.handleAdd(e.detail.item)}>` +``` -### Use Lit-Only When: -- Building small to medium apps -- Don't need persistence -- State is simple and hierarchical -- Want maximum simplicity +## Benefits Over TSX -### Use Full Stack (main branch) When: -- Need IndexedDB persistence -- Complex state shared across many components -- Need cross-tab synchronization -- Want time-travel debugging -- Building larger applications +1. **No build step** - Edit and refresh, instant feedback -## See Also +1. **Minimal dependencies** - Just Lit, nothing else -- [tasks.md](./tasks.md) - Current issues and improvements -- [Lit Documentation](https://lit.dev) -- [Web Components](https://developer.mozilla.org/en-US/docs/Web/Web_Components) -- [Import Maps](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) +1. **Smaller bundle** - No framework runtime, just standards + +1. **Better encapsulation** - Shadow DOM, scoped styles + +1. **Framework agnostic** - Works anywhere, even in React apps + +1. **Future-proof** - Built on web standards + +1. **Easy to learn** - Simple mental model for state, with natural evolution into Zustand/IndexedDB or similar extensions