@xaui/native 0.0.21 → 0.0.24
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/README.md +195 -2
- package/dist/alert/index.js +1 -2
- package/dist/app-bar/index.cjs +217 -0
- package/dist/app-bar/index.d.cts +52 -0
- package/dist/app-bar/index.d.ts +52 -0
- package/dist/app-bar/index.js +142 -0
- package/dist/autocomplete/index.js +48 -36
- package/dist/avatar/index.js +1 -2
- package/dist/badge/index.js +1 -2
- package/dist/bottom-sheet/index.js +1 -2
- package/dist/bottom-tab-bar/index.cjs +571 -0
- package/dist/bottom-tab-bar/index.d.cts +211 -0
- package/dist/bottom-tab-bar/index.d.ts +211 -0
- package/dist/bottom-tab-bar/index.js +497 -0
- package/dist/button/index.d.cts +102 -5
- package/dist/button/index.d.ts +102 -5
- package/dist/button/index.js +2 -3
- package/dist/button.type-j1ZdkkSl.d.cts +4 -0
- package/dist/button.type-j1ZdkkSl.d.ts +4 -0
- package/dist/card/index.cjs +2 -0
- package/dist/card/index.d.cts +6 -1
- package/dist/card/index.d.ts +6 -1
- package/dist/card/index.js +4 -2
- package/dist/carousel/index.js +1 -1
- package/dist/chart/index.cjs +1067 -0
- package/dist/chart/index.d.cts +218 -0
- package/dist/chart/index.d.ts +218 -0
- package/dist/chart/index.js +1026 -0
- package/dist/checkbox/index.js +1 -2
- package/dist/chip/index.js +1 -2
- package/dist/chunk-3XSXTM3G.js +661 -0
- package/dist/chunk-4KSZLONZ.js +79 -0
- package/dist/{chunk-DXXNBF5P.js → chunk-CZFDZPAS.js} +0 -5
- package/dist/{chunk-LTKYHG5V.js → chunk-GHCVNQET.js} +12 -5
- package/dist/chunk-I4V5Y5GD.js +76 -0
- package/dist/{chunk-F7WH4DMG.js → chunk-UI5L26KD.js} +1 -1
- package/dist/{chunk-LUBWRVI2.js → chunk-ULJSCNPE.js} +1 -1
- package/dist/chunk-URBEEDFX.js +79 -0
- package/dist/core/index.js +3 -5
- package/dist/datepicker/index.js +1 -2
- package/dist/divider/index.js +2 -3
- package/dist/drawer/index.cjs +310 -0
- package/dist/drawer/index.d.cts +58 -0
- package/dist/drawer/index.d.ts +58 -0
- package/dist/drawer/index.js +236 -0
- package/dist/{accordion → expansion-panel}/index.cjs +45 -45
- package/dist/{accordion → expansion-panel}/index.d.cts +30 -30
- package/dist/{accordion → expansion-panel}/index.d.ts +30 -30
- package/dist/{accordion → expansion-panel}/index.js +40 -41
- package/dist/fab/index.d.cts +3 -3
- package/dist/fab/index.d.ts +3 -3
- package/dist/fab/index.js +3 -4
- package/dist/fab-menu/index.d.cts +2 -2
- package/dist/fab-menu/index.d.ts +2 -2
- package/dist/fab-menu/index.js +3 -4
- package/dist/{fab.type-Ba0QMprb.d.ts → fab.type-CgIYqQlT.d.ts} +1 -1
- package/dist/{fab.type-U09H8B7D.d.cts → fab.type-l2vjG8-p.d.cts} +1 -1
- package/dist/feature-discovery/index.cjs +531 -0
- package/dist/feature-discovery/index.d.cts +82 -0
- package/dist/feature-discovery/index.d.ts +82 -0
- package/dist/feature-discovery/index.js +464 -0
- package/dist/indicator/index.js +2 -3
- package/dist/input/index.cjs +258 -164
- package/dist/input/index.d.cts +15 -1
- package/dist/input/index.d.ts +15 -1
- package/dist/input/index.js +219 -126
- package/dist/list/index.js +1 -2
- package/dist/menu/index.js +2 -2
- package/dist/menubox/index.cjs +369 -0
- package/dist/menubox/index.d.cts +98 -0
- package/dist/menubox/index.d.ts +98 -0
- package/dist/menubox/index.js +296 -0
- package/dist/pager/index.cjs +243 -0
- package/dist/pager/index.d.cts +93 -0
- package/dist/pager/index.d.ts +93 -0
- package/dist/pager/index.js +205 -0
- package/dist/progress/index.js +1 -2
- package/dist/radio/index.cjs +537 -0
- package/dist/radio/index.d.cts +145 -0
- package/dist/radio/index.d.ts +145 -0
- package/dist/radio/index.js +464 -0
- package/dist/segment-button/index.js +2 -2
- package/dist/select/index.js +22 -10
- package/dist/skeleton/index.js +2 -2
- package/dist/slider/index.cjs +655 -0
- package/dist/slider/index.d.cts +171 -0
- package/dist/slider/index.d.ts +171 -0
- package/dist/slider/index.js +575 -0
- package/dist/stepper/index.cjs +624 -0
- package/dist/stepper/index.d.cts +137 -0
- package/dist/stepper/index.d.ts +137 -0
- package/dist/stepper/index.js +549 -0
- package/dist/switch/index.js +1 -2
- package/dist/tabs/index.cjs +523 -0
- package/dist/tabs/index.d.cts +176 -0
- package/dist/tabs/index.d.ts +176 -0
- package/dist/tabs/index.js +438 -0
- package/dist/timepicker/index.cjs +1280 -0
- package/dist/timepicker/index.d.cts +215 -0
- package/dist/timepicker/index.d.ts +215 -0
- package/dist/timepicker/index.js +1181 -0
- package/dist/toolbar/index.cjs +395 -0
- package/dist/toolbar/index.d.cts +100 -0
- package/dist/toolbar/index.d.ts +100 -0
- package/dist/toolbar/index.js +325 -0
- package/dist/typography/index.js +1 -2
- package/dist/view/index.cjs +16 -2
- package/dist/view/index.js +16 -2
- package/package.json +73 -8
- package/dist/button.type-D8tzEBo7.d.ts +0 -104
- package/dist/button.type-ikaWzhIg.d.cts +0 -104
- package/dist/chunk-GBHQCAKW.js +0 -19
- package/dist/chunk-JEGEPGVU.js +0 -287
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/components/feature-discovery/index.ts
|
|
31
|
+
var feature_discovery_exports = {};
|
|
32
|
+
__export(feature_discovery_exports, {
|
|
33
|
+
FeatureDiscovery: () => FeatureDiscovery
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(feature_discovery_exports);
|
|
36
|
+
|
|
37
|
+
// src/components/feature-discovery/feature-discovery.tsx
|
|
38
|
+
var import_react7 = __toESM(require("react"), 1);
|
|
39
|
+
var import_react_native6 = require("react-native");
|
|
40
|
+
var import_core3 = require("@xaui/core");
|
|
41
|
+
|
|
42
|
+
// src/components/feature-discovery/feature-discovery.style.ts
|
|
43
|
+
var import_react_native = require("react-native");
|
|
44
|
+
var styles = import_react_native.StyleSheet.create({
|
|
45
|
+
root: {
|
|
46
|
+
flex: 1
|
|
47
|
+
},
|
|
48
|
+
absoluteFill: {
|
|
49
|
+
...import_react_native.StyleSheet.absoluteFillObject
|
|
50
|
+
},
|
|
51
|
+
circle: {
|
|
52
|
+
position: "absolute"
|
|
53
|
+
},
|
|
54
|
+
spotlightHalo: {
|
|
55
|
+
position: "absolute",
|
|
56
|
+
borderWidth: 1,
|
|
57
|
+
borderColor: "rgba(255, 255, 255, 0.35)"
|
|
58
|
+
},
|
|
59
|
+
highlightContainer: {
|
|
60
|
+
position: "absolute",
|
|
61
|
+
alignItems: "center",
|
|
62
|
+
justifyContent: "center"
|
|
63
|
+
},
|
|
64
|
+
messageContainer: {
|
|
65
|
+
position: "absolute",
|
|
66
|
+
gap: 10,
|
|
67
|
+
paddingVertical: 16,
|
|
68
|
+
paddingHorizontal: 16,
|
|
69
|
+
borderRadius: 12
|
|
70
|
+
},
|
|
71
|
+
messageHeader: {
|
|
72
|
+
flexDirection: "row",
|
|
73
|
+
alignItems: "flex-start",
|
|
74
|
+
justifyContent: "space-between",
|
|
75
|
+
gap: 8
|
|
76
|
+
},
|
|
77
|
+
messageTitleWrapper: {
|
|
78
|
+
flex: 1
|
|
79
|
+
},
|
|
80
|
+
title: {
|
|
81
|
+
fontSize: 24,
|
|
82
|
+
fontWeight: "700"
|
|
83
|
+
},
|
|
84
|
+
closeButton: {
|
|
85
|
+
padding: 4
|
|
86
|
+
},
|
|
87
|
+
closeIcon: {
|
|
88
|
+
fontSize: 18,
|
|
89
|
+
fontWeight: "600"
|
|
90
|
+
},
|
|
91
|
+
description: {
|
|
92
|
+
fontSize: 16,
|
|
93
|
+
fontWeight: "400",
|
|
94
|
+
opacity: 0.86,
|
|
95
|
+
lineHeight: 22
|
|
96
|
+
},
|
|
97
|
+
actionPressable: {
|
|
98
|
+
alignSelf: "flex-start"
|
|
99
|
+
},
|
|
100
|
+
actionText: {
|
|
101
|
+
fontSize: 14,
|
|
102
|
+
fontWeight: "600",
|
|
103
|
+
textDecorationLine: "underline"
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// src/components/feature-discovery/feature-discovery.hook.ts
|
|
108
|
+
var import_react6 = require("react");
|
|
109
|
+
var import_react_native5 = require("react-native");
|
|
110
|
+
var import_core = require("@xaui/core");
|
|
111
|
+
|
|
112
|
+
// src/core/theme-context.tsx
|
|
113
|
+
var import_react4 = __toESM(require("react"), 1);
|
|
114
|
+
var import_react_native3 = require("react-native");
|
|
115
|
+
var import_theme = require("@xaui/core/theme");
|
|
116
|
+
var import_palette = require("@xaui/core/palette");
|
|
117
|
+
|
|
118
|
+
// src/core/portal/portal.tsx
|
|
119
|
+
var import_react2 = require("react");
|
|
120
|
+
|
|
121
|
+
// src/core/portal/portal-context.ts
|
|
122
|
+
var import_react = require("react");
|
|
123
|
+
var PortalContext = (0, import_react.createContext)(null);
|
|
124
|
+
|
|
125
|
+
// src/core/portal/portal-host.tsx
|
|
126
|
+
var import_react3 = __toESM(require("react"), 1);
|
|
127
|
+
var import_react_native2 = require("react-native");
|
|
128
|
+
var hostStyles = import_react_native2.StyleSheet.create({
|
|
129
|
+
container: {
|
|
130
|
+
flex: 1
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// src/core/theme-context.tsx
|
|
135
|
+
var XUIThemeContext = (0, import_react4.createContext)(null);
|
|
136
|
+
|
|
137
|
+
// src/core/theme-hooks.ts
|
|
138
|
+
var import_react5 = require("react");
|
|
139
|
+
var import_react_native4 = require("react-native");
|
|
140
|
+
function useXUITheme() {
|
|
141
|
+
const theme = (0, import_react5.useContext)(XUIThemeContext);
|
|
142
|
+
if (!theme) {
|
|
143
|
+
throw new Error("useXUITheme must be used within XUIProvider");
|
|
144
|
+
}
|
|
145
|
+
return theme;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// src/core/index.ts
|
|
149
|
+
var import_theme2 = require("@xaui/core/theme");
|
|
150
|
+
|
|
151
|
+
// src/components/feature-discovery/feature-discovery.hook.ts
|
|
152
|
+
var useFeatureDiscoveryAnimations = () => {
|
|
153
|
+
const backdropOpacity = (0, import_react6.useRef)(new import_react_native5.Animated.Value(0)).current;
|
|
154
|
+
const circleAnimScale = (0, import_react6.useRef)(new import_react_native5.Animated.Value(0.2)).current;
|
|
155
|
+
const contentOpacity = (0, import_react6.useRef)(new import_react_native5.Animated.Value(0)).current;
|
|
156
|
+
const haloScale = (0, import_react6.useRef)(new import_react_native5.Animated.Value(0.8)).current;
|
|
157
|
+
const startAnimations = (0, import_react6.useCallback)(() => {
|
|
158
|
+
import_react_native5.Animated.parallel([
|
|
159
|
+
import_react_native5.Animated.timing(backdropOpacity, {
|
|
160
|
+
toValue: 1,
|
|
161
|
+
duration: 220,
|
|
162
|
+
useNativeDriver: true
|
|
163
|
+
}),
|
|
164
|
+
import_react_native5.Animated.spring(circleAnimScale, {
|
|
165
|
+
toValue: 1,
|
|
166
|
+
friction: 8,
|
|
167
|
+
tension: 80,
|
|
168
|
+
useNativeDriver: true
|
|
169
|
+
}),
|
|
170
|
+
import_react_native5.Animated.timing(contentOpacity, {
|
|
171
|
+
toValue: 1,
|
|
172
|
+
duration: 260,
|
|
173
|
+
useNativeDriver: true
|
|
174
|
+
}),
|
|
175
|
+
import_react_native5.Animated.spring(haloScale, {
|
|
176
|
+
toValue: 1,
|
|
177
|
+
friction: 8,
|
|
178
|
+
tension: 80,
|
|
179
|
+
useNativeDriver: true
|
|
180
|
+
})
|
|
181
|
+
]).start();
|
|
182
|
+
}, [backdropOpacity, circleAnimScale, contentOpacity, haloScale]);
|
|
183
|
+
const resetAnimations = (0, import_react6.useCallback)(() => {
|
|
184
|
+
backdropOpacity.setValue(0);
|
|
185
|
+
circleAnimScale.setValue(0.2);
|
|
186
|
+
contentOpacity.setValue(0);
|
|
187
|
+
haloScale.setValue(0.8);
|
|
188
|
+
}, [backdropOpacity, circleAnimScale, contentOpacity, haloScale]);
|
|
189
|
+
return {
|
|
190
|
+
backdropOpacity,
|
|
191
|
+
circleAnimScale,
|
|
192
|
+
contentOpacity,
|
|
193
|
+
haloScale,
|
|
194
|
+
startAnimations,
|
|
195
|
+
resetAnimations
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
var useFeatureDiscoveryLayout = (targetRef) => {
|
|
199
|
+
const { width: viewportWidth, height: viewportHeight } = (0, import_react_native5.useWindowDimensions)();
|
|
200
|
+
const [targetLayout, setTargetLayout] = (0, import_react6.useState)(null);
|
|
201
|
+
const measureTarget = (0, import_react6.useCallback)(() => {
|
|
202
|
+
targetRef.current?.measureInWindow((x, y, width, height) => {
|
|
203
|
+
if (!width && !height) {
|
|
204
|
+
setTargetLayout({
|
|
205
|
+
x: viewportWidth / 2 - 28,
|
|
206
|
+
y: viewportHeight / 2 - 28,
|
|
207
|
+
width: 56,
|
|
208
|
+
height: 56
|
|
209
|
+
});
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
setTargetLayout({ x, y, width, height });
|
|
213
|
+
});
|
|
214
|
+
}, [targetRef, viewportHeight, viewportWidth]);
|
|
215
|
+
const fallbackTarget = (0, import_react6.useMemo)(
|
|
216
|
+
() => ({
|
|
217
|
+
x: viewportWidth / 2 - 28,
|
|
218
|
+
y: viewportHeight / 2 - 28,
|
|
219
|
+
width: 56,
|
|
220
|
+
height: 56
|
|
221
|
+
}),
|
|
222
|
+
[viewportWidth, viewportHeight]
|
|
223
|
+
);
|
|
224
|
+
const target = targetLayout ?? fallbackTarget;
|
|
225
|
+
return {
|
|
226
|
+
targetLayout,
|
|
227
|
+
target,
|
|
228
|
+
measureTarget,
|
|
229
|
+
setTargetLayout,
|
|
230
|
+
viewportWidth,
|
|
231
|
+
viewportHeight
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
var useFeatureDiscoveryGeometry = (target, viewportWidth, viewportHeight, spotlightPadding, circleScale) => {
|
|
235
|
+
const HIGHLIGHT_EDGE_INSET = 16;
|
|
236
|
+
const maxTargetX = Math.max(
|
|
237
|
+
HIGHLIGHT_EDGE_INSET,
|
|
238
|
+
viewportWidth - target.width - HIGHLIGHT_EDGE_INSET
|
|
239
|
+
);
|
|
240
|
+
const maxTargetY = Math.max(
|
|
241
|
+
HIGHLIGHT_EDGE_INSET,
|
|
242
|
+
viewportHeight - target.height - HIGHLIGHT_EDGE_INSET
|
|
243
|
+
);
|
|
244
|
+
const clampedTargetX = Math.min(
|
|
245
|
+
Math.max(target.x, HIGHLIGHT_EDGE_INSET),
|
|
246
|
+
maxTargetX
|
|
247
|
+
);
|
|
248
|
+
const clampedTargetY = Math.min(
|
|
249
|
+
Math.max(target.y, HIGHLIGHT_EDGE_INSET),
|
|
250
|
+
maxTargetY
|
|
251
|
+
);
|
|
252
|
+
const targetCenterX = clampedTargetX + target.width / 2;
|
|
253
|
+
const targetCenterY = clampedTargetY + target.height / 2;
|
|
254
|
+
const spotlightSize = Math.max(target.width, target.height) + spotlightPadding * 2;
|
|
255
|
+
const circleDiameter = (0, import_react6.useMemo)(() => {
|
|
256
|
+
return viewportWidth * circleScale;
|
|
257
|
+
}, [circleScale, viewportWidth]);
|
|
258
|
+
const circleRadius = circleDiameter / 2;
|
|
259
|
+
const TEXT_PADDING = 24;
|
|
260
|
+
const TARGET_GAP = 30;
|
|
261
|
+
const MIN_MESSAGE_HEIGHT = 140;
|
|
262
|
+
const MIN_MESSAGE_WIDTH = 280;
|
|
263
|
+
const MESSAGE_VERTICAL_OFFSET = 14;
|
|
264
|
+
const isTargetInTopHalf = targetCenterY < viewportHeight * 0.55;
|
|
265
|
+
const baseMessageTop = isTargetInTopHalf ? Math.min(viewportHeight - 200, clampedTargetY + target.height + TARGET_GAP) : Math.max(TEXT_PADDING, clampedTargetY - 150);
|
|
266
|
+
const messageTop = Math.max(TEXT_PADDING, baseMessageTop - MESSAGE_VERTICAL_OFFSET);
|
|
267
|
+
const textDy = messageTop - targetCenterY;
|
|
268
|
+
const textHalfChord = Math.abs(textDy) < circleRadius ? Math.sqrt(circleRadius ** 2 - textDy ** 2) : 0;
|
|
269
|
+
const baseMsgLeft = Math.max(
|
|
270
|
+
TEXT_PADDING,
|
|
271
|
+
targetCenterX - textHalfChord + TEXT_PADDING
|
|
272
|
+
);
|
|
273
|
+
const baseMsgRight = Math.max(
|
|
274
|
+
TEXT_PADDING,
|
|
275
|
+
viewportWidth - (targetCenterX + textHalfChord - TEXT_PADDING)
|
|
276
|
+
);
|
|
277
|
+
const baseMsgWidth = viewportWidth - baseMsgLeft - baseMsgRight;
|
|
278
|
+
const clampedMinMessageWidth = Math.min(
|
|
279
|
+
MIN_MESSAGE_WIDTH,
|
|
280
|
+
viewportWidth - TEXT_PADDING * 2
|
|
281
|
+
);
|
|
282
|
+
const isTargetOnLeft = targetCenterX < viewportWidth / 2;
|
|
283
|
+
const shouldUseSideAnchoredLayout = baseMsgWidth < clampedMinMessageWidth;
|
|
284
|
+
const msgLeft = shouldUseSideAnchoredLayout ? isTargetOnLeft ? TEXT_PADDING : viewportWidth - TEXT_PADDING - clampedMinMessageWidth : baseMsgLeft;
|
|
285
|
+
const msgRight = shouldUseSideAnchoredLayout ? isTargetOnLeft ? viewportWidth - TEXT_PADDING - clampedMinMessageWidth : TEXT_PADDING : baseMsgRight;
|
|
286
|
+
const circleBottomY = targetCenterY + circleRadius - TEXT_PADDING;
|
|
287
|
+
const msgMaxHeight = Math.max(MIN_MESSAGE_HEIGHT, circleBottomY - messageTop);
|
|
288
|
+
return {
|
|
289
|
+
targetCenterX,
|
|
290
|
+
targetCenterY,
|
|
291
|
+
spotlightSize,
|
|
292
|
+
circleDiameter,
|
|
293
|
+
circleRadius,
|
|
294
|
+
messageTop,
|
|
295
|
+
msgLeft,
|
|
296
|
+
msgRight,
|
|
297
|
+
msgMaxHeight,
|
|
298
|
+
isTargetOnLeft,
|
|
299
|
+
highlightX: clampedTargetX,
|
|
300
|
+
highlightY: clampedTargetY
|
|
301
|
+
};
|
|
302
|
+
};
|
|
303
|
+
var useFeatureDiscoveryTheme = (themeColor, overlayColor) => {
|
|
304
|
+
const theme = useXUITheme();
|
|
305
|
+
const colorScheme = theme.colors[(0, import_core.getSafeThemeColor)(themeColor)];
|
|
306
|
+
const resolvedOverlayColor = (0, import_react6.useMemo)(
|
|
307
|
+
() => overlayColor ?? (0, import_core.withOpacity)(theme.colors.foreground, 0.42),
|
|
308
|
+
[overlayColor, theme.colors.foreground]
|
|
309
|
+
);
|
|
310
|
+
return {
|
|
311
|
+
colorScheme,
|
|
312
|
+
resolvedOverlayColor
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
// src/components/feature-discovery/feature-discovery.tsx
|
|
317
|
+
var DEFAULT_SPOTLIGHT_PADDING = 14;
|
|
318
|
+
var DEFAULT_CIRCLE_SCALE = 1.65;
|
|
319
|
+
var FeatureDiscovery = ({
|
|
320
|
+
isVisible,
|
|
321
|
+
targetRef,
|
|
322
|
+
title,
|
|
323
|
+
description,
|
|
324
|
+
actionText,
|
|
325
|
+
onActionPress,
|
|
326
|
+
onDismiss,
|
|
327
|
+
dismissOnBackdropPress = true,
|
|
328
|
+
themeColor = "primary",
|
|
329
|
+
overlayColor,
|
|
330
|
+
spotlightPadding = DEFAULT_SPOTLIGHT_PADDING,
|
|
331
|
+
circleScale = DEFAULT_CIRCLE_SCALE,
|
|
332
|
+
highlightContent,
|
|
333
|
+
customAppearance
|
|
334
|
+
}) => {
|
|
335
|
+
const {
|
|
336
|
+
backdropOpacity,
|
|
337
|
+
circleAnimScale,
|
|
338
|
+
contentOpacity,
|
|
339
|
+
haloScale,
|
|
340
|
+
startAnimations,
|
|
341
|
+
resetAnimations
|
|
342
|
+
} = useFeatureDiscoveryAnimations();
|
|
343
|
+
const { target, measureTarget, setTargetLayout, viewportWidth, viewportHeight } = useFeatureDiscoveryLayout(targetRef);
|
|
344
|
+
const {
|
|
345
|
+
targetCenterX,
|
|
346
|
+
targetCenterY,
|
|
347
|
+
spotlightSize,
|
|
348
|
+
circleDiameter,
|
|
349
|
+
messageTop,
|
|
350
|
+
msgLeft,
|
|
351
|
+
msgRight,
|
|
352
|
+
msgMaxHeight,
|
|
353
|
+
isTargetOnLeft,
|
|
354
|
+
highlightX,
|
|
355
|
+
highlightY
|
|
356
|
+
} = useFeatureDiscoveryGeometry(
|
|
357
|
+
target,
|
|
358
|
+
viewportWidth,
|
|
359
|
+
viewportHeight,
|
|
360
|
+
spotlightPadding,
|
|
361
|
+
circleScale
|
|
362
|
+
);
|
|
363
|
+
const { colorScheme, resolvedOverlayColor } = useFeatureDiscoveryTheme(
|
|
364
|
+
themeColor,
|
|
365
|
+
overlayColor
|
|
366
|
+
);
|
|
367
|
+
(0, import_react7.useEffect)(() => {
|
|
368
|
+
if (!isVisible) {
|
|
369
|
+
setTargetLayout(null);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
resetAnimations();
|
|
373
|
+
const timer = setTimeout(() => {
|
|
374
|
+
measureTarget();
|
|
375
|
+
startAnimations();
|
|
376
|
+
}, 0);
|
|
377
|
+
return () => clearTimeout(timer);
|
|
378
|
+
}, [isVisible, measureTarget, resetAnimations, setTargetLayout, startAnimations]);
|
|
379
|
+
if (!isVisible) return null;
|
|
380
|
+
const renderContent = (content, textStyle) => {
|
|
381
|
+
if (typeof content === "string" || typeof content === "number") {
|
|
382
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_react_native6.Text, { style: textStyle }, content);
|
|
383
|
+
}
|
|
384
|
+
return content;
|
|
385
|
+
};
|
|
386
|
+
return /* @__PURE__ */ import_react7.default.createElement(
|
|
387
|
+
import_react_native6.Modal,
|
|
388
|
+
{
|
|
389
|
+
visible: isVisible,
|
|
390
|
+
transparent: true,
|
|
391
|
+
animationType: "none",
|
|
392
|
+
statusBarTranslucent: true,
|
|
393
|
+
onRequestClose: onDismiss
|
|
394
|
+
},
|
|
395
|
+
/* @__PURE__ */ import_react7.default.createElement(
|
|
396
|
+
import_react_native6.View,
|
|
397
|
+
{
|
|
398
|
+
style: [styles.root, customAppearance?.root, customAppearance?.container]
|
|
399
|
+
},
|
|
400
|
+
/* @__PURE__ */ import_react7.default.createElement(
|
|
401
|
+
import_react_native6.Pressable,
|
|
402
|
+
{
|
|
403
|
+
style: styles.absoluteFill,
|
|
404
|
+
onPress: dismissOnBackdropPress ? onDismiss : void 0
|
|
405
|
+
},
|
|
406
|
+
/* @__PURE__ */ import_react7.default.createElement(
|
|
407
|
+
import_react_native6.Animated.View,
|
|
408
|
+
{
|
|
409
|
+
style: [
|
|
410
|
+
styles.absoluteFill,
|
|
411
|
+
{
|
|
412
|
+
backgroundColor: resolvedOverlayColor,
|
|
413
|
+
opacity: backdropOpacity
|
|
414
|
+
}
|
|
415
|
+
]
|
|
416
|
+
}
|
|
417
|
+
)
|
|
418
|
+
),
|
|
419
|
+
/* @__PURE__ */ import_react7.default.createElement(
|
|
420
|
+
import_react_native6.Animated.View,
|
|
421
|
+
{
|
|
422
|
+
style: [
|
|
423
|
+
styles.circle,
|
|
424
|
+
{
|
|
425
|
+
width: circleDiameter,
|
|
426
|
+
height: circleDiameter,
|
|
427
|
+
borderRadius: circleDiameter / 2,
|
|
428
|
+
left: targetCenterX - circleDiameter / 2,
|
|
429
|
+
top: targetCenterY - circleDiameter / 2,
|
|
430
|
+
backgroundColor: colorScheme.main,
|
|
431
|
+
opacity: contentOpacity,
|
|
432
|
+
transform: [{ scale: circleAnimScale }]
|
|
433
|
+
}
|
|
434
|
+
]
|
|
435
|
+
}
|
|
436
|
+
),
|
|
437
|
+
/* @__PURE__ */ import_react7.default.createElement(
|
|
438
|
+
import_react_native6.Animated.View,
|
|
439
|
+
{
|
|
440
|
+
style: [
|
|
441
|
+
styles.spotlightHalo,
|
|
442
|
+
{
|
|
443
|
+
width: spotlightSize,
|
|
444
|
+
height: spotlightSize,
|
|
445
|
+
borderRadius: spotlightSize / 2,
|
|
446
|
+
left: targetCenterX - spotlightSize / 2,
|
|
447
|
+
top: targetCenterY - spotlightSize / 2,
|
|
448
|
+
opacity: contentOpacity,
|
|
449
|
+
transform: [{ scale: haloScale }]
|
|
450
|
+
}
|
|
451
|
+
]
|
|
452
|
+
}
|
|
453
|
+
),
|
|
454
|
+
highlightContent && /* @__PURE__ */ import_react7.default.createElement(
|
|
455
|
+
import_react_native6.Animated.View,
|
|
456
|
+
{
|
|
457
|
+
style: [
|
|
458
|
+
styles.highlightContainer,
|
|
459
|
+
{
|
|
460
|
+
left: highlightX,
|
|
461
|
+
top: highlightY,
|
|
462
|
+
width: target.width,
|
|
463
|
+
height: target.height,
|
|
464
|
+
opacity: contentOpacity
|
|
465
|
+
},
|
|
466
|
+
customAppearance?.highlightContainer
|
|
467
|
+
],
|
|
468
|
+
pointerEvents: "none"
|
|
469
|
+
},
|
|
470
|
+
highlightContent
|
|
471
|
+
),
|
|
472
|
+
/* @__PURE__ */ import_react7.default.createElement(
|
|
473
|
+
import_react_native6.Animated.View,
|
|
474
|
+
{
|
|
475
|
+
style: [
|
|
476
|
+
styles.messageContainer,
|
|
477
|
+
{
|
|
478
|
+
top: messageTop,
|
|
479
|
+
left: msgLeft,
|
|
480
|
+
right: msgRight,
|
|
481
|
+
maxHeight: msgMaxHeight,
|
|
482
|
+
opacity: contentOpacity
|
|
483
|
+
},
|
|
484
|
+
customAppearance?.messageContainer
|
|
485
|
+
],
|
|
486
|
+
pointerEvents: "box-none"
|
|
487
|
+
},
|
|
488
|
+
/* @__PURE__ */ import_react7.default.createElement(import_react_native6.View, { style: styles.messageHeader }, /* @__PURE__ */ import_react7.default.createElement(import_react_native6.View, { style: styles.messageTitleWrapper }, renderContent(title, [
|
|
489
|
+
styles.title,
|
|
490
|
+
{ color: colorScheme.foreground },
|
|
491
|
+
{ textAlign: isTargetOnLeft ? "left" : "right" },
|
|
492
|
+
customAppearance?.title
|
|
493
|
+
])), /* @__PURE__ */ import_react7.default.createElement(
|
|
494
|
+
import_react_native6.Pressable,
|
|
495
|
+
{
|
|
496
|
+
onPress: onDismiss,
|
|
497
|
+
style: styles.closeButton,
|
|
498
|
+
accessibilityRole: "button"
|
|
499
|
+
},
|
|
500
|
+
/* @__PURE__ */ import_react7.default.createElement(import_react_native6.Text, { style: [styles.closeIcon, { color: colorScheme.foreground }] }, "\u2715")
|
|
501
|
+
)),
|
|
502
|
+
description ? renderContent(description, [
|
|
503
|
+
styles.description,
|
|
504
|
+
{ color: (0, import_core3.withOpacity)(colorScheme.foreground, 0.9) },
|
|
505
|
+
{ textAlign: isTargetOnLeft ? "left" : "right" },
|
|
506
|
+
customAppearance?.description
|
|
507
|
+
]) : null,
|
|
508
|
+
actionText ? /* @__PURE__ */ import_react7.default.createElement(
|
|
509
|
+
import_react_native6.Pressable,
|
|
510
|
+
{
|
|
511
|
+
onPress: onActionPress,
|
|
512
|
+
style: [
|
|
513
|
+
styles.actionPressable,
|
|
514
|
+
{ alignSelf: isTargetOnLeft ? "flex-start" : "flex-end" }
|
|
515
|
+
],
|
|
516
|
+
accessibilityRole: "button"
|
|
517
|
+
},
|
|
518
|
+
renderContent(actionText, [
|
|
519
|
+
styles.actionText,
|
|
520
|
+
{ color: colorScheme.foreground },
|
|
521
|
+
customAppearance?.actionText
|
|
522
|
+
])
|
|
523
|
+
) : null
|
|
524
|
+
)
|
|
525
|
+
)
|
|
526
|
+
);
|
|
527
|
+
};
|
|
528
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
529
|
+
0 && (module.exports = {
|
|
530
|
+
FeatureDiscovery
|
|
531
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React, { RefObject, ReactNode } from 'react';
|
|
2
|
+
import { ViewStyle, TextStyle } from 'react-native';
|
|
3
|
+
import { T as ThemeColor } from '../index-BOw6tbkc.cjs';
|
|
4
|
+
|
|
5
|
+
type MeasurableNode = {
|
|
6
|
+
measureInWindow: (callback: (x: number, y: number, width: number, height: number) => void) => void;
|
|
7
|
+
};
|
|
8
|
+
type FeatureDiscoveryCustomAppearance = {
|
|
9
|
+
root?: ViewStyle;
|
|
10
|
+
container?: ViewStyle;
|
|
11
|
+
title?: TextStyle;
|
|
12
|
+
description?: TextStyle;
|
|
13
|
+
actionText?: TextStyle;
|
|
14
|
+
highlightContainer?: ViewStyle;
|
|
15
|
+
messageContainer?: ViewStyle;
|
|
16
|
+
};
|
|
17
|
+
type FeatureDiscoveryProps = {
|
|
18
|
+
/**
|
|
19
|
+
* Whether the discovery overlay is visible.
|
|
20
|
+
*/
|
|
21
|
+
isVisible: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Ref to the target element to highlight.
|
|
24
|
+
*/
|
|
25
|
+
targetRef: RefObject<MeasurableNode | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Discovery title.
|
|
28
|
+
*/
|
|
29
|
+
title: ReactNode;
|
|
30
|
+
/**
|
|
31
|
+
* Optional discovery description.
|
|
32
|
+
*/
|
|
33
|
+
description?: ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* Optional action label displayed under the text.
|
|
36
|
+
*/
|
|
37
|
+
actionText?: ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* Called when action text is pressed.
|
|
40
|
+
*/
|
|
41
|
+
onActionPress?: () => void;
|
|
42
|
+
/**
|
|
43
|
+
* Called when overlay should close.
|
|
44
|
+
*/
|
|
45
|
+
onDismiss?: () => void;
|
|
46
|
+
/**
|
|
47
|
+
* Whether tapping outside dismisses the overlay.
|
|
48
|
+
* @default true
|
|
49
|
+
*/
|
|
50
|
+
dismissOnBackdropPress?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Accent color for the discovery circle.
|
|
53
|
+
* @default 'primary'
|
|
54
|
+
*/
|
|
55
|
+
themeColor?: ThemeColor;
|
|
56
|
+
/**
|
|
57
|
+
* Backdrop color.
|
|
58
|
+
*/
|
|
59
|
+
overlayColor?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Extra spacing around target highlight.
|
|
62
|
+
* @default 14
|
|
63
|
+
*/
|
|
64
|
+
spotlightPadding?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Scale multiplier for discovery circle diameter.
|
|
67
|
+
* @default 1.65
|
|
68
|
+
*/
|
|
69
|
+
circleScale?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Optional custom content rendered over the highlighted target.
|
|
72
|
+
*/
|
|
73
|
+
highlightContent?: ReactNode;
|
|
74
|
+
/**
|
|
75
|
+
* Optional style overrides.
|
|
76
|
+
*/
|
|
77
|
+
customAppearance?: FeatureDiscoveryCustomAppearance;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
declare const FeatureDiscovery: React.FC<FeatureDiscoveryProps>;
|
|
81
|
+
|
|
82
|
+
export { FeatureDiscovery, type FeatureDiscoveryCustomAppearance, type FeatureDiscoveryProps };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React, { RefObject, ReactNode } from 'react';
|
|
2
|
+
import { ViewStyle, TextStyle } from 'react-native';
|
|
3
|
+
import { T as ThemeColor } from '../index-BOw6tbkc.js';
|
|
4
|
+
|
|
5
|
+
type MeasurableNode = {
|
|
6
|
+
measureInWindow: (callback: (x: number, y: number, width: number, height: number) => void) => void;
|
|
7
|
+
};
|
|
8
|
+
type FeatureDiscoveryCustomAppearance = {
|
|
9
|
+
root?: ViewStyle;
|
|
10
|
+
container?: ViewStyle;
|
|
11
|
+
title?: TextStyle;
|
|
12
|
+
description?: TextStyle;
|
|
13
|
+
actionText?: TextStyle;
|
|
14
|
+
highlightContainer?: ViewStyle;
|
|
15
|
+
messageContainer?: ViewStyle;
|
|
16
|
+
};
|
|
17
|
+
type FeatureDiscoveryProps = {
|
|
18
|
+
/**
|
|
19
|
+
* Whether the discovery overlay is visible.
|
|
20
|
+
*/
|
|
21
|
+
isVisible: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Ref to the target element to highlight.
|
|
24
|
+
*/
|
|
25
|
+
targetRef: RefObject<MeasurableNode | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Discovery title.
|
|
28
|
+
*/
|
|
29
|
+
title: ReactNode;
|
|
30
|
+
/**
|
|
31
|
+
* Optional discovery description.
|
|
32
|
+
*/
|
|
33
|
+
description?: ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* Optional action label displayed under the text.
|
|
36
|
+
*/
|
|
37
|
+
actionText?: ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* Called when action text is pressed.
|
|
40
|
+
*/
|
|
41
|
+
onActionPress?: () => void;
|
|
42
|
+
/**
|
|
43
|
+
* Called when overlay should close.
|
|
44
|
+
*/
|
|
45
|
+
onDismiss?: () => void;
|
|
46
|
+
/**
|
|
47
|
+
* Whether tapping outside dismisses the overlay.
|
|
48
|
+
* @default true
|
|
49
|
+
*/
|
|
50
|
+
dismissOnBackdropPress?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Accent color for the discovery circle.
|
|
53
|
+
* @default 'primary'
|
|
54
|
+
*/
|
|
55
|
+
themeColor?: ThemeColor;
|
|
56
|
+
/**
|
|
57
|
+
* Backdrop color.
|
|
58
|
+
*/
|
|
59
|
+
overlayColor?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Extra spacing around target highlight.
|
|
62
|
+
* @default 14
|
|
63
|
+
*/
|
|
64
|
+
spotlightPadding?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Scale multiplier for discovery circle diameter.
|
|
67
|
+
* @default 1.65
|
|
68
|
+
*/
|
|
69
|
+
circleScale?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Optional custom content rendered over the highlighted target.
|
|
72
|
+
*/
|
|
73
|
+
highlightContent?: ReactNode;
|
|
74
|
+
/**
|
|
75
|
+
* Optional style overrides.
|
|
76
|
+
*/
|
|
77
|
+
customAppearance?: FeatureDiscoveryCustomAppearance;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
declare const FeatureDiscovery: React.FC<FeatureDiscoveryProps>;
|
|
81
|
+
|
|
82
|
+
export { FeatureDiscovery, type FeatureDiscoveryCustomAppearance, type FeatureDiscoveryProps };
|