Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/test-headless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ on:
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
browser: [chromium, firefox, webkit]
container:
image: mcr.microsoft.com/playwright:v1.59.1-noble

Expand Down Expand Up @@ -36,4 +40,4 @@ jobs:
run: bunx vitest run
env:
HOME: /root
VITEST_BROWSERS: chromium,firefox,webkit
VITEST_BROWSERS: ${{ matrix.browser }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ builds/**/meta
test-results/
.claude/worktrees/
__screenshots__
.dts-tmp/
.nx/
.vitest-attachments/
48 changes: 34 additions & 14 deletions tko.io/public/examples/honeycomb.html
Original file line number Diff line number Diff line change
Expand Up @@ -557,34 +557,54 @@ <h1>Honeycomb</h1>
lastKey: ko.observable(null),
activeSource: null,
activeNeighbors: [],
_pendingHover: null,
_hoverRaf: 0,
_clickRaf: 0,
hoverCell(cell) {
if (!cell.interactive || cell.key === viewModel.lastKey()) return true

if (viewModel.activeSource) {
viewModel.activeSource.source(false)
}
viewModel.activeNeighbors.forEach(neighbor => neighbor.neighbor(false))
viewModel._pendingHover = cell
if (!viewModel._hoverRaf) {
viewModel._hoverRaf = requestAnimationFrame(() => {
viewModel._hoverRaf = 0
const target = viewModel._pendingHover
if (!target) return

if (viewModel.activeSource) {
viewModel.activeSource.source(false)
}
viewModel.activeNeighbors.forEach(neighbor => neighbor.neighbor(false))

viewModel.lastKey(cell.key)
viewModel.activeSource = cell
viewModel.activeNeighbors = cell.neighbors
viewModel.lastKey(target.key)
viewModel.activeSource = target
viewModel.activeNeighbors = target.neighbors

cell.source(true)
cell.neighbors.forEach(neighbor => neighbor.neighbor(true))
target.source(true)
target.neighbors.forEach(neighbor => neighbor.neighbor(true))

viewModel.vdomCount(viewModel.vdomCount() + viewModel.totalVisible())
viewModel.obsCount(viewModel.obsCount() + cell.neighbors.length)
viewModel.vdomCount(viewModel.vdomCount() + viewModel.totalVisible())
viewModel.obsCount(viewModel.obsCount() + target.neighbors.length)
})
}
return true
},
clickCell(cell) {
if (!cell.interactive) return true

if (viewModel._clickRaf) {
cancelAnimationFrame(viewModel._clickRaf)
viewModel._clickRaf = 0
}

const queue = buildWaterfallQueue(cell, cells)
let index = 0
const batchSize = 24

function advanceBurst() {
if (index >= queue.length) return
if (index >= queue.length) {
viewModel._clickRaf = 0
return
}

let touched = 0
while (index < queue.length && touched < batchSize) {
Expand All @@ -604,10 +624,10 @@ <h1>Honeycomb</h1>

viewModel.vdomCount(viewModel.vdomCount() + touched * viewModel.totalVisible())
viewModel.obsCount(viewModel.obsCount() + touched)
requestAnimationFrame(advanceBurst)
viewModel._clickRaf = requestAnimationFrame(advanceBurst)
}

requestAnimationFrame(advanceBurst)
viewModel._clickRaf = requestAnimationFrame(advanceBurst)
return true
}
}
Expand Down
69 changes: 39 additions & 30 deletions tko.io/src/content/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ description: Modern Knockout — reactive data binding and UI templating with ze
import { Tabs, TabItem } from '@astrojs/starlight/components';

<div class="landing-hero">
<p class="landing-kicker">TKO v4.0.1</p>
<h2>Modern Knockout, clarified</h2>
<h2 class="landing-version">TKO v4.0.1</h2>
<p class="landing-kicker">Modern Knockout, clarified</p>
<p class="landing-lede">Reactive data binding and UI templating with zero runtime dependencies. Start with the package you need and move from overview to working bindings.</p>
<div class="landing-actions">
<a class="landing-button landing-button--primary" href="/bindings/">Start with bindings</a>
Expand All @@ -17,50 +17,53 @@ import { Tabs, TabItem } from '@astrojs/starlight/components';

## Quick start

### Script tag (global)
### Browser

```html
<script src="https://cdn.jsdelivr.net/npm/@tko/build.knockout/dist/browser.min.js"></script>
<script>
const ko = globalThis.ko
</script>
```

### ES module (browser)

```html
<script type="module">
import ko from 'https://esm.run/@tko/build.knockout'
const name = ko.observable('TKO')
</script>
```
<Tabs syncKey="script">
<TabItem label="ES module">
```html
<script type="module">
import ko from 'https://esm.run/@tko/build.reference'
const name = ko.observable('TKO')
</script>
```
</TabItem>
<TabItem label="Classic script">
```html
<script src="https://cdn.jsdelivr.net/npm/@tko/build.reference/dist/browser.min.js"></script>
<script>
const ko = globalThis.tko
</script>
```
</TabItem>
</Tabs>
Comment on lines +20 to +39
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find agent guide files in tko.io and check whether they mention the new quick-start patterns
fd -i 'agents\.md$' tko.io
fd -i 'agents\.md$' tko.io -x rg -n "esm\.run|globalThis\.ko|@tko/build\.knockout|Quick start|Browser"

Repository: knockout/tko

Length of output: 38


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for agent guide files in tko.io/public/ as indicated by learnings
echo "=== Finding agent guide files in tko.io/public/ ==="
fd '\.md$' tko.io/public/ 2>/dev/null | head -20

echo ""
echo "=== Checking tko.io structure ==="
ls -la tko.io/ 2>/dev/null | grep -E '^d' || echo "No directories found"

echo ""
echo "=== Searching for any guide/agent related files ==="
find tko.io -type f -name '*guide*' -o -name '*agent*' 2>/dev/null | head -20

Repository: knockout/tko

Length of output: 1676


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking tko.io/public/agents/guide.md for quick-start patterns ==="
rg -n "esm\.run|globalThis\.ko|@tko/build\.knockout|Quick start|Browser|import ko from|cdn.jsdelivr" tko.io/public/agents/guide.md 2>/dev/null || echo "No matches found"

echo ""
echo "=== Checking tko.io/public/agent-guide.md ==="
rg -n "esm\.run|globalThis\.ko|@tko/build\.knockout|Quick start|Browser|import ko from|cdn.jsdelivr" tko.io/public/agent-guide.md 2>/dev/null || echo "No matches found"

echo ""
echo "=== Full content of tko.io/public/agents/guide.md (first 100 lines) ==="
head -100 tko.io/public/agents/guide.md

echo ""
echo "=== Searching for setup/installation/import sections in guide.md ==="
rg -n -A 5 "setup|installation|import|browser|quick" tko.io/public/agents/guide.md -i | head -50

Repository: knockout/tko

Length of output: 6482


Update agent guide setup section to match new quick-start patterns.

The new Starlight docs (lines 20–39) introduce https://cdn.jsdelivr.net/npm/@tko/build.knockout and globalThis.ko, but tko.io/public/agents/guide.md (lines 10–12) still references the legacy https://tko.io/lib/tko.js and globalThis.tko. Update the agent guide to use the new CDN endpoint and globalThis.ko to keep automated guidance aligned with the canonical quick-start pattern.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tko.io/src/content/docs/index.mdx` around lines 20 - 39, Update the agent
guide to match the new quick-start pattern by replacing the legacy CDN string
"https://tko.io/lib/tko.js" and the global reference "globalThis.tko" with the
new CDN endpoint
"https://cdn.jsdelivr.net/npm/@tko/build.knockout/dist/browser.min.js" and
"globalThis.ko" respectively in the guide content (look for occurrences of those
exact strings in the guide); ensure any example snippets and prose reflect the
ES module/classic script pattern used in the Starlight docs (importing
'@tko/build.knockout' for modules and referencing globalThis.ko for the browser
bundle).


### Package manager

<Tabs syncKey="pkg">
<TabItem label="npm">
```sh
npm install @tko/build.knockout
npm install @tko/build.reference
```
</TabItem>
<TabItem label="bun">
```sh
bun add @tko/build.knockout
bun add @tko/build.reference
```
</TabItem>
<TabItem label="pnpm">
```sh
pnpm add @tko/build.knockout
pnpm add @tko/build.reference
```
</TabItem>
<TabItem label="yarn">
```sh
yarn add @tko/build.knockout
yarn add @tko/build.reference
```
</TabItem>
</Tabs>

For the modern TSX / `ko-*` path, use `@tko/build.reference` instead.
For Knockout 3.x compatibility, use `@tko/build.knockout` instead.

## First binding example

Expand All @@ -73,25 +76,26 @@ For the modern TSX / `ko-*` path, use `@tko/build.reference` instead.
<p>Hello, <strong data-bind="text: name"></strong>.</p>
</div>

<script src="https://cdn.jsdelivr.net/npm/@tko/build.knockout/dist/browser.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@tko/build.reference/dist/browser.min.js"></script>
<script>
const ko = globalThis.tko
ko.applyBindings({ name: ko.observable('TKO') }, document.getElementById('app'))
</script>
```

## Choose a build

<div class="landing-grid">
<a class="landing-card" href="/bindings/">
<span class="landing-card__eyebrow">Recommended for migrations</span>
<h3><code>@tko/build.knockout</code></h3>
<p>Compatibility-focused. Closest match to a traditional Knockout application. Includes `data-bind` and `foreach`.</p>
</a>
<a class="landing-card" href="/advanced/provider/">
<span class="landing-card__eyebrow">Recommended for new projects</span>
<span class="landing-card__eyebrow">Recommended</span>
<h3><code>@tko/build.reference</code></h3>
<p>Modern path with TSX, `ko-*` attributes, native provider, and strict equality in expressions.</p>
</a>
<a class="landing-card" href="/3to4/">
<span class="landing-card__eyebrow">Knockout 3.x migrations</span>
<h3><code>@tko/build.knockout</code></h3>
<p>Compatibility-focused. Drop-in replacement for existing Knockout applications.</p>
</a>
</div>

## What stays familiar
Expand All @@ -118,6 +122,11 @@ For the modern TSX / `ko-*` path, use `@tko/build.reference` instead.
<h3>Components</h3>
<p>Reusable UI, loading strategies, and component architecture.</p>
</a>
<a class="landing-card" href="/examples/">
<span class="landing-card__eyebrow">See it in action</span>
<h3>Examples</h3>
<p>Interactive demos showing observable updates, dependency graphs, and reactive state.</p>
</a>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</div>

## Community
Expand Down
13 changes: 10 additions & 3 deletions tko.io/src/styles/tko.css
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,7 @@ header {

.sidebar,
.right-sidebar-panel,
.content-panel,
.sidebar-pane {
.content-panel {
background: transparent;
}

Expand Down Expand Up @@ -258,7 +257,15 @@ header {
color: var(--sl-color-text-accent);
}

.landing-hero h2 {
.landing-hero .landing-version {
margin: 0 0 0.3rem;
font-family: var(--tko-font-display);
font-size: clamp(2rem, 5vw, 3.2rem);
font-weight: 700;
color: var(--sl-color-white);
}

.landing-hero h2:not(.landing-version) {
margin: 0;
max-width: 11ch;
font-size: clamp(1.55rem, 3.7vw, 2.55rem);
Expand Down
Loading