@syntrologie/adapt-product 2.49.1 → 2.50.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/dist/cdn.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  onActivate,
3
3
  runtime
4
- } from "./chunk-LFYTHTQS.js";
4
+ } from "./chunk-P64UMUWD.js";
5
5
  import "./chunk-D2W6UYLT.js";
6
6
 
7
7
  // src/cdn.ts
@@ -342,6 +342,110 @@ var NotifyZ = z.object({
342
342
  icon: z.string().optional().describe("Notification icon (emoji or URL)")
343
343
  }).describe("Optional toast notification shown when this action triggers.").nullable().optional();
344
344
 
345
+ // ../../sdk-contracts/dist/viewport.js
346
+ var VIEWPORT_CLASS_ATTR = "data-viewport";
347
+ var DESKTOP_MIN_WIDTH_PX = 720;
348
+ function isCoarsePointer() {
349
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function")
350
+ return true;
351
+ return window.matchMedia("(pointer: coarse)").matches;
352
+ }
353
+ function classifyPointer() {
354
+ return isCoarsePointer() ? "coarse" : "fine";
355
+ }
356
+ function hasAnyFinePointer() {
357
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function")
358
+ return true;
359
+ return window.matchMedia("(any-pointer: fine)").matches;
360
+ }
361
+ function observePointer(cb) {
362
+ const read = () => ({ primary: classifyPointer(), anyFine: hasAnyFinePointer() });
363
+ let current = read();
364
+ cb(current);
365
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function")
366
+ return () => {
367
+ };
368
+ const coarse = window.matchMedia("(pointer: coarse)");
369
+ const anyFine = window.matchMedia("(any-pointer: fine)");
370
+ const onChange = () => {
371
+ const next = read();
372
+ if (next.primary !== current.primary || next.anyFine !== current.anyFine) {
373
+ current = next;
374
+ cb(next);
375
+ }
376
+ };
377
+ const sub = (mq) => {
378
+ if (mq.addEventListener)
379
+ mq.addEventListener("change", onChange);
380
+ else
381
+ mq.addListener?.(onChange);
382
+ };
383
+ const unsub = (mq) => {
384
+ if (mq.removeEventListener)
385
+ mq.removeEventListener("change", onChange);
386
+ else
387
+ mq.removeListener?.(onChange);
388
+ };
389
+ sub(coarse);
390
+ sub(anyFine);
391
+ return () => {
392
+ unsub(coarse);
393
+ unsub(anyFine);
394
+ };
395
+ }
396
+ var POINTER_CLASS_ATTR = "data-pointer";
397
+ function classifyViewport() {
398
+ if (typeof window === "undefined")
399
+ return "mobile";
400
+ return window.innerWidth >= DESKTOP_MIN_WIDTH_PX ? "desktop" : "mobile";
401
+ }
402
+ function observeViewportClass(cb) {
403
+ let current = classifyViewport();
404
+ cb(current);
405
+ if (typeof window === "undefined")
406
+ return () => {
407
+ };
408
+ const onResize = () => {
409
+ const next = classifyViewport();
410
+ if (next !== current) {
411
+ current = next;
412
+ cb(next);
413
+ }
414
+ };
415
+ window.addEventListener("resize", onResize, { passive: true });
416
+ return () => window.removeEventListener("resize", onResize);
417
+ }
418
+ var ViewportClassController = class {
419
+ constructor(host) {
420
+ this.value = classifyViewport();
421
+ this.pointer = classifyPointer();
422
+ this.anyFinePointer = hasAnyFinePointer();
423
+ this._unsubscribes = [];
424
+ this._host = host;
425
+ host.addController(this);
426
+ }
427
+ hostConnected() {
428
+ this._unsubscribes = [
429
+ observeViewportClass((c2) => {
430
+ this.value = c2;
431
+ this._host.setAttribute(VIEWPORT_CLASS_ATTR, c2);
432
+ this._host.requestUpdate();
433
+ }),
434
+ observePointer(({ primary, anyFine }) => {
435
+ this.pointer = primary;
436
+ this.anyFinePointer = anyFine;
437
+ this._host.setAttribute(POINTER_CLASS_ATTR, primary);
438
+ this._host.requestUpdate();
439
+ })
440
+ ];
441
+ }
442
+ hostDisconnected() {
443
+ for (const off of this._unsubscribes)
444
+ off();
445
+ this._unsubscribes = [];
446
+ }
447
+ };
448
+
345
449
  // src/presets-store.ts
346
450
  function presetsWindow() {
347
451
  if (typeof window === "undefined") return void 0;
@@ -1903,16 +2007,22 @@ syntro-pdp-other-products-carousel {
1903
2007
  box-sizing: border-box;
1904
2008
  }
1905
2009
 
1906
- @media (max-width: 719px) {
1907
- .opc-item {
1908
- flex: 0 0 80%;
1909
- }
2010
+ /* viewport-scoped (was a width media query): classification is central
2011
+ (sdk-contracts classifyViewport()); the host tag carries data-viewport. */
2012
+ syntro-pdp-other-products-carousel[data-viewport="mobile"] .opc-item {
2013
+ flex: 0 0 80%;
1910
2014
  }
1911
2015
  `;
1912
2016
  var PdpOtherProductsCarouselLit = class extends LitElement4 {
1913
2017
  constructor() {
1914
2018
  super(...arguments);
1915
2019
  this.data = null;
2020
+ /** Stamps data-viewport on this tag (central classification,
2021
+ * sdk-contracts) — the viewport-scoped CSS keys off it. */
2022
+ // biome-ignore lint/correctness/noUnusedPrivateClassMembers: the
2023
+ // constructor registers the controller (stamps data-viewport); the
2024
+ // field exists to own its lifetime, not to be read.
2025
+ this._viewport = new ViewportClassController(this);
1916
2026
  }
1917
2027
  createRenderRoot() {
1918
2028
  return this;
@@ -1969,16 +2079,22 @@ syntro-pdp-other-products-grid {
1969
2079
  gap: 0.75rem;
1970
2080
  }
1971
2081
 
1972
- @media (max-width: 719px) {
1973
- .grid {
1974
- grid-template-columns: 1fr;
1975
- }
2082
+ /* viewport-scoped (was a width media query): classification is central
2083
+ (sdk-contracts classifyViewport()); the host tag carries data-viewport. */
2084
+ syntro-pdp-other-products-grid[data-viewport="mobile"] .grid {
2085
+ grid-template-columns: 1fr;
1976
2086
  }
1977
2087
  `;
1978
2088
  var PdpOtherProductsGridLit = class extends LitElement5 {
1979
2089
  constructor() {
1980
2090
  super(...arguments);
1981
2091
  this.data = null;
2092
+ /** Stamps data-viewport on this tag (central classification,
2093
+ * sdk-contracts) — the viewport-scoped CSS keys off it. */
2094
+ // biome-ignore lint/correctness/noUnusedPrivateClassMembers: the
2095
+ // constructor registers the controller (stamps data-viewport); the
2096
+ // field exists to own its lifetime, not to be read.
2097
+ this._viewport = new ViewportClassController(this);
1982
2098
  }
1983
2099
  createRenderRoot() {
1984
2100
  return this;
@@ -2443,8 +2559,10 @@ var SECTION_LAYOUT_CSS = `
2443
2559
  the full-bleed band (a grid can't be both full-width AND content-centered)
2444
2560
  for the side-by-side reading rhythm; the section reads as a deliberate
2445
2561
  magazine block on the base background. Mobile keeps the stacked layout. */
2446
- @media (min-width: 720px) {
2447
- [data-syntro-pdp-section][data-slot='pdp-slot-trending-news'] {
2562
+ /* viewport-scoped (was a width media query): classification is central
2563
+ (sdk-contracts classifyViewport()); the syntro-pdp tag carries
2564
+ data-viewport, stamped by ViewportClassController. */
2565
+ syntro-pdp[data-viewport="desktop"] [data-syntro-pdp-section][data-slot='pdp-slot-trending-news'] {
2448
2566
  background: transparent;
2449
2567
  display: grid;
2450
2568
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.6fr);
@@ -2456,26 +2574,26 @@ var SECTION_LAYOUT_CSS = `
2456
2574
  }
2457
2575
  /* Title column: header left-aligned (not the full-band centered eyebrow),
2458
2576
  and gently sticky so it holds while the stories scroll past. */
2459
- [data-syntro-pdp-section][data-slot='pdp-slot-trending-news'] > syntro-pdp-section-header {
2577
+ syntro-pdp[data-viewport="desktop"] [data-syntro-pdp-section][data-slot='pdp-slot-trending-news'] > syntro-pdp-section-header {
2460
2578
  position: sticky;
2461
2579
  top: clamp(24px, 8vh, 72px);
2462
2580
  }
2463
- [data-syntro-pdp-section][data-slot='pdp-slot-trending-news'] .syntro-pdp-section-eyebrow {
2581
+ syntro-pdp[data-viewport="desktop"] [data-syntro-pdp-section][data-slot='pdp-slot-trending-news'] .syntro-pdp-section-eyebrow {
2464
2582
  justify-content: flex-start;
2465
2583
  }
2466
- [data-syntro-pdp-section][data-slot='pdp-slot-trending-news'] .syntro-pdp-section-headline {
2584
+ syntro-pdp[data-viewport="desktop"] [data-syntro-pdp-section][data-slot='pdp-slot-trending-news'] .syntro-pdp-section-headline {
2467
2585
  max-width: none;
2468
2586
  margin-inline: 0;
2469
2587
  padding-inline: 0;
2470
2588
  }
2471
2589
  /* Stories column: the body fills the wider right column (drop the centered
2472
2590
  inner constraint + the header-gap top margin \u2014 the grid gap spaces it). */
2473
- [data-syntro-pdp-section][data-slot='pdp-slot-trending-news'] > [data-syntro-pdp-section-inner] {
2591
+ syntro-pdp[data-viewport="desktop"] [data-syntro-pdp-section][data-slot='pdp-slot-trending-news'] > [data-syntro-pdp-section-inner] {
2474
2592
  max-width: none;
2475
2593
  margin: 0;
2476
2594
  padding: 0;
2477
2595
  }
2478
- }
2596
+
2479
2597
  `;
2480
2598
  var CHAT_EXCERPT_KEY = "syntro.chat.lastExcerpt";
2481
2599
  var CHAT_EXCERPT_MAX = 7500;
@@ -2662,6 +2780,12 @@ var _SyntroPdpLit = class _SyntroPdpLit extends LitElement6 {
2662
2780
  const open = e2.target.open;
2663
2781
  this._dispatchDecision({ type: "dossier-toggled", open });
2664
2782
  };
2783
+ /** Stamps data-viewport on this tag (central classification,
2784
+ * sdk-contracts) — the viewport-scoped CSS keys off it. */
2785
+ // biome-ignore lint/correctness/noUnusedPrivateClassMembers: the
2786
+ // constructor registers the controller (stamps data-viewport); the
2787
+ // field exists to own its lifetime, not to be read.
2788
+ this._viewport = new ViewportClassController(this);
2665
2789
  }
2666
2790
  /**
2667
2791
  * Widget props (the `adaptive-product:pdp` mountable sets `el.props` before
@@ -6534,7 +6658,12 @@ function renderProductCardInner(product, density, resolved, visibleFacts, ctas,
6534
6658
  justifyContent: "space-between",
6535
6659
  gap: "var(--sc-card-cta-gap, 0.5rem)",
6536
6660
  marginTop: "0",
6537
- minWidth: "0"
6661
+ minWidth: "0",
6662
+ // Lift the CTA pair off the card's bottom edge where a canvas overlays
6663
+ // chrome there (velvet's deck pager circles half-lap that edge — the
6664
+ // "Product Page" link sat right under them on crushed cards). The
6665
+ // canvas sets the token; default 0 keeps every other surface as-is.
6666
+ paddingBottom: "var(--sc-card-cta-padding-bottom, 0)"
6538
6667
  };
6539
6668
  const primaryCtaStyles = {
6540
6669
  display: "inline-flex",
@@ -11977,4 +12106,4 @@ export {
11977
12106
  * SPDX-License-Identifier: BSD-3-Clause
11978
12107
  *)
11979
12108
  */
11980
- //# sourceMappingURL=chunk-LFYTHTQS.js.map
12109
+ //# sourceMappingURL=chunk-P64UMUWD.js.map