@digilogiclabs/saas-factory-ui 1.26.1 → 1.27.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/index.d.mts CHANGED
@@ -3609,6 +3609,22 @@ declare function useOptimizedMemo<T>(factory: () => T, deps: React.DependencyLis
3609
3609
 
3610
3610
  declare function useLockBody(): void;
3611
3611
 
3612
+ /**
3613
+ * Tracks a CSS media query.
3614
+ *
3615
+ * Always returns `false` on the server and on the client's first
3616
+ * render so SSR markup matches the hydrated DOM — reading
3617
+ * `window.matchMedia` during useState init caused React #418 in
3618
+ * consumers that branched rendered markup on the result (e.g. a
3619
+ * mobile-vs-desktop layout switch) because the server always
3620
+ * rendered `false` while clients matching the query rendered
3621
+ * `true`. The actual value is read in `useEffect` after commit
3622
+ * and kept in sync via a `matchMedia` change listener.
3623
+ *
3624
+ * The trade-off is one extra render on the client before the
3625
+ * correct value applies — acceptable because the correct markup
3626
+ * is an enhancement, not the initial content.
3627
+ */
3612
3628
  declare function useMediaQuery(query: string): boolean;
3613
3629
 
3614
3630
  interface IntersectionObserverOptions {
@@ -3751,10 +3767,19 @@ declare function useDarkMode(forced?: boolean): boolean;
3751
3767
  * Returns `true` when the user has requested reduced motion via
3752
3768
  * `prefers-reduced-motion: reduce`.
3753
3769
  *
3754
- * Reads the media query synchronously during state init so the
3755
- * first render already honors the preference no flash of full
3756
- * motion on first paint. Re-subscribes to changes via `matchMedia`
3757
- * listener. SSR-safe (returns `false` when `window` is undefined).
3770
+ * Always returns `false` on the server and on the client's first
3771
+ * render so that SSR markup and the hydrated DOM match reading
3772
+ * `window.matchMedia` during useState init caused React #418 in
3773
+ * consumers that rendered the value into inline style attributes
3774
+ * (e.g. DynamicHeroBanner's `transition`) because the server
3775
+ * rendered `false` while clients with the preference rendered
3776
+ * `true`. The actual preference is read in `useEffect` after the
3777
+ * initial commit and via a `matchMedia` change listener.
3778
+ *
3779
+ * The trade-off is one extra render/paint before the preference
3780
+ * takes effect — acceptable because reduced-motion is an
3781
+ * accessibility preference about the *next* animation, not a
3782
+ * hard visual flash.
3758
3783
  */
3759
3784
  declare function usePrefersReducedMotion(): boolean;
3760
3785
 
package/dist/index.d.ts CHANGED
@@ -3609,6 +3609,22 @@ declare function useOptimizedMemo<T>(factory: () => T, deps: React.DependencyLis
3609
3609
 
3610
3610
  declare function useLockBody(): void;
3611
3611
 
3612
+ /**
3613
+ * Tracks a CSS media query.
3614
+ *
3615
+ * Always returns `false` on the server and on the client's first
3616
+ * render so SSR markup matches the hydrated DOM — reading
3617
+ * `window.matchMedia` during useState init caused React #418 in
3618
+ * consumers that branched rendered markup on the result (e.g. a
3619
+ * mobile-vs-desktop layout switch) because the server always
3620
+ * rendered `false` while clients matching the query rendered
3621
+ * `true`. The actual value is read in `useEffect` after commit
3622
+ * and kept in sync via a `matchMedia` change listener.
3623
+ *
3624
+ * The trade-off is one extra render on the client before the
3625
+ * correct value applies — acceptable because the correct markup
3626
+ * is an enhancement, not the initial content.
3627
+ */
3612
3628
  declare function useMediaQuery(query: string): boolean;
3613
3629
 
3614
3630
  interface IntersectionObserverOptions {
@@ -3751,10 +3767,19 @@ declare function useDarkMode(forced?: boolean): boolean;
3751
3767
  * Returns `true` when the user has requested reduced motion via
3752
3768
  * `prefers-reduced-motion: reduce`.
3753
3769
  *
3754
- * Reads the media query synchronously during state init so the
3755
- * first render already honors the preference no flash of full
3756
- * motion on first paint. Re-subscribes to changes via `matchMedia`
3757
- * listener. SSR-safe (returns `false` when `window` is undefined).
3770
+ * Always returns `false` on the server and on the client's first
3771
+ * render so that SSR markup and the hydrated DOM match reading
3772
+ * `window.matchMedia` during useState init caused React #418 in
3773
+ * consumers that rendered the value into inline style attributes
3774
+ * (e.g. DynamicHeroBanner's `transition`) because the server
3775
+ * rendered `false` while clients with the preference rendered
3776
+ * `true`. The actual preference is read in `useEffect` after the
3777
+ * initial commit and via a `matchMedia` change listener.
3778
+ *
3779
+ * The trade-off is one extra render/paint before the preference
3780
+ * takes effect — acceptable because reduced-motion is an
3781
+ * accessibility preference about the *next* animation, not a
3782
+ * hard visual flash.
3758
3783
  */
3759
3784
  declare function usePrefersReducedMotion(): boolean;
3760
3785
 
package/dist/index.js CHANGED
@@ -25018,22 +25018,15 @@ function useLockBody() {
25018
25018
  // src/hooks/web/use-media-query.ts
25019
25019
  var import_react50 = require("react");
25020
25020
  function useMediaQuery(query) {
25021
- const [matches, setMatches] = (0, import_react50.useState)(() => {
25022
- if (typeof window !== "undefined") {
25023
- return window.matchMedia(query).matches;
25024
- }
25025
- return false;
25026
- });
25021
+ const [matches, setMatches] = (0, import_react50.useState)(false);
25027
25022
  (0, import_react50.useEffect)(() => {
25028
- if (typeof window === "undefined") return;
25023
+ if (typeof window === "undefined" || !window.matchMedia) return;
25029
25024
  const media = window.matchMedia(query);
25030
- if (media.matches !== matches) {
25031
- setMatches(media.matches);
25032
- }
25025
+ setMatches(media.matches);
25033
25026
  const listener = () => setMatches(media.matches);
25034
25027
  media.addEventListener("change", listener);
25035
25028
  return () => media.removeEventListener("change", listener);
25036
- }, [matches, query]);
25029
+ }, [query]);
25037
25030
  return matches;
25038
25031
  }
25039
25032
 
@@ -25493,13 +25486,11 @@ function useDarkMode(forced) {
25493
25486
  // src/hooks/web/use-prefers-reduced-motion.ts
25494
25487
  var import_react56 = require("react");
25495
25488
  function usePrefersReducedMotion() {
25496
- const [reduced, setReduced] = (0, import_react56.useState)(() => {
25497
- if (typeof window === "undefined" || !window.matchMedia) return false;
25498
- return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
25499
- });
25489
+ const [reduced, setReduced] = (0, import_react56.useState)(false);
25500
25490
  (0, import_react56.useEffect)(() => {
25501
25491
  if (typeof window === "undefined" || !window.matchMedia) return;
25502
25492
  const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
25493
+ setReduced(mq.matches);
25503
25494
  const read = () => setReduced(mq.matches);
25504
25495
  mq.addEventListener("change", read);
25505
25496
  return () => mq.removeEventListener("change", read);