@tamagui/core 1.126.13 → 1.126.15
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/hooks/useElementLayout.cjs +62 -63
- package/dist/cjs/hooks/useElementLayout.js +55 -62
- package/dist/cjs/hooks/useElementLayout.js.map +1 -1
- package/dist/cjs/hooks/useElementLayout.native.js +63 -94
- package/dist/cjs/hooks/useElementLayout.native.js.map +2 -2
- package/dist/cjs/index.cjs +5 -2
- package/dist/cjs/index.js +4 -2
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/index.native.js +6 -2
- package/dist/cjs/index.native.js.map +2 -2
- package/dist/esm/hooks/useElementLayout.js +59 -63
- package/dist/esm/hooks/useElementLayout.js.map +1 -1
- package/dist/esm/hooks/useElementLayout.mjs +62 -64
- package/dist/esm/hooks/useElementLayout.mjs.map +1 -1
- package/dist/esm/hooks/useElementLayout.native.js +77 -106
- package/dist/esm/hooks/useElementLayout.native.js.map +1 -1
- package/dist/esm/index.js +8 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs +3 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +3 -2
- package/dist/esm/index.native.js.map +1 -1
- package/dist/native.js +144 -154
- package/dist/native.js.map +3 -3
- package/dist/test.native.js +141 -153
- package/dist/test.native.js.map +3 -3
- package/package.json +7 -7
- package/src/hooks/useElementLayout.tsx +106 -88
- package/src/index.tsx +8 -1
- package/types/hooks/useElementLayout.d.ts +5 -2
- package/types/hooks/useElementLayout.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamagui/core",
|
|
3
|
-
"version": "1.126.
|
|
3
|
+
"version": "1.126.15",
|
|
4
4
|
"source": "src/index.tsx",
|
|
5
5
|
"main": "dist/cjs",
|
|
6
6
|
"module": "dist/esm",
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
"native-test.d.ts"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@tamagui/react-native-media-driver": "1.126.
|
|
39
|
-
"@tamagui/react-native-use-pressable": "1.126.
|
|
40
|
-
"@tamagui/react-native-use-responder-events": "1.126.
|
|
41
|
-
"@tamagui/use-event": "1.126.
|
|
42
|
-
"@tamagui/web": "1.126.
|
|
38
|
+
"@tamagui/react-native-media-driver": "1.126.15",
|
|
39
|
+
"@tamagui/react-native-use-pressable": "1.126.15",
|
|
40
|
+
"@tamagui/react-native-use-responder-events": "1.126.15",
|
|
41
|
+
"@tamagui/use-event": "1.126.15",
|
|
42
|
+
"@tamagui/web": "1.126.15"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@tamagui/build": "1.126.
|
|
45
|
+
"@tamagui/build": "1.126.15",
|
|
46
46
|
"@testing-library/react": "^16.1.0",
|
|
47
47
|
"csstype": "^3.0.10",
|
|
48
48
|
"typescript": "^5.8.2",
|
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
import { useIsomorphicLayoutEffect } from '@tamagui/constants'
|
|
2
|
-
import
|
|
1
|
+
import { isClient, useIsomorphicLayoutEffect } from '@tamagui/constants'
|
|
2
|
+
import {
|
|
3
|
+
isEqualShallow,
|
|
4
|
+
type TamaguiComponentStateRef,
|
|
5
|
+
___onDidFinishClientRender,
|
|
6
|
+
} from '@tamagui/web'
|
|
3
7
|
import type { RefObject } from 'react'
|
|
4
|
-
import { getBoundingClientRect } from '../helpers/getBoundingClientRect'
|
|
5
8
|
|
|
6
|
-
const LayoutHandlers = new WeakMap<
|
|
7
|
-
const
|
|
9
|
+
const LayoutHandlers = new WeakMap<HTMLElement, Function>()
|
|
10
|
+
const Nodes = new Set<HTMLElement>()
|
|
11
|
+
|
|
12
|
+
type LayoutMeasurementStatus = 'inactive' | 'active'
|
|
13
|
+
|
|
14
|
+
let status: LayoutMeasurementStatus = 'active'
|
|
15
|
+
export function setOnLayoutStrategy(state: LayoutMeasurementStatus) {
|
|
16
|
+
status = state
|
|
17
|
+
}
|
|
8
18
|
|
|
9
19
|
export type LayoutValue = {
|
|
10
20
|
x: number
|
|
@@ -23,48 +33,90 @@ export type LayoutEvent = {
|
|
|
23
33
|
timeStamp: number
|
|
24
34
|
}
|
|
25
35
|
|
|
26
|
-
|
|
36
|
+
const NodeRectCache = new WeakMap<HTMLElement, DOMRect>()
|
|
37
|
+
const ParentRectCache = new WeakMap<HTMLElement, DOMRect>()
|
|
38
|
+
|
|
39
|
+
const rAF = typeof window !== 'undefined' ? window.requestAnimationFrame : undefined
|
|
40
|
+
|
|
41
|
+
if (isClient) {
|
|
42
|
+
if (rAF) {
|
|
43
|
+
// prevent thrashing during first hydration (somewhat, streaming gets trickier)
|
|
44
|
+
let avoidUpdates = true
|
|
45
|
+
const queuedUpdates = new Map<HTMLElement, Function>()
|
|
46
|
+
|
|
47
|
+
___onDidFinishClientRender(() => {
|
|
48
|
+
avoidUpdates = false
|
|
49
|
+
if (queuedUpdates) {
|
|
50
|
+
queuedUpdates.forEach((cb) => cb())
|
|
51
|
+
queuedUpdates.clear()
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
function updateLayoutIfChanged(node: HTMLElement) {
|
|
56
|
+
const nodeRect = node.getBoundingClientRect()
|
|
57
|
+
const parentNode = node.parentElement
|
|
58
|
+
const parentRect = parentNode?.getBoundingClientRect()
|
|
27
59
|
|
|
28
|
-
|
|
29
|
-
// node resize/move
|
|
30
|
-
resizeObserver = new ResizeObserver((entries) => {
|
|
31
|
-
for (const { target } of entries) {
|
|
32
|
-
const onLayout = LayoutHandlers.get(target)
|
|
60
|
+
const onLayout = LayoutHandlers.get(node)
|
|
33
61
|
if (typeof onLayout !== 'function') return
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
62
|
+
|
|
63
|
+
const cachedRect = NodeRectCache.get(node)
|
|
64
|
+
const cachedParentRect = parentNode ? NodeRectCache.get(parentNode) : null
|
|
65
|
+
|
|
66
|
+
if (
|
|
67
|
+
!cachedRect ||
|
|
68
|
+
// has changed one rect
|
|
69
|
+
(!isEqualShallow(cachedRect, nodeRect) &&
|
|
70
|
+
(!cachedParentRect || !isEqualShallow(cachedParentRect, parentRect)))
|
|
71
|
+
) {
|
|
72
|
+
NodeRectCache.set(node, nodeRect)
|
|
73
|
+
if (parentRect && parentNode) {
|
|
74
|
+
ParentRectCache.set(parentNode, parentRect)
|
|
75
|
+
}
|
|
76
|
+
const event = getElementLayoutEvent(node)
|
|
77
|
+
if (avoidUpdates) {
|
|
78
|
+
queuedUpdates.set(node, () => onLayout(event))
|
|
79
|
+
} else {
|
|
80
|
+
onLayout(event)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
37
83
|
}
|
|
38
|
-
})
|
|
39
84
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
85
|
+
// note that getBoundingClientRect() does not thrash layout if its after an animation frame
|
|
86
|
+
rAF!(layoutOnAnimationFrame)
|
|
87
|
+
function layoutOnAnimationFrame() {
|
|
88
|
+
if (status !== 'inactive') {
|
|
89
|
+
Nodes.forEach(updateLayoutIfChanged)
|
|
90
|
+
}
|
|
91
|
+
rAF!(layoutOnAnimationFrame)
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
if (process.env.NODE_ENV === 'development') {
|
|
95
|
+
console.warn(
|
|
96
|
+
`No requestAnimationFrame - please polyfill for onLayout to work correctly`
|
|
97
|
+
)
|
|
98
|
+
}
|
|
49
99
|
}
|
|
50
100
|
}
|
|
51
101
|
|
|
52
|
-
export const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
})
|
|
102
|
+
export const getElementLayoutEvent = (target: HTMLElement): LayoutEvent => {
|
|
103
|
+
let res: LayoutEvent | null = null
|
|
104
|
+
measureLayout(target, null, (x, y, width, height, left, top) => {
|
|
105
|
+
res = {
|
|
106
|
+
nativeEvent: {
|
|
107
|
+
layout: { x, y, width, height, left, top },
|
|
108
|
+
target,
|
|
109
|
+
},
|
|
110
|
+
timeStamp: Date.now(),
|
|
111
|
+
}
|
|
63
112
|
})
|
|
113
|
+
if (!res) {
|
|
114
|
+
throw new Error(`‼️`) // impossible
|
|
115
|
+
}
|
|
116
|
+
return res
|
|
64
117
|
}
|
|
65
118
|
|
|
66
|
-
|
|
67
|
-
|
|
119
|
+
// matching old RN callback API (can we remove?)
|
|
68
120
|
export const measureLayout = (
|
|
69
121
|
node: HTMLElement,
|
|
70
122
|
relativeTo: HTMLElement | null,
|
|
@@ -77,22 +129,17 @@ export const measureLayout = (
|
|
|
77
129
|
top: number
|
|
78
130
|
) => void
|
|
79
131
|
) => {
|
|
80
|
-
const relativeNode = relativeTo || node?.
|
|
132
|
+
const relativeNode = relativeTo || node?.parentElement
|
|
81
133
|
if (relativeNode instanceof HTMLElement) {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
relativeNodeDim
|
|
92
|
-
)
|
|
93
|
-
callback(x, y, width, height, left, top)
|
|
94
|
-
}
|
|
95
|
-
})
|
|
134
|
+
const nodeDim = node.getBoundingClientRect()
|
|
135
|
+
const relativeNodeDim = relativeNode.getBoundingClientRect()
|
|
136
|
+
if (relativeNodeDim && nodeDim) {
|
|
137
|
+
const { x, y, width, height, left, top } = getRelativeDimensions(
|
|
138
|
+
nodeDim,
|
|
139
|
+
relativeNodeDim
|
|
140
|
+
)
|
|
141
|
+
callback(x, y, width, height, left, top)
|
|
142
|
+
}
|
|
96
143
|
}
|
|
97
144
|
}
|
|
98
145
|
|
|
@@ -103,58 +150,29 @@ const getRelativeDimensions = (a: DOMRectReadOnly, b: DOMRectReadOnly) => {
|
|
|
103
150
|
return { x, y, width, height, left, top }
|
|
104
151
|
}
|
|
105
152
|
|
|
106
|
-
const getBoundingClientRectAsync = (
|
|
107
|
-
element: HTMLElement
|
|
108
|
-
): Promise<DOMRectReadOnly | undefined> => {
|
|
109
|
-
return new Promise((resolve) => {
|
|
110
|
-
function fallbackToSync() {
|
|
111
|
-
resolve(getBoundingClientRect(element))
|
|
112
|
-
}
|
|
113
|
-
const tm = setTimeout(fallbackToSync, 10)
|
|
114
|
-
const observer = new IntersectionObserver(
|
|
115
|
-
(entries, ob) => {
|
|
116
|
-
clearTimeout(tm)
|
|
117
|
-
ob.disconnect()
|
|
118
|
-
resolve(entries[0]?.boundingClientRect)
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
threshold: 0.0001,
|
|
122
|
-
}
|
|
123
|
-
)
|
|
124
|
-
observer.observe(element)
|
|
125
|
-
})
|
|
126
|
-
}
|
|
127
|
-
|
|
128
153
|
export function useElementLayout(
|
|
129
154
|
ref: RefObject<TamaguiComponentStateRef>,
|
|
130
155
|
onLayout?: ((e: LayoutEvent) => void) | null
|
|
131
156
|
) {
|
|
132
|
-
const node = ref.current?.host as Element
|
|
133
|
-
|
|
134
157
|
// ensure always up to date so we can avoid re-running effect
|
|
158
|
+
const node = ref.current?.host as HTMLElement
|
|
135
159
|
if (node && onLayout) {
|
|
136
160
|
LayoutHandlers.set(node, onLayout)
|
|
137
161
|
}
|
|
138
162
|
|
|
139
163
|
useIsomorphicLayoutEffect(() => {
|
|
140
|
-
if (!
|
|
141
|
-
const node = ref.current?.host as
|
|
164
|
+
if (!onLayout) return
|
|
165
|
+
const node = ref.current?.host as HTMLElement
|
|
142
166
|
if (!node) return
|
|
143
167
|
|
|
144
|
-
// setup once
|
|
145
168
|
LayoutHandlers.set(node, onLayout)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
measureElement(node as HTMLElement).then(onLayout)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
resizeListeners.add(onResize)
|
|
152
|
-
resizeObserver.observe(node)
|
|
169
|
+
Nodes.add(node)
|
|
170
|
+
onLayout(getElementLayoutEvent(node))
|
|
153
171
|
|
|
154
172
|
return () => {
|
|
173
|
+
Nodes.delete(node)
|
|
155
174
|
LayoutHandlers.delete(node)
|
|
156
|
-
|
|
157
|
-
resizeObserver?.unobserve(node)
|
|
175
|
+
NodeRectCache.delete(node)
|
|
158
176
|
}
|
|
159
177
|
}, [ref, !!onLayout])
|
|
160
178
|
}
|
package/src/index.tsx
CHANGED
|
@@ -21,13 +21,20 @@ import {
|
|
|
21
21
|
} from '@tamagui/web'
|
|
22
22
|
import React from 'react'
|
|
23
23
|
|
|
24
|
+
import { addNativeValidStyles } from './addNativeValidStyles'
|
|
24
25
|
import { createOptimizedView } from './createOptimizedView'
|
|
25
26
|
import { getBaseViews } from './getBaseViews'
|
|
26
27
|
import { getRect } from './helpers/getRect'
|
|
27
28
|
import { measureLayout, useElementLayout } from './hooks/useElementLayout'
|
|
28
29
|
import type { RNTextProps, RNViewProps } from './reactNativeTypes'
|
|
29
30
|
import { usePressability } from './vendor/Pressability'
|
|
30
|
-
|
|
31
|
+
|
|
32
|
+
// helpful for usage outside of tamagui
|
|
33
|
+
export {
|
|
34
|
+
getElementLayoutEvent,
|
|
35
|
+
setOnLayoutStrategy,
|
|
36
|
+
type LayoutEvent,
|
|
37
|
+
} from './hooks/useElementLayout'
|
|
31
38
|
|
|
32
39
|
// add newer style props based on react native version
|
|
33
40
|
addNativeValidStyles()
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type TamaguiComponentStateRef } from '@tamagui/web';
|
|
2
2
|
import type { RefObject } from 'react';
|
|
3
|
+
type LayoutMeasurementStatus = 'inactive' | 'active';
|
|
4
|
+
export declare function setOnLayoutStrategy(state: LayoutMeasurementStatus): void;
|
|
3
5
|
export type LayoutValue = {
|
|
4
6
|
x: number;
|
|
5
7
|
y: number;
|
|
@@ -15,7 +17,8 @@ export type LayoutEvent = {
|
|
|
15
17
|
};
|
|
16
18
|
timeStamp: number;
|
|
17
19
|
};
|
|
18
|
-
export declare const
|
|
20
|
+
export declare const getElementLayoutEvent: (target: HTMLElement) => LayoutEvent;
|
|
19
21
|
export declare const measureLayout: (node: HTMLElement, relativeTo: HTMLElement | null, callback: (x: number, y: number, width: number, height: number, left: number, top: number) => void) => void;
|
|
20
22
|
export declare function useElementLayout(ref: RefObject<TamaguiComponentStateRef>, onLayout?: ((e: LayoutEvent) => void) | null): void;
|
|
23
|
+
export {};
|
|
21
24
|
//# sourceMappingURL=useElementLayout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useElementLayout.d.ts","sourceRoot":"","sources":["../../src/hooks/useElementLayout.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"useElementLayout.d.ts","sourceRoot":"","sources":["../../src/hooks/useElementLayout.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,wBAAwB,EAE9B,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,KAAK,uBAAuB,GAAG,UAAU,GAAG,QAAQ,CAAA;AAGpD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,uBAAuB,QAEjE;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,EAAE;QACX,MAAM,EAAE,WAAW,CAAA;QACnB,MAAM,EAAE,GAAG,CAAA;KACZ,CAAA;IACD,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAoED,eAAO,MAAM,qBAAqB,GAAI,QAAQ,WAAW,KAAG,WAe3D,CAAA;AAGD,eAAO,MAAM,aAAa,GACxB,MAAM,WAAW,EACjB,YAAY,WAAW,GAAG,IAAI,EAC9B,UAAU,CACR,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,KACR,IAAI,SAcV,CAAA;AASD,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,SAAS,CAAC,wBAAwB,CAAC,EACxC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC,GAAG,IAAI,QAuB7C"}
|
package/types/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { StackNonStyleProps, StackStyleBase, TamaDefer, TamaguiComponent, TamaguiElement, TamaguiTextElement, TextNonStyleProps, TextProps, TextStylePropsBase } from '@tamagui/web';
|
|
2
2
|
import { createTamagui as createTamaguiWeb } from '@tamagui/web';
|
|
3
3
|
import type { RNTextProps, RNViewProps } from './reactNativeTypes';
|
|
4
|
+
export { getElementLayoutEvent, setOnLayoutStrategy, type LayoutEvent, } from './hooks/useElementLayout';
|
|
4
5
|
type RNExclusiveViewProps = Omit<RNViewProps, keyof StackNonStyleProps>;
|
|
5
6
|
export interface RNTamaguiViewNonStyleProps extends StackNonStyleProps, RNExclusiveViewProps {
|
|
6
7
|
}
|
package/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,SAAS,EACT,kBAAkB,EACnB,MAAM,cAAc,CAAA;AACrB,OAAO,EAKL,aAAa,IAAI,gBAAgB,EAElC,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,SAAS,EACT,kBAAkB,EACnB,MAAM,cAAc,CAAA;AACrB,OAAO,EAKL,aAAa,IAAI,gBAAgB,EAElC,MAAM,cAAc,CAAA;AAQrB,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAIlE,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,KAAK,WAAW,GACjB,MAAM,0BAA0B,CAAA;AAOjC,KAAK,oBAAoB,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,kBAAkB,CAAC,CAAA;AACvE,MAAM,WAAW,0BACf,SAAQ,kBAAkB,EACxB,oBAAoB;CAAG;AAE3B,KAAK,aAAa,GAAG,gBAAgB,CACnC,SAAS,EACT,cAAc,EACd,0BAA0B,EAC1B,cAAc,EACd,EAAE,CACH,CAAA;AAED,KAAK,oBAAoB,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,SAAS,CAAC,CAAA;AAC9D,MAAM,WAAW,0BACf,SAAQ,iBAAiB,EACvB,oBAAoB;CAAG;AAE3B,KAAK,aAAa,GAAG,gBAAgB,CACnC,SAAS,EACT,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,EAClB,EAAE,CACH,CAAA;AAGD,cAAc,cAAc,CAAA;AAG5B,cAAc,oBAAoB,CAAA;AAGlC,eAAO,MAAM,aAAa,EAAE,OAAO,gBAOlC,CAAA;AAmLD,eAAO,MAAM,IAAI,EAAqB,aAAa,CAAA;AACnD,eAAO,MAAM,KAAK,EAAsB,aAAa,CAAA;AACrD,eAAO,MAAM,IAAI,EAAqB,aAAa,CAAA"}
|