@tamagui/core 1.0.1-beta.185 → 1.0.1-beta.186
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.
|
@@ -35,6 +35,7 @@ var import_react = require("react");
|
|
|
35
35
|
var import_platform = require("../constants/platform");
|
|
36
36
|
var import_matchMedia = require("../helpers/matchMedia");
|
|
37
37
|
var import_useSafeRef = require("./useSafeRef");
|
|
38
|
+
var import__ = require("..");
|
|
38
39
|
const mediaState = process.env.NODE_ENV === "development" ? new Proxy(
|
|
39
40
|
{},
|
|
40
41
|
{
|
|
@@ -63,6 +64,15 @@ const mediaQueryConfig = {};
|
|
|
63
64
|
const getMedia = () => {
|
|
64
65
|
return mediaState;
|
|
65
66
|
};
|
|
67
|
+
let currentMediaState;
|
|
68
|
+
let initialMediaState;
|
|
69
|
+
let hasFinishedInitialRender = false;
|
|
70
|
+
const getCurrentMediaState = () => {
|
|
71
|
+
if ((0, import__.getConfig)().disableSSR || hasFinishedInitialRender) {
|
|
72
|
+
return currentMediaState || {};
|
|
73
|
+
}
|
|
74
|
+
return initialMediaState || {};
|
|
75
|
+
};
|
|
66
76
|
const dispose = /* @__PURE__ */ new Set();
|
|
67
77
|
const configureMedia = (config) => {
|
|
68
78
|
const { media, mediaQueryDefaultActive } = config;
|
|
@@ -73,12 +83,11 @@ const configureMedia = (config) => {
|
|
|
73
83
|
}
|
|
74
84
|
Object.assign(mediaQueryConfig, media);
|
|
75
85
|
currentMediaState = { ...mediaState };
|
|
86
|
+
initialMediaState = currentMediaState;
|
|
76
87
|
if (config.disableSSR) {
|
|
77
88
|
setupMediaListeners();
|
|
78
89
|
}
|
|
79
90
|
};
|
|
80
|
-
let currentMediaState;
|
|
81
|
-
const getCurrentMediaState = () => currentMediaState;
|
|
82
91
|
function unlisten() {
|
|
83
92
|
dispose.forEach((cb) => cb());
|
|
84
93
|
dispose.clear();
|
|
@@ -117,17 +126,21 @@ function setupMediaListeners() {
|
|
|
117
126
|
}
|
|
118
127
|
});
|
|
119
128
|
}
|
|
129
|
+
const onIdle = typeof requestIdleCallback === "undefined" ? (cb) => setTimeout(cb, 100) : requestIdleCallback;
|
|
120
130
|
function useMediaQueryListeners(config) {
|
|
121
131
|
if (config.disableSSR) {
|
|
122
132
|
return;
|
|
123
133
|
}
|
|
124
134
|
(0, import_react.useEffect)(() => {
|
|
125
135
|
setupMediaListeners();
|
|
136
|
+
onIdle(() => {
|
|
137
|
+
hasFinishedInitialRender = true;
|
|
138
|
+
});
|
|
126
139
|
return unlisten;
|
|
127
140
|
}, []);
|
|
128
141
|
}
|
|
129
142
|
function useMedia() {
|
|
130
|
-
const [state, setState] = (0, import_react.useState)(
|
|
143
|
+
const [state, setState] = (0, import_react.useState)(getCurrentMediaState());
|
|
131
144
|
const keys = (0, import_useSafeRef.useSafeRef)({});
|
|
132
145
|
function updateState() {
|
|
133
146
|
setState((prev) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/hooks/useMedia.tsx"],
|
|
4
|
-
"sourcesContent": ["import { startTransition, useEffect, useMemo, useState } from 'react'\n\nimport { useIsomorphicLayoutEffect } from '../constants/platform'\nimport { matchMedia } from '../helpers/matchMedia'\nimport {\n MediaQueries,\n MediaQueryKey,\n MediaQueryObject,\n MediaQueryState,\n TamaguiInternalConfig,\n} from '../types'\nimport { useSafeRef } from './useSafeRef'\n\nexport const mediaState: MediaQueryState =\n // development time safeguard\n process.env.NODE_ENV === 'development'\n ? new Proxy(\n {},\n {\n get(target, key) {\n if (typeof key === 'string' && key[0] === '$') {\n throw new Error(`Access of mediaState should never include $`)\n }\n return Reflect.get(target, key)\n },\n }\n )\n : ({} as any)\n\ntype MediaListener = (next: boolean) => void\n\nconst mediaQueryListeners: { [key: string]: Set<MediaListener> } = {}\n\nexport function addMediaQueryListener(key: MediaQueryKey, cb: MediaListener) {\n if (process.env.NODE_ENV === 'development' && key[0] === '$') {\n // eslint-disable-next-line no-console\n console.warn(`Warning, listening to media queries shouldn't use the \"$\" prefix`)\n }\n mediaQueryListeners[key] = mediaQueryListeners[key] || new Set()\n mediaQueryListeners[key].add(cb)\n return () => removeMediaQueryListener(key, cb)\n}\n\nexport function removeMediaQueryListener(key: MediaQueryKey, cb: MediaListener) {\n mediaQueryListeners[key]?.delete(cb)\n}\n\nexport const mediaQueryConfig: MediaQueries = {}\n\nexport const getMedia = () => {\n return mediaState\n}\n\nconst dispose = new Set<Function>()\n\nexport const configureMedia = (config: TamaguiInternalConfig) => {\n const { media, mediaQueryDefaultActive } = config\n if (!media) return\n for (const key in media) {\n mediaState[key] = mediaQueryDefaultActive?.[key] || false\n }\n Object.assign(mediaQueryConfig, media)\n currentMediaState = { ...mediaState }\n if (config.disableSSR) {\n setupMediaListeners()\n }\n}\n\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA8D;AAE9D,sBAA0C;AAC1C,wBAA2B;AAQ3B,wBAA2B;
|
|
4
|
+
"sourcesContent": ["import { startTransition, useEffect, useMemo, useState } from 'react'\n\nimport { useIsomorphicLayoutEffect } from '../constants/platform'\nimport { matchMedia } from '../helpers/matchMedia'\nimport {\n MediaQueries,\n MediaQueryKey,\n MediaQueryObject,\n MediaQueryState,\n TamaguiInternalConfig,\n} from '../types'\nimport { useSafeRef } from './useSafeRef'\nimport { getConfig } from '..'\n\nexport const mediaState: MediaQueryState =\n // development time safeguard\n process.env.NODE_ENV === 'development'\n ? new Proxy(\n {},\n {\n get(target, key) {\n if (typeof key === 'string' && key[0] === '$') {\n throw new Error(`Access of mediaState should never include $`)\n }\n return Reflect.get(target, key)\n },\n }\n )\n : ({} as any)\n\ntype MediaListener = (next: boolean) => void\n\nconst mediaQueryListeners: { [key: string]: Set<MediaListener> } = {}\n\nexport function addMediaQueryListener(key: MediaQueryKey, cb: MediaListener) {\n if (process.env.NODE_ENV === 'development' && key[0] === '$') {\n // eslint-disable-next-line no-console\n console.warn(`Warning, listening to media queries shouldn't use the \"$\" prefix`)\n }\n mediaQueryListeners[key] = mediaQueryListeners[key] || new Set()\n mediaQueryListeners[key].add(cb)\n return () => removeMediaQueryListener(key, cb)\n}\n\nexport function removeMediaQueryListener(key: MediaQueryKey, cb: MediaListener) {\n mediaQueryListeners[key]?.delete(cb)\n}\n\nexport const mediaQueryConfig: MediaQueries = {}\n\nexport const getMedia = () => {\n return mediaState\n}\n\n// for SSR capture it at time of startup\nlet currentMediaState: MediaQueryState | null\nlet initialMediaState: MediaQueryState | null\n// fairly concurrent mode sketchy but such an edge case ok for now\nlet hasFinishedInitialRender = false\nexport const getCurrentMediaState = () => {\n if (getConfig().disableSSR || hasFinishedInitialRender) {\n return currentMediaState || {}\n }\n return initialMediaState || {}\n}\n\nconst dispose = new Set<Function>()\n\nexport const configureMedia = (config: TamaguiInternalConfig) => {\n const { media, mediaQueryDefaultActive } = config\n if (!media) return\n for (const key in media) {\n mediaState[key] = mediaQueryDefaultActive?.[key] || false\n }\n Object.assign(mediaQueryConfig, media)\n currentMediaState = { ...mediaState }\n initialMediaState = currentMediaState\n if (config.disableSSR) {\n setupMediaListeners()\n }\n}\n\nfunction unlisten() {\n dispose.forEach((cb) => cb())\n dispose.clear()\n}\n\n/**\n * Note: This should *not* set the state on the first render!\n * Because to avoid hydration issues SSR must match the server\n * *and then* re-render with the actual media query state.\n */\nlet configuredKey = ''\nfunction setupMediaListeners() {\n // avoid setting up more than once per config\n const nextKey = JSON.stringify(mediaQueryConfig)\n if (nextKey === configuredKey) {\n return\n }\n configuredKey = nextKey\n\n // hmr, undo existing before re-binding\n unlisten()\n\n // theoretically this should make media reactions smoother but potentially delayed?\n // but i believe consistent, so that's a nicer default (we'll see)\n startTransition(() => {\n for (const key in mediaQueryConfig) {\n const str = mediaObjectToString(mediaQueryConfig[key])\n const getMatch = () => matchMedia(str)\n const match = getMatch()\n if (!match) {\n throw new Error('\u26A0\uFE0F No match')\n }\n // react native needs these deprecated apis for now\n match.addListener(update)\n dispose.add(() => match.removeListener(update))\n\n update()\n\n function update() {\n const next = !!getMatch().matches\n if (next === mediaState[key]) return\n mediaState[key] = next\n currentMediaState = { ...mediaState }\n const listeners = mediaQueryListeners[key]\n if (listeners?.size) {\n listeners.forEach((cb) => cb(next))\n }\n }\n }\n })\n}\n\nconst onIdle =\n typeof requestIdleCallback === 'undefined' ? (cb) => setTimeout(cb, 100) : requestIdleCallback\n\nexport function useMediaQueryListeners(config: TamaguiInternalConfig) {\n if (config.disableSSR) {\n return\n }\n\n useEffect(() => {\n setupMediaListeners()\n\n onIdle(() => {\n hasFinishedInitialRender = true\n })\n\n return unlisten\n }, [])\n}\n\nexport function useMedia(): {\n [key in MediaQueryKey]: boolean\n} {\n const [state, setState] = useState(getCurrentMediaState())\n const keys = useSafeRef({} as Record<string, boolean>)\n\n function updateState() {\n setState((prev) => {\n for (const key in keys.current) {\n if (prev[key] !== mediaState[key]) {\n return { ...mediaState }\n }\n }\n return prev\n })\n }\n\n useIsomorphicLayoutEffect(() => {\n const disposes: Function[] = Object.keys(keys.current).map((key) =>\n addMediaQueryListener(key, updateState)\n )\n updateState()\n return () => {\n disposes.forEach((cb) => cb())\n }\n })\n\n return useMemo(\n () =>\n new Proxy(state, {\n get(_, key: string) {\n if (process.env.NODE_ENV === 'development') {\n if (!currentMediaState) {\n throw new Error(\n `To use useMedia() you must pass in media configuration to createTamagui, none was found.`\n )\n }\n }\n if (!keys.current[key]) {\n keys.current[key] = true\n }\n return Reflect.get(state, key)\n },\n }),\n [state, keys]\n )\n}\n\n/**\n * Useful for more complex components that need access to the currently active props,\n * accounting for the currently active media queries.\n *\n * Use sparingly, is will loop props and trigger re-render on all media queries.\n *\n * */\nexport function useMediaPropsActive<A extends Object>(\n props: A\n): {\n // remove all media\n [Key in keyof A extends `$${string}` ? never : keyof A]?: A[Key]\n} {\n const media = useMedia()\n\n return useMemo(() => {\n const evaluated = {} as A\n const lastSetImportanceForKey = {}\n const propNames = Object.keys(props)\n const mediaKeysOrdered = Object.keys(getMedia())\n\n function update(k: string, v: any, importance = 0) {\n if (lastSetImportanceForKey[k] > importance) {\n return\n }\n lastSetImportanceForKey[k] = importance\n evaluated[k] = v\n }\n\n for (let i = propNames.length - 1; i >= 0; i--) {\n const key = propNames[i]\n const val = props[key]\n if (key[0] === '$') {\n const shortKey = key.slice(1)\n if (!media[shortKey]) {\n continue\n }\n if (val && typeof val === 'object') {\n const subPropNames = Object.keys(val)\n const mediaImportance = mediaKeysOrdered.indexOf(shortKey)\n for (let j = subPropNames.length; j--; j >= 0) {\n const skey = subPropNames[j]\n update(skey, val[skey], mediaImportance)\n }\n }\n } else {\n update(key, val)\n }\n }\n\n return evaluated\n }, [media, props])\n}\n\nfunction camelToHyphen(str: string) {\n return str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).toLowerCase()\n}\n\nexport function mediaObjectToString(query: string | MediaQueryObject) {\n if (typeof query === 'string') {\n return query\n }\n return Object.entries(query)\n .map(([feature, value]) => {\n feature = camelToHyphen(feature)\n if (typeof value === 'string') {\n return `(${feature}: ${value})`\n }\n if (typeof value === 'number' && /[height|width]$/.test(feature)) {\n value = `${value}px`\n }\n return `(${feature}: ${value})`\n })\n .join(' and ')\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["update"]
|
|
7
7
|
}
|
|
@@ -2,6 +2,7 @@ import { startTransition, useEffect, useMemo, useState } from "react";
|
|
|
2
2
|
import { useIsomorphicLayoutEffect } from "../constants/platform";
|
|
3
3
|
import { matchMedia } from "../helpers/matchMedia";
|
|
4
4
|
import { useSafeRef } from "./useSafeRef";
|
|
5
|
+
import { getConfig } from "..";
|
|
5
6
|
const mediaState = process.env.NODE_ENV === "development" ? new Proxy(
|
|
6
7
|
{},
|
|
7
8
|
{
|
|
@@ -30,6 +31,15 @@ const mediaQueryConfig = {};
|
|
|
30
31
|
const getMedia = () => {
|
|
31
32
|
return mediaState;
|
|
32
33
|
};
|
|
34
|
+
let currentMediaState;
|
|
35
|
+
let initialMediaState;
|
|
36
|
+
let hasFinishedInitialRender = false;
|
|
37
|
+
const getCurrentMediaState = () => {
|
|
38
|
+
if (getConfig().disableSSR || hasFinishedInitialRender) {
|
|
39
|
+
return currentMediaState || {};
|
|
40
|
+
}
|
|
41
|
+
return initialMediaState || {};
|
|
42
|
+
};
|
|
33
43
|
const dispose = /* @__PURE__ */ new Set();
|
|
34
44
|
const configureMedia = (config) => {
|
|
35
45
|
const { media, mediaQueryDefaultActive } = config;
|
|
@@ -40,12 +50,11 @@ const configureMedia = (config) => {
|
|
|
40
50
|
}
|
|
41
51
|
Object.assign(mediaQueryConfig, media);
|
|
42
52
|
currentMediaState = { ...mediaState };
|
|
53
|
+
initialMediaState = currentMediaState;
|
|
43
54
|
if (config.disableSSR) {
|
|
44
55
|
setupMediaListeners();
|
|
45
56
|
}
|
|
46
57
|
};
|
|
47
|
-
let currentMediaState;
|
|
48
|
-
const getCurrentMediaState = () => currentMediaState;
|
|
49
58
|
function unlisten() {
|
|
50
59
|
dispose.forEach((cb) => cb());
|
|
51
60
|
dispose.clear();
|
|
@@ -84,17 +93,21 @@ function setupMediaListeners() {
|
|
|
84
93
|
}
|
|
85
94
|
});
|
|
86
95
|
}
|
|
96
|
+
const onIdle = typeof requestIdleCallback === "undefined" ? (cb) => setTimeout(cb, 100) : requestIdleCallback;
|
|
87
97
|
function useMediaQueryListeners(config) {
|
|
88
98
|
if (config.disableSSR) {
|
|
89
99
|
return;
|
|
90
100
|
}
|
|
91
101
|
useEffect(() => {
|
|
92
102
|
setupMediaListeners();
|
|
103
|
+
onIdle(() => {
|
|
104
|
+
hasFinishedInitialRender = true;
|
|
105
|
+
});
|
|
93
106
|
return unlisten;
|
|
94
107
|
}, []);
|
|
95
108
|
}
|
|
96
109
|
function useMedia() {
|
|
97
|
-
const [state, setState] = useState(
|
|
110
|
+
const [state, setState] = useState(getCurrentMediaState());
|
|
98
111
|
const keys = useSafeRef({});
|
|
99
112
|
function updateState() {
|
|
100
113
|
setState((prev) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/hooks/useMedia.tsx"],
|
|
4
|
-
"sourcesContent": ["import { startTransition, useEffect, useMemo, useState } from 'react'\n\nimport { useIsomorphicLayoutEffect } from '../constants/platform'\nimport { matchMedia } from '../helpers/matchMedia'\nimport {\n MediaQueries,\n MediaQueryKey,\n MediaQueryObject,\n MediaQueryState,\n TamaguiInternalConfig,\n} from '../types'\nimport { useSafeRef } from './useSafeRef'\n\nexport const mediaState: MediaQueryState =\n // development time safeguard\n process.env.NODE_ENV === 'development'\n ? new Proxy(\n {},\n {\n get(target, key) {\n if (typeof key === 'string' && key[0] === '$') {\n throw new Error(`Access of mediaState should never include $`)\n }\n return Reflect.get(target, key)\n },\n }\n )\n : ({} as any)\n\ntype MediaListener = (next: boolean) => void\n\nconst mediaQueryListeners: { [key: string]: Set<MediaListener> } = {}\n\nexport function addMediaQueryListener(key: MediaQueryKey, cb: MediaListener) {\n if (process.env.NODE_ENV === 'development' && key[0] === '$') {\n // eslint-disable-next-line no-console\n console.warn(`Warning, listening to media queries shouldn't use the \"$\" prefix`)\n }\n mediaQueryListeners[key] = mediaQueryListeners[key] || new Set()\n mediaQueryListeners[key].add(cb)\n return () => removeMediaQueryListener(key, cb)\n}\n\nexport function removeMediaQueryListener(key: MediaQueryKey, cb: MediaListener) {\n mediaQueryListeners[key]?.delete(cb)\n}\n\nexport const mediaQueryConfig: MediaQueries = {}\n\nexport const getMedia = () => {\n return mediaState\n}\n\nconst dispose = new Set<Function>()\n\nexport const configureMedia = (config: TamaguiInternalConfig) => {\n const { media, mediaQueryDefaultActive } = config\n if (!media) return\n for (const key in media) {\n mediaState[key] = mediaQueryDefaultActive?.[key] || false\n }\n Object.assign(mediaQueryConfig, media)\n currentMediaState = { ...mediaState }\n if (config.disableSSR) {\n setupMediaListeners()\n }\n}\n\
|
|
5
|
-
"mappings": "AAAA,SAAS,iBAAiB,WAAW,SAAS,gBAAgB;AAE9D,SAAS,iCAAiC;AAC1C,SAAS,kBAAkB;AAQ3B,SAAS,kBAAkB;
|
|
4
|
+
"sourcesContent": ["import { startTransition, useEffect, useMemo, useState } from 'react'\n\nimport { useIsomorphicLayoutEffect } from '../constants/platform'\nimport { matchMedia } from '../helpers/matchMedia'\nimport {\n MediaQueries,\n MediaQueryKey,\n MediaQueryObject,\n MediaQueryState,\n TamaguiInternalConfig,\n} from '../types'\nimport { useSafeRef } from './useSafeRef'\nimport { getConfig } from '..'\n\nexport const mediaState: MediaQueryState =\n // development time safeguard\n process.env.NODE_ENV === 'development'\n ? new Proxy(\n {},\n {\n get(target, key) {\n if (typeof key === 'string' && key[0] === '$') {\n throw new Error(`Access of mediaState should never include $`)\n }\n return Reflect.get(target, key)\n },\n }\n )\n : ({} as any)\n\ntype MediaListener = (next: boolean) => void\n\nconst mediaQueryListeners: { [key: string]: Set<MediaListener> } = {}\n\nexport function addMediaQueryListener(key: MediaQueryKey, cb: MediaListener) {\n if (process.env.NODE_ENV === 'development' && key[0] === '$') {\n // eslint-disable-next-line no-console\n console.warn(`Warning, listening to media queries shouldn't use the \"$\" prefix`)\n }\n mediaQueryListeners[key] = mediaQueryListeners[key] || new Set()\n mediaQueryListeners[key].add(cb)\n return () => removeMediaQueryListener(key, cb)\n}\n\nexport function removeMediaQueryListener(key: MediaQueryKey, cb: MediaListener) {\n mediaQueryListeners[key]?.delete(cb)\n}\n\nexport const mediaQueryConfig: MediaQueries = {}\n\nexport const getMedia = () => {\n return mediaState\n}\n\n// for SSR capture it at time of startup\nlet currentMediaState: MediaQueryState | null\nlet initialMediaState: MediaQueryState | null\n// fairly concurrent mode sketchy but such an edge case ok for now\nlet hasFinishedInitialRender = false\nexport const getCurrentMediaState = () => {\n if (getConfig().disableSSR || hasFinishedInitialRender) {\n return currentMediaState || {}\n }\n return initialMediaState || {}\n}\n\nconst dispose = new Set<Function>()\n\nexport const configureMedia = (config: TamaguiInternalConfig) => {\n const { media, mediaQueryDefaultActive } = config\n if (!media) return\n for (const key in media) {\n mediaState[key] = mediaQueryDefaultActive?.[key] || false\n }\n Object.assign(mediaQueryConfig, media)\n currentMediaState = { ...mediaState }\n initialMediaState = currentMediaState\n if (config.disableSSR) {\n setupMediaListeners()\n }\n}\n\nfunction unlisten() {\n dispose.forEach((cb) => cb())\n dispose.clear()\n}\n\n/**\n * Note: This should *not* set the state on the first render!\n * Because to avoid hydration issues SSR must match the server\n * *and then* re-render with the actual media query state.\n */\nlet configuredKey = ''\nfunction setupMediaListeners() {\n // avoid setting up more than once per config\n const nextKey = JSON.stringify(mediaQueryConfig)\n if (nextKey === configuredKey) {\n return\n }\n configuredKey = nextKey\n\n // hmr, undo existing before re-binding\n unlisten()\n\n // theoretically this should make media reactions smoother but potentially delayed?\n // but i believe consistent, so that's a nicer default (we'll see)\n startTransition(() => {\n for (const key in mediaQueryConfig) {\n const str = mediaObjectToString(mediaQueryConfig[key])\n const getMatch = () => matchMedia(str)\n const match = getMatch()\n if (!match) {\n throw new Error('\u26A0\uFE0F No match')\n }\n // react native needs these deprecated apis for now\n match.addListener(update)\n dispose.add(() => match.removeListener(update))\n\n update()\n\n function update() {\n const next = !!getMatch().matches\n if (next === mediaState[key]) return\n mediaState[key] = next\n currentMediaState = { ...mediaState }\n const listeners = mediaQueryListeners[key]\n if (listeners?.size) {\n listeners.forEach((cb) => cb(next))\n }\n }\n }\n })\n}\n\nconst onIdle =\n typeof requestIdleCallback === 'undefined' ? (cb) => setTimeout(cb, 100) : requestIdleCallback\n\nexport function useMediaQueryListeners(config: TamaguiInternalConfig) {\n if (config.disableSSR) {\n return\n }\n\n useEffect(() => {\n setupMediaListeners()\n\n onIdle(() => {\n hasFinishedInitialRender = true\n })\n\n return unlisten\n }, [])\n}\n\nexport function useMedia(): {\n [key in MediaQueryKey]: boolean\n} {\n const [state, setState] = useState(getCurrentMediaState())\n const keys = useSafeRef({} as Record<string, boolean>)\n\n function updateState() {\n setState((prev) => {\n for (const key in keys.current) {\n if (prev[key] !== mediaState[key]) {\n return { ...mediaState }\n }\n }\n return prev\n })\n }\n\n useIsomorphicLayoutEffect(() => {\n const disposes: Function[] = Object.keys(keys.current).map((key) =>\n addMediaQueryListener(key, updateState)\n )\n updateState()\n return () => {\n disposes.forEach((cb) => cb())\n }\n })\n\n return useMemo(\n () =>\n new Proxy(state, {\n get(_, key: string) {\n if (process.env.NODE_ENV === 'development') {\n if (!currentMediaState) {\n throw new Error(\n `To use useMedia() you must pass in media configuration to createTamagui, none was found.`\n )\n }\n }\n if (!keys.current[key]) {\n keys.current[key] = true\n }\n return Reflect.get(state, key)\n },\n }),\n [state, keys]\n )\n}\n\n/**\n * Useful for more complex components that need access to the currently active props,\n * accounting for the currently active media queries.\n *\n * Use sparingly, is will loop props and trigger re-render on all media queries.\n *\n * */\nexport function useMediaPropsActive<A extends Object>(\n props: A\n): {\n // remove all media\n [Key in keyof A extends `$${string}` ? never : keyof A]?: A[Key]\n} {\n const media = useMedia()\n\n return useMemo(() => {\n const evaluated = {} as A\n const lastSetImportanceForKey = {}\n const propNames = Object.keys(props)\n const mediaKeysOrdered = Object.keys(getMedia())\n\n function update(k: string, v: any, importance = 0) {\n if (lastSetImportanceForKey[k] > importance) {\n return\n }\n lastSetImportanceForKey[k] = importance\n evaluated[k] = v\n }\n\n for (let i = propNames.length - 1; i >= 0; i--) {\n const key = propNames[i]\n const val = props[key]\n if (key[0] === '$') {\n const shortKey = key.slice(1)\n if (!media[shortKey]) {\n continue\n }\n if (val && typeof val === 'object') {\n const subPropNames = Object.keys(val)\n const mediaImportance = mediaKeysOrdered.indexOf(shortKey)\n for (let j = subPropNames.length; j--; j >= 0) {\n const skey = subPropNames[j]\n update(skey, val[skey], mediaImportance)\n }\n }\n } else {\n update(key, val)\n }\n }\n\n return evaluated\n }, [media, props])\n}\n\nfunction camelToHyphen(str: string) {\n return str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).toLowerCase()\n}\n\nexport function mediaObjectToString(query: string | MediaQueryObject) {\n if (typeof query === 'string') {\n return query\n }\n return Object.entries(query)\n .map(([feature, value]) => {\n feature = camelToHyphen(feature)\n if (typeof value === 'string') {\n return `(${feature}: ${value})`\n }\n if (typeof value === 'number' && /[height|width]$/.test(feature)) {\n value = `${value}px`\n }\n return `(${feature}: ${value})`\n })\n .join(' and ')\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["update"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/core",
|
|
3
|
-
"version": "1.0.1-beta.
|
|
3
|
+
"version": "1.0.1-beta.186",
|
|
4
4
|
"source": "src/index.ts",
|
|
5
5
|
"main": "dist/cjs",
|
|
6
6
|
"module": "dist/esm",
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@expo/match-media": "^0.3.0",
|
|
31
|
-
"@tamagui/compose-refs": "^1.0.1-beta.
|
|
32
|
-
"@tamagui/helpers": "^1.0.1-beta.
|
|
33
|
-
"@tamagui/normalize-css-color-lite": "^1.0.1-beta.
|
|
34
|
-
"@tamagui/rnw": "^1.0.1-beta.
|
|
35
|
-
"@tamagui/rnw-lite": "^1.0.1-beta.
|
|
36
|
-
"@tamagui/use-debounce": "^1.0.1-beta.
|
|
37
|
-
"@tamagui/use-event": "^1.0.1-beta.
|
|
38
|
-
"@tamagui/use-force-update": "^1.0.1-beta.
|
|
31
|
+
"@tamagui/compose-refs": "^1.0.1-beta.186",
|
|
32
|
+
"@tamagui/helpers": "^1.0.1-beta.186",
|
|
33
|
+
"@tamagui/normalize-css-color-lite": "^1.0.1-beta.186",
|
|
34
|
+
"@tamagui/rnw": "^1.0.1-beta.186",
|
|
35
|
+
"@tamagui/rnw-lite": "^1.0.1-beta.186",
|
|
36
|
+
"@tamagui/use-debounce": "^1.0.1-beta.186",
|
|
37
|
+
"@tamagui/use-event": "^1.0.1-beta.186",
|
|
38
|
+
"@tamagui/use-force-update": "^1.0.1-beta.186",
|
|
39
39
|
"expo-screen-orientation": "^4.3.0",
|
|
40
40
|
"hyphenate-style-name": "^1.0.4"
|
|
41
41
|
},
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"react-dom": "*"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@tamagui/build": "^1.0.1-beta.
|
|
47
|
+
"@tamagui/build": "^1.0.1-beta.186",
|
|
48
48
|
"@types/node": "^16.11.9",
|
|
49
49
|
"@types/react": "^18.0.15",
|
|
50
50
|
"csstype": "^3.0.10",
|
package/src/hooks/useMedia.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
TamaguiInternalConfig,
|
|
11
11
|
} from '../types'
|
|
12
12
|
import { useSafeRef } from './useSafeRef'
|
|
13
|
+
import { getConfig } from '..'
|
|
13
14
|
|
|
14
15
|
export const mediaState: MediaQueryState =
|
|
15
16
|
// development time safeguard
|
|
@@ -51,6 +52,18 @@ export const getMedia = () => {
|
|
|
51
52
|
return mediaState
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
// for SSR capture it at time of startup
|
|
56
|
+
let currentMediaState: MediaQueryState | null
|
|
57
|
+
let initialMediaState: MediaQueryState | null
|
|
58
|
+
// fairly concurrent mode sketchy but such an edge case ok for now
|
|
59
|
+
let hasFinishedInitialRender = false
|
|
60
|
+
export const getCurrentMediaState = () => {
|
|
61
|
+
if (getConfig().disableSSR || hasFinishedInitialRender) {
|
|
62
|
+
return currentMediaState || {}
|
|
63
|
+
}
|
|
64
|
+
return initialMediaState || {}
|
|
65
|
+
}
|
|
66
|
+
|
|
54
67
|
const dispose = new Set<Function>()
|
|
55
68
|
|
|
56
69
|
export const configureMedia = (config: TamaguiInternalConfig) => {
|
|
@@ -61,15 +74,12 @@ export const configureMedia = (config: TamaguiInternalConfig) => {
|
|
|
61
74
|
}
|
|
62
75
|
Object.assign(mediaQueryConfig, media)
|
|
63
76
|
currentMediaState = { ...mediaState }
|
|
77
|
+
initialMediaState = currentMediaState
|
|
64
78
|
if (config.disableSSR) {
|
|
65
79
|
setupMediaListeners()
|
|
66
80
|
}
|
|
67
81
|
}
|
|
68
82
|
|
|
69
|
-
// for SSR capture it at time of startup
|
|
70
|
-
let currentMediaState: MediaQueryState | null
|
|
71
|
-
export const getCurrentMediaState = () => currentMediaState
|
|
72
|
-
|
|
73
83
|
function unlisten() {
|
|
74
84
|
dispose.forEach((cb) => cb())
|
|
75
85
|
dispose.clear()
|
|
@@ -122,6 +132,9 @@ function setupMediaListeners() {
|
|
|
122
132
|
})
|
|
123
133
|
}
|
|
124
134
|
|
|
135
|
+
const onIdle =
|
|
136
|
+
typeof requestIdleCallback === 'undefined' ? (cb) => setTimeout(cb, 100) : requestIdleCallback
|
|
137
|
+
|
|
125
138
|
export function useMediaQueryListeners(config: TamaguiInternalConfig) {
|
|
126
139
|
if (config.disableSSR) {
|
|
127
140
|
return
|
|
@@ -129,6 +142,11 @@ export function useMediaQueryListeners(config: TamaguiInternalConfig) {
|
|
|
129
142
|
|
|
130
143
|
useEffect(() => {
|
|
131
144
|
setupMediaListeners()
|
|
145
|
+
|
|
146
|
+
onIdle(() => {
|
|
147
|
+
hasFinishedInitialRender = true
|
|
148
|
+
})
|
|
149
|
+
|
|
132
150
|
return unlisten
|
|
133
151
|
}, [])
|
|
134
152
|
}
|
|
@@ -136,7 +154,7 @@ export function useMediaQueryListeners(config: TamaguiInternalConfig) {
|
|
|
136
154
|
export function useMedia(): {
|
|
137
155
|
[key in MediaQueryKey]: boolean
|
|
138
156
|
} {
|
|
139
|
-
const [state, setState] = useState(
|
|
157
|
+
const [state, setState] = useState(getCurrentMediaState())
|
|
140
158
|
const keys = useSafeRef({} as Record<string, boolean>)
|
|
141
159
|
|
|
142
160
|
function updateState() {
|
|
@@ -5,8 +5,8 @@ export declare function addMediaQueryListener(key: MediaQueryKey, cb: MediaListe
|
|
|
5
5
|
export declare function removeMediaQueryListener(key: MediaQueryKey, cb: MediaListener): void;
|
|
6
6
|
export declare const mediaQueryConfig: MediaQueries;
|
|
7
7
|
export declare const getMedia: () => MediaQueryState;
|
|
8
|
+
export declare const getCurrentMediaState: () => MediaQueryState;
|
|
8
9
|
export declare const configureMedia: (config: TamaguiInternalConfig) => void;
|
|
9
|
-
export declare const getCurrentMediaState: () => MediaQueryState | null;
|
|
10
10
|
export declare function useMediaQueryListeners(config: TamaguiInternalConfig): void;
|
|
11
11
|
export declare function useMedia(): {
|
|
12
12
|
[key in MediaQueryKey]: boolean;
|