@zumer/snapdom-plugins 4.2.0 → 4.2.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Plugin changes
2
2
 
3
+ ## 4.2.1
4
+
5
+ - Fix the stream plugin: a box cut by an ancestor with overflow hidden was painted whole. Patches now stay inside every clipping ancestor.
6
+ - Export asciiFromCanvas and asciiStream from the package entry point, as the type declarations already did.
7
+ - Declare result.toStream() on the capture result type.
8
+ - Set the SnapDOM peer dependency to ^3.4.0 (3.3.8 was never published) and document asciiFromCanvas and asciiStream in the README.
9
+
10
+ Requires SnapDOM 3.4.0 or newer within 3.x.
11
+
3
12
  ## 4.2.0
4
13
 
5
14
  - Export asciiFromCanvas(source, options) from @zumer/snapdom-plugins/ascii-export: the ASCII conversion on its own, for a canvas, an image, a video frame or a stream frame. toAscii() keeps its output.
package/README.md CHANGED
@@ -16,7 +16,7 @@ Install the plugins next to a core supported by their peer dependency:
16
16
  npm install @zumer/snapdom@latest @zumer/snapdom-plugins@latest
17
17
  ```
18
18
 
19
- Plugins 4.x in this checkout require SnapDOM 3.3.8 or newer within 3.x. The 4.x release replaces pdf-image with the full PDF exporter and adds Vector. Both are MIT-licensed and available on npm in `@zumer/snapdom-plugins` 4.x. The `@latest` command above installs the published release. See the [migration guide](https://github.com/zumerlab/snapdom#migrating-from-v2) when upgrading from v2.
19
+ Plugins 4.x in this checkout require SnapDOM 3.4.0 or newer within 3.x. The 4.x release replaces pdf-image with the full PDF exporter and adds Vector. Both are MIT-licensed and available on npm in `@zumer/snapdom-plugins` 4.x. The `@latest` command above installs the published release. See the [migration guide](https://github.com/zumerlab/snapdom#migrating-from-v2) when upgrading from v2.
20
20
 
21
21
  ## Usage
22
22
 
@@ -222,8 +222,22 @@ console.log(art);
222
222
  | `width` | `number` | `80` | Character width of output |
223
223
  | `charset` | `string` | `' .:-=+*#%@'` | Characters from lightest to darkest |
224
224
  | `invert` | `boolean` | `false` | Invert luminance mapping |
225
+ | `format` | `'text' \| 'html'` | `'text'` | Plain text, or colored HTML in a `<pre>` |
226
+ | `contrast` | `number` | `0` | Non-negative luminance contrast boost |
225
227
 
226
- `toAscii({ width, charset, invert })` overrides any of the three per call.
228
+ `toAscii({ width, charset, invert, format, contrast })` overrides any of them per call.
229
+
230
+ The conversion is also exported on its own. `asciiFromCanvas(source, options)` turns any
231
+ drawable (a canvas, an image, a video frame) into ASCII with the same options, and
232
+ `asciiStream(element, options)` runs it on every frame of a [`stream()`](stream/README.md):
233
+
234
+ ```js
235
+ import { asciiStream } from '@zumer/snapdom-plugins/ascii-export';
236
+
237
+ const live = asciiStream(el, { width: 100, fps: 15, onText: (text) => (pre.textContent = text) });
238
+ await live.ready;
239
+ live.stop();
240
+ ```
227
241
 
228
242
  ---
229
243
 
package/context-export.js CHANGED
@@ -228,7 +228,7 @@ function buildNode(el, rootRect, maxNodes, geometry, state) {
228
228
  Math.round(r.left - rootRect.left), Math.round(r.top - rootRect.top),
229
229
  Math.round(r.width), Math.round(r.height),
230
230
  ]
231
- } catch { }
231
+ } catch { /* a node without layout keeps no box */ }
232
232
  }
233
233
  const text = visibleText(el)
234
234
  if (text) node.text = text
package/index.js CHANGED
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  export { timestampOverlay } from './timestamp-overlay.js';
10
- export { asciiExport } from './ascii-export.js';
10
+ export { asciiExport, asciiFromCanvas, asciiStream } from './ascii-export.js';
11
11
  export { replaceText } from './replace-text.js';
12
12
  export { redactInputs } from './redact-inputs.js';
13
13
  export { filter } from './filter.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zumer/snapdom-plugins",
3
- "version": "4.2.0",
3
+ "version": "4.2.1",
4
4
  "description": "Official plugins for SnapDOM",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -66,7 +66,7 @@
66
66
  "url": "https://github.com/sponsors/tinchox5"
67
67
  },
68
68
  "peerDependencies": {
69
- "@zumer/snapdom": "^3.3.8"
69
+ "@zumer/snapdom": "^3.4.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@zumer/snapdom": "file:../.."
package/stream/README.md CHANGED
@@ -131,7 +131,7 @@ const live = await result.toStream({ onFrame });
131
131
  them.
132
132
  - Text ink that spills past a box edge onto a pixel shared with a neighbour waits for the
133
133
  keyframe.
134
- - Needs SnapDOM 3.3.8 or newer, which has the `__subpixel` layout option. On an older core the
134
+ - Needs SnapDOM 3.4.0 or newer, which has the `__subpixel` layout option. On an older core the
135
135
  stream still runs, but patches at fractional positions are not pixel-exact.
136
136
 
137
137
  Demos: `demos/stream-templates.html`, `demos/stream-overlay.html`, `demos/stream-webrtc.html`, `demos/stream-webgl.html`,
@@ -215,27 +215,30 @@ export function stream(element, options = {}) {
215
215
  function hostFor(node) {
216
216
  let el = node?.nodeType === 1 ? node : node?.parentElement
217
217
  if (!el || el === element || !element.contains(el)) return null
218
- const chain = []
219
- for (let a = el; a && a !== element; a = a.parentElement) chain.push(a)
220
- // Search above the highest ancestor with an effect or a clip the box would escape.
218
+ const chain = [], styles = []
219
+ for (let a = el; a && a !== element; a = a.parentElement) { chain.push(a); styles.push(getComputedStyle(a)) }
220
+ // Search above the highest ancestor with an effect.
221
221
  let start = 0
222
- for (let i = 0; i < chain.length; i++) {
223
- const cs = getComputedStyle(chain[i])
224
- if (hasEffect(cs)) start = i + 1
225
- else if (i > 0 && clips(cs) && escapesClip(rectOf(chain[0]), rectOf(chain[i]), cs)) start = i
226
- }
222
+ for (let i = 0; i < chain.length; i++) if (hasEffect(styles[i])) start = i + 1
227
223
  for (let i = start; i < chain.length; i++) {
228
- const cs = getComputedStyle(chain[i])
224
+ const cs = styles[i]
229
225
  if (!opaqueColor(cs.backgroundColor)) continue
230
226
  // Visible overflow paints outside the box, over pixels the patch does not repaint.
231
227
  if (!clips(cs) && (chain[i].scrollWidth > chain[i].clientWidth + 1 || chain[i].scrollHeight > chain[i].clientHeight + 1)) continue
232
- return chain[i]
228
+ // A box a clipping ancestor cuts, past its edges or into a rounded corner, would be
229
+ // drawn whole: a row half out of a 40px scroller painted its hidden half (19200 px
230
+ // off). The host is the box itself, so the test is on its rect, not on the changed
231
+ // node's. Resume at the outermost ancestor that cuts it.
232
+ const r = rectOf(chain[i])
233
+ let cut = -1
234
+ for (let m = i + 1; m < chain.length; m++) if (clips(styles[m]) && escapesClip(r, rectOf(chain[m]), styles[m])) cut = m
235
+ if (cut < 0) return chain[i]
236
+ i = cut - 1
233
237
  }
234
238
  return null
235
239
  }
236
240
 
237
241
  async function full() {
238
- // A full frame is the one long task of a stream; 'auto' lets a long clone yield (#503).
239
242
  const t0 = performance.now()
240
243
  // A full frame is the one long task of a stream; 'auto' lets a long clone yield (#503).
241
244
  // Lab, 1000 cards under constant edits: worst frame gap 67 -> 33 ms. Under edits on
package/stream.d.ts CHANGED
@@ -35,6 +35,12 @@ export function stream(element: Element, options?: StreamOptions): Stream
35
35
  /** Plugin form: adds `result.toStream(options)` to a capture result. */
36
36
  export function streamExport(defaults?: StreamOptions): SnapdomPlugin
37
37
 
38
+ declare module '@zumer/snapdom' {
39
+ interface CaptureResult {
40
+ toStream(options?: StreamOptions): Promise<Stream>
41
+ }
42
+ }
43
+
38
44
  /** A WebGL texture kept in step with a stream; `update` uploads only the changed rects on WebGL2. */
39
45
  export function streamTexture(
40
46
  gl: WebGLRenderingContext | WebGL2RenderingContext,