@guidelytech/react-native 0.6.2 → 0.8.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/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/index.cjs +688 -425
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -3
- package/dist/index.d.ts +83 -3
- package/dist/index.js +533 -282
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -23,15 +23,21 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
23
23
|
var index_exports = {};
|
|
24
24
|
__export(index_exports, {
|
|
25
25
|
DEFAULT_API_URL: () => DEFAULT_API_URL,
|
|
26
|
+
Feature: () => Feature,
|
|
27
|
+
FeatureFlag: () => FeatureFlag,
|
|
28
|
+
FeatureValue: () => FeatureValue,
|
|
29
|
+
FlagsProvider: () => FlagsProvider,
|
|
26
30
|
GuidelyClient: () => GuidelyClient,
|
|
27
31
|
GuidelyOverlay: () => GuidelyOverlay,
|
|
28
32
|
GuidelyProvider: () => GuidelyProvider,
|
|
29
33
|
GuidelyScreenScope: () => GuidelyScreenScope,
|
|
30
34
|
GuidelyTarget: () => GuidelyTarget,
|
|
35
|
+
InMemoryStickyBucketStore: () => import_flags6.InMemoryStickyBucketStore,
|
|
31
36
|
Messenger: () => Messenger,
|
|
32
37
|
SDK_NAME: () => SDK_NAME,
|
|
33
38
|
SDK_VERSION: () => SDK_VERSION,
|
|
34
39
|
TargetRegistry: () => TargetRegistry,
|
|
40
|
+
createFlagsClient: () => import_flags6.createFlagsClient,
|
|
35
41
|
createSseParser: () => createSseParser,
|
|
36
42
|
guidelyScreenLayout: () => guidelyScreenLayout,
|
|
37
43
|
htmlToText: () => htmlToText,
|
|
@@ -41,6 +47,12 @@ __export(index_exports, {
|
|
|
41
47
|
targetIdsFor: () => targetIdsFor,
|
|
42
48
|
useActiveGuide: () => useActiveGuide,
|
|
43
49
|
useChecklistProgress: () => useChecklistProgress,
|
|
50
|
+
useFeatureValue: () => useFeatureValue,
|
|
51
|
+
useFlag: () => useFlag,
|
|
52
|
+
useFlagDetails: () => useFlagDetails,
|
|
53
|
+
useFlags: () => useFlags,
|
|
54
|
+
useFlagsClient: () => useFlagsClient,
|
|
55
|
+
useFlagsReady: () => useFlagsReady,
|
|
44
56
|
useGuideState: () => useGuideState,
|
|
45
57
|
useGuidely: () => useGuidely,
|
|
46
58
|
useGuidelyEvent: () => useGuidelyEvent,
|
|
@@ -51,8 +63,98 @@ __export(index_exports, {
|
|
|
51
63
|
useGuidelyTarget: () => useGuidelyTarget
|
|
52
64
|
});
|
|
53
65
|
module.exports = __toCommonJS(index_exports);
|
|
54
|
-
var
|
|
55
|
-
var
|
|
66
|
+
var import_react9 = require("react");
|
|
67
|
+
var import_react_native12 = require("react-native");
|
|
68
|
+
var import_flags3 = require("@guidelytech/flags");
|
|
69
|
+
|
|
70
|
+
// src/flags.tsx
|
|
71
|
+
var import_flags = require("@guidelytech/flags");
|
|
72
|
+
var import_react = require("react");
|
|
73
|
+
var import_react_native = require("react-native");
|
|
74
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
75
|
+
var FlagsContext = (0, import_react.createContext)(null);
|
|
76
|
+
var EMPTY = (0, import_flags.createStaticFlags)();
|
|
77
|
+
function useFlagsValue(select) {
|
|
78
|
+
const src = (0, import_react.useContext)(FlagsContext);
|
|
79
|
+
const reader = src?.client ?? src?.bootstrap ?? EMPTY;
|
|
80
|
+
const cache = (0, import_react.useRef)(null);
|
|
81
|
+
const get = () => {
|
|
82
|
+
const value = select(reader);
|
|
83
|
+
const c = cache.current;
|
|
84
|
+
if (c && c.reader === reader && (0, import_flags.jsonEquals)(c.value, value)) return c.value;
|
|
85
|
+
cache.current = { reader, value };
|
|
86
|
+
return value;
|
|
87
|
+
};
|
|
88
|
+
return (0, import_react.useSyncExternalStore)(reader.subscribe, get, get);
|
|
89
|
+
}
|
|
90
|
+
function useFlag(key, fallback = false) {
|
|
91
|
+
return useFlagsValue((r) => r.isEnabled(key, fallback));
|
|
92
|
+
}
|
|
93
|
+
function useFeatureValue(key, fallback) {
|
|
94
|
+
return useFlagsValue((r) => r.getValue(key, fallback));
|
|
95
|
+
}
|
|
96
|
+
function useFlagDetails(key, fallback) {
|
|
97
|
+
return useFlagsValue((r) => r.getDetails(key, fallback));
|
|
98
|
+
}
|
|
99
|
+
function useFlags() {
|
|
100
|
+
return useFlagsValue((r) => r.getAll());
|
|
101
|
+
}
|
|
102
|
+
function useFlagsReady() {
|
|
103
|
+
return useFlagsValue((r) => r.isReady());
|
|
104
|
+
}
|
|
105
|
+
function useFlagsClient() {
|
|
106
|
+
return (0, import_react.useContext)(FlagsContext)?.client ?? null;
|
|
107
|
+
}
|
|
108
|
+
function Feature({ flag, children, fallback = null }) {
|
|
109
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: useFlag(flag) ? children : fallback });
|
|
110
|
+
}
|
|
111
|
+
var FeatureFlag = Feature;
|
|
112
|
+
function FeatureValue({ flag, value, children, fallback = null }) {
|
|
113
|
+
const current = useFeatureValue(flag, null);
|
|
114
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: (0, import_flags.jsonEquals)(current, value) ? children : fallback });
|
|
115
|
+
}
|
|
116
|
+
function useBootstrap(payload, attributes) {
|
|
117
|
+
const key = (0, import_flags.stableStringify)(attributes);
|
|
118
|
+
return (0, import_react.useMemo)(() => payload ? (0, import_flags.createStaticFlags)({ payload, attributes }) : EMPTY, [payload, key]);
|
|
119
|
+
}
|
|
120
|
+
function FlagsProvider({ children, client: external, payload, ...options }) {
|
|
121
|
+
const [created, setCreated] = (0, import_react.useState)(null);
|
|
122
|
+
const optionsRef = (0, import_react.useRef)(options);
|
|
123
|
+
optionsRef.current = options;
|
|
124
|
+
const payloadRef = (0, import_react.useRef)(payload);
|
|
125
|
+
payloadRef.current = payload;
|
|
126
|
+
const sdkKey = options.sdkKey ?? options.projectId;
|
|
127
|
+
const { apiUrl, environment } = options;
|
|
128
|
+
(0, import_react.useEffect)(() => {
|
|
129
|
+
if (external || !sdkKey) return;
|
|
130
|
+
let c;
|
|
131
|
+
try {
|
|
132
|
+
c = (0, import_flags.createFlagsClient)({ ...optionsRef.current, sdkKey, payload: payloadRef.current ?? void 0 });
|
|
133
|
+
} catch (err) {
|
|
134
|
+
optionsRef.current.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
setCreated(c);
|
|
138
|
+
const sub = import_react_native.AppState.addEventListener("change", (s) => {
|
|
139
|
+
if (s === "active") void c.refresh();
|
|
140
|
+
else if (s === "background") void c.flush();
|
|
141
|
+
});
|
|
142
|
+
return () => {
|
|
143
|
+
sub.remove();
|
|
144
|
+
c.destroy();
|
|
145
|
+
setCreated((cur) => cur === c ? null : cur);
|
|
146
|
+
};
|
|
147
|
+
}, [external, sdkKey, apiUrl, environment]);
|
|
148
|
+
const client = external ?? created;
|
|
149
|
+
const attributes = options.attributes ?? {};
|
|
150
|
+
const attrsKey = (0, import_flags.stableStringify)(attributes);
|
|
151
|
+
(0, import_react.useEffect)(() => {
|
|
152
|
+
if (client && options.attributes) client.setAttributes(options.attributes);
|
|
153
|
+
}, [client, attrsKey]);
|
|
154
|
+
const bootstrap = useBootstrap(payload, attributes);
|
|
155
|
+
const value = (0, import_react.useMemo)(() => ({ client, bootstrap }), [client, bootstrap]);
|
|
156
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FlagsContext.Provider, { value, children });
|
|
157
|
+
}
|
|
56
158
|
|
|
57
159
|
// ../shared/dist/chunk-OLWGMDRX.js
|
|
58
160
|
function fnv1a(input) {
|
|
@@ -882,6 +984,9 @@ function isWithinSchedule(guide, now = Date.now()) {
|
|
|
882
984
|
return true;
|
|
883
985
|
}
|
|
884
986
|
|
|
987
|
+
// src/core/client.ts
|
|
988
|
+
var import_flags2 = require("@guidelytech/flags");
|
|
989
|
+
|
|
885
990
|
// src/core/targets.ts
|
|
886
991
|
var TargetTimeoutError = class extends Error {
|
|
887
992
|
constructor(ids) {
|
|
@@ -1777,7 +1882,7 @@ var PersistentStore = class {
|
|
|
1777
1882
|
|
|
1778
1883
|
// src/core/client.ts
|
|
1779
1884
|
var SDK_NAME = "@guidelytech/react-native";
|
|
1780
|
-
var SDK_VERSION = "0.
|
|
1885
|
+
var SDK_VERSION = "0.8.0";
|
|
1781
1886
|
var DEFAULT_API_URL = "https://guidelytech.com";
|
|
1782
1887
|
var PAGE_SCOPED = /* @__PURE__ */ new Set(["page_load", "url_match", "element_click", "element_visible", "delay"]);
|
|
1783
1888
|
var nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1824,6 +1929,10 @@ var GuidelyClient = class {
|
|
|
1824
1929
|
__publicField(this, "messenger", null);
|
|
1825
1930
|
__publicField(this, "ui", { steps: [], checklists: [], survey: null, resourceCenterOpen: false, theme: {}, messenger: false });
|
|
1826
1931
|
__publicField(this, "uiListeners", /* @__PURE__ */ new Set());
|
|
1932
|
+
/** Feature flags for this environment: `guidely.flags.isEnabled("new-checkout")`. */
|
|
1933
|
+
__publicField(this, "flags");
|
|
1934
|
+
/** Experiments already reported this session (`experiment_viewed` is sent once per session). */
|
|
1935
|
+
__publicField(this, "exposures", /* @__PURE__ */ new Set());
|
|
1827
1936
|
__publicField(this, "customListeners", /* @__PURE__ */ new Map());
|
|
1828
1937
|
__publicField(this, "eventBus", {
|
|
1829
1938
|
on: (name, cb) => {
|
|
@@ -1852,6 +1961,40 @@ var GuidelyClient = class {
|
|
|
1852
1961
|
this.store = new PersistentStore(options.storage ?? null, (err) => this.log("storage error", err));
|
|
1853
1962
|
if (!options.storage) this.log("no `storage` passed: identity and guide history last only for this app session. Pass AsyncStorage to persist them.");
|
|
1854
1963
|
this.cleanups.push(this.targets.onTap((id) => this.handleTap(id)));
|
|
1964
|
+
if (options.user) this.user = { ...options.user };
|
|
1965
|
+
this.flags = this.createFlags(options.flags);
|
|
1966
|
+
}
|
|
1967
|
+
createFlags(opts) {
|
|
1968
|
+
const base = { sdkKey: this.options.projectId, apiUrl: this.options.apiUrl, fetch: this.options.fetch, sdk: { name: SDK_NAME, version: SDK_VERSION } };
|
|
1969
|
+
if (opts === false) return (0, import_flags2.createFlagsClient)({ ...base, overrideBehaviour: "localOnly", offline: true, reportUsage: false, trackExposures: false, storage: false, logger: null });
|
|
1970
|
+
const o = opts ?? {};
|
|
1971
|
+
return (0, import_flags2.createFlagsClient)({
|
|
1972
|
+
...base,
|
|
1973
|
+
storage: this.options.storage ?? false,
|
|
1974
|
+
reportUsage: this.options.analytics,
|
|
1975
|
+
// Failures surface through onError (and `debug` logs); development warnings (unknown flag keys) reach the console.
|
|
1976
|
+
logger: { warn: (...a) => console.warn("[Guidely]", ...a), error: (...a) => this.log(...a) },
|
|
1977
|
+
...o,
|
|
1978
|
+
contextAttributes: this.flagContext(),
|
|
1979
|
+
// Exposures travel through the event pipeline (with the session) as `experiment_viewed`.
|
|
1980
|
+
trackExposures: false,
|
|
1981
|
+
onFlagEvaluated: (result) => {
|
|
1982
|
+
this.trackExposure(result);
|
|
1983
|
+
o.onFlagEvaluated?.(result);
|
|
1984
|
+
},
|
|
1985
|
+
onReady: () => {
|
|
1986
|
+
this.emitter.emit("flags:ready");
|
|
1987
|
+
o.onReady?.();
|
|
1988
|
+
},
|
|
1989
|
+
onChange: (data) => {
|
|
1990
|
+
this.emitter.emit("flags:change");
|
|
1991
|
+
o.onChange?.(data);
|
|
1992
|
+
},
|
|
1993
|
+
onError: (err) => {
|
|
1994
|
+
this.reportError(err);
|
|
1995
|
+
o.onError?.(err);
|
|
1996
|
+
}
|
|
1997
|
+
});
|
|
1855
1998
|
}
|
|
1856
1999
|
// ---------------------------------------------------------------------------
|
|
1857
2000
|
// Lifecycle
|
|
@@ -1882,6 +2025,7 @@ var GuidelyClient = class {
|
|
|
1882
2025
|
this.session = saved?.id && !this.sessionExpired(Date.parse(saved.lastActiveAt)) ? saved : newSession();
|
|
1883
2026
|
this.persistSession();
|
|
1884
2027
|
this.lastAudiences = new Set(this.state.audienceIds);
|
|
2028
|
+
this.syncFlagAttributes();
|
|
1885
2029
|
this.queue = new EventQueue({
|
|
1886
2030
|
store: this.store,
|
|
1887
2031
|
storageKey: KEYS.queue(key),
|
|
@@ -1971,6 +2115,7 @@ var GuidelyClient = class {
|
|
|
1971
2115
|
this.persistSession();
|
|
1972
2116
|
void this.queue?.flush();
|
|
1973
2117
|
void this.store.flush();
|
|
2118
|
+
void this.flags.flush();
|
|
1974
2119
|
this.messenger?.setForeground(false);
|
|
1975
2120
|
} else if (state === "active" && this.backgroundedAt !== null) {
|
|
1976
2121
|
this.messenger?.setForeground(true);
|
|
@@ -1981,6 +2126,7 @@ var GuidelyClient = class {
|
|
|
1981
2126
|
this.persistSession();
|
|
1982
2127
|
this.firedDelays.clear();
|
|
1983
2128
|
}
|
|
2129
|
+
void this.flags.refresh();
|
|
1984
2130
|
if (Date.now() - this.configFetchedAt > this.options.configRefreshMs) void this.refresh();
|
|
1985
2131
|
else if (this.isReady) this.evaluate("ready");
|
|
1986
2132
|
}
|
|
@@ -2007,6 +2153,7 @@ var GuidelyClient = class {
|
|
|
2007
2153
|
this.cleanups.splice(0).forEach((fn) => fn());
|
|
2008
2154
|
void this.queue?.flush();
|
|
2009
2155
|
this.queue?.destroy();
|
|
2156
|
+
this.flags.destroy();
|
|
2010
2157
|
this.emitter.clear();
|
|
2011
2158
|
this.uiListeners.clear();
|
|
2012
2159
|
}
|
|
@@ -2021,6 +2168,7 @@ var GuidelyClient = class {
|
|
|
2021
2168
|
const same = this.user?.id === id;
|
|
2022
2169
|
this.user = { id, traits: { ...same ? this.user?.traits : {}, ...traits || {} }, account: account ?? (same ? this.user?.account : void 0) };
|
|
2023
2170
|
writeJson(this.store, KEYS.user(this.options.projectId), this.user);
|
|
2171
|
+
this.syncFlagAttributes();
|
|
2024
2172
|
this.enqueue("identify", { properties: { traits: sanitizeProperties(this.user.traits) } });
|
|
2025
2173
|
void this.syncIdentify().then(() => {
|
|
2026
2174
|
this.emitter.emit("identify", { userId: id, anonymousId: this.anonymousId });
|
|
@@ -2064,6 +2212,7 @@ var GuidelyClient = class {
|
|
|
2064
2212
|
};
|
|
2065
2213
|
if (data.firstSeenAt && Date.now() - Date.parse(data.firstSeenAt) > 6e4) this.firstVisit = false;
|
|
2066
2214
|
this.persistState();
|
|
2215
|
+
this.syncFlagAttributes();
|
|
2067
2216
|
this.notify();
|
|
2068
2217
|
}
|
|
2069
2218
|
/** Sets or replaces the account (company / organisation) for the current user. */
|
|
@@ -2072,6 +2221,7 @@ var GuidelyClient = class {
|
|
|
2072
2221
|
if (!this.user?.id) {
|
|
2073
2222
|
this.user = { id: "", traits: this.user?.traits, account };
|
|
2074
2223
|
writeJson(this.store, KEYS.user(this.options.projectId), this.user);
|
|
2224
|
+
this.syncFlagAttributes();
|
|
2075
2225
|
return;
|
|
2076
2226
|
}
|
|
2077
2227
|
await this.identify(this.user.id, void 0, account);
|
|
@@ -2081,6 +2231,7 @@ var GuidelyClient = class {
|
|
|
2081
2231
|
await this.init();
|
|
2082
2232
|
if (!this.user?.id) {
|
|
2083
2233
|
this.user = { id: "", traits: { ...this.user?.traits || {}, ...traits }, account: this.user?.account };
|
|
2234
|
+
this.syncFlagAttributes();
|
|
2084
2235
|
return;
|
|
2085
2236
|
}
|
|
2086
2237
|
await this.identify(this.user.id, traits, this.user.account);
|
|
@@ -2108,6 +2259,8 @@ var GuidelyClient = class {
|
|
|
2108
2259
|
this.lastAudiences = /* @__PURE__ */ new Set();
|
|
2109
2260
|
this.firedDelays.clear();
|
|
2110
2261
|
this.firstVisit = true;
|
|
2262
|
+
this.exposures.clear();
|
|
2263
|
+
this.syncFlagAttributes();
|
|
2111
2264
|
this.emitter.emit("identify", { userId: null, anonymousId: this.anonymousId });
|
|
2112
2265
|
this.notify();
|
|
2113
2266
|
if (this.isReady) this.evaluate("identify");
|
|
@@ -2181,6 +2334,7 @@ var GuidelyClient = class {
|
|
|
2181
2334
|
const changed = name !== this.screenName;
|
|
2182
2335
|
this.screenName = name;
|
|
2183
2336
|
this.targets.setScreen(name);
|
|
2337
|
+
if (changed) this.syncFlagAttributes();
|
|
2184
2338
|
const url = this.currentUrl();
|
|
2185
2339
|
if (changed) this.enqueue("page_view", { properties: { ...properties, path: url, screen: name } });
|
|
2186
2340
|
this.completeChecklistTasksBy("url_visited", url);
|
|
@@ -2851,6 +3005,58 @@ var GuidelyClient = class {
|
|
|
2851
3005
|
showNewMessage(text) {
|
|
2852
3006
|
this.whenHydrated(() => this.messenger?.showNewMessage(text));
|
|
2853
3007
|
}
|
|
3008
|
+
// ---------------------------------------------------------------------------
|
|
3009
|
+
// Feature flags
|
|
3010
|
+
// ---------------------------------------------------------------------------
|
|
3011
|
+
/** Boolean flag value for the current user; `fallback` (default `false`) until loaded or when missing. */
|
|
3012
|
+
isFeatureEnabled(key, fallback = false) {
|
|
3013
|
+
return this.flags.isEnabled(key, fallback);
|
|
3014
|
+
}
|
|
3015
|
+
/** Flag value for the current user; `fallback` when missing or of a different type. */
|
|
3016
|
+
getFeatureValue(key, fallback) {
|
|
3017
|
+
return this.flags.getValue(key, fallback);
|
|
3018
|
+
}
|
|
3019
|
+
/** Flag value plus why it was served (reason, rule, variation, experiment). */
|
|
3020
|
+
getFeatureDetails(key, fallback) {
|
|
3021
|
+
return this.flags.getDetails(key, fallback);
|
|
3022
|
+
}
|
|
3023
|
+
/** Calls `cb` whenever flag values may have changed. Returns an unsubscribe function. */
|
|
3024
|
+
onFlagsChange(cb) {
|
|
3025
|
+
return this.flags.subscribe(cb);
|
|
3026
|
+
}
|
|
3027
|
+
/** Attributes flags are evaluated with: identity, traits, account, audiences, screen and device. */
|
|
3028
|
+
flagContext() {
|
|
3029
|
+
const d = this.bridge.device;
|
|
3030
|
+
const account = this.user?.account;
|
|
3031
|
+
return {
|
|
3032
|
+
platform: d.platform,
|
|
3033
|
+
deviceType: d.deviceType,
|
|
3034
|
+
locale: d.locale,
|
|
3035
|
+
appVersion: this.options.appVersion ?? d.appVersion,
|
|
3036
|
+
environment: this.options.environment,
|
|
3037
|
+
...this.screenName ? { screen: this.screenName, path: this.currentUrl() } : {},
|
|
3038
|
+
...this.user?.traits ?? {},
|
|
3039
|
+
id: this.user?.id || this.anonymousId || void 0,
|
|
3040
|
+
anonymousId: this.anonymousId || void 0,
|
|
3041
|
+
account: account ? { ...account.traits ?? {}, id: account.id } : void 0,
|
|
3042
|
+
$audiences: [...this.state.audienceIds]
|
|
3043
|
+
};
|
|
3044
|
+
}
|
|
3045
|
+
syncFlagAttributes() {
|
|
3046
|
+
if (!this.destroyed) this.flags?.setContextAttributes(this.flagContext());
|
|
3047
|
+
}
|
|
3048
|
+
/** `experiment_viewed`, once per session and assignment, through the event queue (consent applies). */
|
|
3049
|
+
trackExposure(result) {
|
|
3050
|
+
const exp = result.inExperiment ? result.experiment : void 0;
|
|
3051
|
+
if (!exp || this.destroyed) return;
|
|
3052
|
+
this.whenHydrated(() => {
|
|
3053
|
+
const key = `${this.session.id}|${exp.key}|${exp.hashValue}|${exp.variationId}`;
|
|
3054
|
+
if (this.exposures.has(key)) return;
|
|
3055
|
+
if (this.exposures.size > 500) this.exposures.clear();
|
|
3056
|
+
this.exposures.add(key);
|
|
3057
|
+
this.enqueue("experiment_viewed", { properties: { experimentKey: exp.key, variationId: exp.variationId, flagKey: result.key, hashAttribute: exp.hashAttribute, ...exp.variationName ? { variationName: exp.variationName } : {} } });
|
|
3058
|
+
});
|
|
3059
|
+
}
|
|
2854
3060
|
on(event, cb) {
|
|
2855
3061
|
return this.emitter.on(event, cb);
|
|
2856
3062
|
}
|
|
@@ -2879,7 +3085,8 @@ var GuidelyClient = class {
|
|
|
2879
3085
|
audienceIds: this.state.audienceIds,
|
|
2880
3086
|
session: this.session,
|
|
2881
3087
|
pendingEvents: this.queue?.size ?? 0,
|
|
2882
|
-
targets: this.targets.ids()
|
|
3088
|
+
targets: this.targets.ids(),
|
|
3089
|
+
flagsReady: this.flags.isReady()
|
|
2883
3090
|
};
|
|
2884
3091
|
}
|
|
2885
3092
|
// ---------------------------------------------------------------------------
|
|
@@ -2910,20 +3117,20 @@ function forPlatform(config, platform) {
|
|
|
2910
3117
|
}
|
|
2911
3118
|
|
|
2912
3119
|
// src/ui/Overlay.tsx
|
|
2913
|
-
var
|
|
2914
|
-
var
|
|
3120
|
+
var import_react7 = require("react");
|
|
3121
|
+
var import_react_native10 = require("react-native");
|
|
2915
3122
|
|
|
2916
3123
|
// src/ui/Checklist.tsx
|
|
2917
|
-
var
|
|
3124
|
+
var import_react_native4 = require("react-native");
|
|
2918
3125
|
|
|
2919
3126
|
// src/ui/primitives.tsx
|
|
2920
|
-
var
|
|
2921
|
-
var
|
|
3127
|
+
var import_react_native2 = require("react-native");
|
|
3128
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2922
3129
|
function GButton({ label, variant = "primary", onPress, palette: p, style, accessibilityHint, disabled }) {
|
|
2923
3130
|
const filled = variant === "primary";
|
|
2924
3131
|
const outlined = variant === "secondary";
|
|
2925
|
-
return /* @__PURE__ */ (0,
|
|
2926
|
-
|
|
3132
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
3133
|
+
import_react_native2.Pressable,
|
|
2927
3134
|
{
|
|
2928
3135
|
accessibilityRole: "button",
|
|
2929
3136
|
accessibilityLabel: label,
|
|
@@ -2940,17 +3147,17 @@ function GButton({ label, variant = "primary", onPress, palette: p, style, acces
|
|
|
2940
3147
|
variant === "link" && styles.link,
|
|
2941
3148
|
style
|
|
2942
3149
|
],
|
|
2943
|
-
children: /* @__PURE__ */ (0,
|
|
3150
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: [styles.btnText, { color: filled ? p.onPrimary : variant === "link" ? p.primary : variant === "ghost" ? p.muted : p.text, fontFamily: p.fontFamily }, variant === "link" && styles.underline], numberOfLines: 1, children: label })
|
|
2944
3151
|
}
|
|
2945
3152
|
);
|
|
2946
3153
|
}
|
|
2947
3154
|
function CloseButton({ onPress, palette: p, label = "Close" }) {
|
|
2948
|
-
return /* @__PURE__ */ (0,
|
|
3155
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: label, onPress, hitSlop: 10, style: ({ pressed }) => [styles.close, { opacity: pressed ? 0.6 : 1 }], children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: [styles.closeText, { color: p.muted }], children: "\xD7" }) });
|
|
2949
3156
|
}
|
|
2950
3157
|
function Surface({ palette: p, children, style }) {
|
|
2951
|
-
return /* @__PURE__ */ (0,
|
|
3158
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: [styles.surface, { backgroundColor: p.background, borderRadius: p.radius, borderColor: p.border }, style], children });
|
|
2952
3159
|
}
|
|
2953
|
-
var styles =
|
|
3160
|
+
var styles = import_react_native2.StyleSheet.create({
|
|
2954
3161
|
btn: { minHeight: 36, paddingHorizontal: 14, paddingVertical: 8, alignItems: "center", justifyContent: "center" },
|
|
2955
3162
|
link: { paddingHorizontal: 4 },
|
|
2956
3163
|
btnText: { fontSize: 14, fontWeight: "600" },
|
|
@@ -2958,7 +3165,7 @@ var styles = import_react_native.StyleSheet.create({
|
|
|
2958
3165
|
close: { width: 28, height: 28, alignItems: "center", justifyContent: "center", marginTop: -4, marginRight: -6 },
|
|
2959
3166
|
closeText: { fontSize: 24, lineHeight: 26, fontWeight: "400" },
|
|
2960
3167
|
surface: {
|
|
2961
|
-
borderWidth:
|
|
3168
|
+
borderWidth: import_react_native2.StyleSheet.hairlineWidth,
|
|
2962
3169
|
shadowColor: "#000",
|
|
2963
3170
|
shadowOpacity: 0.18,
|
|
2964
3171
|
shadowRadius: 18,
|
|
@@ -2968,8 +3175,8 @@ var styles = import_react_native.StyleSheet.create({
|
|
|
2968
3175
|
});
|
|
2969
3176
|
|
|
2970
3177
|
// src/ui/RichText.tsx
|
|
2971
|
-
var
|
|
2972
|
-
var
|
|
3178
|
+
var import_react2 = require("react");
|
|
3179
|
+
var import_react_native3 = require("react-native");
|
|
2973
3180
|
|
|
2974
3181
|
// src/core/html.ts
|
|
2975
3182
|
var ENTITIES = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: "\xA0", mdash: "\u2014", ndash: "\u2013", hellip: "\u2026", rsquo: "\u2019", lsquo: "\u2018", rdquo: "\u201D", ldquo: "\u201C", copy: "\xA9", reg: "\xAE", trade: "\u2122", times: "\xD7", rarr: "\u2192", larr: "\u2190", bull: "\u2022" };
|
|
@@ -3195,8 +3402,8 @@ function htmlToText(html) {
|
|
|
3195
3402
|
}
|
|
3196
3403
|
|
|
3197
3404
|
// src/ui/RichText.tsx
|
|
3198
|
-
var
|
|
3199
|
-
var MONO =
|
|
3405
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
3406
|
+
var MONO = import_react_native3.Platform.select({ ios: "Menlo", android: "monospace", default: "monospace" });
|
|
3200
3407
|
var HEADING_SIZE = [0, 20, 17, 15];
|
|
3201
3408
|
function runStyle(run, p) {
|
|
3202
3409
|
return {
|
|
@@ -3209,90 +3416,90 @@ function runStyle(run, p) {
|
|
|
3209
3416
|
};
|
|
3210
3417
|
}
|
|
3211
3418
|
function BodyImage({ block, palette: p }) {
|
|
3212
|
-
const [ratio, setRatio] = (0,
|
|
3213
|
-
(0,
|
|
3419
|
+
const [ratio, setRatio] = (0, import_react2.useState)(block.width && block.height ? block.width / block.height : 16 / 9);
|
|
3420
|
+
(0, import_react2.useEffect)(() => {
|
|
3214
3421
|
if (block.width && block.height) return;
|
|
3215
3422
|
let live = true;
|
|
3216
|
-
|
|
3423
|
+
import_react_native3.Image.getSize(block.src, (w, h) => live && w > 0 && h > 0 && setRatio(w / h), () => {
|
|
3217
3424
|
});
|
|
3218
3425
|
return () => {
|
|
3219
3426
|
live = false;
|
|
3220
3427
|
};
|
|
3221
3428
|
}, [block.src, block.width, block.height]);
|
|
3222
|
-
return /* @__PURE__ */ (0,
|
|
3429
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Image, { source: { uri: block.src }, accessible: true, accessibilityRole: "image", accessibilityLabel: block.alt || void 0, resizeMode: "contain", style: [styles2.image, { aspectRatio: ratio, backgroundColor: p.surface }] });
|
|
3223
3430
|
}
|
|
3224
3431
|
function BodyVideo({ block, palette: p, onLink }) {
|
|
3225
|
-
return /* @__PURE__ */ (0,
|
|
3226
|
-
/* @__PURE__ */ (0,
|
|
3227
|
-
/* @__PURE__ */ (0,
|
|
3432
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.Pressable, { accessibilityRole: "link", accessibilityLabel: block.alt, onPress: () => onLink(block.href), style: ({ pressed }) => [styles2.video, { borderColor: p.border, backgroundColor: p.surface, opacity: pressed ? 0.7 : 1 }], children: [
|
|
3433
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [styles2.play, { color: p.primary }], children: "\u25B6" }),
|
|
3434
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: { color: p.primary, fontFamily: p.fontFamily, fontWeight: "600" }, children: block.alt })
|
|
3228
3435
|
] });
|
|
3229
3436
|
}
|
|
3230
3437
|
var PAGE_RATIO = 1 / 1.414;
|
|
3231
3438
|
var pageRatio = (p) => p.width && p.height ? p.width / p.height : PAGE_RATIO;
|
|
3232
3439
|
function PdfBadge() {
|
|
3233
|
-
return /* @__PURE__ */ (0,
|
|
3440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: styles2.badge, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: styles2.badgeText, children: "PDF" }) });
|
|
3234
3441
|
}
|
|
3235
3442
|
function BodyFile({ block, palette: p, onLink }) {
|
|
3236
|
-
return /* @__PURE__ */ (0,
|
|
3237
|
-
/* @__PURE__ */ (0,
|
|
3238
|
-
/* @__PURE__ */ (0,
|
|
3443
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.Pressable, { accessibilityRole: "link", accessibilityLabel: `${block.alt}, PDF`, onPress: () => onLink(block.href), style: ({ pressed }) => [styles2.video, { borderColor: p.border, backgroundColor: p.surface, opacity: pressed ? 0.7 : 1 }], children: [
|
|
3444
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PdfBadge, {}),
|
|
3445
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { numberOfLines: 2, ellipsizeMode: "middle", style: [styles2.flex, { color: p.text, fontFamily: p.fontFamily, fontWeight: "600" }], children: block.alt })
|
|
3239
3446
|
] });
|
|
3240
3447
|
}
|
|
3241
3448
|
function BodyPdf({ block, palette: p, onLink }) {
|
|
3242
3449
|
const pages = block.pages ?? [];
|
|
3243
|
-
const [width, setWidth] = (0,
|
|
3244
|
-
const [index, setIndex] = (0,
|
|
3245
|
-
const [reading, setReading] = (0,
|
|
3450
|
+
const [width, setWidth] = (0, import_react2.useState)(0);
|
|
3451
|
+
const [index, setIndex] = (0, import_react2.useState)(0);
|
|
3452
|
+
const [reading, setReading] = (0, import_react2.useState)(false);
|
|
3246
3453
|
const height = width ? Math.max(...pages.map((pg) => width / pageRatio(pg))) : 0;
|
|
3247
3454
|
const onScroll = (e) => width && setIndex(Math.round(e.nativeEvent.contentOffset.x / width));
|
|
3248
|
-
return /* @__PURE__ */ (0,
|
|
3249
|
-
/* @__PURE__ */ (0,
|
|
3250
|
-
/* @__PURE__ */ (0,
|
|
3251
|
-
/* @__PURE__ */ (0,
|
|
3252
|
-
/* @__PURE__ */ (0,
|
|
3455
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: [styles2.pdf, { borderColor: p.border, backgroundColor: p.surface }], children: [
|
|
3456
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.Pressable, { accessibilityRole: "button", accessibilityLabel: `Read ${block.alt} full screen`, onPress: () => setReading(true), style: ({ pressed }) => [styles2.pdfHeader, { opacity: pressed ? 0.7 : 1 }], children: [
|
|
3457
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PdfBadge, {}),
|
|
3458
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { numberOfLines: 1, ellipsizeMode: "middle", style: [styles2.flex, { color: p.text, fontFamily: p.fontFamily, fontWeight: "600" }], children: block.alt }),
|
|
3459
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: { color: p.muted, fontSize: 16 }, children: "\u2922" })
|
|
3253
3460
|
] }),
|
|
3254
|
-
/* @__PURE__ */ (0,
|
|
3255
|
-
width > 0 && /* @__PURE__ */ (0,
|
|
3256
|
-
pages.length > 1 && /* @__PURE__ */ (0,
|
|
3461
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: styles2.pdfPages, onLayout: (e) => setWidth(e.nativeEvent.layout.width), children: [
|
|
3462
|
+
width > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.ScrollView, { horizontal: true, pagingEnabled: true, showsHorizontalScrollIndicator: false, onScroll, scrollEventThrottle: 32, accessibilityLabel: `${block.alt}, page ${index + 1} of ${pages.length}`, children: pages.map((pg, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Pressable, { onPress: () => setReading(true), accessibilityRole: "imagebutton", accessibilityLabel: pg.alt || `Page ${i + 1}`, accessibilityHint: "Opens the document full screen", style: { width, height, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Image, { source: { uri: pg.src }, resizeMode: "contain", style: [styles2.page, { width: Math.min(width, height * pageRatio(pg)), aspectRatio: pageRatio(pg) }] }) }, i)) }),
|
|
3463
|
+
pages.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { pointerEvents: "none", style: styles2.count, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.Text, { style: styles2.countText, children: [
|
|
3257
3464
|
index + 1,
|
|
3258
3465
|
" / ",
|
|
3259
3466
|
pages.length
|
|
3260
3467
|
] }) })
|
|
3261
3468
|
] }),
|
|
3262
|
-
/* @__PURE__ */ (0,
|
|
3263
|
-
/* @__PURE__ */ (0,
|
|
3264
|
-
/* @__PURE__ */ (0,
|
|
3265
|
-
/* @__PURE__ */ (0,
|
|
3266
|
-
/* @__PURE__ */ (0,
|
|
3469
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Modal, { visible: reading, animationType: "slide", presentationStyle: "fullScreen", onRequestClose: () => setReading(false), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: styles2.reader, children: [
|
|
3470
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: styles2.readerBar, children: [
|
|
3471
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { numberOfLines: 1, ellipsizeMode: "middle", style: [styles2.flex, styles2.readerTitle], accessibilityRole: "header", children: block.alt }),
|
|
3472
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Pressable, { accessibilityRole: "link", onPress: () => onLink(block.href), style: styles2.readerBtn, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: styles2.readerBtnText, children: "Open PDF \u2197" }) }),
|
|
3473
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Pressable, { accessibilityRole: "button", accessibilityLabel: "Close", onPress: () => setReading(false), style: styles2.readerBtn, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: styles2.readerBtnText, children: "Done" }) })
|
|
3267
3474
|
] }),
|
|
3268
|
-
/* @__PURE__ */ (0,
|
|
3475
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.ScrollView, { contentContainerStyle: styles2.readerPages, children: pages.map((pg, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Image, { source: { uri: pg.src }, accessible: true, accessibilityLabel: pg.alt || `Page ${i + 1}`, resizeMode: "contain", style: [styles2.readerPage, { aspectRatio: pageRatio(pg) }] }, i)) })
|
|
3269
3476
|
] }) })
|
|
3270
3477
|
] });
|
|
3271
3478
|
}
|
|
3272
3479
|
function RichText({ html, palette: p, onLink, size = 15 }) {
|
|
3273
|
-
const blocks = (0,
|
|
3480
|
+
const blocks = (0, import_react2.useMemo)(() => parseHtml(html), [html]);
|
|
3274
3481
|
if (!blocks.length) return null;
|
|
3275
3482
|
const base = { color: p.text, fontSize: size, lineHeight: Math.round(size * 1.42), fontFamily: p.fontFamily };
|
|
3276
|
-
return /* @__PURE__ */ (0,
|
|
3277
|
-
if (b.kind === "image") return /* @__PURE__ */ (0,
|
|
3278
|
-
if (b.kind === "video") return /* @__PURE__ */ (0,
|
|
3279
|
-
if (b.kind === "pdf") return /* @__PURE__ */ (0,
|
|
3280
|
-
if (b.kind === "file") return /* @__PURE__ */ (0,
|
|
3281
|
-
const runs = b.runs.map((r, j) => /* @__PURE__ */ (0,
|
|
3483
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: styles2.wrap, children: blocks.map((b, i) => {
|
|
3484
|
+
if (b.kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BodyImage, { block: b, palette: p }, i);
|
|
3485
|
+
if (b.kind === "video") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BodyVideo, { block: b, palette: p, onLink }, i);
|
|
3486
|
+
if (b.kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BodyPdf, { block: b, palette: p, onLink }, i);
|
|
3487
|
+
if (b.kind === "file") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BodyFile, { block: b, palette: p, onLink }, i);
|
|
3488
|
+
const runs = b.runs.map((r, j) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: runStyle(r, p), onPress: r.href ? () => onLink(r.href) : void 0, accessibilityRole: r.href ? "link" : void 0, children: r.text }, j));
|
|
3282
3489
|
if (b.kind === "list-item") {
|
|
3283
|
-
return /* @__PURE__ */ (0,
|
|
3284
|
-
/* @__PURE__ */ (0,
|
|
3285
|
-
/* @__PURE__ */ (0,
|
|
3490
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.View, { style: [styles2.li, { paddingLeft: (b.level - 1) * 14 }], children: [
|
|
3491
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [base, styles2.marker], children: b.marker }),
|
|
3492
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [base, styles2.flex], children: runs })
|
|
3286
3493
|
] }, i);
|
|
3287
3494
|
}
|
|
3288
3495
|
if (b.kind === "heading") {
|
|
3289
3496
|
const fs = HEADING_SIZE[b.level] ?? 15;
|
|
3290
|
-
return /* @__PURE__ */ (0,
|
|
3497
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { accessibilityRole: "header", style: [base, { fontSize: fs, lineHeight: Math.round(fs * 1.3), fontWeight: "700" }], children: runs }, i);
|
|
3291
3498
|
}
|
|
3292
|
-
return /* @__PURE__ */ (0,
|
|
3499
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.Text, { style: [base, b.kind === "quote" && { borderLeftWidth: 3, borderLeftColor: p.border, paddingLeft: 8, color: p.muted }], children: runs }, i);
|
|
3293
3500
|
}) });
|
|
3294
3501
|
}
|
|
3295
|
-
var styles2 =
|
|
3502
|
+
var styles2 = import_react_native3.StyleSheet.create({
|
|
3296
3503
|
wrap: { gap: 6 },
|
|
3297
3504
|
li: { flexDirection: "row", gap: 6 },
|
|
3298
3505
|
marker: { minWidth: 14 },
|
|
@@ -3309,7 +3516,7 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
3309
3516
|
count: { position: "absolute", right: 8, bottom: 8, backgroundColor: "rgba(17,17,17,0.72)", borderRadius: 999, paddingHorizontal: 8, paddingVertical: 2 },
|
|
3310
3517
|
countText: { color: "#fff", fontSize: 11, fontWeight: "500", fontVariant: ["tabular-nums"] },
|
|
3311
3518
|
reader: { flex: 1, backgroundColor: "#0b0b0d" },
|
|
3312
|
-
readerBar: { flexDirection: "row", alignItems: "center", gap: 8, paddingTop:
|
|
3519
|
+
readerBar: { flexDirection: "row", alignItems: "center", gap: 8, paddingTop: import_react_native3.Platform.OS === "ios" ? 52 : 12, paddingBottom: 10, paddingHorizontal: 16 },
|
|
3313
3520
|
readerTitle: { color: "#fff", fontSize: 16, fontWeight: "600" },
|
|
3314
3521
|
readerBtn: { minHeight: 36, justifyContent: "center", paddingHorizontal: 12, borderRadius: 8, backgroundColor: "rgba(255,255,255,0.12)" },
|
|
3315
3522
|
readerBtnText: { color: "#fff", fontWeight: "600" },
|
|
@@ -3318,7 +3525,7 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
3318
3525
|
});
|
|
3319
3526
|
|
|
3320
3527
|
// src/ui/Checklist.tsx
|
|
3321
|
-
var
|
|
3528
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
3322
3529
|
function Checklist({ view, client, palette: p, geometry, showLauncher, launcherBottom }) {
|
|
3323
3530
|
const config = view.guide.config.checklist;
|
|
3324
3531
|
if (!config) return null;
|
|
@@ -3332,27 +3539,27 @@ function Checklist({ view, client, palette: p, geometry, showLauncher, launcherB
|
|
|
3332
3539
|
const width = Math.min(viewport.width - insets.left - insets.right - 32, 360);
|
|
3333
3540
|
const nextOpen = config.ordered ? config.tasks.find((t) => !done.has(t.id))?.id : void 0;
|
|
3334
3541
|
const bottom = insets.bottom + launcherBottom;
|
|
3335
|
-
return /* @__PURE__ */ (0,
|
|
3336
|
-
view.open ? /* @__PURE__ */ (0,
|
|
3337
|
-
/* @__PURE__ */ (0,
|
|
3338
|
-
/* @__PURE__ */ (0,
|
|
3339
|
-
/* @__PURE__ */ (0,
|
|
3340
|
-
/* @__PURE__ */ (0,
|
|
3542
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { pointerEvents: "box-none", style: import_react_native4.StyleSheet.absoluteFill, children: [
|
|
3543
|
+
view.open ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Surface, { palette: p, style: [styles3.panel, side, { width, bottom: bottom + (showLauncher ? 56 : 0), maxHeight: viewport.height - insets.top - bottom - 80 }], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { accessibilityViewIsModal: true, style: styles3.panelInner, children: [
|
|
3544
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: styles3.head, children: [
|
|
3545
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: styles3.flex, children: [
|
|
3546
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { accessibilityRole: "header", style: [styles3.title, { color: p.text, fontFamily: p.fontFamily }], children: finished ? config.completionTitle : config.launcherLabel }),
|
|
3547
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.Text, { style: [styles3.sub, { color: p.muted }], children: [
|
|
3341
3548
|
completed,
|
|
3342
3549
|
" of ",
|
|
3343
3550
|
total,
|
|
3344
3551
|
" complete"
|
|
3345
3552
|
] })
|
|
3346
3553
|
] }),
|
|
3347
|
-
/* @__PURE__ */ (0,
|
|
3554
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CloseButton, { palette: p, onPress: () => client.setChecklistOpen(view.guide.id, false), label: "Close checklist" })
|
|
3348
3555
|
] }),
|
|
3349
|
-
/* @__PURE__ */ (0,
|
|
3350
|
-
finished && config.completionBody ? /* @__PURE__ */ (0,
|
|
3351
|
-
/* @__PURE__ */ (0,
|
|
3556
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: [styles3.bar, { backgroundColor: p.surface }], accessibilityRole: "progressbar", accessibilityValue: { min: 0, max: total, now: completed }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: [styles3.fill, { backgroundColor: p.primary, width: `${total ? completed / total * 100 : 0}%` }] }) }),
|
|
3557
|
+
finished && config.completionBody ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RichText, { html: config.completionBody, palette: p, onLink: (u) => client.navigate(u), size: 14 }) : null,
|
|
3558
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.ScrollView, { style: styles3.tasks, contentContainerStyle: styles3.tasksContent, children: config.tasks.map((task) => {
|
|
3352
3559
|
const isDone = done.has(task.id);
|
|
3353
3560
|
const locked = !!nextOpen && !isDone && task.id !== nextOpen;
|
|
3354
|
-
return /* @__PURE__ */ (0,
|
|
3355
|
-
|
|
3561
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3562
|
+
import_react_native4.Pressable,
|
|
3356
3563
|
{
|
|
3357
3564
|
disabled: locked,
|
|
3358
3565
|
accessibilityRole: "button",
|
|
@@ -3361,23 +3568,23 @@ function Checklist({ view, client, palette: p, geometry, showLauncher, launcherB
|
|
|
3361
3568
|
onPress: () => client.checklistTaskPressed(view.guide.id, task.id),
|
|
3362
3569
|
style: ({ pressed }) => [styles3.task, { borderColor: p.border, opacity: locked ? 0.5 : pressed ? 0.7 : 1 }],
|
|
3363
3570
|
children: [
|
|
3364
|
-
/* @__PURE__ */ (0,
|
|
3365
|
-
/* @__PURE__ */ (0,
|
|
3366
|
-
/* @__PURE__ */ (0,
|
|
3571
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: [styles3.check, isDone ? { backgroundColor: p.primary, borderColor: p.primary } : { borderColor: p.border }], children: isDone ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [styles3.tick, { color: p.onPrimary }], children: "\u2713" }) : null }),
|
|
3572
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: styles3.flex, children: [
|
|
3573
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.Text, { style: [styles3.taskTitle, { color: p.text, fontFamily: p.fontFamily }, isDone && { textDecorationLine: "line-through", color: p.muted }], children: [
|
|
3367
3574
|
task.title,
|
|
3368
|
-
!task.required ? /* @__PURE__ */ (0,
|
|
3575
|
+
!task.required ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: { color: p.muted, fontWeight: "400" }, children: " (optional)" }) : null
|
|
3369
3576
|
] }),
|
|
3370
|
-
task.description ? /* @__PURE__ */ (0,
|
|
3577
|
+
task.description ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [styles3.taskDesc, { color: p.muted }], children: task.description }) : null
|
|
3371
3578
|
] })
|
|
3372
3579
|
]
|
|
3373
3580
|
},
|
|
3374
3581
|
task.id
|
|
3375
3582
|
);
|
|
3376
3583
|
}) }),
|
|
3377
|
-
config.dismissible ? /* @__PURE__ */ (0,
|
|
3584
|
+
config.dismissible ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GButton, { label: finished ? "Close for good" : "Dismiss checklist", variant: "ghost", palette: p, onPress: () => client.dismissChecklist(view.guide.id), style: styles3.dismiss }) : null
|
|
3378
3585
|
] }) }) : null,
|
|
3379
|
-
showLauncher ? /* @__PURE__ */ (0,
|
|
3380
|
-
|
|
3586
|
+
showLauncher ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
3587
|
+
import_react_native4.Pressable,
|
|
3381
3588
|
{
|
|
3382
3589
|
accessibilityRole: "button",
|
|
3383
3590
|
accessibilityLabel: `${config.launcherLabel}, ${completed} of ${total} complete`,
|
|
@@ -3385,14 +3592,14 @@ function Checklist({ view, client, palette: p, geometry, showLauncher, launcherB
|
|
|
3385
3592
|
onPress: () => client.setChecklistOpen(view.guide.id, !view.open),
|
|
3386
3593
|
style: ({ pressed }) => [styles3.launcher, side, { bottom, backgroundColor: p.primary, opacity: pressed ? 0.85 : 1 }],
|
|
3387
3594
|
children: [
|
|
3388
|
-
/* @__PURE__ */ (0,
|
|
3389
|
-
/* @__PURE__ */ (0,
|
|
3595
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: [styles3.count, { borderColor: p.onPrimary }], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [styles3.countText, { color: p.onPrimary }], children: finished ? "\u2713" : `${completed}/${total}` }) }),
|
|
3596
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: [styles3.launcherText, { color: p.onPrimary, fontFamily: p.fontFamily }], numberOfLines: 1, children: config.launcherLabel })
|
|
3390
3597
|
]
|
|
3391
3598
|
}
|
|
3392
3599
|
) : null
|
|
3393
3600
|
] });
|
|
3394
3601
|
}
|
|
3395
|
-
var styles3 =
|
|
3602
|
+
var styles3 = import_react_native4.StyleSheet.create({
|
|
3396
3603
|
flex: { flex: 1 },
|
|
3397
3604
|
panel: { position: "absolute" },
|
|
3398
3605
|
panelInner: { padding: 16, gap: 10, flexShrink: 1 },
|
|
@@ -3403,7 +3610,7 @@ var styles3 = import_react_native3.StyleSheet.create({
|
|
|
3403
3610
|
fill: { height: 6, borderRadius: 3 },
|
|
3404
3611
|
tasks: { flexGrow: 0 },
|
|
3405
3612
|
tasksContent: { gap: 8 },
|
|
3406
|
-
task: { flexDirection: "row", gap: 10, alignItems: "flex-start", borderWidth:
|
|
3613
|
+
task: { flexDirection: "row", gap: 10, alignItems: "flex-start", borderWidth: import_react_native4.StyleSheet.hairlineWidth, borderRadius: 10, padding: 10 },
|
|
3407
3614
|
check: { width: 22, height: 22, borderRadius: 11, borderWidth: 2, alignItems: "center", justifyContent: "center", marginTop: 1 },
|
|
3408
3615
|
tick: { fontSize: 13, fontWeight: "800" },
|
|
3409
3616
|
taskTitle: { fontSize: 15, fontWeight: "600" },
|
|
@@ -3430,22 +3637,22 @@ var styles3 = import_react_native3.StyleSheet.create({
|
|
|
3430
3637
|
});
|
|
3431
3638
|
|
|
3432
3639
|
// src/ui/Messenger.tsx
|
|
3433
|
-
var
|
|
3434
|
-
var
|
|
3435
|
-
var
|
|
3640
|
+
var import_react3 = require("react");
|
|
3641
|
+
var import_react_native5 = require("react-native");
|
|
3642
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
3436
3643
|
function useMessenger(store) {
|
|
3437
|
-
return (0,
|
|
3438
|
-
(0,
|
|
3644
|
+
return (0, import_react3.useSyncExternalStore)(
|
|
3645
|
+
(0, import_react3.useCallback)((cb) => store.subscribe(cb), [store]),
|
|
3439
3646
|
() => store.getSnapshot(),
|
|
3440
3647
|
() => store.getSnapshot()
|
|
3441
3648
|
);
|
|
3442
3649
|
}
|
|
3443
3650
|
function useKeyboardHeight() {
|
|
3444
|
-
const [h, setH] = (0,
|
|
3445
|
-
(0,
|
|
3446
|
-
if (
|
|
3447
|
-
const show =
|
|
3448
|
-
const hide =
|
|
3651
|
+
const [h, setH] = (0, import_react3.useState)(0);
|
|
3652
|
+
(0, import_react3.useEffect)(() => {
|
|
3653
|
+
if (import_react_native5.Platform.OS !== "ios") return;
|
|
3654
|
+
const show = import_react_native5.Keyboard.addListener("keyboardWillShow", (e) => setH(e.endCoordinates.height));
|
|
3655
|
+
const hide = import_react_native5.Keyboard.addListener("keyboardWillHide", () => setH(0));
|
|
3449
3656
|
return () => {
|
|
3450
3657
|
show.remove();
|
|
3451
3658
|
hide.remove();
|
|
@@ -3464,9 +3671,9 @@ function MessengerLauncher({ store, palette: p, style }) {
|
|
|
3464
3671
|
const snap = useMessenger(store);
|
|
3465
3672
|
if (snap.open) return null;
|
|
3466
3673
|
const label = snap.unread ? `Open ${snap.config.name}, ${snap.unread} unread` : `Open ${snap.config.name}`;
|
|
3467
|
-
return /* @__PURE__ */ (0,
|
|
3468
|
-
/* @__PURE__ */ (0,
|
|
3469
|
-
snap.unread ? /* @__PURE__ */ (0,
|
|
3674
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.Pressable, { accessibilityRole: "button", accessibilityLabel: label, onPress: () => store.open(), style: ({ pressed }) => [styles4.launcher, style, { backgroundColor: p.primary, opacity: pressed ? 0.85 : 1 }], children: [
|
|
3675
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.launcherIcon, { color: p.onPrimary }], children: "\u{1F4AC}" }),
|
|
3676
|
+
snap.unread ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: styles4.badge, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: styles4.badgeText, children: snap.unread }) }) : null
|
|
3470
3677
|
] });
|
|
3471
3678
|
}
|
|
3472
3679
|
function MessengerSheet({ store, client, palette: p, topInset, bottomInset }) {
|
|
@@ -3474,14 +3681,14 @@ function MessengerSheet({ store, client, palette: p, topInset, bottomInset }) {
|
|
|
3474
3681
|
const keyboard = useKeyboardHeight();
|
|
3475
3682
|
const v = snap.view;
|
|
3476
3683
|
const title = v.kind === "thread" ? snap.thread?.conversation?.subject || "New conversation" : v.kind === "article" ? "" : v.tab === "home" ? snap.config.name : v.tab === "messages" ? "Messages" : "Help";
|
|
3477
|
-
return /* @__PURE__ */ (0,
|
|
3478
|
-
/* @__PURE__ */ (0,
|
|
3479
|
-
v.kind !== "tab" ? /* @__PURE__ */ (0,
|
|
3480
|
-
/* @__PURE__ */ (0,
|
|
3481
|
-
/* @__PURE__ */ (0,
|
|
3684
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Modal, { visible: snap.open, animationType: "slide", presentationStyle: import_react_native5.Platform.OS === "ios" ? "pageSheet" : "fullScreen", onRequestClose: () => v.kind === "tab" ? store.close() : store.back(), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: [styles4.sheet, { backgroundColor: p.background, paddingTop: import_react_native5.Platform.OS === "ios" ? 8 : topInset, paddingBottom: keyboard }], children: [
|
|
3685
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: [styles4.header, { borderColor: p.border }], children: [
|
|
3686
|
+
v.kind !== "tab" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Pressable, { accessibilityRole: "button", accessibilityLabel: "Back", onPress: () => store.back(), hitSlop: 10, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.back, { color: p.primary }], children: "\u2039 Back" }) }) : null,
|
|
3687
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { accessibilityRole: "header", numberOfLines: 1, style: [styles4.title, { color: p.text, fontFamily: p.fontFamily }], children: title }),
|
|
3688
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CloseButton, { palette: p, onPress: () => store.close(), label: `Close ${snap.config.name}` })
|
|
3482
3689
|
] }),
|
|
3483
|
-
/* @__PURE__ */ (0,
|
|
3484
|
-
v.kind === "tab" && !keyboard ? /* @__PURE__ */ (0,
|
|
3690
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: styles4.flex, children: v.kind === "thread" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Thread, { store, palette: p, bottomInset: keyboard ? 0 : bottomInset }) : v.kind === "article" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Article, { article: snap.article, palette: p, client }) : v.tab === "home" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Home, { store, palette: p }) : v.tab === "messages" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Conversations, { store, palette: p }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Help, { store, client, palette: p }) }),
|
|
3691
|
+
v.kind === "tab" && !keyboard ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Tabs, { store, active: v.tab, palette: p, bottomInset }) : null
|
|
3485
3692
|
] }) });
|
|
3486
3693
|
}
|
|
3487
3694
|
function Tabs({ store, active, palette: p, bottomInset }) {
|
|
@@ -3491,33 +3698,33 @@ function Tabs({ store, active, palette: p, bottomInset }) {
|
|
|
3491
3698
|
["messages", "\u2709\uFE0E", "Messages"],
|
|
3492
3699
|
["help", "?", "Help"]
|
|
3493
3700
|
];
|
|
3494
|
-
return /* @__PURE__ */ (0,
|
|
3701
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { accessibilityRole: "tablist", style: [styles4.tabs, { borderColor: p.border, paddingBottom: Math.max(8, bottomInset) }], children: tabs.map(([tab, icon, label]) => {
|
|
3495
3702
|
const on = tab === active;
|
|
3496
|
-
return /* @__PURE__ */ (0,
|
|
3497
|
-
/* @__PURE__ */ (0,
|
|
3498
|
-
/* @__PURE__ */ (0,
|
|
3499
|
-
tab === "messages" && unread ? /* @__PURE__ */ (0,
|
|
3703
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.Pressable, { accessibilityRole: "tab", accessibilityState: { selected: on }, accessibilityLabel: tab === "messages" && unread ? `${label}, ${unread} unread` : label, onPress: () => store.setTab(tab), style: styles4.tab, children: [
|
|
3704
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.tabIcon, { color: on ? p.primary : p.muted }], children: icon }),
|
|
3705
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.tabLabel, { color: on ? p.primary : p.muted }], children: label }),
|
|
3706
|
+
tab === "messages" && unread ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: [styles4.dot, styles4.tabDot] }) : null
|
|
3500
3707
|
] }, tab);
|
|
3501
3708
|
}) });
|
|
3502
3709
|
}
|
|
3503
3710
|
function Home({ store, palette: p }) {
|
|
3504
3711
|
const snap = useMessenger(store);
|
|
3505
3712
|
const recent = snap.conversations[0];
|
|
3506
|
-
const [q, setQ] = (0,
|
|
3507
|
-
return /* @__PURE__ */ (0,
|
|
3508
|
-
/* @__PURE__ */ (0,
|
|
3509
|
-
/* @__PURE__ */ (0,
|
|
3510
|
-
/* @__PURE__ */ (0,
|
|
3713
|
+
const [q, setQ] = (0, import_react3.useState)("");
|
|
3714
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.ScrollView, { contentContainerStyle: styles4.content, keyboardShouldPersistTaps: "handled", children: [
|
|
3715
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: [styles4.hero, { backgroundColor: p.primary, borderRadius: p.radius }], children: [
|
|
3716
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.heroTitle, { color: p.onPrimary }], children: snap.config.greeting || `Hi! I'm ${snap.config.name}.` }),
|
|
3717
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.heroSub, { color: p.onPrimary }], children: snap.config.aiAvailable ? `${snap.config.name} answers right away${snap.config.handoffEnabled ? ", and the team is here when you need a person" : ""}.` : "The team usually replies within a few hours." })
|
|
3511
3718
|
] }),
|
|
3512
|
-
/* @__PURE__ */ (0,
|
|
3513
|
-
recent ? /* @__PURE__ */ (0,
|
|
3514
|
-
/* @__PURE__ */ (0,
|
|
3515
|
-
/* @__PURE__ */ (0,
|
|
3719
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GButton, { label: "Send us a message", palette: p, onPress: () => store.showNewMessage(), style: styles4.fullWidth }),
|
|
3720
|
+
recent ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: styles4.section, children: [
|
|
3721
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.sectionTitle, { color: p.muted }], children: "RECENT" }),
|
|
3722
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ConversationRow, { c: recent, palette: p, onPress: () => void store.openConversation(recent.id) })
|
|
3516
3723
|
] }) : null,
|
|
3517
|
-
/* @__PURE__ */ (0,
|
|
3518
|
-
/* @__PURE__ */ (0,
|
|
3519
|
-
/* @__PURE__ */ (0,
|
|
3520
|
-
|
|
3724
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: styles4.section, children: [
|
|
3725
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.sectionTitle, { color: p.muted }], children: "SEARCH FOR HELP" }),
|
|
3726
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3727
|
+
import_react_native5.TextInput,
|
|
3521
3728
|
{
|
|
3522
3729
|
value: q,
|
|
3523
3730
|
onChangeText: setQ,
|
|
@@ -3537,37 +3744,37 @@ function Home({ store, palette: p }) {
|
|
|
3537
3744
|
}
|
|
3538
3745
|
var pendingSearch = { current: "" };
|
|
3539
3746
|
function ConversationRow({ c, palette: p, onPress }) {
|
|
3540
|
-
return /* @__PURE__ */ (0,
|
|
3541
|
-
/* @__PURE__ */ (0,
|
|
3542
|
-
/* @__PURE__ */ (0,
|
|
3543
|
-
/* @__PURE__ */ (0,
|
|
3747
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.Pressable, { accessibilityRole: "button", accessibilityLabel: `${c.subject || "Conversation"}${c.unread ? ", unread" : ""}`, onPress, style: ({ pressed }) => [styles4.row, { borderColor: p.border, opacity: pressed ? 0.7 : 1 }], children: [
|
|
3748
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: styles4.flex, children: [
|
|
3749
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { numberOfLines: 1, style: [styles4.rowTitle, { color: p.text }], children: c.subject || "Conversation" }),
|
|
3750
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { numberOfLines: 1, style: [styles4.rowSub, { color: p.muted }], children: c.lastMessagePreview || (c.status === "closed" ? "Closed" : " ") })
|
|
3544
3751
|
] }),
|
|
3545
|
-
/* @__PURE__ */ (0,
|
|
3546
|
-
/* @__PURE__ */ (0,
|
|
3547
|
-
c.unread ? /* @__PURE__ */ (0,
|
|
3752
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: styles4.rowEnd, children: [
|
|
3753
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.time, { color: p.muted }], children: ago(c.lastMessageAt) }),
|
|
3754
|
+
c.unread ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: [styles4.dot, { backgroundColor: p.primary }] }) : null
|
|
3548
3755
|
] })
|
|
3549
3756
|
] });
|
|
3550
3757
|
}
|
|
3551
3758
|
function Conversations({ store, palette: p }) {
|
|
3552
3759
|
const snap = useMessenger(store);
|
|
3553
|
-
return /* @__PURE__ */ (0,
|
|
3554
|
-
snap.conversations.length ? snap.conversations.map((c) => /* @__PURE__ */ (0,
|
|
3555
|
-
/* @__PURE__ */ (0,
|
|
3760
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.ScrollView, { contentContainerStyle: styles4.content, children: [
|
|
3761
|
+
snap.conversations.length ? snap.conversations.map((c) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ConversationRow, { c, palette: p, onPress: () => void store.openConversation(c.id) }, c.id)) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.empty, { color: p.muted }], children: "No conversations yet." }),
|
|
3762
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GButton, { label: "New conversation", palette: p, onPress: () => store.showNewMessage(), style: styles4.fullWidth })
|
|
3556
3763
|
] });
|
|
3557
3764
|
}
|
|
3558
3765
|
function Bubble({ m, text, name, palette: p, onArticle, onGuide }) {
|
|
3559
3766
|
if (m.author === "system")
|
|
3560
|
-
return /* @__PURE__ */ (0,
|
|
3767
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { accessibilityRole: "text", style: [styles4.system, { color: p.muted }], children: text });
|
|
3561
3768
|
const mine = m.author === "user";
|
|
3562
|
-
return /* @__PURE__ */ (0,
|
|
3563
|
-
!mine ? /* @__PURE__ */ (0,
|
|
3564
|
-
/* @__PURE__ */ (0,
|
|
3565
|
-
m.citations.length || m.suggestedGuides.length ? /* @__PURE__ */ (0,
|
|
3566
|
-
m.citations.map((c) => /* @__PURE__ */ (0,
|
|
3769
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: [styles4.bubbleWrap, mine ? styles4.mine : styles4.theirs], children: [
|
|
3770
|
+
!mine ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.author, { color: p.muted }], children: m.author === "agent" ? m.authorName || "Team" : name }) : null,
|
|
3771
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: [styles4.bubble, { borderRadius: Math.max(12, p.radius) }, mine ? { backgroundColor: p.primary } : { backgroundColor: p.surface }], children: m.status === "pending" && !text ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TypingDots, { color: p.muted }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.bubbleText, { color: mine ? p.onPrimary : p.text }], children: text }) }),
|
|
3772
|
+
m.citations.length || m.suggestedGuides.length ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: styles4.chips, children: [
|
|
3773
|
+
m.citations.map((c) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Pressable, { accessibilityRole: "link", accessibilityLabel: `Article: ${c.title}`, onPress: () => onArticle(c.articleId), style: [styles4.chip, { borderColor: p.border }], children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.Text, { style: [styles4.chipText, { color: p.text }], children: [
|
|
3567
3774
|
"\u{1F4C4} ",
|
|
3568
3775
|
c.title
|
|
3569
3776
|
] }) }, c.articleId)),
|
|
3570
|
-
m.suggestedGuides.map((g) => /* @__PURE__ */ (0,
|
|
3777
|
+
m.suggestedGuides.map((g) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Pressable, { accessibilityRole: "button", accessibilityLabel: `Show me: ${g.name}`, onPress: () => onGuide(g.key), style: [styles4.chip, { borderColor: p.primary }], children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.Text, { style: [styles4.chipText, { color: p.primary }], children: [
|
|
3571
3778
|
"\u25B6 Show me: ",
|
|
3572
3779
|
g.name
|
|
3573
3780
|
] }) }, g.key))
|
|
@@ -3575,18 +3782,18 @@ function Bubble({ m, text, name, palette: p, onArticle, onGuide }) {
|
|
|
3575
3782
|
] });
|
|
3576
3783
|
}
|
|
3577
3784
|
function TypingDots({ color }) {
|
|
3578
|
-
return /* @__PURE__ */ (0,
|
|
3785
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.ActivityIndicator, { size: "small", color, accessibilityLabel: "Typing" });
|
|
3579
3786
|
}
|
|
3580
3787
|
function Thread({ store, palette: p, bottomInset }) {
|
|
3581
3788
|
const snap = useMessenger(store);
|
|
3582
3789
|
const t = snap.thread;
|
|
3583
|
-
const [text, setText] = (0,
|
|
3584
|
-
const scroll = (0,
|
|
3790
|
+
const [text, setText] = (0, import_react3.useState)(t?.draft ?? "");
|
|
3791
|
+
const scroll = (0, import_react3.useRef)(null);
|
|
3585
3792
|
const convo = t?.conversation ?? null;
|
|
3586
|
-
(0,
|
|
3793
|
+
(0, import_react3.useEffect)(() => {
|
|
3587
3794
|
if (t?.draft) setText(t.draft);
|
|
3588
3795
|
}, [t?.draft]);
|
|
3589
|
-
const streamingIds = (0,
|
|
3796
|
+
const streamingIds = (0, import_react3.useMemo)(() => Object.keys(t?.streaming ?? {}).filter((id) => !t?.messages.some((m) => m.id === id)), [t]);
|
|
3590
3797
|
if (!t) return null;
|
|
3591
3798
|
const send = () => {
|
|
3592
3799
|
const value = text;
|
|
@@ -3594,22 +3801,22 @@ function Thread({ store, palette: p, bottomInset }) {
|
|
|
3594
3801
|
void store.send(value);
|
|
3595
3802
|
};
|
|
3596
3803
|
const canHandoff = snap.config.handoffEnabled && snap.config.aiAvailable && convo?.status === "bot" && !t.sending;
|
|
3597
|
-
return /* @__PURE__ */ (0,
|
|
3598
|
-
/* @__PURE__ */ (0,
|
|
3599
|
-
!t.messages.length && !t.sending ? /* @__PURE__ */ (0,
|
|
3600
|
-
t.messages.map((m) => /* @__PURE__ */ (0,
|
|
3601
|
-
streamingIds.map((id) => /* @__PURE__ */ (0,
|
|
3804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: styles4.flex, children: [
|
|
3805
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.ScrollView, { ref: scroll, contentContainerStyle: styles4.thread, onContentSizeChange: () => scroll.current?.scrollToEnd({ animated: true }), keyboardShouldPersistTaps: "handled", children: [
|
|
3806
|
+
!t.messages.length && !t.sending ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.empty, { color: p.muted }], children: snap.config.greeting || "Ask us anything." }) : null,
|
|
3807
|
+
t.messages.map((m) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Bubble, { m, text: t.streaming[m.id] ?? m.body, name: snap.config.name, palette: p, onArticle: (id) => void store.openArticle(id), onGuide: (k) => store.startGuide(k) }, m.id)),
|
|
3808
|
+
streamingIds.map((id) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Bubble, { m: { id, author: "scout", body: "", citations: [], suggestedGuides: [], status: "pending", createdAt: (/* @__PURE__ */ new Date()).toISOString() }, text: t.streaming[id] ?? "", name: snap.config.name, palette: p, onArticle: () => {
|
|
3602
3809
|
}, onGuide: () => {
|
|
3603
3810
|
} }, id)),
|
|
3604
|
-
t.sending && !streamingIds.length && snap.config.aiAvailable && t.messages.length ? /* @__PURE__ */ (0,
|
|
3605
|
-
t.error ? /* @__PURE__ */ (0,
|
|
3606
|
-
convo?.status === "closed" && convo.rating == null ? /* @__PURE__ */ (0,
|
|
3607
|
-
convo?.status === "closed" && convo.rating != null ? /* @__PURE__ */ (0,
|
|
3811
|
+
t.sending && !streamingIds.length && snap.config.aiAvailable && t.messages.length ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TypingDots, { color: p.muted }) : null,
|
|
3812
|
+
t.error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { accessibilityLiveRegion: "polite", style: styles4.error, children: t.error }) : null,
|
|
3813
|
+
convo?.status === "closed" && convo.rating == null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Rating, { palette: p, onRate: (n) => void store.rate(n) }) : null,
|
|
3814
|
+
convo?.status === "closed" && convo.rating != null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.system, { color: p.muted }], children: "Thanks for rating this conversation." }) : null
|
|
3608
3815
|
] }),
|
|
3609
|
-
canHandoff ? /* @__PURE__ */ (0,
|
|
3610
|
-
/* @__PURE__ */ (0,
|
|
3611
|
-
/* @__PURE__ */ (0,
|
|
3612
|
-
|
|
3816
|
+
canHandoff ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GButton, { label: "Talk to a person", variant: "secondary", palette: p, onPress: () => void store.handoff(), style: styles4.handoff }) : null,
|
|
3817
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: [styles4.composer, { borderColor: p.border, paddingBottom: Math.max(10, bottomInset) }], children: [
|
|
3818
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3819
|
+
import_react_native5.TextInput,
|
|
3613
3820
|
{
|
|
3614
3821
|
value: text,
|
|
3615
3822
|
onChangeText: (v) => setText(v.slice(0, 4e3)),
|
|
@@ -3620,26 +3827,26 @@ function Thread({ store, palette: p, bottomInset }) {
|
|
|
3620
3827
|
style: [styles4.input, { color: p.text, backgroundColor: p.surface, borderRadius: Math.min(18, p.radius + 6) }]
|
|
3621
3828
|
}
|
|
3622
3829
|
),
|
|
3623
|
-
/* @__PURE__ */ (0,
|
|
3830
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GButton, { label: "Send", palette: p, onPress: send, disabled: !text.trim() || t.sending })
|
|
3624
3831
|
] })
|
|
3625
3832
|
] });
|
|
3626
3833
|
}
|
|
3627
3834
|
function Rating({ palette: p, onRate }) {
|
|
3628
|
-
return /* @__PURE__ */ (0,
|
|
3629
|
-
/* @__PURE__ */ (0,
|
|
3630
|
-
/* @__PURE__ */ (0,
|
|
3835
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: styles4.rating, children: [
|
|
3836
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.ratingTitle, { color: p.text }], children: "How did we do?" }),
|
|
3837
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { accessibilityRole: "radiogroup", style: styles4.stars, children: [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Pressable, { accessibilityRole: "radio", accessibilityLabel: `${n} of 5`, onPress: () => onRate(n), hitSlop: 6, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.star, { color: p.primary }], children: "\u2605" }) }, n)) })
|
|
3631
3838
|
] });
|
|
3632
3839
|
}
|
|
3633
3840
|
function Help({ store, client, palette: p }) {
|
|
3634
3841
|
const snap = useMessenger(store);
|
|
3635
3842
|
const rc = client.getResourceCenter();
|
|
3636
|
-
const [q, setQ] = (0,
|
|
3637
|
-
const [results, setResults] = (0,
|
|
3638
|
-
const [faq, setFaq] = (0,
|
|
3639
|
-
(0,
|
|
3843
|
+
const [q, setQ] = (0, import_react3.useState)(pendingSearch.current);
|
|
3844
|
+
const [results, setResults] = (0, import_react3.useState)(null);
|
|
3845
|
+
const [faq, setFaq] = (0, import_react3.useState)(null);
|
|
3846
|
+
(0, import_react3.useEffect)(() => {
|
|
3640
3847
|
pendingSearch.current = "";
|
|
3641
3848
|
}, []);
|
|
3642
|
-
(0,
|
|
3849
|
+
(0, import_react3.useEffect)(() => {
|
|
3643
3850
|
const query = q.trim();
|
|
3644
3851
|
if (query.length < 2) return setResults(null);
|
|
3645
3852
|
let alive = true;
|
|
@@ -3652,35 +3859,35 @@ function Help({ store, client, palette: p }) {
|
|
|
3652
3859
|
const guides = client.getGuides();
|
|
3653
3860
|
const recommended = (rc?.recommendedGuideIds ?? []).map((id) => guides.find((g) => g.id === id || g.key === id)).filter((g) => !!g);
|
|
3654
3861
|
const articles = snap.articles;
|
|
3655
|
-
const row = (key, title, sub, onPress, icon = "\u203A") => /* @__PURE__ */ (0,
|
|
3656
|
-
/* @__PURE__ */ (0,
|
|
3657
|
-
/* @__PURE__ */ (0,
|
|
3658
|
-
sub ? /* @__PURE__ */ (0,
|
|
3862
|
+
const row = (key, title, sub, onPress, icon = "\u203A") => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.Pressable, { accessibilityRole: "button", accessibilityLabel: title, onPress, style: ({ pressed }) => [styles4.row, { borderColor: p.border, opacity: pressed ? 0.7 : 1 }], children: [
|
|
3863
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: styles4.flex, children: [
|
|
3864
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.rowTitle, { color: p.text }], children: title }),
|
|
3865
|
+
sub ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { numberOfLines: 2, style: [styles4.rowSub, { color: p.muted }], children: sub }) : null
|
|
3659
3866
|
] }),
|
|
3660
|
-
/* @__PURE__ */ (0,
|
|
3867
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.chev, { color: p.muted }], children: icon })
|
|
3661
3868
|
] }, key);
|
|
3662
3869
|
const open = (a) => a.externalUrl ? client.navigate(a.externalUrl) : void store.openArticle(a.id);
|
|
3663
|
-
const section = (title, children) => /* @__PURE__ */ (0,
|
|
3664
|
-
/* @__PURE__ */ (0,
|
|
3870
|
+
const section = (title, children) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: styles4.section, children: [
|
|
3871
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { accessibilityRole: "header", style: [styles4.sectionTitle, { color: p.muted }], children: title.toUpperCase() }),
|
|
3665
3872
|
children
|
|
3666
3873
|
] }, title);
|
|
3667
3874
|
const audiences = client.getAudienceIds();
|
|
3668
3875
|
const sections = resourceCenterSections(articles?.collections ?? [], articles?.articles ?? [], audiences);
|
|
3669
3876
|
const listed = results?.filter((a) => isArticleListed(articles?.collections ?? [], a, audiences));
|
|
3670
|
-
return /* @__PURE__ */ (0,
|
|
3671
|
-
/* @__PURE__ */ (0,
|
|
3672
|
-
listed ? section(`Results for \u201C${q.trim()}\u201D`, listed.length ? listed.map((a) => row(a.id, a.title, a.summary, () => open(a))) : /* @__PURE__ */ (0,
|
|
3877
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.ScrollView, { contentContainerStyle: styles4.content, keyboardShouldPersistTaps: "handled", children: [
|
|
3878
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.TextInput, { value: q, onChangeText: setQ, placeholder: "Search articles", placeholderTextColor: p.muted, accessibilityLabel: "Search help articles", returnKeyType: "search", style: [styles4.search, { color: p.text, backgroundColor: p.surface, borderRadius: Math.min(10, p.radius) }] }),
|
|
3879
|
+
listed ? section(`Results for \u201C${q.trim()}\u201D`, listed.length ? listed.map((a) => row(a.id, a.title, a.summary, () => open(a))) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.rowSub, { color: p.muted }], children: "No articles found." })) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
3673
3880
|
recommended.length ? section("Recommended", recommended.map((g) => row(g.id, g.name, void 0, () => store.startGuide(g.key), "\u25B6"))) : null,
|
|
3674
|
-
!articles ? /* @__PURE__ */ (0,
|
|
3881
|
+
!articles ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.ActivityIndicator, { color: p.muted }) : null,
|
|
3675
3882
|
sections.map((s) => section(s.collection ? s.path.join(" \u203A ") : "Articles", s.articles.map((a) => row(a.id, a.title, a.summary, () => open(a))))),
|
|
3676
3883
|
rc?.faqs.length ? section(
|
|
3677
3884
|
"FAQ",
|
|
3678
|
-
rc.faqs.map((f) => /* @__PURE__ */ (0,
|
|
3679
|
-
/* @__PURE__ */ (0,
|
|
3680
|
-
/* @__PURE__ */ (0,
|
|
3681
|
-
/* @__PURE__ */ (0,
|
|
3885
|
+
rc.faqs.map((f) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: [styles4.row, styles4.faq, { borderColor: p.border }], children: [
|
|
3886
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.Pressable, { accessibilityRole: "button", accessibilityState: { expanded: faq === f.id }, onPress: () => setFaq(faq === f.id ? null : f.id), style: styles4.faqHead, children: [
|
|
3887
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.rowTitle, styles4.flex, { color: p.text }], children: f.question }),
|
|
3888
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: [styles4.chev, { color: p.muted }], children: faq === f.id ? "\u2212" : "+" })
|
|
3682
3889
|
] }),
|
|
3683
|
-
faq === f.id ? /* @__PURE__ */ (0,
|
|
3890
|
+
faq === f.id ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RichText, { html: f.answer, palette: p, onLink: (u) => client.navigate(u), size: 14 }) : null
|
|
3684
3891
|
] }, f.id))
|
|
3685
3892
|
) : null,
|
|
3686
3893
|
rc?.links.length ? section("Links", rc.links.map((l) => row(l.id, l.label, void 0, () => client.navigate(l.url), "\u2197"))) : null
|
|
@@ -3688,23 +3895,23 @@ function Help({ store, client, palette: p }) {
|
|
|
3688
3895
|
] });
|
|
3689
3896
|
}
|
|
3690
3897
|
function Article({ article, palette: p, client }) {
|
|
3691
|
-
if (!article) return /* @__PURE__ */ (0,
|
|
3692
|
-
return /* @__PURE__ */ (0,
|
|
3693
|
-
/* @__PURE__ */ (0,
|
|
3694
|
-
/* @__PURE__ */ (0,
|
|
3898
|
+
if (!article) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.ActivityIndicator, { style: styles4.loading, color: p.muted });
|
|
3899
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.ScrollView, { contentContainerStyle: styles4.content, children: [
|
|
3900
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { accessibilityRole: "header", style: [styles4.articleTitle, { color: p.text, fontFamily: p.fontFamily }], children: article.title }),
|
|
3901
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RichText, { html: article.body, palette: p, onLink: (u) => client.navigate(u) })
|
|
3695
3902
|
] });
|
|
3696
3903
|
}
|
|
3697
|
-
var styles4 =
|
|
3904
|
+
var styles4 = import_react_native5.StyleSheet.create({
|
|
3698
3905
|
flex: { flex: 1 },
|
|
3699
3906
|
launcher: { position: "absolute", width: 54, height: 54, borderRadius: 27, alignItems: "center", justifyContent: "center", elevation: 8, shadowColor: "#000", shadowOpacity: 0.22, shadowRadius: 12, shadowOffset: { width: 0, height: 4 } },
|
|
3700
3907
|
launcherIcon: { fontSize: 24 },
|
|
3701
3908
|
badge: { position: "absolute", top: -2, right: -2, minWidth: 20, height: 20, borderRadius: 10, backgroundColor: "#dc2626", alignItems: "center", justifyContent: "center", paddingHorizontal: 5, borderWidth: 2, borderColor: "#ffffff" },
|
|
3702
3909
|
badgeText: { color: "#ffffff", fontSize: 11, fontWeight: "800" },
|
|
3703
3910
|
sheet: { flex: 1 },
|
|
3704
|
-
header: { flexDirection: "row", alignItems: "center", gap: 12, paddingHorizontal: 16, paddingVertical: 12, borderBottomWidth:
|
|
3911
|
+
header: { flexDirection: "row", alignItems: "center", gap: 12, paddingHorizontal: 16, paddingVertical: 12, borderBottomWidth: import_react_native5.StyleSheet.hairlineWidth },
|
|
3705
3912
|
back: { fontSize: 16, fontWeight: "600" },
|
|
3706
3913
|
title: { flex: 1, fontSize: 18, fontWeight: "700" },
|
|
3707
|
-
tabs: { flexDirection: "row", borderTopWidth:
|
|
3914
|
+
tabs: { flexDirection: "row", borderTopWidth: import_react_native5.StyleSheet.hairlineWidth, paddingTop: 8 },
|
|
3708
3915
|
tab: { flex: 1, alignItems: "center", gap: 2 },
|
|
3709
3916
|
tabIcon: { fontSize: 18 },
|
|
3710
3917
|
tabLabel: { fontSize: 11, fontWeight: "600" },
|
|
@@ -3718,7 +3925,7 @@ var styles4 = import_react_native4.StyleSheet.create({
|
|
|
3718
3925
|
section: { gap: 8 },
|
|
3719
3926
|
sectionTitle: { fontSize: 12, fontWeight: "700", letterSpacing: 0.6 },
|
|
3720
3927
|
search: { height: 42, paddingHorizontal: 12, fontSize: 15 },
|
|
3721
|
-
row: { flexDirection: "row", alignItems: "center", gap: 10, borderWidth:
|
|
3928
|
+
row: { flexDirection: "row", alignItems: "center", gap: 10, borderWidth: import_react_native5.StyleSheet.hairlineWidth, borderRadius: 10, paddingVertical: 12, paddingHorizontal: 12 },
|
|
3722
3929
|
rowTitle: { fontSize: 15, fontWeight: "600" },
|
|
3723
3930
|
rowSub: { fontSize: 13, marginTop: 2 },
|
|
3724
3931
|
rowEnd: { alignItems: "flex-end", gap: 6 },
|
|
@@ -3740,7 +3947,7 @@ var styles4 = import_react_native4.StyleSheet.create({
|
|
|
3740
3947
|
chipText: { fontSize: 13, fontWeight: "600" },
|
|
3741
3948
|
error: { color: "#dc2626", fontSize: 13, textAlign: "center" },
|
|
3742
3949
|
handoff: { alignSelf: "center", marginBottom: 8 },
|
|
3743
|
-
composer: { flexDirection: "row", alignItems: "flex-end", gap: 8, paddingHorizontal: 12, paddingTop: 10, borderTopWidth:
|
|
3950
|
+
composer: { flexDirection: "row", alignItems: "flex-end", gap: 8, paddingHorizontal: 12, paddingTop: 10, borderTopWidth: import_react_native5.StyleSheet.hairlineWidth },
|
|
3744
3951
|
input: { flex: 1, minHeight: 40, maxHeight: 120, paddingHorizontal: 14, paddingTop: 10, paddingBottom: 10, fontSize: 15 },
|
|
3745
3952
|
rating: { alignItems: "center", gap: 6, paddingVertical: 8 },
|
|
3746
3953
|
ratingTitle: { fontSize: 15, fontWeight: "600" },
|
|
@@ -3751,23 +3958,23 @@ var styles4 = import_react_native4.StyleSheet.create({
|
|
|
3751
3958
|
});
|
|
3752
3959
|
|
|
3753
3960
|
// src/ui/ResourceCenter.tsx
|
|
3754
|
-
var
|
|
3755
|
-
var
|
|
3756
|
-
var
|
|
3961
|
+
var import_react4 = require("react");
|
|
3962
|
+
var import_react_native6 = require("react-native");
|
|
3963
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
3757
3964
|
function ResourceCenter({ client, palette: p, open, topInset, bottomInset }) {
|
|
3758
3965
|
const rc = client.getResourceCenter();
|
|
3759
|
-
const [query, setQuery] = (0,
|
|
3760
|
-
const [results, setResults] = (0,
|
|
3761
|
-
const [article, setArticle] = (0,
|
|
3762
|
-
const [faq, setFaq] = (0,
|
|
3763
|
-
(0,
|
|
3966
|
+
const [query, setQuery] = (0, import_react4.useState)("");
|
|
3967
|
+
const [results, setResults] = (0, import_react4.useState)(null);
|
|
3968
|
+
const [article, setArticle] = (0, import_react4.useState)(null);
|
|
3969
|
+
const [faq, setFaq] = (0, import_react4.useState)(null);
|
|
3970
|
+
(0, import_react4.useEffect)(() => {
|
|
3764
3971
|
if (!open) {
|
|
3765
3972
|
setQuery("");
|
|
3766
3973
|
setResults(null);
|
|
3767
3974
|
setArticle(null);
|
|
3768
3975
|
}
|
|
3769
3976
|
}, [open]);
|
|
3770
|
-
(0,
|
|
3977
|
+
(0, import_react4.useEffect)(() => {
|
|
3771
3978
|
const q = query.trim();
|
|
3772
3979
|
if (q.length < 2) {
|
|
3773
3980
|
setResults(null);
|
|
@@ -3783,8 +3990,8 @@ function ResourceCenter({ client, palette: p, open, topInset, bottomInset }) {
|
|
|
3783
3990
|
};
|
|
3784
3991
|
}, [client, query]);
|
|
3785
3992
|
const guides = client.getGuides();
|
|
3786
|
-
const recommended = (0,
|
|
3787
|
-
const checklists = (0,
|
|
3993
|
+
const recommended = (0, import_react4.useMemo)(() => (rc?.recommendedGuideIds ?? []).map((id) => guides.find((g) => g.id === id || g.key === id)).filter((g) => !!g && g.kind !== "checklist"), [rc, guides]);
|
|
3994
|
+
const checklists = (0, import_react4.useMemo)(() => (rc?.checklistGuideIds ?? []).map((id) => guides.find((g) => g.id === id || g.key === id)).filter((g) => !!g && g.kind === "checklist"), [rc, guides]);
|
|
3788
3995
|
if (!rc) return null;
|
|
3789
3996
|
const close = () => client.closeResourceCenter();
|
|
3790
3997
|
const openArticle = (a) => {
|
|
@@ -3792,32 +3999,32 @@ function ResourceCenter({ client, palette: p, open, topInset, bottomInset }) {
|
|
|
3792
3999
|
client.articleViewed(a);
|
|
3793
4000
|
setArticle(a);
|
|
3794
4001
|
};
|
|
3795
|
-
const row = (key, title, subtitle, onPress, icon = "\u203A") => /* @__PURE__ */ (0,
|
|
3796
|
-
/* @__PURE__ */ (0,
|
|
3797
|
-
/* @__PURE__ */ (0,
|
|
3798
|
-
subtitle ? /* @__PURE__ */ (0,
|
|
4002
|
+
const row = (key, title, subtitle, onPress, icon = "\u203A") => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.Pressable, { accessibilityRole: "button", accessibilityLabel: title, onPress, style: ({ pressed }) => [styles5.row, { borderColor: p.border, opacity: pressed ? 0.7 : 1 }], children: [
|
|
4003
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.View, { style: styles5.flex, children: [
|
|
4004
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Text, { style: [styles5.rowTitle, { color: p.text, fontFamily: p.fontFamily }], children: title }),
|
|
4005
|
+
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Text, { style: [styles5.rowSub, { color: p.muted }], numberOfLines: 2, children: subtitle }) : null
|
|
3799
4006
|
] }),
|
|
3800
|
-
/* @__PURE__ */ (0,
|
|
4007
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Text, { style: [styles5.chev, { color: p.muted }], children: icon })
|
|
3801
4008
|
] }, key);
|
|
3802
|
-
const section = (title, children) => /* @__PURE__ */ (0,
|
|
3803
|
-
/* @__PURE__ */ (0,
|
|
4009
|
+
const section = (title, children) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.View, { style: styles5.section, children: [
|
|
4010
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Text, { accessibilityRole: "header", style: [styles5.sectionTitle, { color: p.muted }], children: title.toUpperCase() }),
|
|
3804
4011
|
children
|
|
3805
4012
|
] }, title);
|
|
3806
4013
|
const audiences = client.getAudienceIds();
|
|
3807
4014
|
const sections = resourceCenterSections(rc.collections, rc.articles, audiences);
|
|
3808
4015
|
const listed = results?.filter((a) => isArticleListed(rc.collections, a, audiences));
|
|
3809
|
-
return /* @__PURE__ */ (0,
|
|
3810
|
-
/* @__PURE__ */ (0,
|
|
3811
|
-
article ? /* @__PURE__ */ (0,
|
|
3812
|
-
/* @__PURE__ */ (0,
|
|
3813
|
-
/* @__PURE__ */ (0,
|
|
4016
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Modal, { visible: open, animationType: "slide", presentationStyle: import_react_native6.Platform.OS === "ios" ? "pageSheet" : "fullScreen", onRequestClose: () => article ? setArticle(null) : close(), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.View, { style: [styles5.sheet, { backgroundColor: p.background, paddingTop: import_react_native6.Platform.OS === "ios" ? 8 : topInset }], children: [
|
|
4017
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.View, { style: [styles5.header, { borderColor: p.border }], children: [
|
|
4018
|
+
article ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Pressable, { accessibilityRole: "button", accessibilityLabel: "Back", onPress: () => setArticle(null), hitSlop: 10, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Text, { style: [styles5.back, { color: p.primary }], children: "\u2039 Back" }) }) : null,
|
|
4019
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Text, { accessibilityRole: "header", style: [styles5.title, { color: p.text, fontFamily: p.fontFamily }], numberOfLines: 1, children: article ? "" : rc.title }),
|
|
4020
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseButton, { palette: p, onPress: close, label: "Close help" })
|
|
3814
4021
|
] }),
|
|
3815
|
-
article ? /* @__PURE__ */ (0,
|
|
3816
|
-
/* @__PURE__ */ (0,
|
|
3817
|
-
/* @__PURE__ */ (0,
|
|
3818
|
-
] }) : /* @__PURE__ */ (0,
|
|
3819
|
-
/* @__PURE__ */ (0,
|
|
3820
|
-
|
|
4022
|
+
article ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.ScrollView, { contentContainerStyle: [styles5.content, { paddingBottom: bottomInset + 24 }], children: [
|
|
4023
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Text, { accessibilityRole: "header", style: [styles5.articleTitle, { color: p.text, fontFamily: p.fontFamily }], children: article.title }),
|
|
4024
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RichText, { html: article.body, palette: p, onLink: (u) => client.navigate(u) })
|
|
4025
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.ScrollView, { contentContainerStyle: [styles5.content, { paddingBottom: bottomInset + 24 }], keyboardShouldPersistTaps: "handled", children: [
|
|
4026
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4027
|
+
import_react_native6.TextInput,
|
|
3821
4028
|
{
|
|
3822
4029
|
value: query,
|
|
3823
4030
|
onChangeText: setQuery,
|
|
@@ -3831,19 +4038,19 @@ function ResourceCenter({ client, palette: p, open, topInset, bottomInset }) {
|
|
|
3831
4038
|
),
|
|
3832
4039
|
listed ? section(
|
|
3833
4040
|
`Results for \u201C${query.trim()}\u201D`,
|
|
3834
|
-
listed.length ? listed.map((a) => row(a.id, a.title, a.summary, () => openArticle(a))) : /* @__PURE__ */ (0,
|
|
3835
|
-
) : /* @__PURE__ */ (0,
|
|
4041
|
+
listed.length ? listed.map((a) => row(a.id, a.title, a.summary, () => openArticle(a))) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Text, { style: [styles5.rowSub, { color: p.muted }], children: "No articles found." })
|
|
4042
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
3836
4043
|
recommended.length ? section("Recommended", recommended.map((g) => row(g.id, g.name, void 0, () => (close(), client.startGuide(g.id)), "\u25B6"))) : null,
|
|
3837
4044
|
checklists.length ? section("Checklists", checklists.map((g) => row(g.id, g.name, void 0, () => (close(), client.openChecklist(g.id)), "\u2611"))) : null,
|
|
3838
4045
|
sections.map((s) => section(s.collection ? s.path.join(" \u203A ") : "Articles", s.articles.map((a) => row(a.id, a.title, a.summary, () => openArticle(a))))),
|
|
3839
4046
|
rc.faqs.length ? section(
|
|
3840
4047
|
"FAQ",
|
|
3841
|
-
rc.faqs.map((f) => /* @__PURE__ */ (0,
|
|
3842
|
-
/* @__PURE__ */ (0,
|
|
3843
|
-
/* @__PURE__ */ (0,
|
|
3844
|
-
/* @__PURE__ */ (0,
|
|
4048
|
+
rc.faqs.map((f) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.View, { style: [styles5.row, styles5.faq, { borderColor: p.border }], children: [
|
|
4049
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.Pressable, { accessibilityRole: "button", accessibilityState: { expanded: faq === f.id }, onPress: () => setFaq(faq === f.id ? null : f.id), style: styles5.faqHead, children: [
|
|
4050
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Text, { style: [styles5.rowTitle, styles5.flex, { color: p.text }], children: f.question }),
|
|
4051
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.Text, { style: [styles5.chev, { color: p.muted }], children: faq === f.id ? "\u2212" : "+" })
|
|
3845
4052
|
] }),
|
|
3846
|
-
faq === f.id ? /* @__PURE__ */ (0,
|
|
4053
|
+
faq === f.id ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RichText, { html: f.answer, palette: p, onLink: (u) => client.navigate(u), size: 14 }) : null
|
|
3847
4054
|
] }, f.id))
|
|
3848
4055
|
) : null,
|
|
3849
4056
|
rc.links.length ? section("Links", rc.links.map((l) => row(l.id, l.label, void 0, () => client.navigate(l.url), "\u2197"))) : null
|
|
@@ -3851,17 +4058,17 @@ function ResourceCenter({ client, palette: p, open, topInset, bottomInset }) {
|
|
|
3851
4058
|
] })
|
|
3852
4059
|
] }) });
|
|
3853
4060
|
}
|
|
3854
|
-
var styles5 =
|
|
4061
|
+
var styles5 = import_react_native6.StyleSheet.create({
|
|
3855
4062
|
flex: { flex: 1 },
|
|
3856
4063
|
sheet: { flex: 1 },
|
|
3857
|
-
header: { flexDirection: "row", alignItems: "center", gap: 12, paddingHorizontal: 16, paddingVertical: 12, borderBottomWidth:
|
|
4064
|
+
header: { flexDirection: "row", alignItems: "center", gap: 12, paddingHorizontal: 16, paddingVertical: 12, borderBottomWidth: import_react_native6.StyleSheet.hairlineWidth },
|
|
3858
4065
|
back: { fontSize: 16, fontWeight: "600" },
|
|
3859
4066
|
title: { flex: 1, fontSize: 18, fontWeight: "700" },
|
|
3860
4067
|
content: { padding: 16, gap: 18 },
|
|
3861
4068
|
search: { height: 42, paddingHorizontal: 12, fontSize: 15 },
|
|
3862
4069
|
section: { gap: 8 },
|
|
3863
4070
|
sectionTitle: { fontSize: 12, fontWeight: "700", letterSpacing: 0.6 },
|
|
3864
|
-
row: { flexDirection: "row", alignItems: "center", gap: 10, borderWidth:
|
|
4071
|
+
row: { flexDirection: "row", alignItems: "center", gap: 10, borderWidth: import_react_native6.StyleSheet.hairlineWidth, borderRadius: 10, paddingVertical: 12, paddingHorizontal: 12 },
|
|
3865
4072
|
rowTitle: { fontSize: 15, fontWeight: "600" },
|
|
3866
4073
|
rowSub: { fontSize: 13, marginTop: 2 },
|
|
3867
4074
|
chev: { fontSize: 18 },
|
|
@@ -3871,8 +4078,8 @@ var styles5 = import_react_native5.StyleSheet.create({
|
|
|
3871
4078
|
});
|
|
3872
4079
|
|
|
3873
4080
|
// src/ui/StepLayer.tsx
|
|
3874
|
-
var
|
|
3875
|
-
var
|
|
4081
|
+
var import_react5 = require("react");
|
|
4082
|
+
var import_react_native8 = require("react-native");
|
|
3876
4083
|
|
|
3877
4084
|
// src/core/position.ts
|
|
3878
4085
|
var MARGIN = 12;
|
|
@@ -3912,32 +4119,32 @@ function positionCard(target, size, viewport, insets, placement, offset) {
|
|
|
3912
4119
|
}
|
|
3913
4120
|
|
|
3914
4121
|
// src/ui/StepCard.tsx
|
|
3915
|
-
var
|
|
3916
|
-
var
|
|
4122
|
+
var import_react_native7 = require("react-native");
|
|
4123
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3917
4124
|
function StepCard({ view, client, palette: p, width, style, compact }) {
|
|
3918
4125
|
const { step, guide } = view;
|
|
3919
4126
|
const buttons = visibleButtons(step, view.canGoBack);
|
|
3920
4127
|
const body = step.type === "custom" ? step.customHtml || step.body : step.body;
|
|
3921
4128
|
const showProgress = step.showProgress && view.total > 1;
|
|
3922
4129
|
const onLink = (url) => client.navigate(url);
|
|
3923
|
-
return /* @__PURE__ */ (0,
|
|
3924
|
-
step.imageUrl ? /* @__PURE__ */ (0,
|
|
3925
|
-
step.title ? /* @__PURE__ */ (0,
|
|
3926
|
-
/* @__PURE__ */ (0,
|
|
3927
|
-
step.showClose ? /* @__PURE__ */ (0,
|
|
4130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Surface, { palette: p, style: [{ width }, style], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { accessible: false, accessibilityViewIsModal: view.asModal || step.type === "modal", style: compact ? styles6.compact : styles6.inner, children: [
|
|
4131
|
+
step.imageUrl ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.Image, { source: { uri: step.imageUrl }, style: [styles6.image, { borderRadius: Math.max(0, p.radius - 4) }], resizeMode: "cover", accessibilityIgnoresInvertColors: true }) : null,
|
|
4132
|
+
step.title ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { style: styles6.header, children: [
|
|
4133
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.Text, { accessibilityRole: "header", style: [styles6.title, { color: p.text, fontFamily: p.fontFamily }], children: step.title }),
|
|
4134
|
+
step.showClose ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseButton, { palette: p, onPress: () => client.closeStep(guide.id), label: "Dismiss guide" }) : null
|
|
3928
4135
|
] }) : null,
|
|
3929
4136
|
body ? (
|
|
3930
4137
|
// Without a title the close button floats beside the body instead of taking a row.
|
|
3931
|
-
/* @__PURE__ */ (0,
|
|
4138
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.View, { style: !step.title && step.showClose ? styles6.bodyBesideClose : void 0, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RichText, { html: body, palette: p, onLink }) })
|
|
3932
4139
|
) : null,
|
|
3933
|
-
!step.title && step.showClose ? /* @__PURE__ */ (0,
|
|
3934
|
-
showProgress || buttons.length ? /* @__PURE__ */ (0,
|
|
3935
|
-
showProgress ? /* @__PURE__ */ (0,
|
|
4140
|
+
!step.title && step.showClose ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.View, { style: compact ? styles6.floatingCloseCompact : styles6.floatingClose, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CloseButton, { palette: p, onPress: () => client.closeStep(guide.id), label: "Dismiss guide" }) }) : null,
|
|
4141
|
+
showProgress || buttons.length ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { style: styles6.footer, children: [
|
|
4142
|
+
showProgress ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.Text, { style: [styles6.progress, { color: p.muted }], accessibilityLabel: `Step ${view.index + 1} of ${view.total}`, children: [
|
|
3936
4143
|
view.index + 1,
|
|
3937
4144
|
" of ",
|
|
3938
4145
|
view.total
|
|
3939
|
-
] }) : /* @__PURE__ */ (0,
|
|
3940
|
-
/* @__PURE__ */ (0,
|
|
4146
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.View, { style: styles6.flex }),
|
|
4147
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.View, { style: styles6.buttons, children: buttons.map((b) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(GButton, { label: b.label, variant: b.variant, palette: p, onPress: () => client.pressButton(guide.id, b) }, b.id)) })
|
|
3941
4148
|
] }) : null
|
|
3942
4149
|
] }) });
|
|
3943
4150
|
}
|
|
@@ -3946,7 +4153,7 @@ function announcement(view) {
|
|
|
3946
4153
|
if (view.total > 1) parts.push(`Step ${view.index + 1} of ${view.total}`);
|
|
3947
4154
|
return parts.join(". ");
|
|
3948
4155
|
}
|
|
3949
|
-
var styles6 =
|
|
4156
|
+
var styles6 = import_react_native7.StyleSheet.create({
|
|
3950
4157
|
inner: { padding: 16, gap: 10 },
|
|
3951
4158
|
compact: { paddingHorizontal: 14, paddingVertical: 10, gap: 6 },
|
|
3952
4159
|
image: { width: "100%", height: 140, marginBottom: 2 },
|
|
@@ -3962,10 +4169,10 @@ var styles6 = import_react_native6.StyleSheet.create({
|
|
|
3962
4169
|
});
|
|
3963
4170
|
|
|
3964
4171
|
// src/ui/StepLayer.tsx
|
|
3965
|
-
var
|
|
4172
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
3966
4173
|
function useTargetRect(client, targetId, origin) {
|
|
3967
|
-
const [rect, setRect] = (0,
|
|
3968
|
-
(0,
|
|
4174
|
+
const [rect, setRect] = (0, import_react5.useState)(null);
|
|
4175
|
+
(0, import_react5.useEffect)(() => {
|
|
3969
4176
|
if (!targetId) {
|
|
3970
4177
|
setRect(null);
|
|
3971
4178
|
return;
|
|
@@ -3992,10 +4199,10 @@ function useTargetRect(client, targetId, origin) {
|
|
|
3992
4199
|
return rect;
|
|
3993
4200
|
}
|
|
3994
4201
|
function useFadeIn(key) {
|
|
3995
|
-
const opacity = (0,
|
|
3996
|
-
(0,
|
|
4202
|
+
const opacity = (0, import_react5.useRef)(new import_react_native8.Animated.Value(0)).current;
|
|
4203
|
+
(0, import_react5.useEffect)(() => {
|
|
3997
4204
|
opacity.setValue(0);
|
|
3998
|
-
|
|
4205
|
+
import_react_native8.Animated.timing(opacity, { toValue: 1, duration: 160, easing: import_react_native8.Easing.out(import_react_native8.Easing.quad), useNativeDriver: true }).start();
|
|
3999
4206
|
}, [key, opacity]);
|
|
4000
4207
|
return opacity;
|
|
4001
4208
|
}
|
|
@@ -4005,34 +4212,34 @@ function StepLayer({ view, client, palette: p, geometry }) {
|
|
|
4005
4212
|
const opacity = useFadeIn(view.key);
|
|
4006
4213
|
const { viewport, insets } = geometry;
|
|
4007
4214
|
const cardWidth = Math.min(viewport.width - 32, step.width ?? 340);
|
|
4008
|
-
(0,
|
|
4215
|
+
(0, import_react5.useEffect)(() => {
|
|
4009
4216
|
if (step.type === "hotspot" && !view.expanded) return;
|
|
4010
|
-
|
|
4217
|
+
import_react_native8.AccessibilityInfo.announceForAccessibility?.(announcement(view));
|
|
4011
4218
|
}, [view.key, view.expanded]);
|
|
4012
|
-
const backdrop = (children) => /* @__PURE__ */ (0,
|
|
4219
|
+
const backdrop = (children) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.Pressable, { accessible: false, style: [import_react_native8.StyleSheet.absoluteFill, { backgroundColor: p.overlay }], onPress: () => client.backdropPressed(view.guide.id), children });
|
|
4013
4220
|
const anchored = !view.asModal && ["tooltip", "popover", "spotlight", "hotspot"].includes(step.type);
|
|
4014
4221
|
if (!anchored && step.type === "banner") {
|
|
4015
4222
|
const top = step.position.startsWith("top");
|
|
4016
|
-
return /* @__PURE__ */ (0,
|
|
4223
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.Animated.View, { pointerEvents: "box-none", style: [styles7.banner, top ? { top: insets.top + 8 } : { bottom: insets.bottom + 8 }, { left: insets.left + 8, right: insets.right + 8, opacity }], children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StepCard, { view, client, palette: p, width: viewport.width - insets.left - insets.right - 16, compact: true }) });
|
|
4017
4224
|
}
|
|
4018
4225
|
if (!anchored && step.type === "slideout") {
|
|
4019
4226
|
const wide = viewport.width >= 600;
|
|
4020
4227
|
const right = !step.position.endsWith("left");
|
|
4021
4228
|
const width = wide ? Math.min(380, cardWidth) : viewport.width - insets.left - insets.right - 24;
|
|
4022
|
-
return /* @__PURE__ */ (0,
|
|
4229
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.Animated.View, { pointerEvents: "box-none", style: [styles7.abs, { bottom: insets.bottom + 12, opacity }, wide ? right ? { right: insets.right + 16 } : { left: insets.left + 16 } : { left: insets.left + 12 }], children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StepCard, { view, client, palette: p, width }) });
|
|
4023
4230
|
}
|
|
4024
4231
|
if (!anchored) {
|
|
4025
|
-
return /* @__PURE__ */ (0,
|
|
4232
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native8.Animated.View, { pointerEvents: "box-none", style: [import_react_native8.StyleSheet.absoluteFill, styles7.center, { opacity }], children: [
|
|
4026
4233
|
step.showOverlay ? backdrop() : null,
|
|
4027
|
-
/* @__PURE__ */ (0,
|
|
4234
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StepCard, { view, client, palette: p, width: Math.min(viewport.width - 40, step.width ?? 360) })
|
|
4028
4235
|
] });
|
|
4029
4236
|
}
|
|
4030
4237
|
if (!rect) return null;
|
|
4031
4238
|
if (step.type === "hotspot") {
|
|
4032
4239
|
const size = step.hotspot?.size ?? 14;
|
|
4033
|
-
return /* @__PURE__ */ (0,
|
|
4034
|
-
/* @__PURE__ */ (0,
|
|
4035
|
-
view.expanded ? /* @__PURE__ */ (0,
|
|
4240
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native8.View, { pointerEvents: "box-none", style: import_react_native8.StyleSheet.absoluteFill, children: [
|
|
4241
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Hotspot, { x: rect.x + rect.width - size / 2, y: rect.y - size / 2, size, pulse: step.hotspot?.pulse ?? true, color: p.primary, onPress: () => client.toggleHotspot(view.guide.id), label: step.title || "Show tip" }),
|
|
4242
|
+
view.expanded ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Anchored, { view, client, palette: p, geometry, rect, width: cardWidth }) : null
|
|
4036
4243
|
] });
|
|
4037
4244
|
}
|
|
4038
4245
|
if (step.type === "spotlight") {
|
|
@@ -4047,76 +4254,76 @@ function StepLayer({ view, client, palette: p, geometry }) {
|
|
|
4047
4254
|
[hole.x, hole.y + hole.height - r, -r, -2 * r],
|
|
4048
4255
|
[hole.x + hole.width - r, hole.y + hole.height - r, -2 * r, -2 * r]
|
|
4049
4256
|
];
|
|
4050
|
-
return /* @__PURE__ */ (0,
|
|
4051
|
-
/* @__PURE__ */ (0,
|
|
4052
|
-
/* @__PURE__ */ (0,
|
|
4053
|
-
/* @__PURE__ */ (0,
|
|
4054
|
-
/* @__PURE__ */ (0,
|
|
4055
|
-
r > 0 ? corners.map(([left, top, dx, dy], i) => /* @__PURE__ */ (0,
|
|
4056
|
-
/* @__PURE__ */ (0,
|
|
4057
|
-
/* @__PURE__ */ (0,
|
|
4257
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native8.Animated.View, { pointerEvents: "box-none", style: [import_react_native8.StyleSheet.absoluteFill, { opacity }], children: [
|
|
4258
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.Pressable, { accessible: false, onPress: press, style: [styles7.abs, shade, { left: 0, right: 0, top: 0, height: Math.max(0, hole.y) }] }),
|
|
4259
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.Pressable, { accessible: false, onPress: press, style: [styles7.abs, shade, { left: 0, right: 0, top: hole.y + hole.height, bottom: 0 }] }),
|
|
4260
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.Pressable, { accessible: false, onPress: press, style: [styles7.abs, shade, { left: 0, width: Math.max(0, hole.x), top: hole.y, height: hole.height }] }),
|
|
4261
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.Pressable, { accessible: false, onPress: press, style: [styles7.abs, shade, { left: hole.x + hole.width, right: 0, top: hole.y, height: hole.height }] }),
|
|
4262
|
+
r > 0 ? corners.map(([left, top, dx, dy], i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.View, { pointerEvents: "none", style: [styles7.abs, { left, top, width: r, height: r, overflow: "hidden" }], children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.View, { style: [styles7.abs, { left: dx, top: dy, width: 4 * r, height: 4 * r, borderRadius: 2 * r, borderWidth: r, borderColor: p.overlay }] }) }, i)) : null,
|
|
4263
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.View, { pointerEvents: "none", style: [styles7.abs, { left: hole.x, top: hole.y, width: hole.width, height: hole.height, borderRadius: r, borderWidth: 2, borderColor: p.primary }] }),
|
|
4264
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Anchored, { view, client, palette: p, geometry, rect: hole, width: cardWidth })
|
|
4058
4265
|
] });
|
|
4059
4266
|
}
|
|
4060
|
-
return /* @__PURE__ */ (0,
|
|
4267
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native8.Animated.View, { pointerEvents: "box-none", style: [import_react_native8.StyleSheet.absoluteFill, { opacity }], children: [
|
|
4061
4268
|
step.showOverlay ? backdrop() : null,
|
|
4062
|
-
/* @__PURE__ */ (0,
|
|
4269
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Anchored, { view, client, palette: p, geometry, rect, width: cardWidth })
|
|
4063
4270
|
] });
|
|
4064
4271
|
}
|
|
4065
4272
|
var ARROW = 12;
|
|
4066
4273
|
function Anchored({ view, client, palette: p, geometry, rect, width }) {
|
|
4067
|
-
const [height, setHeight] = (0,
|
|
4274
|
+
const [height, setHeight] = (0, import_react5.useState)(0);
|
|
4068
4275
|
const onLayout = (e) => setHeight(Math.round(e.nativeEvent.layout.height));
|
|
4069
4276
|
const offset = view.step.offset + ARROW / 2;
|
|
4070
4277
|
const pos = positionCard(rect, { width, height: height || 120 }, geometry.viewport, geometry.insets, view.step.placement, offset);
|
|
4071
|
-
return /* @__PURE__ */ (0,
|
|
4072
|
-
/* @__PURE__ */ (0,
|
|
4073
|
-
/* @__PURE__ */ (0,
|
|
4278
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native8.View, { pointerEvents: "box-none", style: [styles7.abs, { left: pos.x, top: pos.y, width, opacity: height ? 1 : 0 }], onLayout, children: [
|
|
4279
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Arrow, { side: pos.side, at: pos.arrow, color: p.background, border: p.border }),
|
|
4280
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StepCard, { view, client, palette: p, width })
|
|
4074
4281
|
] });
|
|
4075
4282
|
}
|
|
4076
4283
|
function Arrow({ side, at, color, border }) {
|
|
4077
4284
|
const half = ARROW / 2;
|
|
4078
4285
|
const place = side === "bottom" ? { top: -half, left: at - half } : side === "top" ? { bottom: -half, left: at - half } : side === "right" ? { left: -half, top: at - half } : { right: -half, top: at - half };
|
|
4079
|
-
return /* @__PURE__ */ (0,
|
|
4286
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.View, { pointerEvents: "none", style: [styles7.abs, styles7.arrow, place, { backgroundColor: color, borderColor: border }] });
|
|
4080
4287
|
}
|
|
4081
4288
|
function Hotspot({ x, y, size, pulse, color, onPress, label }) {
|
|
4082
|
-
const scale = (0,
|
|
4083
|
-
const [reduceMotion, setReduceMotion] = (0,
|
|
4084
|
-
(0,
|
|
4289
|
+
const scale = (0, import_react5.useRef)(new import_react_native8.Animated.Value(0)).current;
|
|
4290
|
+
const [reduceMotion, setReduceMotion] = (0, import_react5.useState)(false);
|
|
4291
|
+
(0, import_react5.useEffect)(() => {
|
|
4085
4292
|
let alive = true;
|
|
4086
|
-
|
|
4293
|
+
import_react_native8.AccessibilityInfo.isReduceMotionEnabled?.().then((v) => alive && setReduceMotion(v), () => {
|
|
4087
4294
|
});
|
|
4088
4295
|
return () => {
|
|
4089
4296
|
alive = false;
|
|
4090
4297
|
};
|
|
4091
4298
|
}, []);
|
|
4092
|
-
(0,
|
|
4299
|
+
(0, import_react5.useEffect)(() => {
|
|
4093
4300
|
if (!pulse || reduceMotion) return;
|
|
4094
|
-
const loop =
|
|
4301
|
+
const loop = import_react_native8.Animated.loop(import_react_native8.Animated.timing(scale, { toValue: 1, duration: 1400, easing: import_react_native8.Easing.out(import_react_native8.Easing.ease), useNativeDriver: true }));
|
|
4095
4302
|
loop.start();
|
|
4096
4303
|
return () => loop.stop();
|
|
4097
4304
|
}, [pulse, reduceMotion, scale]);
|
|
4098
|
-
return /* @__PURE__ */ (0,
|
|
4099
|
-
pulse && !reduceMotion ? /* @__PURE__ */ (0,
|
|
4100
|
-
|
|
4305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native8.Pressable, { accessibilityRole: "button", accessibilityLabel: label, onPress, hitSlop: 14, style: [styles7.abs, { left: x, top: y, width: size, height: size }], children: [
|
|
4306
|
+
pulse && !reduceMotion ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4307
|
+
import_react_native8.Animated.View,
|
|
4101
4308
|
{
|
|
4102
4309
|
pointerEvents: "none",
|
|
4103
4310
|
style: [styles7.abs, { width: size, height: size, borderRadius: size / 2, backgroundColor: color, opacity: scale.interpolate({ inputRange: [0, 1], outputRange: [0.55, 0] }), transform: [{ scale: scale.interpolate({ inputRange: [0, 1], outputRange: [1, 2.6] }) }] }]
|
|
4104
4311
|
}
|
|
4105
4312
|
) : null,
|
|
4106
|
-
/* @__PURE__ */ (0,
|
|
4313
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.View, { style: { width: size, height: size, borderRadius: size / 2, backgroundColor: color, borderWidth: 2, borderColor: "#ffffff" } })
|
|
4107
4314
|
] });
|
|
4108
4315
|
}
|
|
4109
|
-
var styles7 =
|
|
4316
|
+
var styles7 = import_react_native8.StyleSheet.create({
|
|
4110
4317
|
abs: { position: "absolute" },
|
|
4111
4318
|
center: { alignItems: "center", justifyContent: "center" },
|
|
4112
4319
|
banner: { position: "absolute" },
|
|
4113
|
-
arrow: { width: ARROW, height: ARROW, transform: [{ rotate: "45deg" }], borderWidth:
|
|
4320
|
+
arrow: { width: ARROW, height: ARROW, transform: [{ rotate: "45deg" }], borderWidth: import_react_native8.StyleSheet.hairlineWidth }
|
|
4114
4321
|
});
|
|
4115
4322
|
|
|
4116
4323
|
// src/ui/Survey.tsx
|
|
4117
|
-
var
|
|
4118
|
-
var
|
|
4119
|
-
var
|
|
4324
|
+
var import_react6 = require("react");
|
|
4325
|
+
var import_react_native9 = require("react-native");
|
|
4326
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
4120
4327
|
function Survey({
|
|
4121
4328
|
view,
|
|
4122
4329
|
client,
|
|
@@ -4124,12 +4331,12 @@ function Survey({
|
|
|
4124
4331
|
geometry
|
|
4125
4332
|
}) {
|
|
4126
4333
|
const config = view.guide.config.survey;
|
|
4127
|
-
const [answers, setAnswers] = (0,
|
|
4128
|
-
const [error, setError] = (0,
|
|
4129
|
-
(0,
|
|
4334
|
+
const [answers, setAnswers] = (0, import_react6.useState)({});
|
|
4335
|
+
const [error, setError] = (0, import_react6.useState)("");
|
|
4336
|
+
(0, import_react6.useEffect)(() => {
|
|
4130
4337
|
setAnswers({});
|
|
4131
4338
|
setError("");
|
|
4132
|
-
|
|
4339
|
+
import_react_native9.AccessibilityInfo.announceForAccessibility?.(
|
|
4133
4340
|
`Survey: ${config?.questions[0]?.title ?? view.guide.name}`
|
|
4134
4341
|
);
|
|
4135
4342
|
}, [view.key]);
|
|
@@ -4146,11 +4353,11 @@ function Survey({
|
|
|
4146
4353
|
return next;
|
|
4147
4354
|
});
|
|
4148
4355
|
const submit = () => {
|
|
4149
|
-
const
|
|
4356
|
+
const missing2 = config.questions.filter(
|
|
4150
4357
|
(q) => q.required && isQuestionVisible(q, answers) && answers[q.id] === void 0
|
|
4151
4358
|
);
|
|
4152
|
-
if (
|
|
4153
|
-
setError(`Please answer: ${
|
|
4359
|
+
if (missing2.length) {
|
|
4360
|
+
setError(`Please answer: ${missing2.map((q) => q.title).join(", ")}`);
|
|
4154
4361
|
return;
|
|
4155
4362
|
}
|
|
4156
4363
|
setError("");
|
|
@@ -4159,23 +4366,23 @@ function Survey({
|
|
|
4159
4366
|
const close = () => client.closeSurvey(view.guide.id);
|
|
4160
4367
|
return (
|
|
4161
4368
|
// KeyboardAvoidingView owns its bottom padding, so the safe-area padding lives on an inner view.
|
|
4162
|
-
/* @__PURE__ */ (0,
|
|
4163
|
-
|
|
4369
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4370
|
+
import_react_native9.KeyboardAvoidingView,
|
|
4164
4371
|
{
|
|
4165
4372
|
pointerEvents: "box-none",
|
|
4166
|
-
behavior:
|
|
4167
|
-
style:
|
|
4373
|
+
behavior: import_react_native9.Platform.OS === "ios" ? "padding" : void 0,
|
|
4374
|
+
style: import_react_native9.StyleSheet.absoluteFill,
|
|
4168
4375
|
children: [
|
|
4169
|
-
centered ? /* @__PURE__ */ (0,
|
|
4170
|
-
|
|
4376
|
+
centered ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4377
|
+
import_react_native9.Pressable,
|
|
4171
4378
|
{
|
|
4172
4379
|
accessible: false,
|
|
4173
|
-
style: [
|
|
4380
|
+
style: [import_react_native9.StyleSheet.absoluteFill, { backgroundColor: p.overlay }],
|
|
4174
4381
|
onPress: close
|
|
4175
4382
|
}
|
|
4176
4383
|
) : null,
|
|
4177
|
-
/* @__PURE__ */ (0,
|
|
4178
|
-
|
|
4384
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4385
|
+
import_react_native9.View,
|
|
4179
4386
|
{
|
|
4180
4387
|
pointerEvents: "box-none",
|
|
4181
4388
|
style: [
|
|
@@ -4183,21 +4390,21 @@ function Survey({
|
|
|
4183
4390
|
centered ? styles8.center : styles8.bottom,
|
|
4184
4391
|
!centered && { paddingBottom: insets.bottom + 12 }
|
|
4185
4392
|
],
|
|
4186
|
-
children: /* @__PURE__ */ (0,
|
|
4393
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4187
4394
|
Surface,
|
|
4188
4395
|
{
|
|
4189
4396
|
palette: p,
|
|
4190
4397
|
style: { width, maxHeight: viewport.height - insets.top - insets.bottom - 40 },
|
|
4191
|
-
children: view.submitted ? /* @__PURE__ */ (0,
|
|
4192
|
-
/* @__PURE__ */ (0,
|
|
4193
|
-
|
|
4398
|
+
children: view.submitted ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native9.View, { style: styles8.inner, children: [
|
|
4399
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4400
|
+
import_react_native9.Text,
|
|
4194
4401
|
{
|
|
4195
4402
|
accessibilityRole: "header",
|
|
4196
4403
|
style: [styles8.title, { color: p.text, fontFamily: p.fontFamily }],
|
|
4197
4404
|
children: config.thankYouTitle
|
|
4198
4405
|
}
|
|
4199
4406
|
),
|
|
4200
|
-
config.thankYouBody ? /* @__PURE__ */ (0,
|
|
4407
|
+
config.thankYouBody ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4201
4408
|
RichText,
|
|
4202
4409
|
{
|
|
4203
4410
|
html: config.thankYouBody,
|
|
@@ -4205,18 +4412,18 @@ function Survey({
|
|
|
4205
4412
|
onLink: (u) => client.navigate(u)
|
|
4206
4413
|
}
|
|
4207
4414
|
) : null,
|
|
4208
|
-
/* @__PURE__ */ (0,
|
|
4209
|
-
] }) : /* @__PURE__ */ (0,
|
|
4210
|
-
config.questions.filter((q) => isQuestionVisible(q, answers)).map((q, i) => /* @__PURE__ */ (0,
|
|
4211
|
-
/* @__PURE__ */ (0,
|
|
4212
|
-
/* @__PURE__ */ (0,
|
|
4415
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(GButton, { label: "Done", palette: p, onPress: close, style: styles8.end })
|
|
4416
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native9.ScrollView, { contentContainerStyle: styles8.inner, keyboardShouldPersistTaps: "handled", children: [
|
|
4417
|
+
config.questions.filter((q) => isQuestionVisible(q, answers)).map((q, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native9.View, { style: styles8.question, children: [
|
|
4418
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native9.View, { style: styles8.head, children: [
|
|
4419
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native9.Text, { style: [styles8.qTitle, { color: p.text, fontFamily: p.fontFamily }], children: [
|
|
4213
4420
|
q.title,
|
|
4214
|
-
!q.required ? /* @__PURE__ */ (0,
|
|
4421
|
+
!q.required ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.Text, { style: { color: p.muted, fontWeight: "400" }, children: " (optional)" }) : null
|
|
4215
4422
|
] }),
|
|
4216
|
-
i === 0 ? /* @__PURE__ */ (0,
|
|
4423
|
+
i === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CloseButton, { palette: p, onPress: close, label: "Dismiss survey" }) : null
|
|
4217
4424
|
] }),
|
|
4218
|
-
q.description ? /* @__PURE__ */ (0,
|
|
4219
|
-
/* @__PURE__ */ (0,
|
|
4425
|
+
q.description ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.Text, { style: [styles8.desc, { color: p.muted }], children: q.description }) : null,
|
|
4426
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4220
4427
|
QuestionInput,
|
|
4221
4428
|
{
|
|
4222
4429
|
q,
|
|
@@ -4226,8 +4433,8 @@ function Survey({
|
|
|
4226
4433
|
}
|
|
4227
4434
|
)
|
|
4228
4435
|
] }, q.id)),
|
|
4229
|
-
error ? /* @__PURE__ */ (0,
|
|
4230
|
-
/* @__PURE__ */ (0,
|
|
4436
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.Text, { accessibilityLiveRegion: "polite", style: [styles8.error], children: error }) : null,
|
|
4437
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(GButton, { label: "Submit", palette: p, onPress: submit, style: styles8.end })
|
|
4231
4438
|
] })
|
|
4232
4439
|
}
|
|
4233
4440
|
)
|
|
@@ -4262,37 +4469,37 @@ function QuestionInput({
|
|
|
4262
4469
|
const min = q.type === "nps" ? 0 : 1;
|
|
4263
4470
|
const max = q.type === "nps" ? 10 : q.scaleMax ?? 5;
|
|
4264
4471
|
const values = Array.from({ length: max - min + 1 }, (_, i) => min + i);
|
|
4265
|
-
return /* @__PURE__ */ (0,
|
|
4266
|
-
/* @__PURE__ */ (0,
|
|
4267
|
-
|
|
4472
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native9.View, { children: [
|
|
4473
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.View, { style: styles8.scale, accessibilityRole: "radiogroup", accessibilityLabel: q.title, children: values.map((n) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4474
|
+
import_react_native9.Pressable,
|
|
4268
4475
|
{
|
|
4269
4476
|
accessibilityRole: "radio",
|
|
4270
4477
|
accessibilityState: { selected: value === n },
|
|
4271
4478
|
accessibilityLabel: String(n),
|
|
4272
4479
|
onPress: () => onChange(n),
|
|
4273
4480
|
style: [...chip(value === n), styles8.scaleItem],
|
|
4274
|
-
children: /* @__PURE__ */ (0,
|
|
4481
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.Text, { style: chipText(value === n), children: n })
|
|
4275
4482
|
},
|
|
4276
4483
|
n
|
|
4277
4484
|
)) }),
|
|
4278
|
-
q.lowLabel || q.highLabel ? /* @__PURE__ */ (0,
|
|
4279
|
-
/* @__PURE__ */ (0,
|
|
4280
|
-
/* @__PURE__ */ (0,
|
|
4485
|
+
q.lowLabel || q.highLabel ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native9.View, { style: styles8.labels, children: [
|
|
4486
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.Text, { style: [styles8.small, { color: p.muted }], children: q.lowLabel }),
|
|
4487
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.Text, { style: [styles8.small, { color: p.muted }], children: q.highLabel })
|
|
4281
4488
|
] }) : null
|
|
4282
4489
|
] });
|
|
4283
4490
|
}
|
|
4284
4491
|
case "rating": {
|
|
4285
4492
|
const max = q.scaleMax ?? 5;
|
|
4286
|
-
return /* @__PURE__ */ (0,
|
|
4287
|
-
|
|
4493
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.View, { style: styles8.stars, accessibilityRole: "radiogroup", accessibilityLabel: q.title, children: Array.from({ length: max }, (_, i) => i + 1).map((n) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4494
|
+
import_react_native9.Pressable,
|
|
4288
4495
|
{
|
|
4289
4496
|
accessibilityRole: "radio",
|
|
4290
4497
|
accessibilityLabel: `${n} of ${max}`,
|
|
4291
4498
|
accessibilityState: { selected: value === n },
|
|
4292
4499
|
onPress: () => onChange(n),
|
|
4293
4500
|
hitSlop: 4,
|
|
4294
|
-
children: /* @__PURE__ */ (0,
|
|
4295
|
-
|
|
4501
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4502
|
+
import_react_native9.Text,
|
|
4296
4503
|
{
|
|
4297
4504
|
style: [
|
|
4298
4505
|
styles8.star,
|
|
@@ -4306,18 +4513,18 @@ function QuestionInput({
|
|
|
4306
4513
|
)) });
|
|
4307
4514
|
}
|
|
4308
4515
|
case "thumbs":
|
|
4309
|
-
return /* @__PURE__ */ (0,
|
|
4516
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.View, { style: styles8.row, accessibilityRole: "radiogroup", children: [
|
|
4310
4517
|
[true, "\u{1F44D}", "Thumbs up"],
|
|
4311
4518
|
[false, "\u{1F44E}", "Thumbs down"]
|
|
4312
|
-
].map(([val, icon, label]) => /* @__PURE__ */ (0,
|
|
4313
|
-
|
|
4519
|
+
].map(([val, icon, label]) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4520
|
+
import_react_native9.Pressable,
|
|
4314
4521
|
{
|
|
4315
4522
|
accessibilityRole: "radio",
|
|
4316
4523
|
accessibilityLabel: label,
|
|
4317
4524
|
accessibilityState: { selected: value === val },
|
|
4318
4525
|
onPress: () => onChange(val),
|
|
4319
4526
|
style: [...chip(value === val), styles8.thumb],
|
|
4320
|
-
children: /* @__PURE__ */ (0,
|
|
4527
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.Text, { style: styles8.thumbText, children: icon })
|
|
4321
4528
|
},
|
|
4322
4529
|
String(val)
|
|
4323
4530
|
)) });
|
|
@@ -4327,10 +4534,10 @@ function QuestionInput({
|
|
|
4327
4534
|
const selected = new Set(
|
|
4328
4535
|
multi ? value ?? [] : value !== void 0 ? [String(value)] : []
|
|
4329
4536
|
);
|
|
4330
|
-
return /* @__PURE__ */ (0,
|
|
4537
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.View, { style: styles8.choices, children: q.options.map((o) => {
|
|
4331
4538
|
const on = selected.has(o.id);
|
|
4332
|
-
return /* @__PURE__ */ (0,
|
|
4333
|
-
|
|
4539
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4540
|
+
import_react_native9.Pressable,
|
|
4334
4541
|
{
|
|
4335
4542
|
accessibilityRole: multi ? "checkbox" : "radio",
|
|
4336
4543
|
accessibilityState: { checked: on },
|
|
@@ -4347,8 +4554,8 @@ function QuestionInput({
|
|
|
4347
4554
|
{ borderColor: on ? p.primary : p.border, borderRadius: Math.min(10, p.radius) }
|
|
4348
4555
|
],
|
|
4349
4556
|
children: [
|
|
4350
|
-
/* @__PURE__ */ (0,
|
|
4351
|
-
|
|
4557
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4558
|
+
import_react_native9.View,
|
|
4352
4559
|
{
|
|
4353
4560
|
style: [
|
|
4354
4561
|
styles8.dot,
|
|
@@ -4360,7 +4567,7 @@ function QuestionInput({
|
|
|
4360
4567
|
]
|
|
4361
4568
|
}
|
|
4362
4569
|
),
|
|
4363
|
-
/* @__PURE__ */ (0,
|
|
4570
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native9.Text, { style: [styles8.choiceText, { color: p.text }], children: o.label })
|
|
4364
4571
|
]
|
|
4365
4572
|
},
|
|
4366
4573
|
o.id
|
|
@@ -4369,8 +4576,8 @@ function QuestionInput({
|
|
|
4369
4576
|
}
|
|
4370
4577
|
case "text":
|
|
4371
4578
|
default:
|
|
4372
|
-
return /* @__PURE__ */ (0,
|
|
4373
|
-
|
|
4579
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4580
|
+
import_react_native9.TextInput,
|
|
4374
4581
|
{
|
|
4375
4582
|
accessibilityLabel: q.title,
|
|
4376
4583
|
multiline: true,
|
|
@@ -4391,7 +4598,7 @@ function QuestionInput({
|
|
|
4391
4598
|
);
|
|
4392
4599
|
}
|
|
4393
4600
|
}
|
|
4394
|
-
var styles8 =
|
|
4601
|
+
var styles8 = import_react_native9.StyleSheet.create({
|
|
4395
4602
|
fill: { flex: 1 },
|
|
4396
4603
|
center: { alignItems: "center", justifyContent: "center" },
|
|
4397
4604
|
bottom: { alignItems: "center", justifyContent: "flex-end" },
|
|
@@ -4477,29 +4684,29 @@ function palette(theme, systemScheme, explicit) {
|
|
|
4477
4684
|
}
|
|
4478
4685
|
|
|
4479
4686
|
// src/ui/Overlay.tsx
|
|
4480
|
-
var
|
|
4687
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4481
4688
|
function defaultInsets(width, height) {
|
|
4482
|
-
if (
|
|
4483
|
-
const notch = Math.max(width, height) >= 812 && !
|
|
4689
|
+
if (import_react_native10.Platform.OS === "ios") {
|
|
4690
|
+
const notch = Math.max(width, height) >= 812 && !import_react_native10.Platform.isPad;
|
|
4484
4691
|
const landscape = width > height;
|
|
4485
4692
|
return { top: landscape ? 0 : notch ? 50 : 20, bottom: notch ? landscape ? 21 : 34 : 0, left: landscape && notch ? 44 : 0, right: landscape && notch ? 44 : 0 };
|
|
4486
4693
|
}
|
|
4487
|
-
return { top:
|
|
4694
|
+
return { top: import_react_native10.StatusBar.currentHeight ?? 24, bottom: 16, left: 0, right: 0 };
|
|
4488
4695
|
}
|
|
4489
4696
|
function GuidelyOverlay({ client, insets: insetsProp, launcherOffset }) {
|
|
4490
|
-
const ui = (0,
|
|
4491
|
-
(0,
|
|
4697
|
+
const ui = (0, import_react7.useSyncExternalStore)(
|
|
4698
|
+
(0, import_react7.useCallback)((cb) => client.subscribeUi(cb), [client]),
|
|
4492
4699
|
() => client.getUiState(),
|
|
4493
4700
|
() => client.getUiState()
|
|
4494
4701
|
);
|
|
4495
|
-
const { width, height } = (0,
|
|
4496
|
-
const scheme = (0,
|
|
4497
|
-
const ref = (0,
|
|
4498
|
-
const [origin, setOrigin] = (0,
|
|
4499
|
-
(0,
|
|
4702
|
+
const { width, height } = (0, import_react_native10.useWindowDimensions)();
|
|
4703
|
+
const scheme = (0, import_react_native10.useColorScheme)();
|
|
4704
|
+
const ref = (0, import_react7.useRef)(null);
|
|
4705
|
+
const [origin, setOrigin] = (0, import_react7.useState)({ x: 0, y: 0 });
|
|
4706
|
+
(0, import_react7.useEffect)(() => {
|
|
4500
4707
|
client.targets.setViewport(width, height);
|
|
4501
4708
|
}, [client, width, height]);
|
|
4502
|
-
const measureOrigin = (0,
|
|
4709
|
+
const measureOrigin = (0, import_react7.useCallback)(() => {
|
|
4503
4710
|
ref.current?.measureInWindow?.((x, y) => {
|
|
4504
4711
|
if (Number.isFinite(x) && Number.isFinite(y)) setOrigin((o) => o.x === x && o.y === y ? o : { x, y });
|
|
4505
4712
|
});
|
|
@@ -4511,48 +4718,48 @@ function GuidelyOverlay({ client, insets: insetsProp, launcherOffset }) {
|
|
|
4511
4718
|
const showRcLauncher = !messenger && !!client.options.showResourceCenterLauncher && !!client.getResourceCenter();
|
|
4512
4719
|
const messengerLeft = messenger?.getSnapshot().config.launcher.position === "bottom-left";
|
|
4513
4720
|
const checklistOnSameSide = ui.checklists.some((c) => c.guide.config.checklist?.position === "bottom-left" === messengerLeft) && client.options.showChecklistLauncher !== false;
|
|
4514
|
-
return /* @__PURE__ */ (0,
|
|
4515
|
-
ui.checklists.map((c) => /* @__PURE__ */ (0,
|
|
4516
|
-
showRcLauncher ? /* @__PURE__ */ (0,
|
|
4517
|
-
|
|
4721
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native10.View, { ref, collapsable: false, pointerEvents: "box-none", style: import_react_native10.StyleSheet.absoluteFill, onLayout: measureOrigin, children: [
|
|
4722
|
+
ui.checklists.map((c) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Checklist, { view: c, client, palette: palette(client.themeFor(c.guide), scheme), geometry, showLauncher: client.options.showChecklistLauncher !== false, launcherBottom: launcherOffset }, c.guide.id)),
|
|
4723
|
+
showRcLauncher ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4724
|
+
import_react_native10.Pressable,
|
|
4518
4725
|
{
|
|
4519
4726
|
accessibilityRole: "button",
|
|
4520
4727
|
accessibilityLabel: client.getResourceCenter()?.launcher.label || "Help",
|
|
4521
4728
|
onPress: () => client.openResourceCenter(),
|
|
4522
4729
|
style: [styles9.rc, client.getResourceCenter()?.launcher.position === "bottom-left" ? { left: insets.left + 16 } : { right: insets.right + 16 }, { bottom: insets.bottom + launcherOffset + (ui.checklists.length ? 56 : 0), backgroundColor: basePalette.primary }],
|
|
4523
|
-
children: /* @__PURE__ */ (0,
|
|
4730
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native10.Text, { style: [styles9.rcText, { color: basePalette.onPrimary }], children: "?" })
|
|
4524
4731
|
}
|
|
4525
4732
|
) : null,
|
|
4526
|
-
messenger && client.options.showMessengerLauncher !== false ? /* @__PURE__ */ (0,
|
|
4527
|
-
ui.survey ? /* @__PURE__ */ (0,
|
|
4528
|
-
ui.steps.map((s) => /* @__PURE__ */ (0,
|
|
4529
|
-
messenger ? /* @__PURE__ */ (0,
|
|
4733
|
+
messenger && client.options.showMessengerLauncher !== false ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessengerLauncher, { store: messenger, palette: basePalette, style: [messengerLeft ? { left: insets.left + 16 } : { right: insets.right + 16 }, { bottom: insets.bottom + launcherOffset + (checklistOnSameSide ? 56 : 0) }] }) : null,
|
|
4734
|
+
ui.survey ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Survey, { view: ui.survey, client, palette: palette(client.themeFor(ui.survey.guide), scheme), geometry }) : null,
|
|
4735
|
+
ui.steps.map((s) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StepLayer, { view: s, client, palette: palette(client.themeFor(s.guide), scheme, s.guide.config.appearance), geometry }, s.key)),
|
|
4736
|
+
messenger ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MessengerSheet, { store: messenger, client, palette: basePalette, topInset: insets.top, bottomInset: insets.bottom }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ResourceCenter, { client, palette: basePalette, open: ui.resourceCenterOpen, topInset: insets.top, bottomInset: insets.bottom })
|
|
4530
4737
|
] });
|
|
4531
4738
|
}
|
|
4532
|
-
var styles9 =
|
|
4739
|
+
var styles9 = import_react_native10.StyleSheet.create({
|
|
4533
4740
|
rc: { position: "absolute", width: 48, height: 48, borderRadius: 24, alignItems: "center", justifyContent: "center", elevation: 8, shadowColor: "#000", shadowOpacity: 0.2, shadowRadius: 10, shadowOffset: { width: 0, height: 4 } },
|
|
4534
4741
|
rcText: { fontSize: 22, fontWeight: "800" }
|
|
4535
4742
|
});
|
|
4536
4743
|
|
|
4537
4744
|
// src/ui/Target.tsx
|
|
4538
|
-
var
|
|
4539
|
-
var
|
|
4540
|
-
var
|
|
4541
|
-
var GuidelyContext = (0,
|
|
4542
|
-
var GuidelyScreenContext = (0,
|
|
4745
|
+
var import_react8 = require("react");
|
|
4746
|
+
var import_react_native11 = require("react-native");
|
|
4747
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
4748
|
+
var GuidelyContext = (0, import_react8.createContext)(null);
|
|
4749
|
+
var GuidelyScreenContext = (0, import_react8.createContext)(null);
|
|
4543
4750
|
function GuidelyScreenScope({ name, children }) {
|
|
4544
|
-
return /* @__PURE__ */ (0,
|
|
4751
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(GuidelyScreenContext.Provider, { value: name, children });
|
|
4545
4752
|
}
|
|
4546
4753
|
function guidelyScreenLayout({ route, children }) {
|
|
4547
|
-
return /* @__PURE__ */ (0,
|
|
4754
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(GuidelyScreenScope, { name: route.name, children });
|
|
4548
4755
|
}
|
|
4549
4756
|
var TAP_SLOP = 10;
|
|
4550
4757
|
function useGuidelyTarget(id) {
|
|
4551
|
-
const client = (0,
|
|
4552
|
-
const screen = (0,
|
|
4553
|
-
const ref = (0,
|
|
4554
|
-
const start = (0,
|
|
4555
|
-
(0,
|
|
4758
|
+
const client = (0, import_react8.useContext)(GuidelyContext);
|
|
4759
|
+
const screen = (0, import_react8.useContext)(GuidelyScreenContext);
|
|
4760
|
+
const ref = (0, import_react8.useRef)(null);
|
|
4761
|
+
const start = (0, import_react8.useRef)(null);
|
|
4762
|
+
(0, import_react8.useEffect)(() => {
|
|
4556
4763
|
if (!client || !id) return;
|
|
4557
4764
|
return client.targets.register(id, {
|
|
4558
4765
|
screen,
|
|
@@ -4563,11 +4770,11 @@ function useGuidelyTarget(id) {
|
|
|
4563
4770
|
})
|
|
4564
4771
|
});
|
|
4565
4772
|
}, [client, id, screen]);
|
|
4566
|
-
const onLayout = (0,
|
|
4567
|
-
const onTouchStart = (0,
|
|
4773
|
+
const onLayout = (0, import_react8.useCallback)(() => client?.targets.changed(), [client]);
|
|
4774
|
+
const onTouchStart = (0, import_react8.useCallback)((e) => {
|
|
4568
4775
|
start.current = { x: e.nativeEvent.pageX, y: e.nativeEvent.pageY };
|
|
4569
4776
|
}, []);
|
|
4570
|
-
const onTouchEnd = (0,
|
|
4777
|
+
const onTouchEnd = (0, import_react8.useCallback)(
|
|
4571
4778
|
(e) => {
|
|
4572
4779
|
const s = start.current;
|
|
4573
4780
|
start.current = null;
|
|
@@ -4579,8 +4786,8 @@ function useGuidelyTarget(id) {
|
|
|
4579
4786
|
}
|
|
4580
4787
|
function GuidelyTarget({ id, children, onLayout, onTouchStart, onTouchEnd, ...rest }) {
|
|
4581
4788
|
const t = useGuidelyTarget(id);
|
|
4582
|
-
return /* @__PURE__ */ (0,
|
|
4583
|
-
|
|
4789
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4790
|
+
import_react_native11.View,
|
|
4584
4791
|
{
|
|
4585
4792
|
...rest,
|
|
4586
4793
|
ref: t.ref,
|
|
@@ -4603,7 +4810,8 @@ function GuidelyTarget({ id, children, onLayout, onTouchStart, onTouchEnd, ...re
|
|
|
4603
4810
|
}
|
|
4604
4811
|
|
|
4605
4812
|
// src/index.tsx
|
|
4606
|
-
var
|
|
4813
|
+
var import_flags6 = require("@guidelytech/flags");
|
|
4814
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
4607
4815
|
function deviceLocale() {
|
|
4608
4816
|
try {
|
|
4609
4817
|
return Intl.DateTimeFormat().resolvedOptions().locale;
|
|
@@ -4612,30 +4820,50 @@ function deviceLocale() {
|
|
|
4612
4820
|
}
|
|
4613
4821
|
}
|
|
4614
4822
|
function defaultBridge(appVersion) {
|
|
4615
|
-
const { width, height } =
|
|
4823
|
+
const { width, height } = import_react_native12.Dimensions.get("window");
|
|
4616
4824
|
return {
|
|
4617
4825
|
device: {
|
|
4618
|
-
platform:
|
|
4619
|
-
deviceType:
|
|
4826
|
+
platform: import_react_native12.Platform.OS === "android" ? "android" : "ios",
|
|
4827
|
+
deviceType: import_react_native12.Platform.OS === "ios" && import_react_native12.Platform.isPad || Math.min(width, height) >= 600 ? "tablet" : "mobile",
|
|
4620
4828
|
locale: deviceLocale(),
|
|
4621
4829
|
appVersion
|
|
4622
4830
|
},
|
|
4623
|
-
openExternal: (url) => void
|
|
4831
|
+
openExternal: (url) => void import_react_native12.Linking.openURL(url).catch(() => {
|
|
4624
4832
|
})
|
|
4625
4833
|
};
|
|
4626
4834
|
}
|
|
4627
|
-
function GuidelyProvider({ children, user, insets, launcherOffset = 72, ...options }) {
|
|
4628
|
-
const [client, setClient] = (0,
|
|
4629
|
-
const optionsRef = (0,
|
|
4835
|
+
function GuidelyProvider({ children, user, insets, launcherOffset = 72, flagsPayload, flagAttributes, ...options }) {
|
|
4836
|
+
const [client, setClient] = (0, import_react9.useState)(null);
|
|
4837
|
+
const optionsRef = (0, import_react9.useRef)(options);
|
|
4630
4838
|
optionsRef.current = options;
|
|
4839
|
+
const userRef = (0, import_react9.useRef)(user);
|
|
4840
|
+
userRef.current = user;
|
|
4841
|
+
const flagsOpts = options.flags === false ? null : options.flags ?? {};
|
|
4842
|
+
const payload = flagsPayload ?? flagsOpts?.payload ?? null;
|
|
4843
|
+
const payloadRef = (0, import_react9.useRef)(payload);
|
|
4844
|
+
payloadRef.current = payload;
|
|
4845
|
+
const appAttributes = (0, import_react9.useMemo)(() => ({ ...flagsOpts?.attributes ?? {}, ...flagAttributes ?? {} }), [(0, import_flags3.stableStringify)(flagsOpts?.attributes ?? {}), (0, import_flags3.stableStringify)(flagAttributes ?? {})]);
|
|
4846
|
+
const appAttributesRef = (0, import_react9.useRef)(appAttributes);
|
|
4847
|
+
appAttributesRef.current = appAttributes;
|
|
4631
4848
|
const { projectId, environment, apiUrl, storage } = options;
|
|
4632
|
-
(0,
|
|
4849
|
+
(0, import_react9.useEffect)(() => {
|
|
4633
4850
|
if (!projectId) return;
|
|
4634
4851
|
let c;
|
|
4635
4852
|
try {
|
|
4636
4853
|
const latest = optionsRef.current;
|
|
4637
4854
|
c = new GuidelyClient(
|
|
4638
|
-
{
|
|
4855
|
+
{
|
|
4856
|
+
...latest,
|
|
4857
|
+
projectId,
|
|
4858
|
+
environment,
|
|
4859
|
+
apiUrl,
|
|
4860
|
+
storage,
|
|
4861
|
+
// Known up front so flags evaluate for this user from the first render.
|
|
4862
|
+
user: userRef.current?.id ? userRef.current : void 0,
|
|
4863
|
+
flags: latest.flags === false ? false : { ...latest.flags ?? {}, payload: payloadRef.current ?? void 0, attributes: appAttributesRef.current },
|
|
4864
|
+
onNavigate: (url) => optionsRef.current.onNavigate?.(url),
|
|
4865
|
+
onError: (err) => optionsRef.current.onError?.(err)
|
|
4866
|
+
},
|
|
4639
4867
|
defaultBridge(latest.appVersion)
|
|
4640
4868
|
);
|
|
4641
4869
|
} catch (err) {
|
|
@@ -4644,7 +4872,7 @@ function GuidelyProvider({ children, user, insets, launcherOffset = 72, ...optio
|
|
|
4644
4872
|
}
|
|
4645
4873
|
setClient(c);
|
|
4646
4874
|
void c.init();
|
|
4647
|
-
const sub =
|
|
4875
|
+
const sub = import_react_native12.AppState.addEventListener("change", (s) => c.setAppState(s));
|
|
4648
4876
|
return () => {
|
|
4649
4877
|
sub.remove();
|
|
4650
4878
|
c.destroy();
|
|
@@ -4652,8 +4880,8 @@ function GuidelyProvider({ children, user, insets, launcherOffset = 72, ...optio
|
|
|
4652
4880
|
};
|
|
4653
4881
|
}, [projectId, environment, apiUrl, storage]);
|
|
4654
4882
|
const userKey = user ? JSON.stringify([user.id, user.traits ?? null, user.account ?? null]) : "";
|
|
4655
|
-
const hadUser = (0,
|
|
4656
|
-
(0,
|
|
4883
|
+
const hadUser = (0, import_react9.useRef)(false);
|
|
4884
|
+
(0, import_react9.useEffect)(() => {
|
|
4657
4885
|
if (!client) return;
|
|
4658
4886
|
if (user && user.id) {
|
|
4659
4887
|
hadUser.current = true;
|
|
@@ -4663,10 +4891,15 @@ function GuidelyProvider({ children, user, insets, launcherOffset = 72, ...optio
|
|
|
4663
4891
|
client.reset();
|
|
4664
4892
|
}
|
|
4665
4893
|
}, [client, userKey]);
|
|
4666
|
-
|
|
4894
|
+
(0, import_react9.useEffect)(() => {
|
|
4895
|
+
client?.flags.setAttributes(appAttributes);
|
|
4896
|
+
}, [client, appAttributes]);
|
|
4897
|
+
const bootstrap = useBootstrap(payload, { ...user?.id ? { ...user.traits ?? {}, id: user.id } : {}, ...appAttributes });
|
|
4898
|
+
const flags = (0, import_react9.useMemo)(() => ({ client: client?.flags ?? null, bootstrap }), [client, bootstrap]);
|
|
4899
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(GuidelyContext.Provider, { value: client, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(FlagsContext.Provider, { value: flags, children: [
|
|
4667
4900
|
children,
|
|
4668
|
-
client ? /* @__PURE__ */ (0,
|
|
4669
|
-
] });
|
|
4901
|
+
client ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(GuidelyOverlay, { client, insets, launcherOffset }) : null
|
|
4902
|
+
] }) });
|
|
4670
4903
|
}
|
|
4671
4904
|
var NOOP_RESULTS = {
|
|
4672
4905
|
init: Promise.resolve(),
|
|
@@ -4690,20 +4923,38 @@ var NOOP_RESULTS = {
|
|
|
4690
4923
|
},
|
|
4691
4924
|
getState: { ready: false, destroyed: false }
|
|
4692
4925
|
};
|
|
4926
|
+
var noopFlags = new Proxy((0, import_flags3.createStaticFlags)(), {
|
|
4927
|
+
get(target, prop, receiver) {
|
|
4928
|
+
if (prop in target) return Reflect.get(target, prop, receiver);
|
|
4929
|
+
if (prop === "ready" || prop === "refresh" || prop === "flush") return () => Promise.resolve();
|
|
4930
|
+
if (prop === "getPayload") return () => null;
|
|
4931
|
+
if (prop === "forUser") return () => target;
|
|
4932
|
+
return typeof prop === "string" ? () => void 0 : void 0;
|
|
4933
|
+
}
|
|
4934
|
+
});
|
|
4935
|
+
var missing = (key, fallback) => ({ key, value: fallback, reason: "FLAG_NOT_FOUND", inExperiment: false, usedFallback: true });
|
|
4936
|
+
var NOOP_FUNCTIONS = {
|
|
4937
|
+
isFeatureEnabled: (_key, fallback = false) => fallback,
|
|
4938
|
+
getFeatureValue: (_key, fallback) => fallback,
|
|
4939
|
+
getFeatureDetails: (key, fallback) => missing(key, fallback),
|
|
4940
|
+
onFlagsChange: () => () => {
|
|
4941
|
+
}
|
|
4942
|
+
};
|
|
4693
4943
|
var noopClient = new Proxy({}, {
|
|
4694
4944
|
get(_target, prop) {
|
|
4695
4945
|
if (prop === "options") return { projectId: "" };
|
|
4946
|
+
if (prop === "flags") return noopFlags;
|
|
4696
4947
|
if (typeof prop !== "string") return void 0;
|
|
4697
|
-
return () => NOOP_RESULTS[prop];
|
|
4948
|
+
return NOOP_FUNCTIONS[prop] ?? (() => NOOP_RESULTS[prop]);
|
|
4698
4949
|
}
|
|
4699
4950
|
});
|
|
4700
4951
|
function useGuidely() {
|
|
4701
|
-
return (0,
|
|
4952
|
+
return (0, import_react9.useContext)(GuidelyContext) ?? noopClient;
|
|
4702
4953
|
}
|
|
4703
4954
|
function useGuidelyReady() {
|
|
4704
|
-
const client = (0,
|
|
4705
|
-
const [ready, setReady] = (0,
|
|
4706
|
-
(0,
|
|
4955
|
+
const client = (0, import_react9.useContext)(GuidelyContext);
|
|
4956
|
+
const [ready, setReady] = (0, import_react9.useState)(() => !!client?.isClientReady());
|
|
4957
|
+
(0, import_react9.useEffect)(() => {
|
|
4707
4958
|
if (!client) return setReady(false);
|
|
4708
4959
|
setReady(client.isClientReady());
|
|
4709
4960
|
const off = client.on("ready", () => setReady(true));
|
|
@@ -4713,44 +4964,44 @@ function useGuidelyReady() {
|
|
|
4713
4964
|
return ready;
|
|
4714
4965
|
}
|
|
4715
4966
|
function useGuidelyIdentify(userId, traits, account) {
|
|
4716
|
-
const client = (0,
|
|
4967
|
+
const client = (0, import_react9.useContext)(GuidelyContext);
|
|
4717
4968
|
const key = JSON.stringify([userId ?? null, traits ?? null, account ?? null]);
|
|
4718
|
-
(0,
|
|
4969
|
+
(0, import_react9.useEffect)(() => {
|
|
4719
4970
|
if (client && userId) void client.identify(userId, traits, account);
|
|
4720
4971
|
}, [client, key]);
|
|
4721
4972
|
}
|
|
4722
4973
|
function useGuidelyEvent(event, handler) {
|
|
4723
|
-
const client = (0,
|
|
4724
|
-
const ref = (0,
|
|
4974
|
+
const client = (0, import_react9.useContext)(GuidelyContext);
|
|
4975
|
+
const ref = (0, import_react9.useRef)(handler);
|
|
4725
4976
|
ref.current = handler;
|
|
4726
|
-
(0,
|
|
4977
|
+
(0, import_react9.useEffect)(() => {
|
|
4727
4978
|
if (!client) return;
|
|
4728
4979
|
return client.on(event, ((...args) => ref.current(...args)));
|
|
4729
4980
|
}, [client, event]);
|
|
4730
4981
|
}
|
|
4731
4982
|
function useGuidelyScreen(name, properties) {
|
|
4732
|
-
const client = (0,
|
|
4733
|
-
(0,
|
|
4983
|
+
const client = (0, import_react9.useContext)(GuidelyContext);
|
|
4984
|
+
(0, import_react9.useEffect)(() => {
|
|
4734
4985
|
if (client && name) client.screen(name, properties);
|
|
4735
4986
|
}, [client, name]);
|
|
4736
4987
|
}
|
|
4737
4988
|
function useGuidelyNavigation(navigationRef, options = {}) {
|
|
4738
|
-
const client = (0,
|
|
4739
|
-
const nameRef = (0,
|
|
4989
|
+
const client = (0, import_react9.useContext)(GuidelyContext);
|
|
4990
|
+
const nameRef = (0, import_react9.useRef)(options.screenName);
|
|
4740
4991
|
nameRef.current = options.screenName;
|
|
4741
4992
|
const report = () => {
|
|
4742
4993
|
const route = navigationRef.getCurrentRoute?.();
|
|
4743
4994
|
if (client && route?.name) client.screen(nameRef.current ? nameRef.current(route) : route.name);
|
|
4744
4995
|
};
|
|
4745
|
-
(0,
|
|
4996
|
+
(0, import_react9.useEffect)(report, [client]);
|
|
4746
4997
|
return { onReady: report, onStateChange: report };
|
|
4747
4998
|
}
|
|
4748
4999
|
function useUiSelector(select, fallback) {
|
|
4749
|
-
const client = (0,
|
|
4750
|
-
const selectRef = (0,
|
|
5000
|
+
const client = (0, import_react9.useContext)(GuidelyContext);
|
|
5001
|
+
const selectRef = (0, import_react9.useRef)(select);
|
|
4751
5002
|
selectRef.current = select;
|
|
4752
|
-
const [value, setValue] = (0,
|
|
4753
|
-
(0,
|
|
5003
|
+
const [value, setValue] = (0, import_react9.useState)(() => client ? select(client) : fallback);
|
|
5004
|
+
(0, import_react9.useEffect)(() => {
|
|
4754
5005
|
if (!client) return;
|
|
4755
5006
|
let last = JSON.stringify(selectRef.current(client));
|
|
4756
5007
|
setValue(selectRef.current(client));
|
|
@@ -4785,15 +5036,21 @@ function useActiveGuide() {
|
|
|
4785
5036
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4786
5037
|
0 && (module.exports = {
|
|
4787
5038
|
DEFAULT_API_URL,
|
|
5039
|
+
Feature,
|
|
5040
|
+
FeatureFlag,
|
|
5041
|
+
FeatureValue,
|
|
5042
|
+
FlagsProvider,
|
|
4788
5043
|
GuidelyClient,
|
|
4789
5044
|
GuidelyOverlay,
|
|
4790
5045
|
GuidelyProvider,
|
|
4791
5046
|
GuidelyScreenScope,
|
|
4792
5047
|
GuidelyTarget,
|
|
5048
|
+
InMemoryStickyBucketStore,
|
|
4793
5049
|
Messenger,
|
|
4794
5050
|
SDK_NAME,
|
|
4795
5051
|
SDK_VERSION,
|
|
4796
5052
|
TargetRegistry,
|
|
5053
|
+
createFlagsClient,
|
|
4797
5054
|
createSseParser,
|
|
4798
5055
|
guidelyScreenLayout,
|
|
4799
5056
|
htmlToText,
|
|
@@ -4803,6 +5060,12 @@ function useActiveGuide() {
|
|
|
4803
5060
|
targetIdsFor,
|
|
4804
5061
|
useActiveGuide,
|
|
4805
5062
|
useChecklistProgress,
|
|
5063
|
+
useFeatureValue,
|
|
5064
|
+
useFlag,
|
|
5065
|
+
useFlagDetails,
|
|
5066
|
+
useFlags,
|
|
5067
|
+
useFlagsClient,
|
|
5068
|
+
useFlagsReady,
|
|
4806
5069
|
useGuideState,
|
|
4807
5070
|
useGuidely,
|
|
4808
5071
|
useGuidelyEvent,
|