@bicharts/chart-host 0.6.115 → 0.6.116

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.
Files changed (35) hide show
  1. package/README.md +18 -0
  2. package/dist/adapters.mjs +3 -3
  3. package/dist/card.mjs +2 -2
  4. package/dist/category-colours.mjs +275 -0
  5. package/dist/{chunk-AQO4ROMU.mjs → chunk-63IUMWY2.mjs} +40 -3
  6. package/dist/{chunk-YOCYWON4.mjs → chunk-EFKGSDFF.mjs} +1 -1
  7. package/dist/{chunk-7K3F3RZ6.mjs → chunk-GZSYTDFN.mjs} +68 -275
  8. package/dist/{chunk-QLIRQJ6B.mjs → chunk-IW6BKFF5.mjs} +1 -1
  9. package/dist/{chunk-YSRMSDRP.mjs → chunk-JMLSNV5Q.mjs} +1 -1
  10. package/dist/chunk-JTZTTJJK.mjs +244 -0
  11. package/dist/{chunk-VPFP35XI.mjs → chunk-K2TH7D5V.mjs} +299 -299
  12. package/dist/{chunk-GXR7T6G5.mjs → chunk-QG5TENI3.mjs} +4 -0
  13. package/dist/{chunk-PQKLWYKK.mjs → chunk-RLOIA7QK.mjs} +1 -1
  14. package/dist/{chunk-CVTCR7HQ.mjs → chunk-TUZCM7SX.mjs} +2 -2
  15. package/dist/{chunk-DILJDN6C.mjs → chunk-VGJH63LZ.mjs} +1 -1
  16. package/dist/{chunk-2GW3S5VD.mjs → chunk-ZZBX5ZJ6.mjs} +15 -2
  17. package/dist/dax.mjs +23 -1
  18. package/dist/index.mjs +63 -16
  19. package/dist/legend-fit.mjs +3 -3
  20. package/dist/page.mjs +5 -5
  21. package/dist/provinces.mjs +4 -4
  22. package/dist/react.mjs +12 -11
  23. package/dist/testing.mjs +1 -1
  24. package/dist/types/categoryColours.d.ts +71 -0
  25. package/dist/types/contract.d.ts +2 -0
  26. package/dist/types/dax.d.ts +26 -0
  27. package/dist/types/filterScope.d.ts +10 -1
  28. package/dist/types/fit.d.ts +6 -1
  29. package/dist/types/fitDom.d.ts +13 -0
  30. package/dist/types/host.d.ts +10 -0
  31. package/dist/types/index.d.ts +4 -3
  32. package/dist/types/qualifyTable.d.ts +52 -0
  33. package/dist/zoom-memory.mjs +1 -1
  34. package/package.json +6 -1
  35. /package/dist/{chunk-5YSZABCS.mjs → chunk-LXTW6YII.mjs} +0 -0
package/README.md CHANGED
@@ -137,6 +137,21 @@ nothing to the line, since that query keeps every row. A bare filter, `{ filter
137
137
  key column says the whole key. `label` sets what the line calls the filter. Outside React, `filterScopeOf` from
138
138
  `@bicharts/chart-host/page` takes the same list and returns `options.filterScope`.
139
139
 
140
+ ### A query that feeds no chart
141
+
142
+ A form's choice list, a lookup or a count beside a chart reads its query's rows by column name. A DAX result names
143
+ its columns `Table[Column]` and its measures `[Measure]`; `queryRows` from `@bicharts/chart-host/dax` returns each row
144
+ keyed by the bare name. Never parse the headers by hand: a pattern written through a shell and a script can lose its
145
+ backslashes on the way to disk and leave every value blank while the app's tests pass.
146
+
147
+ ```tsx
148
+ const owners = queryRows(useSemanticModelQuery({ connection, query: OWNERS_DAX }).data);
149
+ owners.map(r => r["Sales owner"]); // Owners[Sales owner]
150
+ ```
151
+
152
+ Two columns with one bare name (`Accounts[Name]` and `Owners[Name]`) keep their whole headers. `columnName(header)`
153
+ gives one header's bare name.
154
+
140
155
  ### Several panels that pick the same key
141
156
 
142
157
  A map, a table and a scatter that each pick a country are ONE pick. Give their filters one `group`, and keep each
@@ -156,6 +171,9 @@ whichever panel shows it clears it, and the panel the reader picked in keeps all
156
171
  open items for the picked countries) reads the members' keys, which are that one pick. Without `group` the filters
157
172
  are separate picks, ANDed: a country picked on the map and then in the table is held twice, and clicking it again on
158
173
  the map leaves the page filtered by the table's. Outside React, `scope.filter(column, { group })` does the same.
174
+ A saved view or a link (`useBicUrlState`) names each member on its own (`Country`, `Country-2`, `Country-3`, in the
175
+ order the page makes them), so a lasso saved on the scatter comes back on the scatter; give a member `key` for a name
176
+ that doesn't depend on that order.
159
177
 
160
178
  ## Vanilla
161
179
 
package/dist/adapters.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  censusHitBands,
4
4
  ensureCrossfilterHitTargets,
5
5
  hitBandFlag
6
- } from "./chunk-YOCYWON4.mjs";
6
+ } from "./chunk-EFKGSDFF.mjs";
7
7
  import {
8
8
  clickWasDrag,
9
9
  collectD3GlyphCenters,
@@ -12,13 +12,13 @@ import {
12
12
  markKeyOf,
13
13
  rowIdxsFromMark,
14
14
  selectionRuleOf
15
- } from "./chunk-PQKLWYKK.mjs";
15
+ } from "./chunk-RLOIA7QK.mjs";
16
16
  import {
17
17
  AXIS_FILTER_CLASS,
18
18
  LEGEND_MARK_CLASS,
19
19
  MARK_CLASS,
20
20
  ROW_IDX_ATTR
21
- } from "./chunk-GXR7T6G5.mjs";
21
+ } from "./chunk-QG5TENI3.mjs";
22
22
  import "./chunk-GHODWOAL.mjs";
23
23
 
24
24
  // src/adapters/types.ts
package/dist/card.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  /*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
2
2
  import {
3
3
  computeSelectionCard
4
- } from "./chunk-YSRMSDRP.mjs";
5
- import "./chunk-VPFP35XI.mjs";
4
+ } from "./chunk-JMLSNV5Q.mjs";
5
+ import "./chunk-K2TH7D5V.mjs";
6
6
  import "./chunk-GHODWOAL.mjs";
7
7
 
8
8
  // src/selectionCardChrome.ts
@@ -0,0 +1,275 @@
1
+ /*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
2
+ import {
3
+ MIN_RAMP_FILLS,
4
+ RAMP_SLACK_MAX,
5
+ deltaE2000,
6
+ hexToLab,
7
+ rgbToLab
8
+ } from "./chunk-JTZTTJJK.mjs";
9
+ import {
10
+ CATEGORY_DELTA_E_FLOOR,
11
+ DIM_OPACITY_DEFAULT,
12
+ LEGEND_MARK_CLASS,
13
+ MARK_CLASS,
14
+ ROW_IDX_ATTR
15
+ } from "./chunk-QG5TENI3.mjs";
16
+ import "./chunk-GHODWOAL.mjs";
17
+
18
+ // src/categoryColours.ts
19
+ var MAX_CATEGORY_SLOTS = 24;
20
+ var RAMP_DECLINE_MIN_SLOTS = 6;
21
+ var ELEMENT_CAP = 5e3;
22
+ var MAX_LISTED_PAIRS = 10;
23
+ function emptyCensus(declined, dimOpacity, slots = 0, source = "") {
24
+ return {
25
+ source,
26
+ declined,
27
+ slots,
28
+ closestPair: [],
29
+ closestDeltaE: null,
30
+ closestDeltaEPainted: null,
31
+ closestDeltaEDimmed: null,
32
+ dimOpacity,
33
+ rampLike: false,
34
+ legendMatchesMarks: null,
35
+ floor: CATEGORY_DELTA_E_FLOOR,
36
+ belowFloor: null,
37
+ pairsBelowFloorCount: 0,
38
+ pairsBelowFloor: [],
39
+ closestPairPainted: [],
40
+ closestDeltaEDeutan: null,
41
+ closestDeltaEProtan: null
42
+ };
43
+ }
44
+ function styleOf(el, doc) {
45
+ try {
46
+ const view = doc?.defaultView;
47
+ return view?.getComputedStyle ? view.getComputedStyle(el) : null;
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+ function parsePaint(raw) {
53
+ if (raw === null || raw === void 0) return null;
54
+ const s = String(raw).trim().toLowerCase();
55
+ if (!s || s === "none" || s === "transparent" || s.startsWith("url(")) return null;
56
+ const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/.exec(s);
57
+ if (hex) {
58
+ const h = hex[1].length === 3 ? hex[1].replace(/./g, (c) => c + c) : hex[1];
59
+ return { rgb: [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)], alpha: 1 };
60
+ }
61
+ const m = /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)\s*(?:[,/]\s*([\d.]+%?)\s*)?\)$/.exec(s);
62
+ if (!m) return null;
63
+ let alpha = 1;
64
+ if (m[4] !== void 0) alpha = m[4].endsWith("%") ? parseFloat(m[4]) / 100 : parseFloat(m[4]);
65
+ if (!(alpha > 0)) return null;
66
+ return { rgb: [Math.round(+m[1]), Math.round(+m[2]), Math.round(+m[3])], alpha: Math.min(1, alpha) };
67
+ }
68
+ function numberOr1(v) {
69
+ if (v === null || v === void 0 || String(v).trim() === "") return 1;
70
+ const n = parseFloat(String(v));
71
+ return Number.isFinite(n) ? Math.max(0, Math.min(1, n)) : 1;
72
+ }
73
+ function ownOpacity(el, container) {
74
+ let a = 1;
75
+ for (let n = el; n && n !== container; n = n.parentNode) {
76
+ if (typeof n.getAttribute !== "function") break;
77
+ a *= numberOr1(n.getAttribute("opacity"));
78
+ a *= numberOr1(n.style?.opacity);
79
+ }
80
+ return a;
81
+ }
82
+ function paintOf(el, doc) {
83
+ const cs = styleOf(el, doc);
84
+ const fill = parsePaint(firstSet(el.getAttribute?.("fill"), el.style?.fill, cs?.fill));
85
+ if (fill) return { rgb: fill.rgb, alpha: fill.alpha * numberOr1(firstSet(el.getAttribute?.("fill-opacity"), el.style?.fillOpacity)) };
86
+ const stroke = parsePaint(firstSet(el.getAttribute?.("stroke"), el.style?.stroke, cs?.stroke));
87
+ if (stroke) return { rgb: stroke.rgb, alpha: stroke.alpha * numberOr1(firstSet(el.getAttribute?.("stroke-opacity"), el.style?.strokeOpacity)) };
88
+ return null;
89
+ }
90
+ function firstSet(...vals) {
91
+ for (const v of vals) if (v !== null && v !== void 0 && String(v).trim() !== "") return String(v);
92
+ return null;
93
+ }
94
+ function paintWithin(el, doc, container) {
95
+ let p = paintOf(el, doc);
96
+ let at = el;
97
+ if (!p && typeof el.querySelectorAll === "function") {
98
+ for (const child of Array.from(el.querySelectorAll("*"))) {
99
+ p = paintOf(child, doc);
100
+ if (p) {
101
+ at = child;
102
+ break;
103
+ }
104
+ }
105
+ }
106
+ return p ? { rgb: p.rgb, alpha: p.alpha * ownOpacity(at, container) } : null;
107
+ }
108
+ var hexOf = (rgb) => "#" + rgb.map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
109
+ function blend(rgb, alpha, bg) {
110
+ const a = Math.max(0, Math.min(1, alpha));
111
+ return [rgb[0] * a + bg[0] * (1 - a), rgb[1] * a + bg[1] * (1 - a), rgb[2] * a + bg[2] * (1 - a)].map(Math.round);
112
+ }
113
+ function slotsOf(paints) {
114
+ const byColour = /* @__PURE__ */ new Map();
115
+ for (const p of paints) {
116
+ const k = p.rgb.join(",");
117
+ const slot = byColour.get(k) ?? { rgb: p.rgb, alphas: /* @__PURE__ */ new Map() };
118
+ const a = Math.round(p.alpha * 100) / 100;
119
+ slot.alphas.set(a, (slot.alphas.get(a) ?? 0) + 1);
120
+ byColour.set(k, slot);
121
+ }
122
+ return [...byColour.values()].map((s) => ({
123
+ rgb: s.rgb,
124
+ alpha: [...s.alphas].sort((x, y) => y[1] - x[1] || y[0] - x[0])[0][0]
125
+ }));
126
+ }
127
+ var MACHADO_DEUTAN = [[0.367322, 0.860646, -0.227968], [0.280085, 0.672501, 0.047413], [-0.01182, 0.04294, 0.968881]];
128
+ var MACHADO_PROTAN = [[0.152286, 1.052583, -0.204868], [0.114503, 0.786281, 0.099216], [-3882e-6, -0.048116, 1.051998]];
129
+ var toLinear = (c) => {
130
+ const v = c / 255;
131
+ return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
132
+ };
133
+ var toSrgb = (v) => {
134
+ const x = Math.max(0, Math.min(1, v));
135
+ return 255 * (x <= 31308e-7 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
136
+ };
137
+ function simulatedLab(rgb, m) {
138
+ const lin = rgb.map(toLinear);
139
+ const out = m.map((row) => toSrgb(row[0] * lin[0] + row[1] * lin[1] + row[2] * lin[2]));
140
+ return rgbToLab(out[0], out[1], out[2]);
141
+ }
142
+ function pairsUnder(labs, floor) {
143
+ const out = [];
144
+ for (let i = 0; i < labs.length; i++) {
145
+ for (let j = i + 1; j < labs.length; j++) {
146
+ const d = deltaE2000(labs[i], labs[j]);
147
+ if (d < floor) out.push({ i, j, d });
148
+ }
149
+ }
150
+ return out.sort((x, y) => x.d - y.d);
151
+ }
152
+ function closest(labs) {
153
+ let best = { i: 0, j: 1, d: Infinity };
154
+ for (let i = 0; i < labs.length; i++) {
155
+ for (let j = i + 1; j < labs.length; j++) {
156
+ const d = deltaE2000(labs[i], labs[j]);
157
+ if (d < best.d) best = { i, j, d };
158
+ }
159
+ }
160
+ return best;
161
+ }
162
+ function isRampShaped(labs) {
163
+ if (labs.length < MIN_RAMP_FILLS) return false;
164
+ let span = 0, lo = 0, hi = 1;
165
+ for (let i = 0; i < labs.length; i++) {
166
+ for (let j = i + 1; j < labs.length; j++) {
167
+ const v = deltaE2000(labs[i], labs[j]);
168
+ if (v > span) {
169
+ span = v;
170
+ lo = i;
171
+ hi = j;
172
+ }
173
+ }
174
+ }
175
+ if (span <= 0) return false;
176
+ let slack = 0, interior = 0;
177
+ for (let i = 0; i < labs.length; i++) {
178
+ if (i === lo || i === hi) continue;
179
+ slack += (deltaE2000(labs[lo], labs[i]) + deltaE2000(labs[i], labs[hi])) / span - 1;
180
+ interior++;
181
+ }
182
+ return interior >= 2 && slack / interior <= RAMP_SLACK_MAX;
183
+ }
184
+ var LIGHTNESS_STEP_MIN = 1.5;
185
+ function lightnessFollowsPath(labs) {
186
+ let span = -1, lo = 0;
187
+ for (let i = 0; i < labs.length; i++) {
188
+ for (let j = i + 1; j < labs.length; j++) {
189
+ const v = deltaE2000(labs[i], labs[j]);
190
+ if (v > span) {
191
+ span = v;
192
+ lo = i;
193
+ }
194
+ }
195
+ }
196
+ const order = labs.map((l) => ({ L: l.L, d: deltaE2000(labs[lo], l) })).sort((a, b) => a.d - b.d);
197
+ let turns = 0, dir = 0;
198
+ for (let k = 1; k < order.length; k++) {
199
+ const step = order[k].L - order[k - 1].L;
200
+ if (Math.abs(step) < LIGHTNESS_STEP_MIN) continue;
201
+ const sign = Math.sign(step);
202
+ if (dir !== 0 && sign !== dir) turns++;
203
+ dir = sign;
204
+ }
205
+ return turns <= 1;
206
+ }
207
+ var round1 = (n) => Math.round(n * 10) / 10;
208
+ function censusCategoryColours(container, doc, options = {}) {
209
+ const dimOpacity = typeof options.dimOpacity === "number" && options.dimOpacity >= 0 && options.dimOpacity <= 1 ? options.dimOpacity : DIM_OPACITY_DEFAULT;
210
+ if (!container || typeof container.querySelectorAll !== "function") return emptyCensus("none", dimOpacity);
211
+ try {
212
+ const ownerDoc = doc ?? container.ownerDocument;
213
+ const legendEls = Array.from(container.querySelectorAll(`.${LEGEND_MARK_CLASS}`));
214
+ const markEls = Array.from(container.querySelectorAll(`.${MARK_CLASS}, [${ROW_IDX_ATTR}]`)).filter((el) => !el.classList?.contains(LEGEND_MARK_CLASS));
215
+ if (legendEls.length + markEls.length > ELEMENT_CAP) return emptyCensus("too-many", dimOpacity);
216
+ const paintsOf = (els) => els.map((el) => paintWithin(el, ownerDoc, container)).filter((p) => p !== null);
217
+ const legendSlots = slotsOf(paintsOf(legendEls));
218
+ const markSlots = slotsOf(paintsOf(markEls));
219
+ const useLegend = legendSlots.length >= 2;
220
+ const slots = useLegend ? legendSlots : markSlots;
221
+ const source = useLegend ? "legend" : markSlots.length ? "marks" : "";
222
+ if (slots.length < 2) return emptyCensus("none", dimOpacity, slots.length, source);
223
+ if (slots.length > MAX_CATEGORY_SLOTS) return emptyCensus("too-many", dimOpacity, slots.length, source);
224
+ const labs = slots.map((s) => hexToLab(hexOf(s.rgb))).filter((l) => l !== null);
225
+ if (labs.length !== slots.length) return emptyCensus("none", dimOpacity, slots.length, source);
226
+ const rampLike = isRampShaped(labs);
227
+ if (rampLike && slots.length >= RAMP_DECLINE_MIN_SLOTS && lightnessFollowsPath(labs)) return { ...emptyCensus("ramp", dimOpacity, slots.length, source), rampLike };
228
+ const bgPaint = parsePaint(options.pageBg);
229
+ const bg = bgPaint ? blend(bgPaint.rgb, bgPaint.alpha, [255, 255, 255]) : [255, 255, 255];
230
+ const labsAt = (alphaOf) => slots.map((s) => hexToLab(hexOf(blend(s.rgb, alphaOf(s), bg))));
231
+ const full = closest(labs);
232
+ const paintedLabs = labsAt((s) => s.alpha);
233
+ const painted = closest(paintedLabs);
234
+ const dimmed = closest(labsAt((s) => s.alpha * dimOpacity));
235
+ const under = pairsUnder(paintedLabs, CATEGORY_DELTA_E_FLOOR);
236
+ const paintedRgb = slots.map((s) => blend(s.rgb, s.alpha, bg));
237
+ const deutan = closest(paintedRgb.map((c) => simulatedLab(c, MACHADO_DEUTAN)));
238
+ const protan = closest(paintedRgb.map((c) => simulatedLab(c, MACHADO_PROTAN)));
239
+ let legendMatchesMarks = null;
240
+ if (useLegend && markSlots.length > 0) {
241
+ const markColours = new Set(markSlots.map((s) => s.rgb.join(",")));
242
+ legendMatchesMarks = legendSlots.every((s) => markColours.has(s.rgb.join(",")));
243
+ }
244
+ return {
245
+ source,
246
+ declined: "",
247
+ slots: slots.length,
248
+ closestPair: [hexOf(slots[full.i].rgb), hexOf(slots[full.j].rgb)],
249
+ closestDeltaE: round1(full.d),
250
+ closestDeltaEPainted: round1(painted.d),
251
+ closestDeltaEDimmed: round1(dimmed.d),
252
+ dimOpacity,
253
+ rampLike,
254
+ legendMatchesMarks,
255
+ floor: CATEGORY_DELTA_E_FLOOR,
256
+ belowFloor: painted.d < CATEGORY_DELTA_E_FLOOR,
257
+ pairsBelowFloorCount: under.length,
258
+ pairsBelowFloor: under.slice(0, MAX_LISTED_PAIRS).map((p) => ({
259
+ colours: [hexOf(slots[p.i].rgb), hexOf(slots[p.j].rgb)],
260
+ deltaE: round1(p.d)
261
+ })),
262
+ closestPairPainted: [hexOf(slots[painted.i].rgb), hexOf(slots[painted.j].rgb)],
263
+ closestDeltaEDeutan: round1(deutan.d),
264
+ closestDeltaEProtan: round1(protan.d)
265
+ };
266
+ } catch {
267
+ return emptyCensus("none", dimOpacity);
268
+ }
269
+ }
270
+ export {
271
+ MAX_CATEGORY_SLOTS,
272
+ MAX_LISTED_PAIRS,
273
+ RAMP_DECLINE_MIN_SLOTS,
274
+ censusCategoryColours
275
+ };
@@ -1,8 +1,9 @@
1
1
  /*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
2
2
  import {
3
3
  CONTAINER_SLOT_SCROLL,
4
- SNAPSHOT_SVG_ATTR
5
- } from "./chunk-GXR7T6G5.mjs";
4
+ SNAPSHOT_SVG_ATTR,
5
+ TABLE_SCROLLER_CLASS
6
+ } from "./chunk-QG5TENI3.mjs";
6
7
 
7
8
  // src/fit.ts
8
9
  var SCROLL_SLACK_PX = 8;
@@ -273,10 +274,45 @@ function rememberScroll(container, key) {
273
274
  if (slot[CONTAINER_SLOT_SCROLL]) return;
274
275
  if (container.querySelector(".llm-mm-scroll")) return;
275
276
  const x = container.scrollLeft, y = container.scrollTop;
276
- if (x > 0 || y > 0) slot[CONTAINER_SLOT_SCROLL] = { key, x, y };
277
+ const inner = innerScrollsOf(container);
278
+ if (x > 0 || y > 0 || inner) slot[CONTAINER_SLOT_SCROLL] = inner ? { key, x, y, inner } : { key, x, y };
277
279
  } catch {
278
280
  }
279
281
  }
282
+ var INNER_SCROLLER_CAP = 16;
283
+ var offset = (n) => typeof n === "number" && isFinite(n) && n > 0 ? n : 0;
284
+ function innerScrollsOf(container) {
285
+ const els = container.querySelectorAll("." + TABLE_SCROLLER_CLASS);
286
+ if (!els.length) return null;
287
+ const out = [];
288
+ let any = false;
289
+ for (let i = 0; i < els.length && i < INNER_SCROLLER_CAP; i++) {
290
+ const el = els[i];
291
+ const x = offset(el.scrollLeft), y = offset(el.scrollTop);
292
+ if (x > 0 || y > 0) any = true;
293
+ out.push({ x, y });
294
+ }
295
+ return any ? out : null;
296
+ }
297
+ function restoreInnerScroll(container, memory, key) {
298
+ if (!container || !memory || !memory.inner || !memory.inner.length) return null;
299
+ if (key === void 0 || key === null || memory.key !== key) return null;
300
+ try {
301
+ const els = container.querySelectorAll("." + TABLE_SCROLLER_CLASS);
302
+ if (!els.length) return null;
303
+ const out = [];
304
+ for (let i = 0; i < els.length && i < memory.inner.length; i++) {
305
+ const el = els[i], want = memory.inner[i];
306
+ const x = offset(want && want.x), y = offset(want && want.y);
307
+ if (x > 0 && el.scrollLeft !== x) el.scrollLeft = x;
308
+ if (y > 0 && el.scrollTop !== y) el.scrollTop = y;
309
+ out.push({ x: offset(el.scrollLeft), y: offset(el.scrollTop) });
310
+ }
311
+ return out;
312
+ } catch {
313
+ return null;
314
+ }
315
+ }
280
316
  function takeScroll(container) {
281
317
  if (!container) return null;
282
318
  try {
@@ -625,6 +661,7 @@ export {
625
661
  fitReadingFor,
626
662
  unpinScrolledAxis,
627
663
  rememberScroll,
664
+ restoreInnerScroll,
628
665
  takeScroll,
629
666
  pinScrolledAxis,
630
667
  fitRenderedChart
@@ -4,7 +4,7 @@ import {
4
4
  LEGEND_MARK_CLASS,
5
5
  MARK_CLASS,
6
6
  ROW_IDX_ATTR
7
- } from "./chunk-GXR7T6G5.mjs";
7
+ } from "./chunk-QG5TENI3.mjs";
8
8
 
9
9
  // src/hitTargets.ts
10
10
  var SVG_NS = "http://www.w3.org/2000/svg";