@rcarls/rc-virtual-canvas 0.5.0 → 0.7.0

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,32 @@
1
1
  # @rcarls/rc-virtual-canvas
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 5c006de: Ship component CSS minified. Package builds now run the CSS in Lit `css` styles
8
+ and light-DOM structural styles through Lightning CSS, removing comments and
9
+ whitespace while keeping source maps that resolve to each template. Rendered
10
+ styles are unchanged.
11
+
12
+ `@rcarls/rc-common` adds `cssText`, an identity tag that marks a plain CSS
13
+ string for minification. `rc-chip`, `rc-disclosure`, and `rc-accordion` now
14
+ depend on `@rcarls/rc-common` for it.
15
+
16
+ - 1740c28: Map browser client coordinates to content CSS pixels independently of the canvas
17
+ backing-store resolution. Pointer coordinates no longer double under a 2x
18
+ backing store, and CSS zoom no longer changes the meaning of content positions.
19
+ `canvasScaleX` and `canvasScaleY` now report backing-store pixels per local CSS
20
+ pixel, so they remain accurate when an ancestor applies CSS zoom.
21
+
22
+ ## 0.6.0
23
+
24
+ ### Patch Changes
25
+
26
+ - 57370e4: Align component metadata, aggregate framework typings, development-time native-child
27
+ validation, controlled menu state, package declarations, and public documentation before the
28
+ next release.
29
+
3
30
  ## 0.5.0
4
31
 
5
32
  ## 0.4.2
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # `@rcarls/rc-virtual-canvas`
2
2
 
3
+ <!-- markdownlint-disable MD013 -->
4
+
3
5
  Scrollable virtual canvas for rendering large coordinate-space content.
4
6
 
5
7
  Docs: [https://richardcarls.github.io/rc-webcomponents/components/rc-virtual-canvas](https://richardcarls.github.io/rc-webcomponents/components/rc-virtual-canvas).
@@ -19,8 +21,8 @@ npm install @rcarls/rc-virtual-canvas
19
21
  ## Import
20
22
 
21
23
  ```js
22
- import '@rcarls/rc-virtual-canvas'; // side-effect: registers <rc-virtual-canvas>
23
- import { RCVirtualCanvas } from '@rcarls/rc-virtual-canvas'; // named class export
24
+ import '@rcarls/rc-virtual-canvas'; // side-effect: registers <rc-virtual-canvas>
25
+ import { RCVirtualCanvas } from '@rcarls/rc-virtual-canvas'; // named class export
24
26
  ```
25
27
 
26
28
  ---
@@ -56,7 +58,7 @@ total size of your virtual content. On each `rc-virtual-canvas-render` event, us
56
58
  ```
57
59
 
58
60
  The canvas element should match the component's rendered size (set via CSS). The virtual
59
- content is larger — scrolling is handled by an absolutely-positioned transparent `<div>`
61
+ content is larger; scrolling is handled by an absolutely positioned transparent `<div>`
60
62
  that triggers native scroll events.
61
63
 
62
64
  ---
@@ -65,65 +67,65 @@ that triggers native scroll events.
65
67
 
66
68
  ### Properties / attributes
67
69
 
68
- | Property | Attribute | Type | Default | Description |
69
- |---|---|---|---|---|
70
- | `contentWidth` | `content-width` | `number` | `0` | Total pixel width of the virtual content |
71
- | `contentHeight` | `content-height` | `number` | `0` | Total pixel height of the virtual content |
72
- | `autoResizeCanvas` | `auto-resize-canvas` | `boolean` | `true` | Keeps the slotted canvas backing store aligned to the measured viewport |
73
- | `renderMode` | `render-mode` | `'continuous' \| 'viewport-change' \| 'manual'` | `'continuous'` | Controls when render events are dispatched |
74
- | `imageRendering` | `image-rendering` | `'auto' \| 'crisp-edges' \| 'pixelated'` | `'auto'` | Convenience value applied to the slotted canvas via `image-rendering` |
70
+ | Property | Attribute | Type | Default | Description |
71
+ | ------------------ | -------------------- | ----------------------------------------------- | -------------- | ----------------------------------------------------------------------- |
72
+ | `contentWidth` | `content-width` | `number` | `0` | Total pixel width of the virtual content |
73
+ | `contentHeight` | `content-height` | `number` | `0` | Total pixel height of the virtual content |
74
+ | `autoResizeCanvas` | `auto-resize-canvas` | `boolean` | `true` | Keeps the slotted canvas backing store aligned to the measured viewport |
75
+ | `renderMode` | `render-mode` | `'continuous' \| 'viewport-change' \| 'manual'` | `'continuous'` | Controls when render events are dispatched |
76
+ | `imageRendering` | `image-rendering` | `'auto' \| 'crisp-edges' \| 'pixelated'` | `'auto'` | Convenience value applied to the slotted canvas via `image-rendering` |
75
77
 
76
78
  ### Read-only properties
77
79
 
78
- | Property | Type | Description |
79
- |---|---|---|
80
- | `canvasScaleX` | `number` | Ratio of canvas backing-store pixels to CSS pixels along the x-axis (≈ `devicePixelRatio` when `autoResizeCanvas` is `true`) |
81
- | `canvasScaleY` | `number` | Ratio of canvas backing-store pixels to CSS pixels along the y-axis |
80
+ | Property | Type | Description |
81
+ | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
82
+ | `canvasScaleX` | `number` | Ratio of canvas backing-store pixels to local CSS pixels along the x-axis; CSS zoom can make it differ from `devicePixelRatio` |
83
+ | `canvasScaleY` | `number` | Ratio of canvas backing-store pixels to CSS pixels along the y-axis |
82
84
 
83
85
  ### Methods
84
86
 
85
- | Method | Description |
86
- |---|---|
87
- | `getViewRect()` | Returns an immutable snapshot of the current viewport rectangle |
88
- | `scrollToContent(x, y, options?)` | Scrolls so the content coordinate is at the viewport origin |
89
- | `centerOnContent(x, y, options?)` | Scrolls so the content coordinate is centered in the viewport |
90
- | `clientToContent(clientX, clientY)` | Converts browser client coordinates to content coordinates using the current backing-store scale |
91
- | `contentToClient(x, y)` | Converts content coordinates back to browser client coordinates |
92
- | `requestRender(reason?)` | Queues a render event; required when `renderMode` is `'manual'` |
87
+ | Method | Description |
88
+ | ----------------------------------- | ------------------------------------------------------------------------ |
89
+ | `getViewRect()` | Returns an immutable snapshot of the current viewport rectangle |
90
+ | `scrollToContent(x, y, options?)` | Scrolls so the content coordinate is at the viewport origin |
91
+ | `centerOnContent(x, y, options?)` | Scrolls so the content coordinate is centered in the viewport |
92
+ | `clientToContent(clientX, clientY)` | Converts browser client coordinates to content coordinates in CSS pixels |
93
+ | `contentToClient(x, y)` | Converts content coordinates back to browser client coordinates |
94
+ | `requestRender(reason?)` | Queues a render event; required when `renderMode` is `'manual'` |
93
95
 
94
96
  ### CSS custom properties
95
97
 
96
- | Property | Default | Description |
97
- |---|---|---|
98
- | `--rc-virtual-canvas-image-rendering` | `auto` | Fallback styling hook for the slotted canvas `image-rendering` value |
98
+ | Property | Default | Description |
99
+ | ------------------------------------- | ------- | -------------------------------------------------------------------- |
100
+ | `--rc-virtual-canvas-image-rendering` | `auto` | Fallback styling hook for the slotted canvas `image-rendering` value |
99
101
 
100
102
  ### CSS parts
101
103
 
102
- | Part | Description |
103
- |---|---|
104
- | `scroller` | Internal scroll container that owns the virtual content scroll range |
105
- | `overlay` | Viewport-positioned overlay container rendered inside the scroll container |
104
+ | Part | Description |
105
+ | ---------- | -------------------------------------------------------------------------- |
106
+ | `scroller` | Internal scroll container that owns the virtual content scroll range |
107
+ | `overlay` | Viewport-positioned overlay container rendered inside the scroll container |
106
108
 
107
109
  ### Slots
108
110
 
109
- | Slot | Description |
110
- |---|---|
111
- | *(default)* | A single `<canvas>` element. Non-canvas slotted elements are ignored by the component but rendered. |
112
- | `overlay` | Optional viewport-positioned content rendered over the canvas inside the scroll container. |
111
+ | Slot | Description |
112
+ | ----------- | --------------------------------------------------------------------------------------------------- |
113
+ | _(default)_ | A single `<canvas>` element. Non-canvas slotted elements are ignored by the component but rendered. |
114
+ | `overlay` | Optional viewport-positioned content rendered over the canvas inside the scroll container. |
113
115
 
114
116
  ### Events
115
117
 
116
- | Event | Bubbles | Cancelable | Detail | When |
117
- |---|---|---|---|---|
118
- | `rc-virtual-canvas-render` | Yes (composed) | No | `{ time: DOMHighResTimeStamp, reason: RenderReason, viewRect: ViewRect, contentRect: ViewRect }` | When the active render mode schedules a frame and a canvas is slotted |
118
+ | Event | Bubbles | Cancelable | Detail | When |
119
+ | -------------------------- | -------------- | ---------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------- |
120
+ | `rc-virtual-canvas-render` | Yes (composed) | No | `{ time: DOMHighResTimeStamp, reason: RenderReason, viewRect: ViewRect, contentRect: ViewRect }` | When the active render mode schedules a frame and a canvas is slotted |
119
121
 
120
122
  **`ViewRect` shape:**
121
123
 
122
124
  ```ts
123
125
  type ViewRect = {
124
- x: number; // Scroll offset — the x origin of the visible window in content space
125
- y: number; // Scroll offset — the y origin of the visible window in content space
126
- width: number; // Visible width in device pixels (from ResizeObserver devicePixelContentBoxSize)
126
+ x: number; // Scroll offset; the x origin of the visible window in content space
127
+ y: number; // Scroll offset; the y origin of the visible window in content space
128
+ width: number; // Visible width in device pixels (from ResizeObserver devicePixelContentBoxSize)
127
129
  height: number; // Visible height in device pixels
128
130
  };
129
131
  ```
@@ -134,11 +136,11 @@ type ViewRect = {
134
136
 
135
137
  **Render modes:**
136
138
 
137
- | Mode | Behavior |
138
- |---|---|
139
- | `'continuous'` | Dispatches on every animation frame while connected and a canvas is slotted |
139
+ | Mode | Behavior |
140
+ | ------------------- | ----------------------------------------------------------------------------- |
141
+ | `'continuous'` | Dispatches on every animation frame while connected and a canvas is slotted |
140
142
  | `'viewport-change'` | Dispatches after scroll, resize, content-size changes, and canvas replacement |
141
- | `'manual'` | Dispatches only after `requestRender()` |
143
+ | `'manual'` | Dispatches only after `requestRender()` |
142
144
 
143
145
  ---
144
146
 
@@ -150,9 +152,14 @@ The component maps scroll position directly to content coordinates:
150
152
  - `viewRect.y` = `scrollTop` of the internal scroll container
151
153
  - `viewRect.width` / `viewRect.height` = canvas dimensions in device pixels (high-DPI aware)
152
154
 
155
+ `clientToContent()` and `contentToClient()` use CSS-pixel content coordinates. The
156
+ canvas backing-store resolution does not change pointer coordinates. Use
157
+ `canvasScaleX` and `canvasScaleY` only when scaling the drawing context.
158
+
153
159
  When drawing, offset your scene by `viewRect.x` and `viewRect.y` to align the visible portion with the canvas origin:
154
160
 
155
161
  ```js
162
+ ctx.setTransform(vc.canvasScaleX, 0, 0, vc.canvasScaleY, 0, 0);
156
163
  ctx.translate(-viewRect.x, -viewRect.y);
157
164
  drawEntireScene(ctx);
158
165
  ctx.resetTransform();
@@ -172,7 +179,7 @@ vc.addEventListener('pointerdown', (event) => {
172
179
 
173
180
  ## Accessibility
174
181
 
175
- `rc-virtual-canvas` is a rendering surface. A `<canvas>` element has no inherent semantics — it is a bitmap, not a document. If your canvas renders interactive or informational content, you are responsible for providing supplemental accessibility:
182
+ `rc-virtual-canvas` is a rendering surface. A `<canvas>` element has no inherent semantics; it is a bitmap, not a document. If your canvas renders interactive or informational content, you are responsible for providing supplemental accessibility:
176
183
 
177
184
  - Add an accessible `<div>` or `<table>` alternative outside the canvas with the same information (hidden visually with `clip-path` or similar, not `display: none`).
178
185
  - Use `aria-label` or `aria-labelledby` on the `<canvas>` to describe what it shows.
@@ -182,7 +189,7 @@ vc.addEventListener('pointerdown', (event) => {
182
189
 
183
190
  ## Browser support
184
191
 
185
- | Feature | Requirement |
186
- |---|---|
187
- | Core | Chrome 67+, Firefox 63+, Safari 12.1+ (Web Components) |
192
+ | Feature | Requirement |
193
+ | ---------------------------- | ---------------------------------------------------------------------------------- |
194
+ | Core | Chrome 67+, Firefox 63+, Safari 12.1+ (Web Components) |
188
195
  | Device-pixel-accurate sizing | Chrome 84+, Firefox 93+, Safari 15.4+ (ResizeObserver `devicePixelContentBoxSize`) |
@@ -35,7 +35,7 @@
35
35
  "name": "*",
36
36
  "declaration": {
37
37
  "name": "*",
38
- "module": "src/rc-virtual-canvas"
38
+ "module": "src/rc-virtual-canvas.js"
39
39
  }
40
40
  }
41
41
  ]
@@ -300,14 +300,14 @@
300
300
  "type": {
301
301
  "text": "number"
302
302
  },
303
- "description": "Content x coordinate in CSS pixels"
303
+ "description": "content x coordinate in CSS pixels"
304
304
  },
305
305
  {
306
306
  "name": "y",
307
307
  "type": {
308
308
  "text": "number"
309
309
  },
310
- "description": "Content y coordinate in CSS pixels"
310
+ "description": "content y coordinate in CSS pixels"
311
311
  },
312
312
  {
313
313
  "name": "options",
@@ -315,7 +315,7 @@
315
315
  "type": {
316
316
  "text": "ScrollOptions"
317
317
  },
318
- "description": "Native scroll options passed to scrollTo"
318
+ "description": "native scroll options passed to scrollTo"
319
319
  }
320
320
  ],
321
321
  "description": "Scrolls so the content coordinate is at the viewport origin."
@@ -329,14 +329,14 @@
329
329
  "type": {
330
330
  "text": "number"
331
331
  },
332
- "description": "Content x coordinate in CSS pixels"
332
+ "description": "content x coordinate in CSS pixels"
333
333
  },
334
334
  {
335
335
  "name": "y",
336
336
  "type": {
337
337
  "text": "number"
338
338
  },
339
- "description": "Content y coordinate in CSS pixels"
339
+ "description": "content y coordinate in CSS pixels"
340
340
  },
341
341
  {
342
342
  "name": "options",
@@ -344,7 +344,7 @@
344
344
  "type": {
345
345
  "text": "ScrollOptions"
346
346
  },
347
- "description": "Native scroll options passed to scrollTo"
347
+ "description": "native scroll options passed to scrollTo"
348
348
  }
349
349
  ],
350
350
  "description": "Scrolls so the content coordinate is centered in the viewport."
@@ -358,17 +358,17 @@
358
358
  "type": {
359
359
  "text": "number"
360
360
  },
361
- "description": "Browser client x coordinate (e.g. from a pointer event)"
361
+ "description": "browser client x coordinate (e.g. from a pointer event)"
362
362
  },
363
363
  {
364
364
  "name": "clientY",
365
365
  "type": {
366
366
  "text": "number"
367
367
  },
368
- "description": "Browser client y coordinate"
368
+ "description": "browser client y coordinate"
369
369
  }
370
370
  ],
371
- "description": "Converts browser client coordinates to content coordinates using the current\nbacking-store scale."
371
+ "description": "Converts browser client coordinates to CSS-pixel content coordinates.\nCanvas backing-store resolution does not change content coordinates."
372
372
  },
373
373
  {
374
374
  "kind": "method",
@@ -379,14 +379,14 @@
379
379
  "type": {
380
380
  "text": "number"
381
381
  },
382
- "description": "Content x coordinate in CSS pixels"
382
+ "description": "content x coordinate in CSS pixels"
383
383
  },
384
384
  {
385
385
  "name": "y",
386
386
  "type": {
387
387
  "text": "number"
388
388
  },
389
- "description": "Content y coordinate in CSS pixels"
389
+ "description": "content y coordinate in CSS pixels"
390
390
  }
391
391
  ],
392
392
  "description": "Converts content coordinates back to browser client coordinates."
@@ -401,7 +401,7 @@
401
401
  "type": {
402
402
  "text": "RCVirtualCanvasRenderReason"
403
403
  },
404
- "description": "Render reason reported in the event detail"
404
+ "description": "render reason reported in the event detail"
405
405
  }
406
406
  ],
407
407
  "description": "Queues a render event on the next animation frame.\n\nRequired when `renderMode` is `'manual'`. In other modes the component\nschedules renders automatically; calling this with reason `'animation-frame'`\nis a no-op when `renderMode` is `'viewport-change'`."
@@ -412,7 +412,7 @@
412
412
  "type": {
413
413
  "text": "number"
414
414
  },
415
- "description": "Ratio of canvas backing-store pixels to CSS pixels along the x-axis.\n\nEquals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the x-scale\nfactor in `ctx.scale()` to draw at CSS pixel resolution.",
415
+ "description": "Ratio of canvas backing-store pixels to CSS pixels along the x-axis.\n\nUse as the x-scale factor in `ctx.scale()` to draw at CSS pixel resolution.\nWhen `autoResizeCanvas` is true, CSS zoom changes this ratio along with\nthe backing-store resolution.",
416
416
  "readonly": true
417
417
  },
418
418
  {
@@ -421,7 +421,7 @@
421
421
  "type": {
422
422
  "text": "number"
423
423
  },
424
- "description": "Ratio of canvas backing-store pixels to CSS pixels along the y-axis.\n\nEquals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the y-scale\nfactor in `ctx.scale()` to draw at CSS pixel resolution.",
424
+ "description": "Ratio of canvas backing-store pixels to CSS pixels along the y-axis.\n\nUse as the y-scale factor in `ctx.scale()` to draw at CSS pixel resolution.\nCSS zoom can make this ratio differ from `devicePixelRatio`.",
425
425
  "readonly": true
426
426
  },
427
427
  {
@@ -466,7 +466,7 @@
466
466
  "type": {
467
467
  "text": "DOMHighResTimeStamp"
468
468
  },
469
- "description": "High-resolution timestamp from `requestAnimationFrame`"
469
+ "description": "high-resolution timestamp from `requestAnimationFrame`"
470
470
  }
471
471
  ],
472
472
  "description": "RAF callback. Dispatches `rc-virtual-canvas-render` and re-schedules in continuous mode."
@@ -522,11 +522,36 @@
522
522
  },
523
523
  {
524
524
  "kind": "method",
525
- "name": "_getViewportScaleX",
525
+ "name": "_getCanvasCssWidth",
526
526
  "privacy": "protected",
527
+ "return": {
528
+ "type": {
529
+ "text": "number"
530
+ }
531
+ }
532
+ },
533
+ {
534
+ "kind": "method",
535
+ "name": "_getCanvasCssHeight",
536
+ "privacy": "protected",
537
+ "return": {
538
+ "type": {
539
+ "text": "number"
540
+ }
541
+ }
542
+ },
543
+ {
544
+ "kind": "method",
545
+ "name": "_getClientToContentScaleX",
546
+ "privacy": "protected",
547
+ "return": {
548
+ "type": {
549
+ "text": "number"
550
+ }
551
+ },
527
552
  "parameters": [
528
553
  {
529
- "name": "canvasRect",
554
+ "name": "canvasViewportRect",
530
555
  "type": {
531
556
  "text": "DOMRect"
532
557
  }
@@ -535,11 +560,16 @@
535
560
  },
536
561
  {
537
562
  "kind": "method",
538
- "name": "_getViewportScaleY",
563
+ "name": "_getClientToContentScaleY",
539
564
  "privacy": "protected",
565
+ "return": {
566
+ "type": {
567
+ "text": "number"
568
+ }
569
+ },
540
570
  "parameters": [
541
571
  {
542
- "name": "canvasRect",
572
+ "name": "canvasViewportRect",
543
573
  "type": {
544
574
  "text": "DOMRect"
545
575
  }
@@ -1,79 +1,11 @@
1
- import { css as _, LitElement as p, html as g } from "lit";
1
+ import { css as _, LitElement as g, html as p } from "lit";
2
2
  import { property as h, query as u, state as d } from "lit/decorators.js";
3
3
  import { styleMap as b } from "lit/directives/style-map.js";
4
- const w = _`
5
- *,
6
- *::before,
7
- *::after {
8
- box-sizing: border-box;
9
- }
10
-
11
- :host {
12
- position: relative;
13
- display: block;
14
- width: max-content;
15
- line-height: 0; /* remove extra space under slotted <canvas> element(s) */
16
- }
17
-
18
- :host([hidden]) {
19
- display: none;
20
- }
21
-
22
- #root {
23
- position: absolute;
24
- top: 0;
25
- left: 0;
26
- width: 100%;
27
- height: 100%;
28
-
29
- overflow: auto;
30
- scrollbar-width: var(--rc-virtual-canvas-scrollbar-width, thin);
31
- }
32
-
33
- #root::-webkit-scrollbar {
34
- width: var(--rc-virtual-canvas-scrollbar-size, auto);
35
- height: var(--rc-virtual-canvas-scrollbar-size, auto);
36
- }
37
-
38
- #root::-webkit-scrollbar-thumb {
39
- background: var(--rc-virtual-canvas-scrollbar-thumb-background, ButtonFace);
40
- }
41
-
42
- #root::-webkit-scrollbar-button {
43
- background: var(--rc-virtual-canvas-scrollbar-button-background, ButtonFace);
44
- }
45
-
46
- #root::-webkit-scrollbar-track {
47
- background: var(--rc-virtual-canvas-scrollbar-track-background, Canvas);
48
- }
49
-
50
- #placeholder {
51
- pointer-events: none;
52
- }
53
-
54
- #overlay {
55
- position: sticky;
56
- left: 0;
57
- top: 0;
58
- z-index: 1;
59
- display: block;
60
- width: 100%;
61
- height: 0;
62
- pointer-events: none;
63
- }
64
-
65
- ::slotted([slot='overlay']) {
66
- pointer-events: auto;
67
- }
68
-
69
- ::slotted(canvas) {
70
- image-rendering: var(--rc-virtual-canvas-image-rendering, auto);
71
- }
72
- `;
73
- var R = Object.defineProperty, m = Object.getOwnPropertyDescriptor, o = (r, t, e, i) => {
74
- for (var s = i > 1 ? void 0 : i ? m(t, e) : t, a = r.length - 1, l; a >= 0; a--)
75
- (l = r[a]) && (s = (i ? l(t, e, s) : l(s)) || s);
76
- return i && s && R(t, e, s), s;
4
+ const w = _`*,:before,:after{box-sizing:border-box}:host{width:max-content;line-height:0;display:block;position:relative}:host([hidden]){display:none}#root{scrollbar-width:var(--rc-virtual-canvas-scrollbar-width,thin);width:100%;height:100%;position:absolute;top:0;left:0;overflow:auto}#root::-webkit-scrollbar{width:var(--rc-virtual-canvas-scrollbar-size,auto);height:var(--rc-virtual-canvas-scrollbar-size,auto)}#root::-webkit-scrollbar-thumb{background:var(--rc-virtual-canvas-scrollbar-thumb-background,ButtonFace)}#root::-webkit-scrollbar-button{background:var(--rc-virtual-canvas-scrollbar-button-background,ButtonFace)}#root::-webkit-scrollbar-track{background:var(--rc-virtual-canvas-scrollbar-track-background,Canvas)}#placeholder{pointer-events:none}#overlay{z-index:1;pointer-events:none;width:100%;height:0;display:block;position:sticky;top:0;left:0}::slotted([slot=overlay]){pointer-events:auto}::slotted(canvas){image-rendering:var(--rc-virtual-canvas-image-rendering,auto)}`;
5
+ var C = Object.defineProperty, f = Object.getOwnPropertyDescriptor, o = (r, t, e, n) => {
6
+ for (var s = n > 1 ? void 0 : n ? f(t, e) : t, a = r.length - 1, l; a >= 0; a--)
7
+ (l = r[a]) && (s = (n ? l(t, e, s) : l(s)) || s);
8
+ return n && s && C(t, e, s), s;
77
9
  };
78
10
  function c(r) {
79
11
  return Object.freeze({
@@ -83,7 +15,7 @@ function c(r) {
83
15
  height: r.height
84
16
  });
85
17
  }
86
- const v = class v extends p {
18
+ const v = class v extends g {
87
19
  constructor() {
88
20
  super(...arguments), this._rafHandle = 0, this._handledPointerEvents = /* @__PURE__ */ new WeakSet(), this._boundUpdate = (t) => this._update(t), this._boundPointerEvent = (t) => this._onPointerEvent(t), this._contentWidth = 0, this._contentHeight = 0, this.autoResizeCanvas = !0, this.renderMode = "continuous", this.imageRendering = "auto", this._$canvas = null, this._viewRect = {
89
21
  x: 0,
@@ -97,15 +29,17 @@ const v = class v extends p {
97
29
  height: 0
98
30
  }, this._resizeObserver = new ResizeObserver((t) => {
99
31
  for (const e of t) {
100
- const i = Array.isArray(e.devicePixelContentBoxSize) ? e.devicePixelContentBoxSize[0] : e.devicePixelContentBoxSize;
32
+ const n = Array.isArray(e.devicePixelContentBoxSize) ? e.devicePixelContentBoxSize[0] : e.devicePixelContentBoxSize;
101
33
  this._viewRect.width = this._getMeasuredCanvasWidth(
102
- i?.inlineSize ?? Math.round(e.contentRect.width * window.devicePixelRatio)
34
+ n?.inlineSize ?? Math.round(e.contentRect.width * window.devicePixelRatio)
103
35
  ), this._viewRect.height = this._getMeasuredCanvasHeight(
104
- i?.blockSize ?? Math.round(e.contentRect.height * window.devicePixelRatio)
36
+ n?.blockSize ?? Math.round(e.contentRect.height * window.devicePixelRatio)
105
37
  ), this._syncCanvasBackingStore(), this._scheduleRender("viewport-change");
106
38
  }
107
39
  });
108
40
  }
41
+ firstUpdated() {
42
+ }
109
43
  set contentWidth(t) {
110
44
  const e = this._contentWidth;
111
45
  this._contentWidth = t, this._contentRect.width = this._contentWidth, this.requestUpdate("contentWidth", e), this._scheduleRender("viewport-change");
@@ -157,13 +91,13 @@ const v = class v extends p {
157
91
  /**
158
92
  * Scrolls so the content coordinate is at the viewport origin.
159
93
  *
160
- * @param x - Content x coordinate in CSS pixels
161
- * @param y - Content y coordinate in CSS pixels
162
- * @param options - Native scroll options passed to scrollTo
94
+ * @param x - content x coordinate in CSS pixels
95
+ * @param y - content y coordinate in CSS pixels
96
+ * @param options - native scroll options passed to scrollTo
163
97
  */
164
- scrollToContent(t, e, i = {}) {
98
+ scrollToContent(t, e, n = {}) {
165
99
  this._$root.scrollTo({
166
- ...i,
100
+ ...n,
167
101
  left: t,
168
102
  top: e
169
103
  }), this._viewRect.x = this._$root.scrollLeft, this._viewRect.y = this._$root.scrollTop, this._scheduleRender("viewport-change");
@@ -171,23 +105,23 @@ const v = class v extends p {
171
105
  /**
172
106
  * Scrolls so the content coordinate is centered in the viewport.
173
107
  *
174
- * @param x - Content x coordinate in CSS pixels
175
- * @param y - Content y coordinate in CSS pixels
176
- * @param options - Native scroll options passed to scrollTo
108
+ * @param x - content x coordinate in CSS pixels
109
+ * @param y - content y coordinate in CSS pixels
110
+ * @param options - native scroll options passed to scrollTo
177
111
  */
178
- centerOnContent(t, e, i = {}) {
112
+ centerOnContent(t, e, n = {}) {
179
113
  this.scrollToContent(
180
114
  t - this._$root.clientWidth * 0.5,
181
115
  e - this._$root.clientHeight * 0.5,
182
- i
116
+ n
183
117
  );
184
118
  }
185
119
  /**
186
- * Converts browser client coordinates to content coordinates using the current
187
- * backing-store scale.
120
+ * Converts browser client coordinates to CSS-pixel content coordinates.
121
+ * Canvas backing-store resolution does not change content coordinates.
188
122
  *
189
- * @param clientX - Browser client x coordinate (e.g. from a pointer event)
190
- * @param clientY - Browser client y coordinate
123
+ * @param clientX - browser client x coordinate (e.g. from a pointer event)
124
+ * @param clientY - browser client y coordinate
191
125
  *
192
126
  * @example
193
127
  * vc.addEventListener('pointerdown', (e) => {
@@ -196,28 +130,27 @@ const v = class v extends p {
196
130
  * });
197
131
  */
198
132
  clientToContent(t, e) {
199
- const i = this._getCanvasClientRect(), s = this._getViewportScaleX(i), a = this._getViewportScaleY(i);
133
+ const n = this._getCanvasClientRect(), s = this._getClientToContentScaleX(n), a = this._getClientToContentScaleY(n);
200
134
  return Object.freeze({
201
- x: this._viewRect.x + (t - i.left) * s,
202
- y: this._viewRect.y + (e - i.top) * a
135
+ x: this._viewRect.x + (t - n.left) * s,
136
+ y: this._viewRect.y + (e - n.top) * a
203
137
  });
204
138
  }
205
139
  /**
206
140
  * Converts content coordinates back to browser client coordinates.
207
141
  *
208
- * @param x - Content x coordinate in CSS pixels
209
- * @param y - Content y coordinate in CSS pixels
142
+ * @param x - content x coordinate in CSS pixels
143
+ * @param y - content y coordinate in CSS pixels
210
144
  *
211
145
  * @example
212
146
  * const { x, y } = vc.contentToClient(contentX, contentY);
213
- * tooltip.style.left = `${x}px`;
214
- * tooltip.style.top = `${y}px`;
147
+ * const elementAtPoint = document.elementFromPoint(x, y);
215
148
  */
216
149
  contentToClient(t, e) {
217
- const i = this._getCanvasClientRect(), s = this._getViewportScaleX(i), a = this._getViewportScaleY(i);
150
+ const n = this._getCanvasClientRect(), s = this._getClientToContentScaleX(n), a = this._getClientToContentScaleY(n);
218
151
  return Object.freeze({
219
- x: i.left + (t - this._viewRect.x) / s,
220
- y: i.top + (e - this._viewRect.y) / a
152
+ x: n.left + (t - this._viewRect.x) / s,
153
+ y: n.top + (e - this._viewRect.y) / a
221
154
  });
222
155
  }
223
156
  /**
@@ -227,7 +160,7 @@ const v = class v extends p {
227
160
  * schedules renders automatically; calling this with reason `'animation-frame'`
228
161
  * is a no-op when `renderMode` is `'viewport-change'`.
229
162
  *
230
- * @param reason - Render reason reported in the event detail
163
+ * @param reason - render reason reported in the event detail
231
164
  */
232
165
  requestRender(t = "manual") {
233
166
  this._scheduleRender(t);
@@ -235,8 +168,9 @@ const v = class v extends p {
235
168
  /**
236
169
  * Ratio of canvas backing-store pixels to CSS pixels along the x-axis.
237
170
  *
238
- * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the x-scale
239
- * factor in `ctx.scale()` to draw at CSS pixel resolution.
171
+ * Use as the x-scale factor in `ctx.scale()` to draw at CSS pixel resolution.
172
+ * When `autoResizeCanvas` is true, CSS zoom changes this ratio along with
173
+ * the backing-store resolution.
240
174
  *
241
175
  * @example
242
176
  * vc.addEventListener('rc-virtual-canvas-render', ({ detail: { viewRect } }) => {
@@ -247,18 +181,18 @@ const v = class v extends p {
247
181
  * });
248
182
  */
249
183
  get canvasScaleX() {
250
- const t = this._getCanvasClientRect();
251
- return this._getViewportScaleX(t);
184
+ const t = this._getCanvasCssWidth();
185
+ return t > 0 ? this._viewRect.width / t : 1;
252
186
  }
253
187
  /**
254
188
  * Ratio of canvas backing-store pixels to CSS pixels along the y-axis.
255
189
  *
256
- * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the y-scale
257
- * factor in `ctx.scale()` to draw at CSS pixel resolution.
190
+ * Use as the y-scale factor in `ctx.scale()` to draw at CSS pixel resolution.
191
+ * CSS zoom can make this ratio differ from `devicePixelRatio`.
258
192
  */
259
193
  get canvasScaleY() {
260
- const t = this._getCanvasClientRect();
261
- return this._getViewportScaleY(t);
194
+ const t = this._getCanvasCssHeight();
195
+ return t > 0 ? this._viewRect.height / t : 1;
262
196
  }
263
197
  /** Maps pointer and mouse events to content coordinates and dispatches `rc-virtual-canvas-pointer` */
264
198
  _onPointerEvent(t) {
@@ -295,7 +229,7 @@ const v = class v extends p {
295
229
  /**
296
230
  * RAF callback. Dispatches `rc-virtual-canvas-render` and re-schedules in continuous mode.
297
231
  *
298
- * @param time - High-resolution timestamp from `requestAnimationFrame`
232
+ * @param time - high-resolution timestamp from `requestAnimationFrame`
299
233
  */
300
234
  _update(t) {
301
235
  if (this._rafHandle = 0, !this.isConnected || this._$canvas == null)
@@ -344,14 +278,22 @@ const v = class v extends p {
344
278
  _getMeasuredCanvasHeight(t) {
345
279
  return !this.autoResizeCanvas && this._$canvas && this._$canvas.height > 0 ? this._$canvas.height : t;
346
280
  }
347
- _getViewportScaleX(t) {
348
- return t.width > 0 ? this._viewRect.width / t.width : 1;
281
+ _getCanvasCssWidth() {
282
+ return this._$canvas?.clientWidth ?? this.clientWidth;
283
+ }
284
+ _getCanvasCssHeight() {
285
+ return this._$canvas?.clientHeight ?? this.clientHeight;
286
+ }
287
+ _getClientToContentScaleX(t) {
288
+ const e = this._getCanvasCssWidth();
289
+ return t.width > 0 && e > 0 ? e / t.width : 1;
349
290
  }
350
- _getViewportScaleY(t) {
351
- return t.height > 0 ? this._viewRect.height / t.height : 1;
291
+ _getClientToContentScaleY(t) {
292
+ const e = this._getCanvasCssHeight();
293
+ return t.height > 0 && e > 0 ? e / t.height : 1;
352
294
  }
353
295
  render() {
354
- return g`
296
+ return p`
355
297
  <div
356
298
  id="root"
357
299
  part="scroller"
@@ -381,38 +323,38 @@ const v = class v extends p {
381
323
  }
382
324
  };
383
325
  v.styles = [w];
384
- let n = v;
326
+ let i = v;
385
327
  o([
386
328
  h({ type: Number, attribute: "content-width" })
387
- ], n.prototype, "contentWidth", 1);
329
+ ], i.prototype, "contentWidth", 1);
388
330
  o([
389
331
  h({ type: Number, attribute: "content-height" })
390
- ], n.prototype, "contentHeight", 1);
332
+ ], i.prototype, "contentHeight", 1);
391
333
  o([
392
334
  h({ attribute: "auto-resize-canvas", type: Boolean })
393
- ], n.prototype, "autoResizeCanvas", 2);
335
+ ], i.prototype, "autoResizeCanvas", 2);
394
336
  o([
395
337
  h({ attribute: "render-mode" })
396
- ], n.prototype, "renderMode", 2);
338
+ ], i.prototype, "renderMode", 2);
397
339
  o([
398
340
  h({ attribute: "image-rendering" })
399
- ], n.prototype, "imageRendering", 2);
341
+ ], i.prototype, "imageRendering", 2);
400
342
  o([
401
343
  u("#root", !0)
402
- ], n.prototype, "_$root", 2);
344
+ ], i.prototype, "_$root", 2);
403
345
  o([
404
346
  u("#placeholder", !0)
405
- ], n.prototype, "_$placeholder", 2);
347
+ ], i.prototype, "_$placeholder", 2);
406
348
  o([
407
349
  d()
408
- ], n.prototype, "_$canvas", 2);
350
+ ], i.prototype, "_$canvas", 2);
409
351
  o([
410
352
  d()
411
- ], n.prototype, "_viewRect", 2);
353
+ ], i.prototype, "_viewRect", 2);
412
354
  o([
413
355
  d()
414
- ], n.prototype, "_contentRect", 2);
356
+ ], i.prototype, "_contentRect", 2);
415
357
  export {
416
- n as R
358
+ i as R
417
359
  };
418
- //# sourceMappingURL=rc-virtual-canvas-BSpF0tcY.js.map
360
+ //# sourceMappingURL=rc-virtual-canvas-DIy-ABTk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-virtual-canvas-DIy-ABTk.js","sources":["../src/rc-virtual-canvas.styles.ts","../src/rc-virtual-canvas.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const virtualCanvasStyles = css`\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n :host {\n position: relative;\n display: block;\n width: max-content;\n line-height: 0; /* remove extra space under slotted <canvas> element(s) */\n }\n\n :host([hidden]) {\n display: none;\n }\n\n #root {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n overflow: auto;\n scrollbar-width: var(--rc-virtual-canvas-scrollbar-width, thin);\n }\n\n #root::-webkit-scrollbar {\n width: var(--rc-virtual-canvas-scrollbar-size, auto);\n height: var(--rc-virtual-canvas-scrollbar-size, auto);\n }\n\n #root::-webkit-scrollbar-thumb {\n background: var(--rc-virtual-canvas-scrollbar-thumb-background, ButtonFace);\n }\n\n #root::-webkit-scrollbar-button {\n background: var(--rc-virtual-canvas-scrollbar-button-background, ButtonFace);\n }\n\n #root::-webkit-scrollbar-track {\n background: var(--rc-virtual-canvas-scrollbar-track-background, Canvas);\n }\n\n #placeholder {\n pointer-events: none;\n }\n\n #overlay {\n position: sticky;\n left: 0;\n top: 0;\n z-index: 1;\n display: block;\n width: 100%;\n height: 0;\n pointer-events: none;\n }\n\n ::slotted([slot='overlay']) {\n pointer-events: auto;\n }\n\n ::slotted(canvas) {\n image-rendering: var(--rc-virtual-canvas-image-rendering, auto);\n }\n`;\n\nexport default virtualCanvasStyles;\n","import { LitElement, html } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport virtualCanvasStyles from './rc-virtual-canvas.styles.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-virtual-canvas': RCVirtualCanvas;\n }\n\n interface HTMLElementEventMap {\n 'rc-virtual-canvas-render': CustomEvent<RCVirtualCanvasRenderInit>;\n 'rc-virtual-canvas-pointer': CustomEvent<RCVirtualCanvasPointerInit>;\n }\n}\n\n/**\n * Scrollable virtual canvas for rendering large coordinate-space content.\n *\n * `x` and `y` are scroll offsets in CSS pixels; `width` and `height` are the canvas\n * backing-store dimensions in device pixels (DPR-accurate when `autoResizeCanvas` is `true`).\n */\nexport type RCVirtualCanvasViewRect = Readonly<{\n /** Scroll offset x in content space (CSS px) */\n x: number;\n\n /** Scroll offset y in content space (CSS px) */\n y: number;\n\n /** Visible width in device pixels */\n width: number;\n\n /** Visible height in device pixels */\n height: number;\n}>;\n\n/** Controls when `rc-virtual-canvas-render` events are dispatched */\nexport type RCVirtualCanvasRenderMode = 'continuous' | 'viewport-change' | 'manual';\n\n/** Identifies what triggered a render event */\nexport type RCVirtualCanvasRenderReason = 'animation-frame' | 'viewport-change' | 'manual';\n\n/** Content-space coordinate pair returned by coordinate-conversion methods */\nexport type RCVirtualCanvasPoint = Readonly<{\n /** Content space x coordinate in CSS pixels */\n x: number;\n\n /** Content space y coordinate in CSS pixels */\n y: number;\n}>;\n\n/**\n * Detail shape for `rc-virtual-canvas-pointer` events.\n *\n * Carries the source event's coordinates in both browser-client and content space,\n * along with all modifier key state.\n */\nexport type RCVirtualCanvasPointerInit = {\n /** DOM event type (e.g. `'pointerdown'`, `'click'`) */\n type: string;\n\n /** Browser client x coordinate from the source event */\n clientX: number;\n\n /** Browser client y coordinate from the source event */\n clientY: number;\n\n /** Content x coordinate in CSS pixels */\n contentX: number;\n\n /** Content y coordinate in CSS pixels */\n contentY: number;\n\n /** Frozen viewport snapshot at the moment the pointer event fired */\n viewRect: RCVirtualCanvasViewRect;\n\n /** Mouse button index from the source event */\n button: number;\n\n /** Active button bitmask from the source event */\n buttons: number;\n\n /** Whether the Alt key was held */\n altKey: boolean;\n\n /** Whether the Ctrl key was held */\n ctrlKey: boolean;\n\n /** Whether the Shift key was held */\n shiftKey: boolean;\n\n /** Whether the Meta key was held */\n metaKey: boolean;\n\n /** The original DOM event that produced this detail */\n sourceEvent: PointerEvent | MouseEvent;\n};\n\n/** CSS `image-rendering` value applied to the slotted canvas */\nexport type RCVirtualCanvasImageRendering = 'auto' | 'crisp-edges' | 'pixelated';\n\n/** Detail shape for `rc-virtual-canvas-render` events */\nexport type RCVirtualCanvasRenderInit = {\n /** High-resolution timestamp from `requestAnimationFrame` */\n time: DOMHighResTimeStamp;\n\n /** What triggered this render */\n reason: RCVirtualCanvasRenderReason;\n\n /** Frozen snapshot of the viewport for this frame */\n viewRect: RCVirtualCanvasViewRect;\n\n /** Frozen snapshot of the full content bounds for this frame */\n contentRect: RCVirtualCanvasViewRect;\n};\n\nfunction createRectSnapshot(rect: RCVirtualCanvasViewRect) {\n return Object.freeze({\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n });\n}\n\n/**\n * A scrollable virtual canvas component.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-virtual-canvas rc-virtual-canvas docs}\n *\n * @slot - The HTMLCanvasElement\n * @slot overlay - Optional viewport-positioned content rendered inside the\n * scroll container above the canvas.\n *\n * @fires rc-virtual-canvas-render - Fires with viewport data when the canvas should redraw.\n * @fires rc-virtual-canvas-pointer - Fires pointer/mouse input mapped to virtual content coordinates.\n *\n * @csspart scroller - Internal scroll container that owns the virtual content scroll range.\n * @csspart overlay - Viewport-positioned overlay container rendered inside the scroll container.\n *\n * @attr content-width - Total pixel width of the virtual content.\n * @attr content-height - Total pixel height of the virtual content.\n * @attr auto-resize-canvas - Keep the slotted canvas backing store aligned to the viewport.\n * @attr render-mode - Controls when render events are dispatched.\n * @attr image-rendering - Convenience `image-rendering` value applied to the slotted canvas.\n *\n * @cssprop [--rc-virtual-canvas-scrollbar-width=thin] - `scrollbar-width` of the internal\n * scroll container.\n * @cssprop [--rc-virtual-canvas-scrollbar-size=auto] - WebKit scrollbar thickness.\n * @cssprop [--rc-virtual-canvas-scrollbar-thumb-background=ButtonFace] - WebKit scrollbar\n * thumb color.\n * @cssprop [--rc-virtual-canvas-scrollbar-button-background=ButtonFace] - WebKit scrollbar\n * button color.\n * @cssprop [--rc-virtual-canvas-scrollbar-track-background=Canvas] - WebKit scrollbar\n * track color.\n * @cssprop [--rc-virtual-canvas-image-rendering=auto] - `image-rendering` applied to the\n * slotted canvas; kept in sync with the `imageRendering` property.\n */\nexport class RCVirtualCanvas extends LitElement {\n static styles = [virtualCanvasStyles];\n\n protected _rafHandle: number = 0;\n protected _pendingRenderReason?: RCVirtualCanvasRenderReason;\n\n protected override firstUpdated(): void {\n if (import.meta.env.DEV && !this.querySelector(':scope > canvas')) {\n console.warn(\n '[rc-virtual-canvas] No direct child <canvas> found. Place a native <canvas> inside <rc-virtual-canvas>.',\n this,\n );\n }\n }\n\n protected readonly _handledPointerEvents = new WeakSet<Event>();\n\n // Stored bound reference so the same closure is used for scheduling and\n // cancellation — `bind()` returns a new function every call.\n protected readonly _boundUpdate = (time: DOMHighResTimeStamp) => this._update(time);\n\n protected readonly _boundPointerEvent = (event: PointerEvent | MouseEvent) =>\n this._onPointerEvent(event);\n\n /** Pixel width of the virtual content */\n @property({ type: Number, attribute: 'content-width' })\n set contentWidth(val: number) {\n const oldValue = this._contentWidth;\n\n this._contentWidth = val;\n\n this._contentRect.width = this._contentWidth;\n this.requestUpdate('contentWidth', oldValue);\n this._scheduleRender('viewport-change');\n }\n\n get contentWidth() {\n return this._contentWidth;\n }\n\n private _contentWidth: number = 0;\n\n /** Pixel height of the virtual content */\n @property({ type: Number, attribute: 'content-height' })\n set contentHeight(val: number) {\n const oldValue = this._contentHeight;\n\n this._contentHeight = val;\n\n this._contentRect.height = this._contentHeight;\n this.requestUpdate('contentHeight', oldValue);\n this._scheduleRender('viewport-change');\n }\n\n get contentHeight() {\n return this._contentHeight;\n }\n\n private _contentHeight: number = 0;\n\n /** When true, keep the slotted canvas backing store aligned to the viewport. */\n @property({ attribute: 'auto-resize-canvas', type: Boolean })\n autoResizeCanvas: boolean = true;\n\n /** Controls when render events are dispatched. */\n @property({ attribute: 'render-mode' })\n renderMode: RCVirtualCanvasRenderMode = 'continuous';\n\n /** Convenience image-rendering value applied to the slotted canvas. */\n @property({ attribute: 'image-rendering' })\n imageRendering: RCVirtualCanvasImageRendering = 'auto';\n\n /** Shadow DOM scroll container that owns pointer interaction and native scrolling */\n @query('#root', true)\n protected _$root!: HTMLDivElement;\n\n /** Absolutely-positioned div that establishes the virtual scroll range */\n @query('#placeholder', true)\n protected _$placeholder!: HTMLDivElement;\n\n /** Currently-tracked slotted canvas element; `null` when no canvas is slotted */\n @state()\n protected _$canvas: HTMLCanvasElement | null = null;\n\n /** Mutable current-frame viewport geometry; call `getViewRect()` for a frozen snapshot */\n @state()\n protected _viewRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n };\n\n /** Mutable content bounds; updated when `contentWidth` or `contentHeight` change */\n @state()\n protected _contentRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n };\n\n /** Watches the slotted canvas for DPR-accurate dimension changes */\n protected _resizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => {\n for (const entry of entries) {\n const devicePixelBoxSize = Array.isArray(entry.devicePixelContentBoxSize)\n ? entry.devicePixelContentBoxSize[0]\n : entry.devicePixelContentBoxSize;\n\n this._viewRect.width = this._getMeasuredCanvasWidth(\n devicePixelBoxSize?.inlineSize ??\n Math.round(entry.contentRect.width * window.devicePixelRatio),\n );\n\n this._viewRect.height = this._getMeasuredCanvasHeight(\n devicePixelBoxSize?.blockSize ??\n Math.round(entry.contentRect.height * window.devicePixelRatio),\n );\n\n this._syncCanvasBackingStore();\n this._scheduleRender('viewport-change');\n }\n });\n\n /** Reads scroll position from the root container and schedules a render */\n protected _onScroll() {\n this._viewRect.x = this._$root.scrollLeft;\n this._viewRect.y = this._$root.scrollTop;\n\n this._scheduleRender('viewport-change');\n }\n\n /** Replaces canvas tracking and re-registers the resize observer when slot content changes */\n protected _onSlotChange(e: Event) {\n this._resizeObserver.disconnect();\n\n this._$canvas =\n (e.currentTarget as HTMLSlotElement)\n .assignedElements()\n .filter((el) => el instanceof HTMLCanvasElement)[0] ?? null;\n\n if (this._$canvas != null) {\n this._viewRect = {\n x: this._$root.scrollLeft ?? 0,\n y: this._$root.scrollTop ?? 0,\n width: this._getMeasuredCanvasWidth(this._$canvas.clientWidth),\n height: this._getMeasuredCanvasHeight(this._$canvas.clientHeight),\n };\n\n this._syncCanvasBackingStore();\n this._observeCanvasResize(this._$canvas);\n\n this._scheduleRender('viewport-change');\n }\n }\n\n /** Observes canvas size with DPR-accurate boxes when the browser supports them */\n protected _observeCanvasResize($canvas: HTMLCanvasElement) {\n try {\n this._resizeObserver.observe($canvas, {\n box: 'device-pixel-content-box',\n });\n } catch (error) {\n if (!(error instanceof TypeError)) {\n throw error;\n }\n\n this._resizeObserver.observe($canvas);\n }\n }\n\n /**\n * Returns a frozen snapshot of the current viewport rectangle.\n *\n * Safe to keep between frames — the returned object will not be mutated\n * by future scroll or resize work.\n */\n getViewRect() {\n return createRectSnapshot(this._viewRect);\n }\n\n /**\n * Scrolls so the content coordinate is at the viewport origin.\n *\n * @param x - content x coordinate in CSS pixels\n * @param y - content y coordinate in CSS pixels\n * @param options - native scroll options passed to scrollTo\n */\n scrollToContent(x: number, y: number, options: ScrollOptions = {}) {\n this._$root.scrollTo({\n ...options,\n left: x,\n top: y,\n });\n\n this._viewRect.x = this._$root.scrollLeft;\n this._viewRect.y = this._$root.scrollTop;\n this._scheduleRender('viewport-change');\n }\n\n /**\n * Scrolls so the content coordinate is centered in the viewport.\n *\n * @param x - content x coordinate in CSS pixels\n * @param y - content y coordinate in CSS pixels\n * @param options - native scroll options passed to scrollTo\n */\n centerOnContent(x: number, y: number, options: ScrollOptions = {}) {\n this.scrollToContent(\n x - this._$root.clientWidth * 0.5,\n y - this._$root.clientHeight * 0.5,\n options,\n );\n }\n\n /**\n * Converts browser client coordinates to CSS-pixel content coordinates.\n * Canvas backing-store resolution does not change content coordinates.\n *\n * @param clientX - browser client x coordinate (e.g. from a pointer event)\n * @param clientY - browser client y coordinate\n *\n * @example\n * vc.addEventListener('pointerdown', (e) => {\n * const { x, y } = vc.clientToContent(e.clientX, e.clientY);\n * placeMarkerAt(x, y);\n * });\n */\n clientToContent(clientX: number, clientY: number) {\n const canvasViewportRect = this._getCanvasClientRect();\n const clientToContentScaleX = this._getClientToContentScaleX(canvasViewportRect);\n const clientToContentScaleY = this._getClientToContentScaleY(canvasViewportRect);\n\n return Object.freeze({\n x: this._viewRect.x + (clientX - canvasViewportRect.left) * clientToContentScaleX,\n y: this._viewRect.y + (clientY - canvasViewportRect.top) * clientToContentScaleY,\n });\n }\n\n /**\n * Converts content coordinates back to browser client coordinates.\n *\n * @param x - content x coordinate in CSS pixels\n * @param y - content y coordinate in CSS pixels\n *\n * @example\n * const { x, y } = vc.contentToClient(contentX, contentY);\n * const elementAtPoint = document.elementFromPoint(x, y);\n */\n contentToClient(x: number, y: number) {\n const canvasViewportRect = this._getCanvasClientRect();\n const clientToContentScaleX = this._getClientToContentScaleX(canvasViewportRect);\n const clientToContentScaleY = this._getClientToContentScaleY(canvasViewportRect);\n\n return Object.freeze({\n x: canvasViewportRect.left + (x - this._viewRect.x) / clientToContentScaleX,\n y: canvasViewportRect.top + (y - this._viewRect.y) / clientToContentScaleY,\n });\n }\n\n /**\n * Queues a render event on the next animation frame.\n *\n * Required when `renderMode` is `'manual'`. In other modes the component\n * schedules renders automatically; calling this with reason `'animation-frame'`\n * is a no-op when `renderMode` is `'viewport-change'`.\n *\n * @param reason - render reason reported in the event detail\n */\n requestRender(reason: RCVirtualCanvasRenderReason = 'manual') {\n this._scheduleRender(reason);\n }\n\n /**\n * Ratio of canvas backing-store pixels to CSS pixels along the x-axis.\n *\n * Use as the x-scale factor in `ctx.scale()` to draw at CSS pixel resolution.\n * When `autoResizeCanvas` is true, CSS zoom changes this ratio along with\n * the backing-store resolution.\n *\n * @example\n * vc.addEventListener('rc-virtual-canvas-render', ({ detail: { viewRect } }) => {\n * ctx.save();\n * ctx.scale(vc.canvasScaleX, vc.canvasScaleY);\n * drawScene(ctx, viewRect);\n * ctx.restore();\n * });\n */\n get canvasScaleX(): number {\n const cssWidth = this._getCanvasCssWidth();\n\n return cssWidth > 0 ? this._viewRect.width / cssWidth : 1;\n }\n\n /**\n * Ratio of canvas backing-store pixels to CSS pixels along the y-axis.\n *\n * Use as the y-scale factor in `ctx.scale()` to draw at CSS pixel resolution.\n * CSS zoom can make this ratio differ from `devicePixelRatio`.\n */\n get canvasScaleY(): number {\n const cssHeight = this._getCanvasCssHeight();\n\n return cssHeight > 0 ? this._viewRect.height / cssHeight : 1;\n }\n\n /** Maps pointer and mouse events to content coordinates and dispatches `rc-virtual-canvas-pointer` */\n protected _onPointerEvent(event: PointerEvent | MouseEvent) {\n if (this._handledPointerEvents.has(event)) {\n return;\n }\n\n if (this._isOverlayEvent(event)) {\n return;\n }\n\n this._handledPointerEvents.add(event);\n\n const contentPoint = this.clientToContent(event.clientX, event.clientY);\n\n const shouldContinue = this.dispatchEvent(\n new CustomEvent<RCVirtualCanvasPointerInit>('rc-virtual-canvas-pointer', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: {\n type: event.type,\n clientX: event.clientX,\n clientY: event.clientY,\n contentX: contentPoint.x,\n contentY: contentPoint.y,\n viewRect: createRectSnapshot(this._viewRect),\n button: event.button,\n buttons: event.buttons,\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n shiftKey: event.shiftKey,\n metaKey: event.metaKey,\n sourceEvent: event,\n },\n }),\n );\n\n if (!shouldContinue) {\n event.preventDefault();\n }\n }\n\n protected _isOverlayEvent(event: Event): boolean {\n return event\n .composedPath()\n .some(($node) => $node instanceof HTMLSlotElement && $node.name === 'overlay');\n }\n\n /**\n * RAF callback. Dispatches `rc-virtual-canvas-render` and re-schedules in continuous mode.\n *\n * @param time - high-resolution timestamp from `requestAnimationFrame`\n */\n protected _update(time: DOMHighResTimeStamp) {\n this._rafHandle = 0;\n\n if (!this.isConnected || this._$canvas == null) {\n return;\n }\n\n const reason =\n this._pendingRenderReason ??\n (this.renderMode === 'continuous' ? 'animation-frame' : 'manual');\n\n this._pendingRenderReason = undefined;\n\n this.dispatchEvent(\n new CustomEvent<RCVirtualCanvasRenderInit>('rc-virtual-canvas-render', {\n bubbles: true,\n composed: true,\n detail: {\n time,\n reason,\n viewRect: createRectSnapshot(this._viewRect),\n contentRect: createRectSnapshot(this._contentRect),\n },\n }),\n );\n\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n }\n }\n\n /** Registers pointer event listeners and starts rendering in continuous mode */\n override connectedCallback() {\n super.connectedCallback();\n\n this.addEventListener('pointerdown', this._boundPointerEvent);\n this.addEventListener('pointermove', this._boundPointerEvent);\n this.addEventListener('pointerup', this._boundPointerEvent);\n this.addEventListener('click', this._boundPointerEvent);\n this.addEventListener('dblclick', this._boundPointerEvent);\n this.addEventListener('contextmenu', this._boundPointerEvent);\n\n if (this._rafHandle) {\n cancelAnimationFrame(this._rafHandle);\n this._rafHandle = 0;\n }\n\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n }\n }\n\n /** Cancels any pending animation frame, disconnects the resize observer, and removes pointer listeners */\n override disconnectedCallback() {\n super.disconnectedCallback();\n\n cancelAnimationFrame(this._rafHandle);\n this._rafHandle = 0;\n this._resizeObserver.disconnect();\n\n this.removeEventListener('pointerdown', this._boundPointerEvent);\n this.removeEventListener('pointermove', this._boundPointerEvent);\n this.removeEventListener('pointerup', this._boundPointerEvent);\n this.removeEventListener('click', this._boundPointerEvent);\n this.removeEventListener('dblclick', this._boundPointerEvent);\n this.removeEventListener('contextmenu', this._boundPointerEvent);\n }\n\n /** Reacts to `renderMode`, `autoResizeCanvas`, and `imageRendering` property changes */\n protected override updated(changed: Map<string, unknown>) {\n if (changed.has('renderMode')) {\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n } else if (this._pendingRenderReason === 'animation-frame') {\n if (this._rafHandle) {\n cancelAnimationFrame(this._rafHandle);\n\n this._rafHandle = 0;\n }\n\n this._pendingRenderReason = undefined;\n } else if (this.renderMode === 'viewport-change') {\n this._scheduleRender('viewport-change');\n }\n }\n\n if (changed.has('autoResizeCanvas')) {\n this._syncCanvasBackingStore();\n }\n\n if (changed.has('imageRendering')) {\n this.style.setProperty('--rc-virtual-canvas-image-rendering', this.imageRendering);\n }\n }\n\n protected _scheduleRender(reason: RCVirtualCanvasRenderReason) {\n if (this.renderMode === 'manual' && reason !== 'manual') {\n return;\n }\n\n if (this.renderMode === 'viewport-change' && reason === 'animation-frame') {\n return;\n }\n\n this._pendingRenderReason = reason;\n\n if (!this.isConnected || this._rafHandle) {\n return;\n }\n\n this._rafHandle = window.requestAnimationFrame(this._boundUpdate);\n }\n\n protected _syncCanvasBackingStore() {\n if (!this.autoResizeCanvas || this._$canvas == null) {\n return;\n }\n\n const width = Math.max(0, Math.round(this._viewRect.width));\n const height = Math.max(0, Math.round(this._viewRect.height));\n\n if (this._$canvas.width !== width) {\n this._$canvas.width = width;\n }\n\n if (this._$canvas.height !== height) {\n this._$canvas.height = height;\n }\n }\n\n protected _getCanvasClientRect() {\n if (this._$canvas == null) {\n return this.getBoundingClientRect();\n }\n\n return this._$canvas.getBoundingClientRect();\n }\n\n protected _getMeasuredCanvasWidth(fallbackWidth: number) {\n if (!this.autoResizeCanvas && this._$canvas && this._$canvas.width > 0) {\n return this._$canvas.width;\n }\n\n return fallbackWidth;\n }\n\n protected _getMeasuredCanvasHeight(fallbackHeight: number) {\n if (!this.autoResizeCanvas && this._$canvas && this._$canvas.height > 0) {\n return this._$canvas.height;\n }\n\n return fallbackHeight;\n }\n\n protected _getCanvasCssWidth(): number {\n return this._$canvas?.clientWidth ?? this.clientWidth;\n }\n\n protected _getCanvasCssHeight(): number {\n return this._$canvas?.clientHeight ?? this.clientHeight;\n }\n\n protected _getClientToContentScaleX(canvasViewportRect: DOMRect): number {\n const canvasCssWidth = this._getCanvasCssWidth();\n\n return canvasViewportRect.width > 0 && canvasCssWidth > 0\n ? canvasCssWidth / canvasViewportRect.width\n : 1;\n }\n\n protected _getClientToContentScaleY(canvasViewportRect: DOMRect): number {\n const canvasCssHeight = this._getCanvasCssHeight();\n\n return canvasViewportRect.height > 0 && canvasCssHeight > 0\n ? canvasCssHeight / canvasViewportRect.height\n : 1;\n }\n\n render() {\n return html`\n <div\n id=\"root\"\n part=\"scroller\"\n @scroll=${this._onScroll}\n @pointerdown=${this._onPointerEvent}\n @pointermove=${this._onPointerEvent}\n @pointerup=${this._onPointerEvent}\n @click=${this._onPointerEvent}\n @dblclick=${this._onPointerEvent}\n @contextmenu=${this._onPointerEvent}\n >\n <div id=\"overlay\" part=\"overlay\">\n <slot name=\"overlay\"></slot>\n </div>\n\n <div\n id=\"placeholder\"\n style=${styleMap({\n width: `${this.contentWidth}px`,\n height: `${this.contentHeight}px`,\n })}\n ></div>\n </div>\n\n <slot @slotchange=${this._onSlotChange}></slot>\n `;\n }\n}\n\nexport default RCVirtualCanvas;\n"],"names":["virtualCanvasStyles","css","createRectSnapshot","rect","_RCVirtualCanvas","LitElement","time","event","entries","entry","devicePixelBoxSize","val","oldValue","e","el","$canvas","error","x","y","options","clientX","clientY","canvasViewportRect","clientToContentScaleX","clientToContentScaleY","reason","cssWidth","cssHeight","contentPoint","$node","changed","width","height","fallbackWidth","fallbackHeight","canvasCssWidth","canvasCssHeight","html","styleMap","RCVirtualCanvas","__decorateClass","property","query","state"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { R as a } from "./rc-virtual-canvas-BSpF0tcY.js";
1
+ import { R as a } from "./rc-virtual-canvas-DIy-ABTk.js";
2
2
  customElements.get("rc-virtual-canvas") || customElements.define("rc-virtual-canvas", a);
3
3
  export {
4
4
  a as RCVirtualCanvas
@@ -1 +1 @@
1
- {"version":3,"file":"rc-virtual-canvas-define.js","sources":["../src/define.ts"],"sourcesContent":["import { RCVirtualCanvas } from './index.js';\n\ncustomElements.get('rc-virtual-canvas') || customElements.define('rc-virtual-canvas', RCVirtualCanvas);\n\nexport * from './index.js';\n"],"names":["RCVirtualCanvas"],"mappings":";AAEA,eAAe,IAAI,mBAAmB,KAAK,eAAe,OAAO,qBAAqBA,CAAe;"}
1
+ {"version":3,"file":"rc-virtual-canvas-define.js","sources":["../src/define.ts"],"sourcesContent":["import { RCVirtualCanvas } from './index.js';\n\ncustomElements.get('rc-virtual-canvas') ||\n customElements.define('rc-virtual-canvas', RCVirtualCanvas);\n\nexport * from './index.js';\n"],"names":["RCVirtualCanvas"],"mappings":";AAEA,eAAe,IAAI,mBAAmB,KACpC,eAAe,OAAO,qBAAqBA,CAAe;"}
@@ -1,4 +1,4 @@
1
- import { R as o } from "./rc-virtual-canvas-BSpF0tcY.js";
1
+ import { R as o } from "./rc-virtual-canvas-DIy-ABTk.js";
2
2
  export {
3
3
  o as RCVirtualCanvas
4
4
  };
@@ -1 +1 @@
1
- export * from './rc-virtual-canvas';
1
+ export * from './rc-virtual-canvas.js';
@@ -48,9 +48,9 @@ export type RCVirtualCanvasPointerInit = {
48
48
  clientX: number;
49
49
  /** Browser client y coordinate from the source event */
50
50
  clientY: number;
51
- /** Content x coordinate mapped through the current backing-store scale */
51
+ /** Content x coordinate in CSS pixels */
52
52
  contentX: number;
53
- /** Content y coordinate mapped through the current backing-store scale */
53
+ /** Content y coordinate in CSS pixels */
54
54
  contentY: number;
55
55
  /** Frozen viewport snapshot at the moment the pointer event fired */
56
56
  viewRect: RCVirtualCanvasViewRect;
@@ -119,6 +119,7 @@ export declare class RCVirtualCanvas extends LitElement {
119
119
  static styles: import('lit').CSSResult[];
120
120
  protected _rafHandle: number;
121
121
  protected _pendingRenderReason?: RCVirtualCanvasRenderReason;
122
+ protected firstUpdated(): void;
122
123
  protected readonly _handledPointerEvents: WeakSet<Event>;
123
124
  protected readonly _boundUpdate: (time: DOMHighResTimeStamp) => void;
124
125
  protected readonly _boundPointerEvent: (event: PointerEvent | MouseEvent) => void;
@@ -179,25 +180,25 @@ export declare class RCVirtualCanvas extends LitElement {
179
180
  /**
180
181
  * Scrolls so the content coordinate is at the viewport origin.
181
182
  *
182
- * @param x - Content x coordinate in CSS pixels
183
- * @param y - Content y coordinate in CSS pixels
184
- * @param options - Native scroll options passed to scrollTo
183
+ * @param x - content x coordinate in CSS pixels
184
+ * @param y - content y coordinate in CSS pixels
185
+ * @param options - native scroll options passed to scrollTo
185
186
  */
186
187
  scrollToContent(x: number, y: number, options?: ScrollOptions): void;
187
188
  /**
188
189
  * Scrolls so the content coordinate is centered in the viewport.
189
190
  *
190
- * @param x - Content x coordinate in CSS pixels
191
- * @param y - Content y coordinate in CSS pixels
192
- * @param options - Native scroll options passed to scrollTo
191
+ * @param x - content x coordinate in CSS pixels
192
+ * @param y - content y coordinate in CSS pixels
193
+ * @param options - native scroll options passed to scrollTo
193
194
  */
194
195
  centerOnContent(x: number, y: number, options?: ScrollOptions): void;
195
196
  /**
196
- * Converts browser client coordinates to content coordinates using the current
197
- * backing-store scale.
197
+ * Converts browser client coordinates to CSS-pixel content coordinates.
198
+ * Canvas backing-store resolution does not change content coordinates.
198
199
  *
199
- * @param clientX - Browser client x coordinate (e.g. from a pointer event)
200
- * @param clientY - Browser client y coordinate
200
+ * @param clientX - browser client x coordinate (e.g. from a pointer event)
201
+ * @param clientY - browser client y coordinate
201
202
  *
202
203
  * @example
203
204
  * vc.addEventListener('pointerdown', (e) => {
@@ -212,13 +213,12 @@ export declare class RCVirtualCanvas extends LitElement {
212
213
  /**
213
214
  * Converts content coordinates back to browser client coordinates.
214
215
  *
215
- * @param x - Content x coordinate in CSS pixels
216
- * @param y - Content y coordinate in CSS pixels
216
+ * @param x - content x coordinate in CSS pixels
217
+ * @param y - content y coordinate in CSS pixels
217
218
  *
218
219
  * @example
219
220
  * const { x, y } = vc.contentToClient(contentX, contentY);
220
- * tooltip.style.left = `${x}px`;
221
- * tooltip.style.top = `${y}px`;
221
+ * const elementAtPoint = document.elementFromPoint(x, y);
222
222
  */
223
223
  contentToClient(x: number, y: number): Readonly<{
224
224
  x: number;
@@ -231,14 +231,15 @@ export declare class RCVirtualCanvas extends LitElement {
231
231
  * schedules renders automatically; calling this with reason `'animation-frame'`
232
232
  * is a no-op when `renderMode` is `'viewport-change'`.
233
233
  *
234
- * @param reason - Render reason reported in the event detail
234
+ * @param reason - render reason reported in the event detail
235
235
  */
236
236
  requestRender(reason?: RCVirtualCanvasRenderReason): void;
237
237
  /**
238
238
  * Ratio of canvas backing-store pixels to CSS pixels along the x-axis.
239
239
  *
240
- * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the x-scale
241
- * factor in `ctx.scale()` to draw at CSS pixel resolution.
240
+ * Use as the x-scale factor in `ctx.scale()` to draw at CSS pixel resolution.
241
+ * When `autoResizeCanvas` is true, CSS zoom changes this ratio along with
242
+ * the backing-store resolution.
242
243
  *
243
244
  * @example
244
245
  * vc.addEventListener('rc-virtual-canvas-render', ({ detail: { viewRect } }) => {
@@ -252,8 +253,8 @@ export declare class RCVirtualCanvas extends LitElement {
252
253
  /**
253
254
  * Ratio of canvas backing-store pixels to CSS pixels along the y-axis.
254
255
  *
255
- * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the y-scale
256
- * factor in `ctx.scale()` to draw at CSS pixel resolution.
256
+ * Use as the y-scale factor in `ctx.scale()` to draw at CSS pixel resolution.
257
+ * CSS zoom can make this ratio differ from `devicePixelRatio`.
257
258
  */
258
259
  get canvasScaleY(): number;
259
260
  /** Maps pointer and mouse events to content coordinates and dispatches `rc-virtual-canvas-pointer` */
@@ -262,7 +263,7 @@ export declare class RCVirtualCanvas extends LitElement {
262
263
  /**
263
264
  * RAF callback. Dispatches `rc-virtual-canvas-render` and re-schedules in continuous mode.
264
265
  *
265
- * @param time - High-resolution timestamp from `requestAnimationFrame`
266
+ * @param time - high-resolution timestamp from `requestAnimationFrame`
266
267
  */
267
268
  protected _update(time: DOMHighResTimeStamp): void;
268
269
  /** Registers pointer event listeners and starts rendering in continuous mode */
@@ -276,8 +277,10 @@ export declare class RCVirtualCanvas extends LitElement {
276
277
  protected _getCanvasClientRect(): DOMRect;
277
278
  protected _getMeasuredCanvasWidth(fallbackWidth: number): number;
278
279
  protected _getMeasuredCanvasHeight(fallbackHeight: number): number;
279
- protected _getViewportScaleX(canvasRect: DOMRect): number;
280
- protected _getViewportScaleY(canvasRect: DOMRect): number;
281
- render(): import('lit').TemplateResult<1>;
280
+ protected _getCanvasCssWidth(): number;
281
+ protected _getCanvasCssHeight(): number;
282
+ protected _getClientToContentScaleX(canvasViewportRect: DOMRect): number;
283
+ protected _getClientToContentScaleY(canvasViewportRect: DOMRect): number;
284
+ render(): import('lit-html').TemplateResult<1>;
282
285
  }
283
286
  export default RCVirtualCanvas;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.5.0",
6
+ "version": "0.7.0",
7
7
  "description": "Scrollable virtual canvas for rendering large coordinate-space content.",
8
8
  "repository": {
9
9
  "type": "git",
@@ -1 +0,0 @@
1
- {"version":3,"file":"rc-virtual-canvas-BSpF0tcY.js","sources":["../src/rc-virtual-canvas.styles.ts","../src/rc-virtual-canvas.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const virtualCanvasStyles = css`\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n :host {\n position: relative;\n display: block;\n width: max-content;\n line-height: 0; /* remove extra space under slotted <canvas> element(s) */\n }\n\n :host([hidden]) {\n display: none;\n }\n\n #root {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n overflow: auto;\n scrollbar-width: var(--rc-virtual-canvas-scrollbar-width, thin);\n }\n\n #root::-webkit-scrollbar {\n width: var(--rc-virtual-canvas-scrollbar-size, auto);\n height: var(--rc-virtual-canvas-scrollbar-size, auto);\n }\n\n #root::-webkit-scrollbar-thumb {\n background: var(--rc-virtual-canvas-scrollbar-thumb-background, ButtonFace);\n }\n\n #root::-webkit-scrollbar-button {\n background: var(--rc-virtual-canvas-scrollbar-button-background, ButtonFace);\n }\n\n #root::-webkit-scrollbar-track {\n background: var(--rc-virtual-canvas-scrollbar-track-background, Canvas);\n }\n\n #placeholder {\n pointer-events: none;\n }\n\n #overlay {\n position: sticky;\n left: 0;\n top: 0;\n z-index: 1;\n display: block;\n width: 100%;\n height: 0;\n pointer-events: none;\n }\n\n ::slotted([slot='overlay']) {\n pointer-events: auto;\n }\n\n ::slotted(canvas) {\n image-rendering: var(--rc-virtual-canvas-image-rendering, auto);\n }\n`;\n\nexport default virtualCanvasStyles;\n","import { LitElement, html } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport virtualCanvasStyles from './rc-virtual-canvas.styles';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-virtual-canvas': RCVirtualCanvas;\n }\n\n interface HTMLElementEventMap {\n 'rc-virtual-canvas-render': CustomEvent<RCVirtualCanvasRenderInit>;\n 'rc-virtual-canvas-pointer': CustomEvent<RCVirtualCanvasPointerInit>;\n }\n}\n\n/**\n * Scrollable virtual canvas for rendering large coordinate-space content.\n *\n * `x` and `y` are scroll offsets in CSS pixels; `width` and `height` are the canvas\n * backing-store dimensions in device pixels (DPR-accurate when `autoResizeCanvas` is `true`).\n */\nexport type RCVirtualCanvasViewRect = Readonly<{\n /** Scroll offset x in content space (CSS px) */\n x: number;\n\n /** Scroll offset y in content space (CSS px) */\n y: number;\n\n /** Visible width in device pixels */\n width: number;\n\n /** Visible height in device pixels */\n height: number;\n}>;\n\n/** Controls when `rc-virtual-canvas-render` events are dispatched */\nexport type RCVirtualCanvasRenderMode = 'continuous' | 'viewport-change' | 'manual';\n\n/** Identifies what triggered a render event */\nexport type RCVirtualCanvasRenderReason = 'animation-frame' | 'viewport-change' | 'manual';\n\n/** Content-space coordinate pair returned by coordinate-conversion methods */\nexport type RCVirtualCanvasPoint = Readonly<{\n /** Content space x coordinate in CSS pixels */\n x: number;\n\n /** Content space y coordinate in CSS pixels */\n y: number;\n}>;\n\n/**\n * Detail shape for `rc-virtual-canvas-pointer` events.\n *\n * Carries the source event's coordinates in both browser-client and content space,\n * along with all modifier key state.\n */\nexport type RCVirtualCanvasPointerInit = {\n /** DOM event type (e.g. `'pointerdown'`, `'click'`) */\n type: string;\n\n /** Browser client x coordinate from the source event */\n clientX: number;\n\n /** Browser client y coordinate from the source event */\n clientY: number;\n\n /** Content x coordinate mapped through the current backing-store scale */\n contentX: number;\n\n /** Content y coordinate mapped through the current backing-store scale */\n contentY: number;\n\n /** Frozen viewport snapshot at the moment the pointer event fired */\n viewRect: RCVirtualCanvasViewRect;\n\n /** Mouse button index from the source event */\n button: number;\n\n /** Active button bitmask from the source event */\n buttons: number;\n\n /** Whether the Alt key was held */\n altKey: boolean;\n\n /** Whether the Ctrl key was held */\n ctrlKey: boolean;\n\n /** Whether the Shift key was held */\n shiftKey: boolean;\n\n /** Whether the Meta key was held */\n metaKey: boolean;\n\n /** The original DOM event that produced this detail */\n sourceEvent: PointerEvent | MouseEvent;\n};\n\n/** CSS `image-rendering` value applied to the slotted canvas */\nexport type RCVirtualCanvasImageRendering = 'auto' | 'crisp-edges' | 'pixelated';\n\n/** Detail shape for `rc-virtual-canvas-render` events */\nexport type RCVirtualCanvasRenderInit = {\n /** High-resolution timestamp from `requestAnimationFrame` */\n time: DOMHighResTimeStamp;\n\n /** What triggered this render */\n reason: RCVirtualCanvasRenderReason;\n\n /** Frozen snapshot of the viewport for this frame */\n viewRect: RCVirtualCanvasViewRect;\n\n /** Frozen snapshot of the full content bounds for this frame */\n contentRect: RCVirtualCanvasViewRect;\n};\n\nfunction createRectSnapshot(rect: RCVirtualCanvasViewRect) {\n return Object.freeze({\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n });\n}\n\n/**\n * A scrollable virtual canvas component.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-virtual-canvas rc-virtual-canvas docs}\n *\n * @slot - The HTMLCanvasElement\n * @slot overlay - Optional viewport-positioned content rendered inside the\n * scroll container above the canvas.\n *\n * @fires rc-virtual-canvas-render - Fires with viewport data when the canvas should redraw.\n * @fires rc-virtual-canvas-pointer - Fires pointer/mouse input mapped to virtual content coordinates.\n *\n * @csspart scroller - Internal scroll container that owns the virtual content scroll range.\n * @csspart overlay - Viewport-positioned overlay container rendered inside the scroll container.\n *\n * @attr content-width - Total pixel width of the virtual content.\n * @attr content-height - Total pixel height of the virtual content.\n * @attr auto-resize-canvas - Keep the slotted canvas backing store aligned to the viewport.\n * @attr render-mode - Controls when render events are dispatched.\n * @attr image-rendering - Convenience `image-rendering` value applied to the slotted canvas.\n *\n * @cssprop [--rc-virtual-canvas-scrollbar-width=thin] - `scrollbar-width` of the internal\n * scroll container.\n * @cssprop [--rc-virtual-canvas-scrollbar-size=auto] - WebKit scrollbar thickness.\n * @cssprop [--rc-virtual-canvas-scrollbar-thumb-background=ButtonFace] - WebKit scrollbar\n * thumb color.\n * @cssprop [--rc-virtual-canvas-scrollbar-button-background=ButtonFace] - WebKit scrollbar\n * button color.\n * @cssprop [--rc-virtual-canvas-scrollbar-track-background=Canvas] - WebKit scrollbar\n * track color.\n * @cssprop [--rc-virtual-canvas-image-rendering=auto] - `image-rendering` applied to the\n * slotted canvas; kept in sync with the `imageRendering` property.\n */\nexport class RCVirtualCanvas extends LitElement {\n static styles = [virtualCanvasStyles];\n\n protected _rafHandle: number = 0;\n protected _pendingRenderReason?: RCVirtualCanvasRenderReason;\n protected readonly _handledPointerEvents = new WeakSet<Event>();\n\n // Stored bound reference so the same closure is used for scheduling and\n // cancellation — `bind()` returns a new function every call.\n protected readonly _boundUpdate = (time: DOMHighResTimeStamp) => this._update(time);\n\n protected readonly _boundPointerEvent = (event: PointerEvent | MouseEvent) =>\n this._onPointerEvent(event);\n\n /** Pixel width of the virtual content */\n @property({ type: Number, attribute: 'content-width' })\n set contentWidth(val: number) {\n const oldValue = this._contentWidth;\n\n this._contentWidth = val;\n\n this._contentRect.width = this._contentWidth;\n this.requestUpdate('contentWidth', oldValue);\n this._scheduleRender('viewport-change');\n }\n get contentWidth() {\n return this._contentWidth;\n }\n private _contentWidth: number = 0;\n\n /** Pixel height of the virtual content */\n @property({ type: Number, attribute: 'content-height' })\n set contentHeight(val: number) {\n const oldValue = this._contentHeight;\n\n this._contentHeight = val;\n\n this._contentRect.height = this._contentHeight;\n this.requestUpdate('contentHeight', oldValue);\n this._scheduleRender('viewport-change');\n }\n get contentHeight() {\n return this._contentHeight;\n }\n private _contentHeight: number = 0;\n\n /** When true, keep the slotted canvas backing store aligned to the viewport. */\n @property({ attribute: 'auto-resize-canvas', type: Boolean })\n autoResizeCanvas: boolean = true;\n\n /** Controls when render events are dispatched. */\n @property({ attribute: 'render-mode' })\n renderMode: RCVirtualCanvasRenderMode = 'continuous';\n\n /** Convenience image-rendering value applied to the slotted canvas. */\n @property({ attribute: 'image-rendering' })\n imageRendering: RCVirtualCanvasImageRendering = 'auto';\n\n /** Shadow DOM scroll container that owns pointer interaction and native scrolling */\n @query('#root', true)\n protected _$root!: HTMLDivElement;\n\n /** Absolutely-positioned div that establishes the virtual scroll range */\n @query('#placeholder', true)\n protected _$placeholder!: HTMLDivElement;\n\n /** Currently-tracked slotted canvas element; `null` when no canvas is slotted */\n @state()\n protected _$canvas: HTMLCanvasElement | null = null;\n\n /** Mutable current-frame viewport geometry; call `getViewRect()` for a frozen snapshot */\n @state()\n protected _viewRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n };\n\n /** Mutable content bounds; updated when `contentWidth` or `contentHeight` change */\n @state()\n protected _contentRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n };\n\n /** Watches the slotted canvas for DPR-accurate dimension changes */\n protected _resizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => {\n for (const entry of entries) {\n const devicePixelBoxSize = Array.isArray(entry.devicePixelContentBoxSize)\n ? entry.devicePixelContentBoxSize[0]\n : entry.devicePixelContentBoxSize;\n\n this._viewRect.width = this._getMeasuredCanvasWidth(\n devicePixelBoxSize?.inlineSize ??\n Math.round(entry.contentRect.width * window.devicePixelRatio),\n );\n\n this._viewRect.height = this._getMeasuredCanvasHeight(\n devicePixelBoxSize?.blockSize ??\n Math.round(entry.contentRect.height * window.devicePixelRatio),\n );\n\n this._syncCanvasBackingStore();\n this._scheduleRender('viewport-change');\n }\n });\n\n /** Reads scroll position from the root container and schedules a render */\n protected _onScroll() {\n this._viewRect.x = this._$root.scrollLeft;\n this._viewRect.y = this._$root.scrollTop;\n\n this._scheduleRender('viewport-change');\n }\n\n /** Replaces canvas tracking and re-registers the resize observer when slot content changes */\n protected _onSlotChange(e: Event) {\n this._resizeObserver.disconnect();\n\n this._$canvas =\n (e.currentTarget as HTMLSlotElement)\n .assignedElements()\n .filter((el) => el instanceof HTMLCanvasElement)\n [0] ?? null;\n\n if (this._$canvas != null) {\n this._viewRect = {\n x: this._$root.scrollLeft ?? 0,\n y: this._$root.scrollTop ?? 0,\n width: this._getMeasuredCanvasWidth(this._$canvas.clientWidth),\n height: this._getMeasuredCanvasHeight(this._$canvas.clientHeight),\n };\n\n this._syncCanvasBackingStore();\n this._observeCanvasResize(this._$canvas);\n\n this._scheduleRender('viewport-change');\n }\n }\n\n /** Observes canvas size with DPR-accurate boxes when the browser supports them */\n protected _observeCanvasResize($canvas: HTMLCanvasElement) {\n try {\n this._resizeObserver.observe($canvas, {\n box: 'device-pixel-content-box',\n });\n } catch (error) {\n if (!(error instanceof TypeError)) {\n throw error;\n }\n\n this._resizeObserver.observe($canvas);\n }\n }\n\n /**\n * Returns a frozen snapshot of the current viewport rectangle.\n *\n * Safe to keep between frames — the returned object will not be mutated\n * by future scroll or resize work.\n */\n getViewRect() {\n return createRectSnapshot(this._viewRect);\n }\n\n /**\n * Scrolls so the content coordinate is at the viewport origin.\n *\n * @param x - Content x coordinate in CSS pixels\n * @param y - Content y coordinate in CSS pixels\n * @param options - Native scroll options passed to scrollTo\n */\n scrollToContent(x: number, y: number, options: ScrollOptions = {}) {\n this._$root.scrollTo({\n ...options,\n left: x,\n top: y,\n });\n\n this._viewRect.x = this._$root.scrollLeft;\n this._viewRect.y = this._$root.scrollTop;\n this._scheduleRender('viewport-change');\n }\n\n /**\n * Scrolls so the content coordinate is centered in the viewport.\n *\n * @param x - Content x coordinate in CSS pixels\n * @param y - Content y coordinate in CSS pixels\n * @param options - Native scroll options passed to scrollTo\n */\n centerOnContent(x: number, y: number, options: ScrollOptions = {}) {\n this.scrollToContent(\n x - this._$root.clientWidth * 0.5,\n y - this._$root.clientHeight * 0.5,\n options,\n );\n }\n\n /**\n * Converts browser client coordinates to content coordinates using the current\n * backing-store scale.\n *\n * @param clientX - Browser client x coordinate (e.g. from a pointer event)\n * @param clientY - Browser client y coordinate\n *\n * @example\n * vc.addEventListener('pointerdown', (e) => {\n * const { x, y } = vc.clientToContent(e.clientX, e.clientY);\n * placeMarkerAt(x, y);\n * });\n */\n clientToContent(clientX: number, clientY: number) {\n const canvasRect = this._getCanvasClientRect();\n const scaleX = this._getViewportScaleX(canvasRect);\n const scaleY = this._getViewportScaleY(canvasRect);\n\n return Object.freeze({\n x: this._viewRect.x + (clientX - canvasRect.left) * scaleX,\n y: this._viewRect.y + (clientY - canvasRect.top) * scaleY,\n });\n }\n\n /**\n * Converts content coordinates back to browser client coordinates.\n *\n * @param x - Content x coordinate in CSS pixels\n * @param y - Content y coordinate in CSS pixels\n *\n * @example\n * const { x, y } = vc.contentToClient(contentX, contentY);\n * tooltip.style.left = `${x}px`;\n * tooltip.style.top = `${y}px`;\n */\n contentToClient(x: number, y: number) {\n const canvasRect = this._getCanvasClientRect();\n const scaleX = this._getViewportScaleX(canvasRect);\n const scaleY = this._getViewportScaleY(canvasRect);\n\n return Object.freeze({\n x: canvasRect.left + (x - this._viewRect.x) / scaleX,\n y: canvasRect.top + (y - this._viewRect.y) / scaleY,\n });\n }\n\n /**\n * Queues a render event on the next animation frame.\n *\n * Required when `renderMode` is `'manual'`. In other modes the component\n * schedules renders automatically; calling this with reason `'animation-frame'`\n * is a no-op when `renderMode` is `'viewport-change'`.\n *\n * @param reason - Render reason reported in the event detail\n */\n requestRender(reason: RCVirtualCanvasRenderReason = 'manual') {\n this._scheduleRender(reason);\n }\n\n /**\n * Ratio of canvas backing-store pixels to CSS pixels along the x-axis.\n *\n * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the x-scale\n * factor in `ctx.scale()` to draw at CSS pixel resolution.\n *\n * @example\n * vc.addEventListener('rc-virtual-canvas-render', ({ detail: { viewRect } }) => {\n * ctx.save();\n * ctx.scale(vc.canvasScaleX, vc.canvasScaleY);\n * drawScene(ctx, viewRect);\n * ctx.restore();\n * });\n */\n get canvasScaleX(): number {\n const canvasRect = this._getCanvasClientRect();\n\n return this._getViewportScaleX(canvasRect);\n }\n\n /**\n * Ratio of canvas backing-store pixels to CSS pixels along the y-axis.\n *\n * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the y-scale\n * factor in `ctx.scale()` to draw at CSS pixel resolution.\n */\n get canvasScaleY(): number {\n const canvasRect = this._getCanvasClientRect();\n\n return this._getViewportScaleY(canvasRect);\n }\n\n /** Maps pointer and mouse events to content coordinates and dispatches `rc-virtual-canvas-pointer` */\n protected _onPointerEvent(event: PointerEvent | MouseEvent) {\n if (this._handledPointerEvents.has(event)) {\n return;\n }\n\n if (this._isOverlayEvent(event)) {\n return;\n }\n\n this._handledPointerEvents.add(event);\n\n const contentPoint = this.clientToContent(event.clientX, event.clientY);\n\n const shouldContinue = this.dispatchEvent(\n new CustomEvent<RCVirtualCanvasPointerInit>('rc-virtual-canvas-pointer', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: {\n type: event.type,\n clientX: event.clientX,\n clientY: event.clientY,\n contentX: contentPoint.x,\n contentY: contentPoint.y,\n viewRect: createRectSnapshot(this._viewRect),\n button: event.button,\n buttons: event.buttons,\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n shiftKey: event.shiftKey,\n metaKey: event.metaKey,\n sourceEvent: event,\n },\n }),\n );\n\n if (!shouldContinue) event.preventDefault();\n }\n\n protected _isOverlayEvent(event: Event): boolean {\n return event\n .composedPath()\n .some(($node) => $node instanceof HTMLSlotElement && $node.name === 'overlay');\n }\n\n /**\n * RAF callback. Dispatches `rc-virtual-canvas-render` and re-schedules in continuous mode.\n *\n * @param time - High-resolution timestamp from `requestAnimationFrame`\n */\n protected _update(time: DOMHighResTimeStamp) {\n this._rafHandle = 0;\n\n if (!this.isConnected || this._$canvas == null) {\n return;\n }\n\n const reason =\n this._pendingRenderReason ??\n (this.renderMode === 'continuous' ? 'animation-frame' : 'manual');\n\n this._pendingRenderReason = undefined;\n\n this.dispatchEvent(\n new CustomEvent<RCVirtualCanvasRenderInit>('rc-virtual-canvas-render', {\n bubbles: true,\n composed: true,\n detail: {\n time,\n reason,\n viewRect: createRectSnapshot(this._viewRect),\n contentRect: createRectSnapshot(this._contentRect),\n },\n }),\n );\n\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n }\n }\n\n /** Registers pointer event listeners and starts rendering in continuous mode */\n override connectedCallback() {\n super.connectedCallback();\n\n this.addEventListener('pointerdown', this._boundPointerEvent);\n this.addEventListener('pointermove', this._boundPointerEvent);\n this.addEventListener('pointerup', this._boundPointerEvent);\n this.addEventListener('click', this._boundPointerEvent);\n this.addEventListener('dblclick', this._boundPointerEvent);\n this.addEventListener('contextmenu', this._boundPointerEvent);\n\n if (this._rafHandle) {\n cancelAnimationFrame(this._rafHandle);\n this._rafHandle = 0;\n }\n\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n }\n }\n\n /** Cancels any pending animation frame, disconnects the resize observer, and removes pointer listeners */\n override disconnectedCallback() {\n super.disconnectedCallback();\n\n cancelAnimationFrame(this._rafHandle);\n this._rafHandle = 0;\n this._resizeObserver.disconnect();\n\n this.removeEventListener('pointerdown', this._boundPointerEvent);\n this.removeEventListener('pointermove', this._boundPointerEvent);\n this.removeEventListener('pointerup', this._boundPointerEvent);\n this.removeEventListener('click', this._boundPointerEvent);\n this.removeEventListener('dblclick', this._boundPointerEvent);\n this.removeEventListener('contextmenu', this._boundPointerEvent);\n }\n\n /** Reacts to `renderMode`, `autoResizeCanvas`, and `imageRendering` property changes */\n protected override updated(changed: Map<string, unknown>) {\n if (changed.has('renderMode')) {\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n } else if (this._pendingRenderReason === 'animation-frame') {\n if (this._rafHandle) {\n cancelAnimationFrame(this._rafHandle);\n\n this._rafHandle = 0;\n }\n\n this._pendingRenderReason = undefined;\n } else if (this.renderMode === 'viewport-change') {\n this._scheduleRender('viewport-change');\n }\n }\n\n if (changed.has('autoResizeCanvas')) {\n this._syncCanvasBackingStore();\n }\n\n if (changed.has('imageRendering')) {\n this.style.setProperty('--rc-virtual-canvas-image-rendering', this.imageRendering);\n }\n }\n\n protected _scheduleRender(reason: RCVirtualCanvasRenderReason) {\n if (this.renderMode === 'manual' && reason !== 'manual') {\n return;\n }\n\n if (this.renderMode === 'viewport-change' && reason === 'animation-frame') {\n return;\n }\n\n this._pendingRenderReason = reason;\n\n if (!this.isConnected || this._rafHandle) {\n return;\n }\n\n this._rafHandle = window.requestAnimationFrame(this._boundUpdate);\n }\n\n protected _syncCanvasBackingStore() {\n if (!this.autoResizeCanvas || this._$canvas == null) {\n return;\n }\n\n const width = Math.max(0, Math.round(this._viewRect.width));\n const height = Math.max(0, Math.round(this._viewRect.height));\n\n if (this._$canvas.width !== width) {\n this._$canvas.width = width;\n }\n\n if (this._$canvas.height !== height) {\n this._$canvas.height = height;\n }\n }\n\n protected _getCanvasClientRect() {\n if (this._$canvas == null) {\n return this.getBoundingClientRect();\n }\n\n return this._$canvas.getBoundingClientRect();\n }\n\n protected _getMeasuredCanvasWidth(fallbackWidth: number) {\n if (!this.autoResizeCanvas && this._$canvas && this._$canvas.width > 0) {\n return this._$canvas.width;\n }\n\n return fallbackWidth;\n }\n\n protected _getMeasuredCanvasHeight(fallbackHeight: number) {\n if (!this.autoResizeCanvas && this._$canvas && this._$canvas.height > 0) {\n return this._$canvas.height;\n }\n\n return fallbackHeight;\n }\n\n protected _getViewportScaleX(canvasRect: DOMRect) {\n return canvasRect.width > 0 ? this._viewRect.width / canvasRect.width : 1;\n }\n\n protected _getViewportScaleY(canvasRect: DOMRect) {\n return canvasRect.height > 0 ? this._viewRect.height / canvasRect.height : 1;\n }\n\n render() {\n return html`\n <div\n id=\"root\"\n part=\"scroller\"\n @scroll=${this._onScroll}\n @pointerdown=${this._onPointerEvent}\n @pointermove=${this._onPointerEvent}\n @pointerup=${this._onPointerEvent}\n @click=${this._onPointerEvent}\n @dblclick=${this._onPointerEvent}\n @contextmenu=${this._onPointerEvent}\n >\n <div id=\"overlay\" part=\"overlay\">\n <slot name=\"overlay\"></slot>\n </div>\n\n <div\n id=\"placeholder\"\n style=${styleMap({\n width: `${this.contentWidth}px`,\n height: `${this.contentHeight}px`,\n })}\n ></div>\n </div>\n\n <slot @slotchange=${this._onSlotChange}></slot>\n `;\n }\n}\n\nexport default RCVirtualCanvas;\n"],"names":["virtualCanvasStyles","css","createRectSnapshot","rect","_RCVirtualCanvas","LitElement","time","event","entries","entry","devicePixelBoxSize","val","oldValue","e","el","$canvas","error","x","y","options","clientX","clientY","canvasRect","scaleX","scaleY","reason","contentPoint","$node","changed","width","height","fallbackWidth","fallbackHeight","html","styleMap","RCVirtualCanvas","__decorateClass","property","query","state"],"mappings":"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"}
File without changes