@classic-homes/theme-svelte 1.15.0 → 1.15.1

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.
@@ -0,0 +1,45 @@
1
+ /**
2
+ * DataPanel card sizing uses the layout viewport, not window.innerWidth.
3
+ *
4
+ * innerWidth includes a vertical scrollbar; the layout width does not. With
5
+ * a 15px scrollbar the card used to be 16px from the left edge and 1px from
6
+ * the right, because both its width and its centred offset came from the
7
+ * wider number.
8
+ */
9
+ import { describe, it, expect, vi, afterEach } from 'vitest';
10
+ import { mount, unmount, flushSync, createRawSnippet } from 'svelte';
11
+ import DataPanel from '../lib/components/DataPanel.svelte';
12
+ const children = createRawSnippet(() => ({ render: () => '<p>Legend</p>' }));
13
+ let instance = null;
14
+ afterEach(() => {
15
+ if (instance)
16
+ unmount(instance);
17
+ instance = null;
18
+ vi.restoreAllMocks();
19
+ });
20
+ describe('DataPanel card viewport width', () => {
21
+ it('insets the card equally when a scrollbar makes innerWidth wider than the layout', () => {
22
+ // 390px window with a 15px vertical scrollbar: 375px of layout
23
+ vi.spyOn(window, 'innerWidth', 'get').mockReturnValue(390);
24
+ vi.spyOn(document.documentElement, 'clientWidth', 'get').mockReturnValue(375);
25
+ const host = document.createElement('div');
26
+ document.body.appendChild(host);
27
+ instance = mount(DataPanel, {
28
+ target: host,
29
+ props: {
30
+ title: 'Legend & Information',
31
+ variant: 'card',
32
+ expanded: false,
33
+ disableClose: true,
34
+ mobileBreakpoint: 768,
35
+ cardConfig: { maxWidth: 480, horizontalMargin: 16 },
36
+ children,
37
+ },
38
+ });
39
+ flushSync();
40
+ const panel = host.querySelector('[role="dialog"]');
41
+ expect(panel.style.left).toBe('16px');
42
+ // 375 - 2 * 16, so the right margin is 16px too
43
+ expect(panel.style.width).toBe('343px');
44
+ });
45
+ });
@@ -244,8 +244,19 @@
244
244
  // Panel element ref
245
245
  let panelRef = $state<HTMLDivElement | null>(null);
246
246
 
247
+ /**
248
+ * Layout viewport width. Not layoutViewportWidth(): that includes a vertical
249
+ * scrollbar, and the card sheet's width and centred left offset are
250
+ * computed from this number, so with a scrollbar showing (a desktop
251
+ * browser at phone width, device toolbars) the card came out 16px from the
252
+ * left edge and a scrollbar's width short of the right one.
253
+ */
254
+ function layoutViewportWidth(): number {
255
+ return document.documentElement.clientWidth;
256
+ }
257
+
247
258
  // Viewport dimensions
248
- let viewportWidth = $state(typeof window !== 'undefined' ? window.innerWidth : 1024);
259
+ let viewportWidth = $state(typeof document !== 'undefined' ? layoutViewportWidth() : 1024);
249
260
  let viewportHeight = $state(typeof window !== 'undefined' ? window.innerHeight : 768);
250
261
 
251
262
  // Detect mobile
@@ -311,7 +322,7 @@
311
322
  // Initialize from persistence on mount
312
323
  onMount(() => {
313
324
  // Update viewport dimensions
314
- viewportWidth = window.innerWidth;
325
+ viewportWidth = layoutViewportWidth();
315
326
  viewportHeight = window.innerHeight;
316
327
 
317
328
  // Initialize card expanded height
@@ -319,7 +330,7 @@
319
330
 
320
331
  // Listen for resize
321
332
  const handleResize = () => {
322
- viewportWidth = window.innerWidth;
333
+ viewportWidth = layoutViewportWidth();
323
334
  viewportHeight = window.innerHeight;
324
335
  cardExpandedHeight = viewportHeight * resolvedCardConfig.expandedRatio;
325
336
  };
@@ -348,7 +359,7 @@
348
359
  ) {
349
360
  detachedPosition = getInitialDetachedPosition(
350
361
  detachedSize,
351
- window.innerWidth,
362
+ layoutViewportWidth(),
352
363
  window.innerHeight
353
364
  );
354
365
  }
@@ -465,7 +476,7 @@
465
476
  const snap = detectEdgeSnap(
466
477
  newPosition,
467
478
  detachedSize,
468
- window.innerWidth,
479
+ layoutViewportWidth(),
469
480
  window.innerHeight,
470
481
  snapThreshold
471
482
  );
@@ -476,7 +487,7 @@
476
487
  detachedPosition = constrainPosition(
477
488
  newPosition,
478
489
  detachedSize,
479
- window.innerWidth,
490
+ layoutViewportWidth(),
480
491
  window.innerHeight
481
492
  );
482
493
  }
@@ -517,7 +528,7 @@
517
528
  pinnedSize,
518
529
  detachedSize,
519
530
  edge,
520
- window.innerWidth,
531
+ layoutViewportWidth(),
521
532
  window.innerHeight
522
533
  );
523
534
 
@@ -708,7 +719,7 @@
708
719
  result.position,
709
720
  result.size,
710
721
  resolvedConstraints,
711
- window.innerWidth,
722
+ layoutViewportWidth(),
712
723
  window.innerHeight,
713
724
  resizeHandle
714
725
  );
@@ -725,7 +736,7 @@
725
736
  const newSize = resizeSizeStart.width + delta * direction;
726
737
 
727
738
  if (isHorizontalEdge(edge)) {
728
- pinnedSize = constrainPinnedWidth(newSize, resolvedConstraints, window.innerWidth);
739
+ pinnedSize = constrainPinnedWidth(newSize, resolvedConstraints, layoutViewportWidth());
729
740
  } else {
730
741
  pinnedSize = constrainPinnedHeight(newSize, resolvedConstraints, window.innerHeight);
731
742
  }
@@ -791,7 +802,7 @@
791
802
  candidatePosition,
792
803
  { width, height },
793
804
  resolvedConstraints,
794
- window.innerWidth,
805
+ layoutViewportWidth(),
795
806
  window.innerHeight,
796
807
  handle
797
808
  );
@@ -829,7 +840,7 @@
829
840
  if (handled) {
830
841
  e.preventDefault();
831
842
  pinnedSize = horizontal
832
- ? constrainPinnedWidth(newSize, resolvedConstraints, window.innerWidth)
843
+ ? constrainPinnedWidth(newSize, resolvedConstraints, layoutViewportWidth())
833
844
  : constrainPinnedHeight(newSize, resolvedConstraints, window.innerHeight);
834
845
  debouncedSave();
835
846
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classic-homes/theme-svelte",
3
- "version": "1.15.0",
3
+ "version": "1.15.1",
4
4
  "description": "Svelte components for the Classic theme system",
5
5
  "type": "module",
6
6
  "svelte": "./dist/lib/index.js",