@quario/viewer 0.9.0 → 0.11.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/lib/outline.js ADDED
@@ -0,0 +1,166 @@
1
+ /**
2
+ * The outline panel: the report's group tree as a list of rows beside the
3
+ * sheet, each one a step to where that instance begins. The tree is the
4
+ * layout list's own `marks` — the entries the PDF target writes as bookmarks
5
+ * — so the panel derives it exactly as that target does, and an author
6
+ * declares nothing for it (`docs/adr/0044` for the icon, ADR 0047 for the
7
+ * chrome). A hollow instance is not a mark, so it is not a row.
8
+ *
9
+ * Optional: a host turns it on with the `outline` property, and the bar then
10
+ * carries one toggle. The reader opens and closes the panel; the property
11
+ * says only whether the module is there at all.
12
+ *
13
+ * A title goes in as a template value, never as markup — a group's key is
14
+ * report data — so this module has no markup edge to escape at (hard
15
+ * constraint 4).
16
+ */
17
+ import { css, html } from "lit";
18
+ import { button } from "./button.js";
19
+ import { listTree } from "./icons.js";
20
+
21
+ export let OUTLINE = css`
22
+ .qv-outline {
23
+ flex: none;
24
+ width: 220px;
25
+ min-width: 0;
26
+ overflow: auto;
27
+ padding: 6px;
28
+ background: var(--_bar);
29
+ border-right: 1px solid var(--_border);
30
+ }
31
+
32
+ .qv-outline ol {
33
+ margin: 0;
34
+ padding: 0;
35
+ list-style: none;
36
+ }
37
+
38
+ /* Each level steps in by one indent, written on the list rather than the
39
+ row, so a row's own box stays the full width the hover fills. */
40
+ .qv-outline ol ol {
41
+ padding-left: 12px;
42
+ }
43
+
44
+ .qv-outline-row {
45
+ display: block;
46
+ width: 100%;
47
+ padding: 4px 8px;
48
+ border: none;
49
+ border-radius: 5px;
50
+ background: transparent;
51
+ color: inherit;
52
+ font: inherit;
53
+ text-align: left;
54
+ white-space: nowrap;
55
+ overflow: hidden;
56
+ text-overflow: ellipsis;
57
+ cursor: pointer;
58
+ }
59
+
60
+ .qv-outline-empty {
61
+ margin: 0;
62
+ padding: 4px 8px;
63
+ color: var(--_icon);
64
+ }
65
+ `;
66
+
67
+ /**
68
+ * @typedef {{ title: string, depth: number, page: number, x: number, y: number }} Mark
69
+ * @typedef {{ mark: Mark, children: Node[] }} Node
70
+ */
71
+
72
+ /**
73
+ * The marks as a tree: a mark is a child of the nearest mark before it at
74
+ * the depth above. Depth is the group's nesting, so the walk that emitted
75
+ * the marks in document order has already put every child after its parent.
76
+ *
77
+ * @param {readonly Mark[]} marks
78
+ * @returns {Node[]}
79
+ */
80
+ export let tree = (marks) => {
81
+ /** @type {Node[]} */
82
+ let roots = [];
83
+ /** @type {Node[]} */
84
+ let open = [];
85
+ for (let mark of marks) {
86
+ /** @type {Node} */
87
+ let node = { mark, children: [] };
88
+ open.length = mark.depth;
89
+ (open[mark.depth - 1]?.children ?? roots).push(node);
90
+ open.push(node);
91
+ }
92
+ return roots;
93
+ };
94
+
95
+ /** @type {(event: HTMLElement) => HTMLElement[]} */
96
+ let rows = (panel) => /** @type {HTMLElement[]} */ ([...panel.querySelectorAll(".qv-outline-row")]);
97
+
98
+ /** @type {Record<string, (list: HTMLElement[], at: number) => HTMLElement>} */
99
+ let MOVE = {
100
+ ArrowDown: (list, at) => list[Math.min(at + 1, list.length - 1)],
101
+ ArrowUp: (list, at) => list[Math.max(at - 1, 0)],
102
+ Home: (list) => list[0],
103
+ End: (list) => list[list.length - 1],
104
+ };
105
+
106
+ /**
107
+ * Arrow keys walk the rows in document order, whatever their depth; Tab
108
+ * leaves the panel as it left the bar. The platform owns activation.
109
+ *
110
+ * @param {KeyboardEvent} event
111
+ */
112
+ let navigate = (event) => {
113
+ let move = MOVE[event.key];
114
+ if (!move) return;
115
+ event.preventDefault();
116
+ let list = rows(/** @type {HTMLElement} */ (event.currentTarget));
117
+ let at = list.indexOf(/** @type {HTMLElement} */ (event.target));
118
+ move(list, at).focus();
119
+ };
120
+
121
+ /**
122
+ * @param {Node[]} nodes
123
+ * @param {(mark: Mark) => void} go
124
+ * @returns {import('lit').TemplateResult}
125
+ */
126
+ let branch = (nodes, go) => html`
127
+ <ol>
128
+ ${nodes.map(
129
+ (node) => html`
130
+ <li>
131
+ <button type="button" class="qv-outline-row" @click=${() => go(node.mark)}>
132
+ ${node.mark.title}
133
+ </button>
134
+ ${node.children.length ? branch(node.children, go) : ""}
135
+ </li>
136
+ `,
137
+ )}
138
+ </ol>
139
+ `;
140
+
141
+ /**
142
+ * The bar's toggle, drawn only while the module is on.
143
+ *
144
+ * @param {{ open: boolean, toggle: () => void }} state
145
+ */
146
+ export let outlineToggle = ({ open, toggle }) => html`
147
+ <div class="qv-outline-toggle">
148
+ ${button({ title: open ? "Hide outline" : "Show outline", click: toggle, content: listTree })}
149
+ </div>
150
+ `;
151
+
152
+ /**
153
+ * The panel itself. A report with no groups has no tree, and the panel says
154
+ * so rather than standing empty.
155
+ *
156
+ * @param {{ marks: readonly Mark[], go: (mark: Mark) => void }} state
157
+ */
158
+ export let outlinePanel = ({ marks, go }) => html`
159
+ <nav class="qv-outline" aria-label="Outline" @keydown=${navigate}>
160
+ ${
161
+ marks.length
162
+ ? branch(tree(marks), go)
163
+ : html`<p class="qv-outline-empty">This report has no groups.</p>`
164
+ }
165
+ </nav>
166
+ `;
package/lib/panel.js CHANGED
@@ -6,15 +6,13 @@
6
6
  * Always the compound — "the error panel", never a bare "panel", which stays
7
7
  * the word for the host's own UI regions around the viewer (see CONTEXT.md).
8
8
  *
9
- * It is the one place the viewer states wording of its own. Everything else it
10
- * shows comes from the report: the fragment is the html target's, and even the
11
- * unlicensed marking's wording arrives inside it. A label cannot, because no
12
- * error knows whether it was a mount, an update or an export that failed —
13
- * which is exactly what the error event's `kind` names.
9
+ * It is the one place the viewer states wording of its own: no error knows
10
+ * whether it was a mount, an update or an export that failed, which is what
11
+ * the error event's `kind` names.
14
12
  *
15
- * What it prints beside that label is the error's own message, as a template
16
- * value. That is a markup edge, and it stays one: a message can carry report
17
- * data, because a host's registry function is free to interpolate a row into
13
+ * Beside that label it prints the error's own message, as a template value.
14
+ * That is a markup edge and stays one: a message can carry report data,
15
+ * because a host's registry function is free to interpolate a row into
18
16
  * whatever it throws (hard constraint 4).
19
17
  */
20
18
  import { css, html } from "lit";
package/lib/stage.js CHANGED
@@ -13,68 +13,46 @@
13
13
  *
14
14
  * The sheet carries the whole list's extent, but only the
15
15
  * [reach](../../../CONTEXT.md#reach) carries elements and pixels — the pages
16
- * on screen and one viewport height either side. The extent the reader scrolls
17
- * through is whole and synchronous whatever is standing, because the sheet is
18
- * given its height and width inline and paints the page silhouettes itself; a
19
- * page leaving the reach is removed, which takes its backing store with it
20
- * (ADR 0065). A scroll or a resize runs the same arithmetic over the list's own
21
- * geometry, coalesced to one pass a frame. ADR 0043 says what the reach is
22
- * worth: painting the whole sheet asked a thousand-page report for gigabytes of
23
- * backing store, and past what the browser would grant the pages simply came up
24
- * blank.
16
+ * on screen and one viewport height either side. The extent is whole and
17
+ * synchronous whatever is standing, because the sheet is given its height and
18
+ * width inline and paints the page silhouettes itself; a page leaving the
19
+ * reach is removed, which takes its backing store with it (ADR 0043, 0065).
25
20
  *
26
21
  * **A page the browser will not paint is blank, not a failure.** `start`
27
22
  * swallows and nothing here rejects: the report laid out and the list reached
28
- * the sheet, which is all a render promised, so the surfaces have no channel
29
- * for it and deliberately grow none.
30
- *
31
- * Little reaches it. An image that will not decode is the layout's own to
32
- * absorb — `paint` draws it as nothing and draws the page around it — and a
33
- * face is parsed with fontkit while the report is measured, so bytes that will
34
- * not parse are a render error long before the sheet. What is left is the face
35
- * fontkit accepted and the browser refuses, which the browser suite drives by
36
- * making `FontFace.prototype.load` reject under a record handed straight to
37
- * `swap`.
23
+ * the sheet, which is all a render promised.
38
24
  *
39
25
  * **A canvas on the sheet is never re-pointed at a second paint.** `paint()`
40
26
  * awaits before it draws, so a canvas whose paint is still in flight is
41
- * *retired* rather than painted over or emptied: it comes off the sheet, its
42
- * pixels go back, and a fresh one stands in its place, so the superseded
43
- * paint draws into an element nobody is looking at. A canvas whose paint has
44
- * settled has nothing that could land late and is re-sized in place as before;
45
- * a page leaving the reach is removed either way, which takes its pixels with
46
- * it whether that paint has landed or not. Without this a zoom landing mid-paint could leave a page
47
- * carrying old-scale content on a new-scale canvas, with the memo below
48
- * calling it painted so that nothing repainted it again (ADR 0046).
27
+ * *retired*: it comes off the sheet and a fresh one stands in its place, so
28
+ * the superseded paint draws into an element nobody is looking at. Otherwise
29
+ * a zoom landing mid-paint could leave a page carrying old-scale content on a
30
+ * new-scale canvas, with the memo below calling it painted (ADR 0046). A
31
+ * canvas whose paint has settled is re-sized in place.
32
+ *
33
+ * Retirement is lazy: a scale change sizes the reach's CSS boxes at once but
34
+ * retires a page only when the repaint loop reaches it, so a page further
35
+ * down shows its old pixels stretched until its turn comes. The cost is that
36
+ * a retired page is a replaced `role="img"` node, which assistive technology
37
+ * sees swapped under it — accepted, because the alternative is a second
38
+ * element per page on a sheet ADR 0043 exists to keep cheap.
49
39
  *
50
- * Retirement is lazy, and only the paint is guarded. A scale change sizes the
51
- * reach's CSS boxes at once but retires a page only when the repaint loop
52
- * reaches it, so a page further down the reach shows its old pixels stretched
53
- * into the new box until its turn comes the ordinary look of a zoom in
54
- * progress, not the artefact above. The cost is that a retired page is a
55
- * replaced `role="img"` node: assistive technology reading that page sees it
56
- * swapped under them. Judged acceptable because retirement only happens while
57
- * that very page is mid-repaint and about to change what it shows anyway, and
58
- * because the alternative — a stable wrapper element per page to announce
59
- * from — is a second element per page on a sheet ADR 0043 exists to keep
60
- * cheap.
40
+ * The linked runs get a **focusable region each**, in `links.js`, hung on the
41
+ * sheet over the rectangles the painter drew them in and rebuilt as the band
42
+ * under the reader or the scale moves. They follow the reach for the reason the
43
+ * pages do, and this file owns the two numbers they need: the band, and the
44
+ * scale on screen.
61
45
  *
62
46
  * What the stage does not decide is which percentage to show: `fit()`
63
47
  * measures what would make one page span the width available, and `zoom.js`
64
- * owns the policy over that answer. What is on screen, though, is the
65
- * stage's own — `percent()` reports it, so no caller keeps a second copy.
66
- *
67
- * The editor builds its own stack of pages next door, and deliberately: what
68
- * the two surfaces share is the display list and the size of a point, not the
69
- * sheet. Each is a canvas element, a device-pixel size and a `paint()` call
70
- * around policy neither could lend the other — this one repaints under zoom
71
- * and guards a superseded repaint, that one builds once per swap and lays box
72
- * elements over the result.
48
+ * owns the policy over that answer. `percent()` reports what is on screen, so
49
+ * no caller keeps a second copy.
73
50
  */
74
51
 
75
52
  import { css } from "lit";
76
53
  import { GUTTER, sheet } from "@quario/landing";
77
54
  import { PX_PER_POINT } from "@quario/layout";
55
+ import { overlay } from "./links.js";
78
56
 
79
57
  // `GUTTER` comes from `@quario/landing`, which walks the reach over it: the CSS
80
58
  // below and the sheet's own arithmetic have to agree about where a page sits,
@@ -130,6 +108,7 @@ export let SURFACE = css`
130
108
  * percent: () => number, scale: (percent: number) => void,
131
109
  * resize: (geometry: PageBox) => void,
132
110
  * swap: (list: any, fonts: any) => Promise<void>,
111
+ * reveal: (page: number, y: number) => void,
133
112
  * watch: (changed: () => void) => () => void }} Stage
134
113
  */
135
114
 
@@ -169,7 +148,42 @@ export let stage = () => {
169
148
  * the elements above stay this file's, because the CSS is the viewer's own
170
149
  * public surface. */
171
150
  let paged = sheet(scroll, sheetEl, ratio);
172
- return {
151
+
152
+ /** The band of the sheet the reader is looking at, in the sheet's own CSS
153
+ * pixels: the frame a page is placed in. The sheet starts one gutter down
154
+ * the scroll extent, which is the same offset `reveal` scrolls through. */
155
+ let view = () => {
156
+ let top = scroll.scrollTop - GUTTER;
157
+ return { top, bottom: top + scroll.clientHeight };
158
+ };
159
+
160
+ /** The focusable regions over the linked runs. The viewer's own and not the
161
+ * editor's, which is the whole of ADR 0085's "a link in the editor's
162
+ * preview is not clickable". */
163
+ let links = overlay({
164
+ sheet: sheetEl,
165
+ paged,
166
+ ratio,
167
+ view,
168
+ reveal: (page, y) => api.reveal(page, y),
169
+ });
170
+
171
+ /** One region pass a frame, however many scrolls ask — the same coalescing
172
+ * the sheet's own reach pass uses, and a separate listener because the two
173
+ * answer different questions about the same scroll. */
174
+ let following = false;
175
+ let follow = () => {
176
+ if (following) return;
177
+ following = true;
178
+ requestAnimationFrame(() => {
179
+ following = false;
180
+ links.update();
181
+ });
182
+ };
183
+ scroll.addEventListener("scroll", follow);
184
+
185
+ /** @type {Stage} */
186
+ let api = {
173
187
  element: scroll,
174
188
 
175
189
  /**
@@ -191,23 +205,19 @@ export let stage = () => {
191
205
 
192
206
  /**
193
207
  * Scale to `percent`, holding the middle of the viewport where it was:
194
- * scaling about the sheet's corner would otherwise throw the reader back
195
- * toward the top-left of whatever they were reading. The sheet starts one
196
- * gutter down the scroll extent, so the centre converts through that
197
- * offset; horizontally the wrapper is centred by auto margins while it
198
- * fits — which is exactly when `scrollLeft` is 0 anyway — and its margins
199
- * are 0 once it overflows, so the plain ratio holds wherever it can be
200
- * seen. The browser clamps whatever it cannot honour. A sheet with no list
201
- * on it has no view to hold, which is what mounting at an authored zoom
202
- * takes. Asked of the list rather than of the sheet's children, which
203
- * since ADR 0065 are the reach's and can be none of them while a list is
204
- * standing — and it saves a DOM read besides.
208
+ * scaling about the sheet's corner would throw the reader back toward the
209
+ * top-left of what they were reading. The sheet starts one gutter down the
210
+ * scroll extent, so the centre converts through that offset; horizontally
211
+ * the wrapper is centred by auto margins while it fits — exactly when
212
+ * `scrollLeft` is 0 — and its margins are 0 once it overflows. A sheet
213
+ * with no list on it has no view to hold. Asked of the list rather than
214
+ * the sheet's children, which since ADR 0065 are the reach's and can be
215
+ * none of them while a list is standing.
205
216
  *
206
- * Only the reach is repainted, and only where the scale actually changed,
207
- * so a zoom step costs a handful of pages however long the report is.
217
+ * Only the reach is repainted, and only where the scale actually changed.
208
218
  */
209
219
  scale: (percent) => {
210
- let held = paged.count() > 0 && {
220
+ let held = paged.width() !== null && {
211
221
  top: scroll.scrollTop,
212
222
  left: scroll.scrollLeft,
213
223
  height: scroll.clientHeight,
@@ -222,6 +232,7 @@ export let stage = () => {
222
232
  scroll.scrollLeft = (held.left + held.width / 2) * ratioOf - held.width / 2;
223
233
  }
224
234
  void paged.repaint();
235
+ links.update();
225
236
  },
226
237
 
227
238
  /**
@@ -236,22 +247,17 @@ export let stage = () => {
236
247
  },
237
248
 
238
249
  /**
239
- * Put a laid-out report on the sheet, keeping the reader where they
240
- * were: the extent whole at once, with the reach's pages painted at the
241
- * applied scale. The order is the point of the method: the sheet takes its
242
- * height from the list before anything else, so the browser clamps the
243
- * offsets going back against the extent the sheet will have rather than
244
- * the one it had — and the reach is read from those offsets, so it is
245
- * chosen after they are in. What the
246
- * returned promise settles behind is the reach, which is what the caller's
247
- * `renderComplete` means by "the pages on screen have finished trying to
248
- * paint" — and **it never rejects**, because `start` swallows a page the
249
- * browser will not draw and the reach walks on past it.
250
+ * Put a laid-out report on the sheet, keeping the reader where they were.
251
+ * The order is the point of the method: the sheet takes its height from
252
+ * the list first, so the browser clamps the offsets going back against
253
+ * the extent the sheet will have rather than the one it had, and the
254
+ * reach is read from those offsets afterwards. The returned promise
255
+ * settles behind the reach and **never rejects**.
250
256
  */
251
257
  swap: async (next, faces) => {
252
258
  // Reading the offsets flushes layout, so only an actual reswap pays for
253
259
  // it: with no list standing there is nothing scrolled to preserve.
254
- let held = paged.count() > 0 && {
260
+ let held = paged.width() !== null && {
255
261
  top: scroll.scrollTop,
256
262
  left: scroll.scrollLeft,
257
263
  };
@@ -260,6 +266,24 @@ export let stage = () => {
260
266
  scroll.scrollTop = held.top;
261
267
  scroll.scrollLeft = held.left;
262
268
  }
269
+ // After the offsets go back, so the band the regions are built for is
270
+ // the one the reader is left looking at.
271
+ links.swap(next);
272
+ },
273
+
274
+ /**
275
+ * Scroll so that a point on a page sits at the top of the view: the
276
+ * outline's step to where an instance begins. The offset is the sheet's
277
+ * own — `topOf()` is where the sheet places that page, and the point
278
+ * scales as the page does — so this restates no stacking (ADR 0070).
279
+ * Horizontal stays where the reader left it.
280
+ *
281
+ * @param {number} page
282
+ * @param {number} y In points, down that page.
283
+ */
284
+ reveal: (page, y) => {
285
+ scroll.scrollTop = GUTTER + paged.topOf(page) + y * ratio();
286
+ paged.follow();
263
287
  },
264
288
 
265
289
  /**
@@ -273,10 +297,12 @@ export let stage = () => {
273
297
  // A resize that changes the fit repaints through `changed()`; one
274
298
  // that does not still moved the viewport the reach is measured in.
275
299
  paged.follow();
300
+ follow();
276
301
  changed();
277
302
  });
278
303
  observer.observe(scroll);
279
304
  return () => observer.disconnect();
280
305
  },
281
306
  };
307
+ return api;
282
308
  };
package/lib/zoom.js CHANGED
@@ -5,24 +5,17 @@
5
5
  * it (see stage.js).
6
6
  *
7
7
  * The preview **scales; it never reflows**. Fit shrinks the rendered sheet
8
- * like a photograph, so line breaks, column widths and point sizes stay
9
- * exactly what they are at 100%. Letting the sheet's width follow the viewer
10
- * instead would keep small text readable, but it would lay the report out
11
- * differently from the document the pdf target will page — and the `page`
12
- * property exists to promise those two agree. A legible-at-any-width reading mode
13
- * would be a separate feature under its own name, not something fit becomes
14
- * quietly.
8
+ * like a photograph, so line breaks, column widths and point sizes stay what
9
+ * they are at 100%. Letting the sheet's width follow the viewer would lay the
10
+ * report out differently from the document the pdf target pages, and the
11
+ * `page` property exists to promise those two agree.
15
12
  */
16
13
 
17
14
  /**
18
15
  * The percentages the menu offers, and — through its ends — the range the
19
16
  * `zoom` property accepts (check.js reads them, so the two cannot drift).
20
- *
21
- * The ends are therefore public API, not a menu detail: moving the first or
22
- * last entry widens or narrows what a host may author. `viewer.test.js` spells
23
- * the current range out in the message it expects, so such a move fails a test
24
- * that says so rather than passing quietly. Adding a stop between the ends is
25
- * free.
17
+ * The ends are therefore public API: moving the first or last entry widens or
18
+ * narrows what a host may author. Adding a stop between them is free.
26
19
  */
27
20
  export let STEPS = [25, 50, 75, 100, 150, 200];
28
21
 
package/package.json CHANGED
@@ -1,7 +1,14 @@
1
1
  {
2
2
  "name": "@quario/viewer",
3
- "version": "0.9.0",
4
- "description": "The embeddable report viewer shell for quario in the makings, not yet released",
3
+ "version": "0.11.0",
4
+ "description": "Tiny, embeddable report viewer for quario. A custom element that pages on screen and exports what you hand it.",
5
+ "keywords": [
6
+ "csp",
7
+ "custom-element",
8
+ "quario",
9
+ "report",
10
+ "viewer"
11
+ ],
5
12
  "homepage": "https://getquario.com",
6
13
  "license": "SEE LICENSE IN LICENSE",
7
14
  "repository": {
@@ -33,19 +40,20 @@
33
40
  "access": "public"
34
41
  },
35
42
  "scripts": {
36
- "check": "npm run size && npm test && npm run test:browser",
43
+ "check": "npm run size && npm test",
44
+ "coverage:check": "c8 report --src lib/ --temp-directory=../../coverage/tmp --reporter=text --check-coverage --100",
37
45
  "size": "size-limit",
38
- "test": "npm run test:unit && npm run test:types",
46
+ "test": "npm run test:unit && npm run test:browser && npm run test:types && npm run coverage:check",
39
47
  "test:browser": "node test/browser/setup.js",
40
48
  "test:types": "tsc && attw --pack . --profile esm-only",
41
- "test:unit": "node --disallow-code-generation-from-strings --test --test-concurrency=1 test/*.test.js",
49
+ "test:unit": "c8 --clean=false --src lib/ --reporter=none --temp-directory=../../coverage/tmp node --disallow-code-generation-from-strings --test --test-concurrency=1 test/*.test.js",
42
50
  "prepack": "node -e \"require('fs').copyFileSync('../../LICENSE','LICENSE')\"",
43
51
  "postpack": "node -e \"require('fs').rmSync('LICENSE',{force:true})\""
44
52
  },
45
53
  "dependencies": {
46
54
  "@lit/task": "^1.0.3",
47
- "@quario/landing": "^0.2.1",
48
- "@quario/layout": "^0.6.0",
55
+ "@quario/landing": "^0.3.1",
56
+ "@quario/layout": "^0.8.0",
49
57
  "lit": "^3.3.3"
50
58
  },
51
59
  "devDependencies": {
@@ -53,13 +61,12 @@
53
61
  "@cantoo/pdf-lib": "~2.9.1",
54
62
  "@size-limit/preset-small-lib": "^13.0.3",
55
63
  "esbuild": "^0.28.2",
56
- "exceljs": "^4.4.0",
57
- "quario": "^0.9.0",
64
+ "quario": "^0.11.0",
58
65
  "size-limit": "^13.0.3",
59
66
  "typescript": "^7.0.2"
60
67
  },
61
68
  "peerDependencies": {
62
- "quario": "^0.9.0"
69
+ "quario": "^0.11.0"
63
70
  },
64
71
  "size-limit": [
65
72
  {
@@ -71,7 +78,7 @@
71
78
  "lit",
72
79
  "@lit/task"
73
80
  ],
74
- "limit": "8.5 kB"
81
+ "limit": "9.5 kB"
75
82
  }
76
83
  ],
77
84
  "engines": {