@namiml/expo-sdk 3.4.4-dev.202607022250 → 3.4.4-dev.202607031905
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@namiml/expo-sdk",
|
|
3
|
-
"version": "3.4.4-dev.
|
|
3
|
+
"version": "3.4.4-dev.202607031905",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Nami Expo SDK — paywall and subscription management for Expo apps",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"prepublishOnly": "yarn clean && yarn build:prod"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@namiml/expo-nami-iap": "3.4.4-dev.
|
|
33
|
-
"@namiml/sdk-core": "3.4.4-dev.
|
|
32
|
+
"@namiml/expo-nami-iap": "3.4.4-dev.202607031905",
|
|
33
|
+
"@namiml/sdk-core": "3.4.4-dev.202607031905",
|
|
34
34
|
"react-native-qrcode-svg": "^6.3.21",
|
|
35
35
|
"react-native-safe-area-context": "^5.6.0",
|
|
36
36
|
"react-native-svg": "^15.15.4"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import React, { useMemo } from 'react';
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
2
|
import { ScrollView, StyleSheet, View } from 'react-native';
|
|
3
|
-
import { applyStyles, parseSize } from '../../utils/styles';
|
|
3
|
+
import { applyStyles, focusedStyleOverrides, parseSize } from '../../utils/styles';
|
|
4
4
|
import { NamiSegmentPickerItem } from './NamiSegmentPickerItem';
|
|
5
|
+
import { FocusScope, useFocusEnabled } from '../../context/FocusContext';
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
8
|
component: any;
|
|
@@ -16,17 +17,28 @@ export const NamiSegmentPicker: React.FC<Props> = ({
|
|
|
16
17
|
onClose,
|
|
17
18
|
parentDirection,
|
|
18
19
|
}) => {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
)
|
|
20
|
+
const focusEnabled = useFocusEnabled();
|
|
21
|
+
|
|
22
|
+
// NAM-1213 CTV: track whether any segment item currently holds remote focus so the
|
|
23
|
+
// whole container can apply its focused visual treatment (focusedFillColor etc.).
|
|
24
|
+
const [isContainerFocused, setIsContainerFocused] = useState(false);
|
|
25
|
+
|
|
26
|
+
const containerStyle = useMemo(() => {
|
|
27
|
+
const base = applyStyles(component, scaleFactor, false, parentDirection);
|
|
28
|
+
// Container focused treatment: apply focusedFillColor/focusedBorder* with fallback
|
|
29
|
+
// to non-focused equivalents (per design doc §2 property-fallback contract).
|
|
30
|
+
if (focusEnabled && isContainerFocused) {
|
|
31
|
+
Object.assign(base, focusedStyleOverrides(component, scaleFactor));
|
|
32
|
+
}
|
|
33
|
+
return base;
|
|
34
|
+
}, [component, scaleFactor, parentDirection, focusEnabled, isContainerFocused]);
|
|
23
35
|
|
|
24
36
|
const direction = component.direction ?? 'horizontal';
|
|
25
37
|
const parentFormId = component.formId ?? component.id ?? '';
|
|
26
38
|
const segments = component.components ?? [];
|
|
27
39
|
const spacing = parseSize(component.spacing, scaleFactor) ?? 0;
|
|
28
40
|
|
|
29
|
-
|
|
41
|
+
const inner = (
|
|
30
42
|
<View style={containerStyle}>
|
|
31
43
|
<ScrollView
|
|
32
44
|
horizontal={direction !== 'vertical'}
|
|
@@ -55,6 +67,18 @@ export const NamiSegmentPicker: React.FC<Props> = ({
|
|
|
55
67
|
</ScrollView>
|
|
56
68
|
</View>
|
|
57
69
|
);
|
|
70
|
+
|
|
71
|
+
// On television form factors, wrap in a FocusScope so we can detect when any child
|
|
72
|
+
// segment item gains remote focus and apply the container's focused visual state.
|
|
73
|
+
if (focusEnabled) {
|
|
74
|
+
return (
|
|
75
|
+
<FocusScope onFocusWithinChange={setIsContainerFocused}>
|
|
76
|
+
{inner}
|
|
77
|
+
</FocusScope>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return inner;
|
|
58
82
|
};
|
|
59
83
|
|
|
60
84
|
const styles = StyleSheet.create({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useRef } from 'react';
|
|
2
|
-
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
2
|
+
import { Platform, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
3
3
|
import { useFirstFocusReadyContext, usePaywallContext } from '../../context/PaywallContext';
|
|
4
4
|
import {
|
|
5
5
|
applyStyles,
|
|
@@ -95,6 +95,15 @@ export const NamiSegmentPickerItem: React.FC<Props> = ({
|
|
|
95
95
|
return base;
|
|
96
96
|
}, [merged, scaleFactor, parentDirection, isFocused]);
|
|
97
97
|
|
|
98
|
+
// NAM-1213 CTV: focused fill overlay. When the remote is on this item, draw an
|
|
99
|
+
// absolute-fill View with focusedFillColor over the active/inactive background —
|
|
100
|
+
// same full-cell geometry as the active fill (design doc §6b fill-rule).
|
|
101
|
+
// Item border when focused defaults to NONE if focusedBorder* are not authored (§2).
|
|
102
|
+
const focusedOverlayColor = useMemo(() => {
|
|
103
|
+
if (!focusEnabled || !isFocused) return null;
|
|
104
|
+
return parseColor(component.focusedFillColor) ?? null;
|
|
105
|
+
}, [focusEnabled, isFocused, component.focusedFillColor]);
|
|
106
|
+
|
|
98
107
|
const onPress = () => {
|
|
99
108
|
if (component.formId && parentFormId) {
|
|
100
109
|
ctx.setFormState(parentFormId, component.formId);
|
|
@@ -143,8 +152,19 @@ export const NamiSegmentPickerItem: React.FC<Props> = ({
|
|
|
143
152
|
onFocus={handleFocus}
|
|
144
153
|
onBlur={onBlur}
|
|
145
154
|
hasTVPreferredFocus={focusEnabled && Boolean(component.focused || component.checked)}
|
|
155
|
+
// Suppress platform default focus ripple/highlight so only our focused overlay shows.
|
|
156
|
+
android_ripple={Platform.isTV ? null : undefined}
|
|
146
157
|
style={({ pressed }) => [styles.item, itemStyle, pressed ? styles.pressed : null]}
|
|
147
158
|
>
|
|
159
|
+
{/* NAM-1213 CTV: focused fill overlay — drawn over the active/inactive background,
|
|
160
|
+
under the text/children, spanning the full cell (same geometry as active fill).
|
|
161
|
+
Only shown when the remote is on this item and focusedFillColor is authored. */}
|
|
162
|
+
{focusedOverlayColor != null && (
|
|
163
|
+
<View
|
|
164
|
+
style={[StyleSheet.absoluteFillObject, { backgroundColor: focusedOverlayColor }]}
|
|
165
|
+
pointerEvents="none"
|
|
166
|
+
/>
|
|
167
|
+
)}
|
|
148
168
|
<FocusedStyleProvider focused={isFocused || isActive}>
|
|
149
169
|
{component.components?.length ? (
|
|
150
170
|
component.components.map((child: TComponent, i: number) => (
|
|
@@ -163,10 +183,21 @@ export const NamiSegmentPickerItem: React.FC<Props> = ({
|
|
|
163
183
|
) : (
|
|
164
184
|
<Text
|
|
165
185
|
style={[
|
|
166
|
-
|
|
167
|
-
|
|
186
|
+
// Base text style uses active/inactive merged props; isFocused=false here
|
|
187
|
+
// so we can apply focused font color separately with correct precedence.
|
|
188
|
+
textStyles(merged, scaleFactor, false),
|
|
189
|
+
// Active font color — overrides base when isActive and not focused.
|
|
190
|
+
!isFocused && isActive && {
|
|
168
191
|
color: parseColor(activeStyles.fontColor ?? activeStyles.textColor ?? component.selectedFontColor) ?? '#fff',
|
|
169
192
|
},
|
|
193
|
+
// NAM-1213 CTV: focused font color wins over active/inactive (design doc §2).
|
|
194
|
+
focusEnabled && isFocused && {
|
|
195
|
+
color: parseColor(component.focusedFontColor)
|
|
196
|
+
?? parseColor(isActive
|
|
197
|
+
? (activeStyles.fontColor ?? activeStyles.textColor ?? component.selectedFontColor)
|
|
198
|
+
: (inactiveStyles.fontColor ?? inactiveStyles.textColor))
|
|
199
|
+
?? undefined,
|
|
200
|
+
},
|
|
170
201
|
]}
|
|
171
202
|
allowFontScaling={false}
|
|
172
203
|
>
|