@astronox/core 0.4.3 → 0.4.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astronox/core",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "Reusable Astro components, patterns, styles, and infrastructure for AstroNox sites.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -49,10 +49,7 @@
49
49
 
50
50
  .table[data-table-sticky-header]:has([data-sticky-surface])
51
51
  [data-table-header] {
52
- top: var(
53
- --surface-group-sticky-occlusion-size,
54
- calc(var(--nox-layout-gap) + var(--nox-section-responsive-block-size))
55
- );
52
+ top: calc(var(--nox-layout-gap) + var(--nox-section-responsive-block-size));
56
53
  }
57
54
 
58
55
  @container nox-table (width < 32rem) {
@@ -63,10 +60,7 @@
63
60
 
64
61
  .table[data-table-sticky-header]:has([data-sticky-surface])
65
62
  [data-table-header] {
66
- top: var(
67
- --surface-group-sticky-occlusion-size,
68
- calc(var(--nox-layout-gap) + var(--nox-section-compact-block-size))
69
- );
63
+ top: calc(var(--nox-layout-gap) + var(--nox-section-compact-block-size));
70
64
  }
71
65
  }
72
66
 
@@ -55,23 +55,6 @@ const stateMessage =
55
55
  data-tooltip-boundary
56
56
  data-tone={dataTone}
57
57
  >
58
- <div
59
- class="table-body__initial-skeleton"
60
- data-table-initial-skeleton
61
- aria-hidden="true"
62
- >
63
- {
64
- columns.map((column) => (
65
- <div
66
- class="table-skeleton__cell"
67
- data-align={getTableColumnAlignment(column)}
68
- data-table-column-role={column.role}
69
- >
70
- <span class="table-skeleton__placeholder" />
71
- </div>
72
- ))
73
- }
74
- </div>
75
58
  <table class="table-body__table">
76
59
  <caption class="table-body__visually-hidden">{caption}</caption>
77
60
  <thead class="table-body__visually-hidden">
@@ -7,23 +7,6 @@
7
7
  border-block-start: 0;
8
8
  }
9
9
 
10
- .table-body__initial-skeleton {
11
- display: none;
12
- min-width: 0;
13
- min-height: var(--table-row-min-block-size);
14
- grid-template-columns: var(--table-column-template);
15
- }
16
-
17
- [data-nox-table-enhanced]
18
- .table:is(
19
- [data-table-loading-state='pending'],
20
- [data-table-loading-state='refreshing']
21
- )
22
- .table-body:not(:has(.table-skeleton__row))
23
- > .table-body__initial-skeleton {
24
- display: grid;
25
- }
26
-
27
10
  .table-skeleton__row + .table-skeleton__row,
28
11
  [data-nox-table-enhanced]
29
12
  .table[data-table-loading-state='appending']
@@ -34,6 +17,9 @@
34
17
 
35
18
  [data-nox-table-enhanced]
36
19
  .table[data-table-loading-state='pending']
20
+ .table-body__row[data-table-row],
21
+ [data-nox-table-enhanced]
22
+ .table[data-table-loading-state='refreshing']
37
23
  .table-body__row[data-table-row] {
38
24
  display: none;
39
25
  }
@@ -97,11 +83,6 @@
97
83
  min-height: var(--table-index-row-block-size);
98
84
  }
99
85
 
100
- .table[data-table-layout='index'] .table-body__initial-skeleton {
101
- block-size: var(--table-index-row-block-size);
102
- min-height: var(--table-index-row-block-size);
103
- }
104
-
105
86
  @media (prefers-reduced-motion: no-preference) {
106
87
  .table-skeleton__placeholder {
107
88
  animation: table-skeleton-pulse 1.4s ease-in-out infinite;
@@ -119,8 +100,7 @@
119
100
  }
120
101
 
121
102
  @container (width < 36rem) {
122
- .table-skeleton__row,
123
- .table-body__initial-skeleton {
103
+ .table-skeleton__row {
124
104
  min-height: var(--table-row-narrow-min-block-size);
125
105
  }
126
106
  }
@@ -3,7 +3,6 @@ import type {
3
3
  TableProgressiveModel,
4
4
  } from '../../display/contracts';
5
5
  import { tableProgressiveBatchSize } from '../../display/tableProgressive';
6
- import { mutateTablePreservingScroll } from './tableScrollPosition';
7
6
 
8
7
  const initializedAttribute = 'data-table-progressive-initialized';
9
8
 
@@ -152,8 +151,6 @@ export function initTableProgressive(root: HTMLElement): () => void {
152
151
  let disposed = false;
153
152
  let generation = 0;
154
153
  let prepared = false;
155
- let retainedWindowSize = Math.max(batchSize, getRows(activeRowsRoot).length);
156
- let scheduledRenderFrame: number | null = null;
157
154
 
158
155
  registerRows(getRows(activeRowsRoot));
159
156
 
@@ -184,11 +181,8 @@ export function initTableProgressive(root: HTMLElement): () => void {
184
181
  activeSkeletonTemplate.content.querySelectorAll<HTMLElement>(
185
182
  '[data-table-skeleton-row]',
186
183
  ),
187
- );
188
- if (candidates.length === 0) return;
189
- skeletonRows = Array.from({ length: count }, (_, index) =>
190
- document.importNode(candidates[index % candidates.length]!, true),
191
- );
184
+ ).slice(0, count);
185
+ skeletonRows = candidates.map((row) => document.importNode(row, true));
192
186
  insertBeforeEmpty(activeRowsRoot, empty, skeletonRows);
193
187
  }
194
188
 
@@ -210,21 +204,6 @@ export function initTableProgressive(root: HTMLElement): () => void {
210
204
  );
211
205
  }
212
206
 
213
- function replaceRows(rows: readonly HTMLElement[]): void {
214
- for (const row of rows) row.hidden = false;
215
- mutateTablePreservingScroll(root, () => {
216
- removeSkeleton();
217
- detachRenderedRows();
218
- insertBeforeEmpty(activeRowsRoot, empty, rows);
219
- });
220
- root.dispatchEvent(
221
- new CustomEvent<TableRowsAppendedDetail>('table:rows-appended', {
222
- bubbles: true,
223
- detail: { rows },
224
- }),
225
- );
226
- }
227
-
228
207
  function updateEmptyState(): void {
229
208
  if (empty) empty.hidden = results.length > 0;
230
209
  }
@@ -307,12 +286,10 @@ export function initTableProgressive(root: HTMLElement): () => void {
307
286
  TableLoadingState,
308
287
  'pending' | 'refreshing' | 'appending'
309
288
  > = 'appending',
310
- requestedCount = batchSize,
311
- replace = false,
312
289
  ): Promise<void> {
313
290
  if (request || disposed || cursor >= results.length) return;
314
291
 
315
- const target = results.slice(cursor, cursor + requestedCount);
292
+ const target = results.slice(cursor, cursor + batchSize);
316
293
  if (target.length === 0) {
317
294
  removeSkeleton();
318
295
  updatePagination();
@@ -328,9 +305,7 @@ export function initTableProgressive(root: HTMLElement): () => void {
328
305
  request = activeRequest;
329
306
  setPaginationState(activePagination, activeStatus, 'loading');
330
307
  updateTableState(loadingState);
331
- if (loadingState === 'appending' || skeletonRows.length === 0) {
332
- addSkeleton(target.length);
333
- }
308
+ addSkeleton(target.length);
334
309
 
335
310
  try {
336
311
  await loadSources(missing, activeRequest.signal);
@@ -361,16 +336,9 @@ export function initTableProgressive(root: HTMLElement): () => void {
361
336
  return;
362
337
  }
363
338
 
364
- if (replace) replaceRows(rows as HTMLElement[]);
365
- else {
366
- removeSkeleton();
367
- appendRows(rows as HTMLElement[]);
368
- }
339
+ removeSkeleton();
340
+ appendRows(rows as HTMLElement[]);
369
341
  cursor += target.length;
370
- retainedWindowSize = Math.max(
371
- retainedWindowSize,
372
- getRows(activeRowsRoot).length,
373
- );
374
342
  updatePagination();
375
343
  updateTableState('ready');
376
344
  }
@@ -435,48 +403,22 @@ export function initTableProgressive(root: HTMLElement): () => void {
435
403
  offset: number,
436
404
  state: Extract<TableLoadingState, 'pending' | 'refreshing'>,
437
405
  ): void {
438
- retainedWindowSize = Math.max(
439
- retainedWindowSize,
440
- getRows(activeRowsRoot).length,
441
- );
442
406
  generation += 1;
443
407
  request?.abort();
444
408
  request = null;
445
- if (scheduledRenderFrame !== null) {
446
- window.cancelAnimationFrame(scheduledRenderFrame);
447
- scheduledRenderFrame = null;
448
- }
449
- observer.disconnect();
450
409
  updateTableState(state);
451
- setPaginationState(activePagination, activeStatus, 'loading');
452
- if (empty) empty.hidden = true;
453
- mutateTablePreservingScroll(root, () => {
454
- detachRenderedRows();
455
- addSkeleton(retainedWindowSize);
456
- });
457
-
410
+ addSkeleton(batchSize);
411
+ detachRenderedRows();
458
412
  applyQuery();
459
413
  cursor = Math.min(offset, results.length);
460
- const activeGeneration = generation;
461
- scheduledRenderFrame = window.requestAnimationFrame(() => {
462
- scheduledRenderFrame = window.requestAnimationFrame(() => {
463
- scheduledRenderFrame = null;
464
- if (disposed || generation !== activeGeneration) return;
465
-
466
- updateEmptyState();
467
- if (results.length === 0) {
468
- replaceRows([]);
469
- updatePagination();
470
- updateTableState('empty');
471
- return;
472
- }
473
- void renderNextBatch(
474
- state,
475
- Math.min(retainedWindowSize, results.length - cursor),
476
- true,
477
- );
478
- });
479
- });
414
+ updateEmptyState();
415
+ if (results.length === 0) {
416
+ removeSkeleton();
417
+ updatePagination();
418
+ updateTableState('empty');
419
+ return;
420
+ }
421
+ void renderNextBatch(state);
480
422
  }
481
423
 
482
424
  function refresh(): void {
@@ -492,10 +434,6 @@ export function initTableProgressive(root: HTMLElement): () => void {
492
434
  destroy() {
493
435
  disposed = true;
494
436
  request?.abort();
495
- if (scheduledRenderFrame !== null) {
496
- window.cancelAnimationFrame(scheduledRenderFrame);
497
- scheduledRenderFrame = null;
498
- }
499
437
  observer.disconnect();
500
438
  removeSkeleton();
501
439
  activePagination.hidden = !fallbackLink;
@@ -4,7 +4,6 @@ import {
4
4
  setTableProgressiveSort,
5
5
  updateTableProgressiveEntry,
6
6
  } from './tableProgressiveController';
7
- import { mutateTablePreservingScroll } from './tableScrollPosition';
8
7
 
9
8
  type SortDirection = 'ascending' | 'descending';
10
9
  type SortType = 'number' | 'text';
@@ -97,11 +96,9 @@ export function initTableSort(root: HTMLElement): () => void {
97
96
  orderDirty = activeState !== null;
98
97
  if (rows.every((row, index) => row === sortedRows[index])) return;
99
98
 
100
- mutateTablePreservingScroll(root, () => {
101
- const fragment = document.createDocumentFragment();
102
- for (const row of sortedRows) fragment.append(row);
103
- rowsRoot.prepend(fragment);
104
- });
99
+ const fragment = document.createDocumentFragment();
100
+ for (const row of sortedRows) fragment.append(row);
101
+ rowsRoot.prepend(fragment);
105
102
  };
106
103
 
107
104
  const scheduleSort = (): void => {
@@ -1,41 +0,0 @@
1
- type ScrollRestoreState = {
2
- frame: number;
3
- originalOverflowAnchor: string;
4
- scrollRoot: HTMLElement;
5
- scrollTop: number;
6
- };
7
-
8
- const restoreStates = new WeakMap<HTMLElement, ScrollRestoreState>();
9
-
10
- export function mutateTablePreservingScroll(
11
- root: HTMLElement,
12
- mutation: () => void,
13
- ): void {
14
- const scrollRoot = root.closest<HTMLElement>('[data-site-viewport]');
15
- if (!scrollRoot) {
16
- mutation();
17
- return;
18
- }
19
-
20
- const previous = restoreStates.get(root);
21
- if (previous) window.cancelAnimationFrame(previous.frame);
22
- const originalOverflowAnchor =
23
- previous?.originalOverflowAnchor ?? root.style.overflowAnchor;
24
- const scrollTop = scrollRoot.scrollTop;
25
-
26
- root.style.overflowAnchor = 'none';
27
- mutation();
28
- scrollRoot.scrollTop = scrollTop;
29
-
30
- const state: ScrollRestoreState = {
31
- frame: window.requestAnimationFrame(() => {
32
- scrollRoot.scrollTop = scrollTop;
33
- root.style.overflowAnchor = originalOverflowAnchor;
34
- restoreStates.delete(root);
35
- }),
36
- originalOverflowAnchor,
37
- scrollRoot,
38
- scrollTop,
39
- };
40
- restoreStates.set(root, state);
41
- }