@livetemplate/client 0.11.5 → 0.11.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dom/directives.d.ts +153 -0
- package/dist/dom/directives.d.ts.map +1 -1
- package/dist/dom/directives.js +851 -0
- package/dist/dom/directives.js.map +1 -1
- package/dist/livetemplate-client.browser.js +4 -4
- package/dist/livetemplate-client.browser.js.map +3 -3
- package/dist/livetemplate-client.d.ts.map +1 -1
- package/dist/livetemplate-client.js +30 -0
- package/dist/livetemplate-client.js.map +1 -1
- package/dist/tests/directives.test.js +1091 -0
- package/dist/tests/directives.test.js.map +1 -1
- package/package.json +1 -1
package/dist/dom/directives.d.ts
CHANGED
|
@@ -153,4 +153,157 @@ export declare function setupToastClickOutside(): void;
|
|
|
153
153
|
* also logs a console.warn so the divergence is visible.
|
|
154
154
|
*/
|
|
155
155
|
export declare function handleShadowRootHydration(rootElement: Element): void;
|
|
156
|
+
/**
|
|
157
|
+
* Apply area-select directives. `lvt-fx:area-select="<actionName>"` on
|
|
158
|
+
* an element (typically an `<img>` inside a positioned parent) lets
|
|
159
|
+
* the user drag a rectangle locally — a `<div>` overlay tracks the
|
|
160
|
+
* gesture in real time without a server round-trip — and on
|
|
161
|
+
* `pointerup` dispatches a single livetemplate action with the final
|
|
162
|
+
* `{x, y, w, h}` as 0..1 fractions of the element's rendered bounding
|
|
163
|
+
* rect. The image's intrinsic dimensions don't matter for the
|
|
164
|
+
* fractions: any uniform scale (zoom, responsive layout) preserves
|
|
165
|
+
* the fraction. The consumer scales to pixels using the natural size
|
|
166
|
+
* if it needs them.
|
|
167
|
+
*
|
|
168
|
+
* Contract:
|
|
169
|
+
* - Host's `parentElement` must establish a positioning context
|
|
170
|
+
* (`position: relative` / `absolute` / `fixed`). The overlay is
|
|
171
|
+
* `position: absolute` inside that parent so it follows the host
|
|
172
|
+
* on scroll / reflow.
|
|
173
|
+
* - Consumers usually pair this with `touch-action: none` on the
|
|
174
|
+
* host so iOS Safari doesn't interpret the drag as a pinch/scroll.
|
|
175
|
+
* - `<img>` and other natively-draggable hosts work automatically:
|
|
176
|
+
* the directive calls `preventDefault()` on `dragstart` so the
|
|
177
|
+
* browser's native drag (which would otherwise steal the gesture)
|
|
178
|
+
* is suppressed.
|
|
179
|
+
* - On pointer-cancel (e.g. system gesture, app switch), the overlay
|
|
180
|
+
* is removed and no action is dispatched — same effect as cancelling
|
|
181
|
+
* a click on `mouseleave`.
|
|
182
|
+
* - Drags smaller than `MIN_AREA_FRACTION` in BOTH dimensions are
|
|
183
|
+
* dropped — a click on the host still fires normal `click`
|
|
184
|
+
* handlers via the compatibility mouse events.
|
|
185
|
+
* - For text-bearing hosts, set `user-select: none` (the directive
|
|
186
|
+
* deliberately does NOT call `preventDefault()` on `pointerdown`
|
|
187
|
+
* so click handlers still receive the gesture; that means the
|
|
188
|
+
* browser's default text-selection-on-drag behaviour also fires
|
|
189
|
+
* unless the host opts out via CSS).
|
|
190
|
+
* - The overlay uses `z-index: var(--lvt-area-select-z-index, 9999)`.
|
|
191
|
+
* 9999 is high enough for most use cases but can collide with
|
|
192
|
+
* portals / modals / drawers that also sit at a high z-index.
|
|
193
|
+
* Set `--lvt-area-select-z-index` on the host (or any ancestor)
|
|
194
|
+
* to override. Color + fill follow the same pattern via
|
|
195
|
+
* `--lvt-area-select-color` and `--lvt-area-select-fill`.
|
|
196
|
+
* - **No keyboard equivalent.** Pointer-only by design (a keyboard-
|
|
197
|
+
* selected rectangle requires a different UX — focus + arrow keys
|
|
198
|
+
* to position + arrow keys to size). Consumers needing a11y for
|
|
199
|
+
* area selection should provide a parallel form-based affordance.
|
|
200
|
+
*
|
|
201
|
+
* Idempotent across renders: an element re-armed with the same action
|
|
202
|
+
* keeps its existing listeners. A different action causes a tear-down
|
|
203
|
+
* and re-arm. Disconnected elements (and elements whose attribute was
|
|
204
|
+
* cleared by a server diff) get their listeners cleaned up by the
|
|
205
|
+
* sweep at the top of every call — we use a regular Map (not WeakMap)
|
|
206
|
+
* specifically so the sweep can iterate.
|
|
207
|
+
*
|
|
208
|
+
* Module-level singleton: `areaSelectArmed` is shared across all
|
|
209
|
+
* LiveTemplateClient instances in the same window. If two clients
|
|
210
|
+
* ever arm the same element with different actions, the second wins
|
|
211
|
+
* and the first client's send() is orphaned. Single-client use is
|
|
212
|
+
* unaffected.
|
|
213
|
+
*/
|
|
214
|
+
export declare function handleAreaSelectDirectives(rootElement: Element, send: (message: {
|
|
215
|
+
action: string;
|
|
216
|
+
data: Record<string, unknown>;
|
|
217
|
+
}) => void): void;
|
|
218
|
+
/**
|
|
219
|
+
* Cancel area-select listeners for every armed element under root.
|
|
220
|
+
* Mirrors teardownAutoClickTimers: meant for the client's disconnect /
|
|
221
|
+
* destroy lifecycle so the module-level singleton doesn't outlive a
|
|
222
|
+
* client that was torn down without a subsequent
|
|
223
|
+
* handleAreaSelectDirectives call (e.g. network error closed the
|
|
224
|
+
* socket while an element was armed). Without this, a SPA that mounts
|
|
225
|
+
* + tears down livetemplate trees would leak listeners across mounts.
|
|
226
|
+
*/
|
|
227
|
+
export declare function teardownAreaSelectForRoot(rootElement: Element): void;
|
|
228
|
+
/**
|
|
229
|
+
* Apply url-hash directives. `lvt-fx:url-hash="<actionName>"` plus a
|
|
230
|
+
* `data-lvt-url-hash="<hash>"` attribute on an element (typically the
|
|
231
|
+
* `<body>`) wires a two-way bridge between server state and
|
|
232
|
+
* `location.hash`:
|
|
233
|
+
*
|
|
234
|
+
* - **State → URL** (every render): if `data-lvt-url-hash` differs
|
|
235
|
+
* from `location.hash`, mirror the data-attr into the URL via
|
|
236
|
+
* `history.pushState` when the path component changed (everything
|
|
237
|
+
* before the first `:`) or `history.replaceState` when only the
|
|
238
|
+
* target (line range / anchor) changed. Replace is the right
|
|
239
|
+
* default for line scrolls so the back-button cycles between files,
|
|
240
|
+
* not between every clicked line.
|
|
241
|
+
* - **URL → State** (on `hashchange` AND initial arm): dispatch
|
|
242
|
+
* `{action: <actionName>, data: {hash: <hash>}}` so the server can
|
|
243
|
+
* parse the hash and update its state (which then renders back as
|
|
244
|
+
* a matching data-attr — closing the loop).
|
|
245
|
+
*
|
|
246
|
+
* The directive uses `history.pushState`/`replaceState` (not
|
|
247
|
+
* `location.hash = ...`) for the state→URL direction precisely so
|
|
248
|
+
* those writes do NOT fire `hashchange` — only true user-initiated
|
|
249
|
+
* navigation (anchor click, address-bar edit, back-button) reaches
|
|
250
|
+
* the URL→state listener. This avoids the obvious infinite loop.
|
|
251
|
+
*
|
|
252
|
+
* Idempotent across renders: same action → keep listener + update
|
|
253
|
+
* send. Different action → cleanup + re-arm. Detached / attribute-
|
|
254
|
+
* removed elements are swept on every call (same pattern as
|
|
255
|
+
* area-select). The window listener is registered on first arm and
|
|
256
|
+
* removed when the armed map becomes empty.
|
|
257
|
+
*
|
|
258
|
+
* Coexistence with `setupHashLink`: prereview-style hashes
|
|
259
|
+
* (`README.md:L4`, `foo/bar.html:h-anchor`) never match a
|
|
260
|
+
* `document.getElementById(...)`, so the existing dialog/popover/
|
|
261
|
+
* details hash machinery silently no-ops. If a deep-link hash
|
|
262
|
+
* happens to collide with an element id, both handlers will fire —
|
|
263
|
+
* the server is expected to no-op on hashes that don't resolve to a
|
|
264
|
+
* known file.
|
|
265
|
+
*
|
|
266
|
+
* **Pre-encoding contract**: `data-lvt-url-hash` must hold the hash
|
|
267
|
+
* value already in URL-encoded form. The directive writes the
|
|
268
|
+
* attribute verbatim into `history.pushState`/`replaceState`, so a
|
|
269
|
+
* value containing spaces, `[`, `]`, `%`, or other reserved
|
|
270
|
+
* characters needs to be percent-encoded by the server. The hash
|
|
271
|
+
* sent to the action on `hashchange` is also passed through unmodified
|
|
272
|
+
* (no decoding) — both directions are byte-exact mirrors of what's
|
|
273
|
+
* in `location.hash`.
|
|
274
|
+
*
|
|
275
|
+
* **URL/state divergence after a non-deep-link initial load**: if
|
|
276
|
+
* the user lands with a native-anchor hash (`#hero`) AND the server
|
|
277
|
+
* has a selected file, the directive leaves the URL on `#hero` (case
|
|
278
|
+
* b) — URL and server state diverge until the user navigates. This
|
|
279
|
+
* is intentional: popovers/anchors aren't ours to overwrite. The
|
|
280
|
+
* next user action that triggers a server render will re-sync only
|
|
281
|
+
* once URL and state share a deep-link hash.
|
|
282
|
+
*
|
|
283
|
+
* **Path-only deep links require an extension**: the
|
|
284
|
+
* `looksLikeDeepLinkHash` heuristic dispatches only hashes
|
|
285
|
+
* containing `:`, `/`, or `.`. Extension-less root files
|
|
286
|
+
* (`#Makefile`, `#Dockerfile`, `#LICENSE`) won't dispatch as
|
|
287
|
+
* path-only deep links — use the line form (`#Makefile:L1`)
|
|
288
|
+
* instead. The trade-off favours not clobbering native-anchor
|
|
289
|
+
* machinery for single-token hashes.
|
|
290
|
+
*/
|
|
291
|
+
export declare function handleURLHashDirective(rootElement: Element, send: (message: {
|
|
292
|
+
action: string;
|
|
293
|
+
data: Record<string, unknown>;
|
|
294
|
+
}) => void): void;
|
|
295
|
+
/**
|
|
296
|
+
* Cancel url-hash listeners for every armed element under root. Same
|
|
297
|
+
* lifecycle role as teardownAreaSelectForRoot.
|
|
298
|
+
*/
|
|
299
|
+
export declare function teardownURLHashForRoot(rootElement: Element): void;
|
|
300
|
+
/**
|
|
301
|
+
* Test-only: reset the per-page dedupe Set that suppresses repeated
|
|
302
|
+
* `warnIfUnencodedHash` calls for the same hash value. Production
|
|
303
|
+
* code shouldn't need this — the Set is bounded by the number of
|
|
304
|
+
* unique malformed hashes — but tests that re-use the same hash
|
|
305
|
+
* across cases need to clear it or the second test won't see the
|
|
306
|
+
* warning. Mirrors `__resetAnimatedElementsForTesting`.
|
|
307
|
+
*/
|
|
308
|
+
export declare function __resetURLHashUnencodedWarnedForTesting(): void;
|
|
156
309
|
//# sourceMappingURL=directives.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../../dom/directives.ts"],"names":[],"mappings":"AA4CA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iCAAiC,IAAI,IAAI,CAKxD;AAsBD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CA0CvF;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAWrE;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,OAAO,EACpB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,IAAI,CAiBN;AAiLD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAiBpE;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAUvE;AAaD,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAMjE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CA8FpE;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAMpE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAQlE;AAwCD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CA4BhE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAW7C;AAkFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAyGpE"}
|
|
1
|
+
{"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../../dom/directives.ts"],"names":[],"mappings":"AA4CA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iCAAiC,IAAI,IAAI,CAKxD;AAsBD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,CA0CvF;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAWrE;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,OAAO,EACpB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,IAAI,CAiBN;AAiLD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAiBpE;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAUvE;AAaD,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAMjE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CA8FpE;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAMpE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAQlE;AAwCD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CA4BhE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAW7C;AAkFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAyGpE;AA4CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,OAAO,EACpB,IAAI,EAAE,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,KAAK,IAAI,GACzE,IAAI,CAyCN;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CAQpE;AAqDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,OAAO,EACpB,IAAI,EAAE,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,KAAK,IAAI,GACzE,IAAI,CAyFN;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,OAAO,GAAG,IAAI,CA0BjE;AAgFD;;;;;;;GAOG;AACH,wBAAgB,uCAAuC,IAAI,IAAI,CAE9D"}
|