@astronox/core 0.4.6 → 0.4.7

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.6",
3
+ "version": "0.4.7",
4
4
  "description": "Reusable Astro components, patterns, styles, and infrastructure for AstroNox sites.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -3,7 +3,7 @@ import type { HTMLAttributes } from 'astro/types';
3
3
  import type { Tone } from '../../theme/contracts';
4
4
 
5
5
  type StackElement = 'div' | 'form' | 'section' | 'nav';
6
- type StackGap = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
6
+ type StackGap = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'layout';
7
7
  type StackAttributes = HTMLAttributes<'div'> &
8
8
  HTMLAttributes<'form'> &
9
9
  HTMLAttributes<'section'> &
@@ -29,3 +29,7 @@
29
29
  .stack[data-gap='xl'] {
30
30
  --stack-gap: var(--nox-space-6);
31
31
  }
32
+
33
+ .stack[data-gap='layout'] {
34
+ --stack-gap: var(--nox-layout-gap);
35
+ }
@@ -16,9 +16,15 @@
16
16
  pointer-events: none;
17
17
  }
18
18
 
19
+ .surface-group:has(> [data-sticky-surface]) {
20
+ --surface-group-sticky-surface-block-size: var(
21
+ --nox-section-responsive-block-size
22
+ );
23
+ }
24
+
19
25
  .surface-group:has(> [data-sticky-surface])::before {
20
26
  --surface-group-sticky-occlusion-size: calc(
21
- var(--nox-layout-gap) + var(--nox-section-responsive-block-size)
27
+ var(--nox-layout-gap) + var(--surface-group-sticky-surface-block-size)
22
28
  );
23
29
 
24
30
  position: sticky;
@@ -71,9 +77,9 @@
71
77
  }
72
78
 
73
79
  @container nox-surface-group (width < 32rem) {
74
- .surface-group:has(> [data-sticky-surface])::before {
75
- --surface-group-sticky-occlusion-size: calc(
76
- var(--nox-layout-gap) + var(--nox-section-compact-block-size)
80
+ .surface-group:has(> [data-sticky-surface]) {
81
+ --surface-group-sticky-surface-block-size: var(
82
+ --nox-section-compact-block-size
77
83
  );
78
84
  }
79
85
  }
@@ -1,4 +1,6 @@
1
1
  const noop = () => {};
2
+ const stickySurfaceBlockSizeProperty =
3
+ '--surface-group-sticky-surface-block-size';
2
4
 
3
5
  const getScrollParent = (element: HTMLElement): HTMLElement | Window => {
4
6
  let parent = element.parentElement;
@@ -37,12 +39,21 @@ export const initStickySurfaceGroup = (root: HTMLElement): (() => void) => {
37
39
  stickySurface.before(sentinel);
38
40
 
39
41
  let observer: IntersectionObserver | null = null;
42
+ let surfaceResizeObserver: ResizeObserver | null = null;
40
43
  let resizeFrame = 0;
41
44
 
42
45
  const observe = () => {
43
46
  resizeFrame = 0;
44
47
  observer?.disconnect();
45
48
 
49
+ const stickySurfaceBlockSize = stickySurface.getBoundingClientRect().height;
50
+ if (stickySurfaceBlockSize > 0) {
51
+ root.style.setProperty(
52
+ stickySurfaceBlockSizeProperty,
53
+ `${stickySurfaceBlockSize}px`,
54
+ );
55
+ }
56
+
46
57
  const stickyOffset =
47
58
  Number.parseFloat(window.getComputedStyle(stickySurface).top) || 0;
48
59
  observer = new IntersectionObserver(
@@ -72,11 +83,15 @@ export const initStickySurfaceGroup = (root: HTMLElement): (() => void) => {
72
83
 
73
84
  root.setAttribute('data-sticky-initialized', 'true');
74
85
  window.addEventListener('resize', scheduleObserve, { passive: true });
86
+ surfaceResizeObserver =
87
+ 'ResizeObserver' in window ? new ResizeObserver(scheduleObserve) : null;
88
+ surfaceResizeObserver?.observe(stickySurface);
75
89
  observe();
76
90
 
77
91
  return () => {
78
92
  window.removeEventListener('resize', scheduleObserve);
79
93
  observer?.disconnect();
94
+ surfaceResizeObserver?.disconnect();
80
95
  sentinel.remove();
81
96
 
82
97
  if (resizeFrame !== 0) {
@@ -85,5 +100,6 @@ export const initStickySurfaceGroup = (root: HTMLElement): (() => void) => {
85
100
 
86
101
  root.removeAttribute('data-sticky-active');
87
102
  root.removeAttribute('data-sticky-initialized');
103
+ root.style.removeProperty(stickySurfaceBlockSizeProperty);
88
104
  };
89
105
  };
@@ -49,7 +49,9 @@
49
49
 
50
50
  .table[data-table-sticky-header]:has([data-sticky-surface])
51
51
  [data-table-header] {
52
- top: calc(var(--nox-layout-gap) + var(--nox-section-responsive-block-size));
52
+ top: calc(
53
+ var(--nox-layout-gap) + var(--surface-group-sticky-surface-block-size)
54
+ );
53
55
  }
54
56
 
55
57
  @container nox-table (width < 32rem) {
@@ -57,11 +59,6 @@
57
59
  --table-cell-padding-inline: var(--nox-space-1);
58
60
  --table-edge-padding-inline: var(--nox-space-2);
59
61
  }
60
-
61
- .table[data-table-sticky-header]:has([data-sticky-surface])
62
- [data-table-header] {
63
- top: calc(var(--nox-layout-gap) + var(--nox-section-compact-block-size));
64
- }
65
62
  }
66
63
 
67
64
  @container nox-table (width < 36rem) {
@@ -1,17 +1,17 @@
1
1
  type TableStartScrollInput = {
2
2
  currentScrollTop: number;
3
- layoutGap: number;
3
+ stickyOffset: number;
4
4
  tableTop: number;
5
5
  viewportTop: number;
6
6
  };
7
7
 
8
8
  export function resolveTableStartScrollTop({
9
9
  currentScrollTop,
10
- layoutGap,
10
+ stickyOffset,
11
11
  tableTop,
12
12
  viewportTop,
13
13
  }: TableStartScrollInput): number {
14
- const targetTop = viewportTop + layoutGap;
14
+ const targetTop = viewportTop + stickyOffset;
15
15
  if (tableTop >= targetTop) return currentScrollTop;
16
16
 
17
17
  return Math.max(0, currentScrollTop + tableTop - targetTop);
@@ -21,18 +21,22 @@ export function resolveTableScrollRoot(root: HTMLElement): HTMLElement | null {
21
21
  return root.closest<HTMLElement>('[data-site-viewport]');
22
22
  }
23
23
 
24
+ function resolveTableStickyOffset(root: HTMLElement): number {
25
+ const stickySurface = root.querySelector<HTMLElement>(
26
+ '[data-sticky-surface]',
27
+ );
28
+ if (!stickySurface) return 0;
29
+
30
+ return Number.parseFloat(window.getComputedStyle(stickySurface).top) || 0;
31
+ }
32
+
24
33
  export function revealTableStart(root: HTMLElement): void {
25
34
  const scrollRoot = resolveTableScrollRoot(root);
26
35
  if (!scrollRoot) return;
27
36
 
28
37
  const nextScrollTop = resolveTableStartScrollTop({
29
38
  currentScrollTop: scrollRoot.scrollTop,
30
- layoutGap:
31
- Number.parseFloat(
32
- window
33
- .getComputedStyle(document.documentElement)
34
- .getPropertyValue('--nox-layout-gap'),
35
- ) || 0,
39
+ stickyOffset: resolveTableStickyOffset(root),
36
40
  tableTop: root.getBoundingClientRect().top,
37
41
  viewportTop: scrollRoot.getBoundingClientRect().top,
38
42
  });