@tamagui/adapt 1.115.4 → 1.116.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/cjs/Adapt.cjs +124 -47
- package/dist/cjs/Adapt.cjs.map +1 -1
- package/dist/cjs/Adapt.native.js +100 -41
- package/dist/cjs/Adapt.native.js.map +2 -2
- package/dist/esm/Adapt.js +95 -35
- package/dist/esm/Adapt.js.map +1 -1
- package/dist/esm/Adapt.mjs +120 -46
- package/dist/esm/Adapt.mjs.map +1 -1
- package/dist/esm/Adapt.native.js +98 -41
- package/dist/esm/Adapt.native.js.map +2 -2
- package/package.json +6 -5
- package/src/Adapt.tsx +206 -71
- package/types/Adapt.d.ts +48 -25
- package/types/Adapt.d.ts.map +1 -1
package/src/Adapt.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
1
|
import {
|
|
3
2
|
isAndroid,
|
|
4
3
|
isIos,
|
|
@@ -6,116 +5,252 @@ import {
|
|
|
6
5
|
isWeb,
|
|
7
6
|
useIsomorphicLayoutEffect,
|
|
8
7
|
} from '@tamagui/constants'
|
|
9
|
-
import type {
|
|
10
|
-
import { useMedia } from '@tamagui/core'
|
|
8
|
+
import type { AllPlatforms, MediaQueryKey } from '@tamagui/core'
|
|
9
|
+
import { createStyledContext, useMedia } from '@tamagui/core'
|
|
11
10
|
import { withStaticProperties } from '@tamagui/helpers'
|
|
11
|
+
import { PortalHost, PortalItem } from '@tamagui/portal'
|
|
12
|
+
import React, { createContext, useContext, useEffect, useId } from 'react'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Interfaces
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export type AdaptWhen = MediaQueryKeyString | boolean | null
|
|
19
|
+
export type AdaptPlatform = AllPlatforms | 'touch' | null
|
|
20
|
+
|
|
21
|
+
type AdaptParentContextI = {
|
|
22
|
+
Contents: Component
|
|
23
|
+
scopeName: string
|
|
24
|
+
platform: AdaptPlatform
|
|
25
|
+
setPlatform: (when: AdaptPlatform) => any
|
|
26
|
+
when: AdaptWhen
|
|
27
|
+
setWhen: (when: AdaptWhen) => any
|
|
28
|
+
setChildren: (children: any) => any
|
|
29
|
+
portalName?: string
|
|
30
|
+
}
|
|
12
31
|
|
|
13
32
|
type MediaQueryKeyString = MediaQueryKey extends string ? MediaQueryKey : never
|
|
14
33
|
|
|
15
34
|
export type AdaptProps = {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
| ((state: { enabled: boolean; media: UseMediaState }) => JSX.Element)
|
|
35
|
+
scope?: string
|
|
36
|
+
when?: AdaptWhen
|
|
37
|
+
platform?: AdaptPlatform
|
|
38
|
+
children: JSX.Element | ((children: React.ReactNode) => React.ReactNode)
|
|
21
39
|
}
|
|
22
40
|
|
|
23
|
-
type When = MediaQueryKeyString | boolean | null
|
|
24
|
-
|
|
25
41
|
type Component = (props: any) => any
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Contexts
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
const CurrentAdaptContextScope = createContext('')
|
|
48
|
+
|
|
49
|
+
export const AdaptContext = createStyledContext<AdaptParentContextI>({
|
|
50
|
+
Contents: null as any,
|
|
51
|
+
scopeName: '',
|
|
52
|
+
portalName: '',
|
|
53
|
+
platform: null as any,
|
|
54
|
+
setPlatform: null as any,
|
|
55
|
+
when: null as any,
|
|
56
|
+
setChildren: null as any,
|
|
57
|
+
setWhen: null as any,
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const ProvideAdaptContext = ({
|
|
61
|
+
children,
|
|
62
|
+
...context
|
|
63
|
+
}: AdaptParentContextI & { children: any }) => {
|
|
64
|
+
const scope = context.scopeName || ''
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<CurrentAdaptContextScope.Provider value={scope}>
|
|
68
|
+
<AdaptContext.Provider scope={scope} {...context}>
|
|
69
|
+
{children}
|
|
70
|
+
</AdaptContext.Provider>
|
|
71
|
+
</CurrentAdaptContextScope.Provider>
|
|
72
|
+
)
|
|
29
73
|
}
|
|
30
74
|
|
|
31
|
-
export const
|
|
75
|
+
export const useAdaptContext = (scope = '') => {
|
|
76
|
+
const contextScope = useContext(CurrentAdaptContextScope)
|
|
77
|
+
const context = AdaptContext.useStyledContext(
|
|
78
|
+
scope === '' ? contextScope || scope : scope
|
|
79
|
+
)
|
|
80
|
+
return context
|
|
81
|
+
}
|
|
32
82
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Hooks
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
type AdaptParentProps = {
|
|
88
|
+
children?: React.ReactNode
|
|
89
|
+
scope: string
|
|
90
|
+
Contents?: AdaptParentContextI['Contents']
|
|
91
|
+
portal?:
|
|
92
|
+
| boolean
|
|
93
|
+
| {
|
|
94
|
+
forwardProps?: any
|
|
95
|
+
}
|
|
44
96
|
}
|
|
45
97
|
|
|
46
|
-
|
|
98
|
+
const AdaptPortals = new Map()
|
|
47
99
|
|
|
48
|
-
export const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const [when, setWhen] = React.useState<When>(null)
|
|
100
|
+
export const AdaptParent = ({ children, Contents, scope, portal }: AdaptParentProps) => {
|
|
101
|
+
const portalName = `AdaptPortal${scope}`
|
|
102
|
+
const id = useId()
|
|
52
103
|
|
|
53
|
-
|
|
54
|
-
const context: AdaptParentContextI = {
|
|
55
|
-
Contents,
|
|
56
|
-
setWhen,
|
|
57
|
-
}
|
|
104
|
+
let FinalContents = Contents || AdaptPortals.get(id)
|
|
58
105
|
|
|
59
|
-
|
|
106
|
+
if (!FinalContents) {
|
|
107
|
+
FinalContents = () => {
|
|
60
108
|
return (
|
|
61
|
-
<
|
|
62
|
-
{
|
|
63
|
-
|
|
109
|
+
<PortalHost
|
|
110
|
+
name={portalName}
|
|
111
|
+
forwardProps={typeof portal === 'boolean' ? undefined : portal?.forwardProps}
|
|
112
|
+
/>
|
|
64
113
|
)
|
|
65
114
|
}
|
|
115
|
+
AdaptPortals.set(id, FinalContents)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
return () => {
|
|
120
|
+
AdaptPortals.delete(id)
|
|
121
|
+
}
|
|
122
|
+
}, [])
|
|
66
123
|
|
|
67
|
-
|
|
68
|
-
|
|
124
|
+
const [when, setWhen] = React.useState<AdaptWhen>(null)
|
|
125
|
+
const [platform, setPlatform] = React.useState<AdaptPlatform>(null)
|
|
126
|
+
const [children2, setChildren] = React.useState(null)
|
|
69
127
|
|
|
70
|
-
return
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
128
|
+
return (
|
|
129
|
+
<ProvideAdaptContext
|
|
130
|
+
Contents={FinalContents}
|
|
131
|
+
when={when}
|
|
132
|
+
platform={platform}
|
|
133
|
+
setPlatform={setPlatform}
|
|
134
|
+
setWhen={setWhen}
|
|
135
|
+
setChildren={setChildren}
|
|
136
|
+
portalName={portalName}
|
|
137
|
+
scopeName={scope}
|
|
138
|
+
>
|
|
139
|
+
{children}
|
|
140
|
+
</ProvideAdaptContext>
|
|
141
|
+
)
|
|
74
142
|
}
|
|
75
143
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const media = useMedia()
|
|
144
|
+
/**
|
|
145
|
+
* Components
|
|
146
|
+
*/
|
|
80
147
|
|
|
81
|
-
|
|
148
|
+
export const AdaptContents = ({ scope, ...rest }: { scope?: string }) => {
|
|
149
|
+
const context = useAdaptContext(scope)
|
|
82
150
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
151
|
+
if (!context?.Contents) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
process.env.NODE_ENV === 'production'
|
|
154
|
+
? `tamagui.dev/docs/intro/errors#warning-002`
|
|
155
|
+
: `You're rendering a Tamagui <Adapt /> component without nesting it inside a parent that is able to adapt.`
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// forwards props - see shouldForwardSpace
|
|
160
|
+
return React.createElement(context.Contents, { ...rest, key: `stable` })
|
|
161
|
+
}
|
|
87
162
|
|
|
88
|
-
|
|
89
|
-
if (platform === 'native') enabled = !isWeb
|
|
90
|
-
if (platform === 'web') enabled = isWeb
|
|
91
|
-
if (platform === 'ios') enabled = isIos
|
|
92
|
-
if (platform === 'android') enabled = isAndroid
|
|
163
|
+
AdaptContents.shouldForwardSpace = true
|
|
93
164
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
165
|
+
export const Adapt = withStaticProperties(
|
|
166
|
+
function Adapt(props: AdaptProps) {
|
|
167
|
+
const { platform, when, children, scope } = props
|
|
168
|
+
const context = useAdaptContext(scope)
|
|
169
|
+
const scopeName = scope ?? context.scopeName
|
|
170
|
+
const enabled = useAdaptIsActiveGiven(props)
|
|
98
171
|
|
|
99
172
|
useIsomorphicLayoutEffect(() => {
|
|
100
|
-
|
|
101
|
-
context?.
|
|
173
|
+
context?.setWhen((when || enabled) as AdaptWhen)
|
|
174
|
+
context?.setPlatform(platform || null)
|
|
175
|
+
}, [when, platform, context, enabled])
|
|
102
176
|
|
|
177
|
+
useIsomorphicLayoutEffect(() => {
|
|
103
178
|
return () => {
|
|
104
179
|
context?.setWhen(null)
|
|
105
180
|
}
|
|
106
|
-
}, [
|
|
181
|
+
}, [])
|
|
107
182
|
|
|
108
|
-
|
|
109
|
-
return null
|
|
110
|
-
}
|
|
183
|
+
let output: React.ReactNode
|
|
111
184
|
|
|
112
185
|
if (typeof children === 'function') {
|
|
113
|
-
|
|
186
|
+
const Component = context?.Contents
|
|
187
|
+
output = children(Component ? <Component /> : null)
|
|
188
|
+
} else {
|
|
189
|
+
output = children
|
|
114
190
|
}
|
|
115
191
|
|
|
116
|
-
|
|
192
|
+
// TODO this isn't ideal using an effect to set children, will cause double-renders
|
|
193
|
+
// on every change
|
|
194
|
+
useEffect(() => {
|
|
195
|
+
if (typeof children === 'function' && output !== undefined) {
|
|
196
|
+
context?.setChildren(output)
|
|
197
|
+
}
|
|
198
|
+
}, [output])
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<CurrentAdaptContextScope.Provider value={scopeName}>
|
|
202
|
+
{!enabled ? null : output}
|
|
203
|
+
</CurrentAdaptContextScope.Provider>
|
|
204
|
+
)
|
|
117
205
|
},
|
|
118
206
|
{
|
|
119
207
|
Contents: AdaptContents,
|
|
120
208
|
}
|
|
121
209
|
)
|
|
210
|
+
|
|
211
|
+
export const AdaptPortalContents = (props: {
|
|
212
|
+
children: React.ReactNode
|
|
213
|
+
scope?: string
|
|
214
|
+
}) => {
|
|
215
|
+
// const isActive = useAdaptIsActive(props.scope)
|
|
216
|
+
const { portalName } = useAdaptContext(props.scope)
|
|
217
|
+
|
|
218
|
+
// if (!isActive) {
|
|
219
|
+
// return null
|
|
220
|
+
// }
|
|
221
|
+
|
|
222
|
+
return (
|
|
223
|
+
<PortalItem
|
|
224
|
+
// passthrough={!isWeb && !isActive}
|
|
225
|
+
hostName={portalName}
|
|
226
|
+
>
|
|
227
|
+
{props.children}
|
|
228
|
+
</PortalItem>
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const useAdaptIsActiveGiven = ({
|
|
233
|
+
when,
|
|
234
|
+
platform,
|
|
235
|
+
}: Pick<AdaptProps, 'when' | 'platform'>) => {
|
|
236
|
+
const media = useMedia()
|
|
237
|
+
|
|
238
|
+
let enabled = false
|
|
239
|
+
|
|
240
|
+
if (platform === 'touch') enabled = isTouchable
|
|
241
|
+
if (platform === 'native') enabled = !isWeb
|
|
242
|
+
if (platform === 'web') enabled = isWeb
|
|
243
|
+
if (platform === 'ios') enabled = isIos
|
|
244
|
+
if (platform === 'android') enabled = isAndroid
|
|
245
|
+
|
|
246
|
+
if (when && typeof when === 'string' && !media[when]) {
|
|
247
|
+
enabled = false
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return enabled
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export const useAdaptIsActive = (scope?: string) => {
|
|
254
|
+
const props = useAdaptContext(scope)
|
|
255
|
+
return useAdaptIsActiveGiven(props)
|
|
256
|
+
}
|
package/types/Adapt.d.ts
CHANGED
|
@@ -1,40 +1,63 @@
|
|
|
1
|
+
import type { AllPlatforms, MediaQueryKey } from '@tamagui/core';
|
|
1
2
|
import React from 'react';
|
|
2
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Interfaces
|
|
5
|
+
*/
|
|
6
|
+
export type AdaptWhen = MediaQueryKeyString | boolean | null;
|
|
7
|
+
export type AdaptPlatform = AllPlatforms | 'touch' | null;
|
|
8
|
+
type AdaptParentContextI = {
|
|
9
|
+
Contents: Component;
|
|
10
|
+
scopeName: string;
|
|
11
|
+
platform: AdaptPlatform;
|
|
12
|
+
setPlatform: (when: AdaptPlatform) => any;
|
|
13
|
+
when: AdaptWhen;
|
|
14
|
+
setWhen: (when: AdaptWhen) => any;
|
|
15
|
+
setChildren: (children: any) => any;
|
|
16
|
+
portalName?: string;
|
|
17
|
+
};
|
|
3
18
|
type MediaQueryKeyString = MediaQueryKey extends string ? MediaQueryKey : never;
|
|
4
19
|
export type AdaptProps = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
children: JSX.Element | ((state: {
|
|
10
|
-
enabled: boolean;
|
|
11
|
-
media: UseMediaState;
|
|
12
|
-
}) => JSX.Element);
|
|
20
|
+
scope?: string;
|
|
21
|
+
when?: AdaptWhen;
|
|
22
|
+
platform?: AdaptPlatform;
|
|
23
|
+
children: JSX.Element | ((children: React.ReactNode) => React.ReactNode);
|
|
13
24
|
};
|
|
14
|
-
type When = MediaQueryKeyString | boolean | null;
|
|
15
25
|
type Component = (props: any) => any;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
26
|
+
export declare const AdaptContext: import("@tamagui/core").StyledContext<AdaptParentContextI>;
|
|
27
|
+
export declare const useAdaptContext: (scope?: string) => AdaptParentContextI;
|
|
28
|
+
/**
|
|
29
|
+
* Hooks
|
|
30
|
+
*/
|
|
31
|
+
type AdaptParentProps = {
|
|
32
|
+
children?: React.ReactNode;
|
|
33
|
+
scope: string;
|
|
34
|
+
Contents?: AdaptParentContextI['Contents'];
|
|
35
|
+
portal?: boolean | {
|
|
36
|
+
forwardProps?: any;
|
|
37
|
+
};
|
|
19
38
|
};
|
|
20
|
-
export declare const
|
|
39
|
+
export declare const AdaptParent: ({ children, Contents, scope, portal }: AdaptParentProps) => import("react/jsx-runtime").JSX.Element;
|
|
40
|
+
/**
|
|
41
|
+
* Components
|
|
42
|
+
*/
|
|
21
43
|
export declare const AdaptContents: {
|
|
22
|
-
(
|
|
44
|
+
({ scope, ...rest }: {
|
|
45
|
+
scope?: string;
|
|
46
|
+
}): React.FunctionComponentElement<any>;
|
|
23
47
|
shouldForwardSpace: boolean;
|
|
24
48
|
};
|
|
25
|
-
export declare const
|
|
26
|
-
Contents: AdaptParentContextI["Contents"];
|
|
27
|
-
}) => {
|
|
28
|
-
AdaptProvider: (props: {
|
|
29
|
-
children?: any;
|
|
30
|
-
}) => import("react/jsx-runtime").JSX.Element;
|
|
31
|
-
when: When;
|
|
32
|
-
};
|
|
33
|
-
export declare const Adapt: (({ platform, when, children }: AdaptProps) => JSX.Element | null) & {
|
|
49
|
+
export declare const Adapt: ((props: AdaptProps) => import("react/jsx-runtime").JSX.Element) & {
|
|
34
50
|
Contents: {
|
|
35
|
-
(
|
|
51
|
+
({ scope, ...rest }: {
|
|
52
|
+
scope?: string;
|
|
53
|
+
}): React.FunctionComponentElement<any>;
|
|
36
54
|
shouldForwardSpace: boolean;
|
|
37
55
|
};
|
|
38
56
|
};
|
|
57
|
+
export declare const AdaptPortalContents: (props: {
|
|
58
|
+
children: React.ReactNode;
|
|
59
|
+
scope?: string;
|
|
60
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
61
|
+
export declare const useAdaptIsActive: (scope?: string) => boolean;
|
|
39
62
|
export {};
|
|
40
63
|
//# sourceMappingURL=Adapt.d.ts.map
|
package/types/Adapt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Adapt.d.ts","sourceRoot":"","sources":["../src/Adapt.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Adapt.d.ts","sourceRoot":"","sources":["../src/Adapt.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAIhE,OAAO,KAAsD,MAAM,OAAO,CAAA;AAE1E;;GAEG;AAEH,MAAM,MAAM,SAAS,GAAG,mBAAmB,GAAG,OAAO,GAAG,IAAI,CAAA;AAC5D,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,OAAO,GAAG,IAAI,CAAA;AAEzD,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,aAAa,CAAA;IACvB,WAAW,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,GAAG,CAAA;IACzC,IAAI,EAAE,SAAS,CAAA;IACf,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,GAAG,CAAA;IACjC,WAAW,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,GAAG,CAAA;IACnC,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,KAAK,mBAAmB,GAAG,aAAa,SAAS,MAAM,GAAG,aAAa,GAAG,KAAK,CAAA;AAE/E,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB,QAAQ,EAAE,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,SAAS,CAAC,CAAA;CACzE,CAAA;AAED,KAAK,SAAS,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,CAAA;AAQpC,eAAO,MAAM,YAAY,4DASvB,CAAA;AAiBF,eAAO,MAAM,eAAe,yCAM3B,CAAA;AAED;;GAEG;AAEH,KAAK,gBAAgB,GAAG;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAA;IAC1C,MAAM,CAAC,EACH,OAAO,GACP;QACE,YAAY,CAAC,EAAE,GAAG,CAAA;KACnB,CAAA;CACN,CAAA;AAID,eAAO,MAAM,WAAW,0CAA2C,gBAAgB,4CA0ClF,CAAA;AAED;;GAEG;AAEH,eAAO,MAAM,aAAa;yBAAwB;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;;CAanE,CAAA;AAID,eAAO,MAAM,KAAK,WACM,UAAU;;6BAlBgB;YAAE,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE;;;CA6DnE,CAAA;AAED,eAAO,MAAM,mBAAmB,UAAW;IACzC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,4CAgBA,CAAA;AAuBD,eAAO,MAAM,gBAAgB,WAAY,MAAM,YAG9C,CAAA"}
|