From ee45c3c4605430ee4aae64a5ae38e7d9f6ff0141 Mon Sep 17 00:00:00 2001
From: adnaan <758447+adnaan@users.noreply.github.com>
Date: Sun, 6 Sep 2026 10:24:22 +0000
Subject: [PATCH] Sync from client@v0.25.1
---
content/changelog/client.md | 79 +++++++++++++++++++++++++++++++++-
content/client/index.md | 6 +--
content/contributing/client.md | 4 +-
3 files changed, 82 insertions(+), 7 deletions(-)
diff --git a/content/changelog/client.md b/content/changelog/client.md
index 809cb88..e6c2f71 100644
--- a/content/changelog/client.md
+++ b/content/changelog/client.md
@@ -2,8 +2,8 @@
title: "Changelog"
source_repo: "https://github.com/livetemplate/client"
source_path: "CHANGELOG.md"
-source_ref: "v0.25.0"
-source_commit: "bcaba2b8bc6062bdcb56045d3b0ba5bc052ef77d"
+source_ref: "v0.25.1"
+source_commit: "9719c9f61a9785ad4fd04db1b6d55debcd366587"
---
# Changelog
@@ -13,6 +13,81 @@ All notable changes to @livetemplate/client 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).
+## [v0.25.1] - 2026-09-06
+
+### Added
+
+- **`lvt-*` attributes are now extensible: `LiveTemplateClient.registerAttribute()`.**
+ Adding an attribute used to mean forking this library — writing a `dom/*.ts`
+ module, importing it into `livetemplate-client.ts`, and inserting a call at the
+ right position in a hardcoded ~20-entry sequence. An app that wanted
+ `lvt-x:copy-to-clipboard` had no supported way to get one.
+
+ There are two layers. Most authors only need the declarative one: declare an
+ attribute *name* and get called per element.
+
+ ```html
+
+
+
+ ```
+
+ The framework owns selector escaping, the DOM scan, per-element match
+ tracking, empty-value rejection, and sweeping elements that lost the attribute
+ or left the DOM — the sweep runs on every render, so `onElementRemoved` is
+ never deferred — so the three classic mistakes (no sweep, listeners stacking
+ on every render, a captured transport that dies at reconnect) are not
+ reachable from this layer. `ctx.value` and `ctx.send` are live accessors, so a
+ listener wired once still reads the current attribute value and dispatches
+ through the current transport.
+
+ Set `needsServerChannel: true` to get `ctx.send`; the message routes through
+ the same path an `lvt-on:click` action uses, and the server cannot tell the
+ difference. No server-side registration, no new wire message type, no build
+ step.
+
+ A `selectors` + `setup()`/`teardown()` escape hatch covers handlers with
+ cross-element state; every built-in uses it, so an author is never on a lesser
+ API than the framework itself.
+
+ Registration is static and late registration is supported: calling
+ `registerAttribute` after the client has connected runs the handler against
+ the live DOM immediately, rather than waiting for the next render. That is the
+ only sequence available to a second `