@wireai/activation 0.1.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/AGENTS.md +73 -0
- package/CHANGELOG.md +572 -0
- package/INTEGRATION_PROMPT.md +55 -0
- package/LICENSE +21 -0
- package/README.md +923 -0
- package/dist/CenteredModal-C3qQBHsA.d.mts +38 -0
- package/dist/CenteredModal-Cdgns6--.d.ts +38 -0
- package/dist/coachmarks/index.d.mts +352 -0
- package/dist/coachmarks/index.d.ts +352 -0
- package/dist/coachmarks/index.js +944 -0
- package/dist/coachmarks/index.js.map +1 -0
- package/dist/coachmarks/index.mjs +918 -0
- package/dist/coachmarks/index.mjs.map +1 -0
- package/dist/decision-CFvGY6nP.d.ts +228 -0
- package/dist/decision-Cl8OFYzu.d.mts +228 -0
- package/dist/index.d.mts +1390 -0
- package/dist/index.d.ts +1390 -0
- package/dist/index.js +3260 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3186 -0
- package/dist/index.mjs.map +1 -0
- package/dist/questionnaire/index.d.mts +249 -0
- package/dist/questionnaire/index.d.ts +249 -0
- package/dist/questionnaire/index.js +922 -0
- package/dist/questionnaire/index.js.map +1 -0
- package/dist/questionnaire/index.mjs +906 -0
- package/dist/questionnaire/index.mjs.map +1 -0
- package/dist/reviews/index.d.mts +213 -0
- package/dist/reviews/index.d.ts +213 -0
- package/dist/reviews/index.js +1001 -0
- package/dist/reviews/index.js.map +1 -0
- package/dist/reviews/index.mjs +971 -0
- package/dist/reviews/index.mjs.map +1 -0
- package/dist/showcase/index.d.mts +119 -0
- package/dist/showcase/index.d.ts +119 -0
- package/dist/showcase/index.js +660 -0
- package/dist/showcase/index.js.map +1 -0
- package/dist/showcase/index.mjs +651 -0
- package/dist/showcase/index.mjs.map +1 -0
- package/dist/types-BKfpdZzX.d.mts +84 -0
- package/dist/types-BKfpdZzX.d.ts +84 -0
- package/dist/types-CMuOexw0.d.mts +116 -0
- package/dist/types-CMuOexw0.d.ts +116 -0
- package/dist/types-GL_hQ0TN.d.mts +46 -0
- package/dist/types-GL_hQ0TN.d.ts +46 -0
- package/llms.txt +36 -0
- package/metro/index.d.ts +32 -0
- package/metro/index.js +83 -0
- package/package.json +171 -0
- package/src/DemoOnboarding.tsx +133 -0
- package/src/OnboardingFlow.tsx +504 -0
- package/src/WireOnboarding.tsx +248 -0
- package/src/analytics/analyticsEvent.ts +69 -0
- package/src/analytics/reportClientEvent.ts +119 -0
- package/src/analytics/sendPreview.ts +73 -0
- package/src/attribution/attribution.ts +46 -0
- package/src/cards/ChipSelectCard.tsx +265 -0
- package/src/cards/InterstitialCard.tsx +299 -0
- package/src/cards/NumberStepperCard.tsx +121 -0
- package/src/cards/SelectionCard.tsx +270 -0
- package/src/cards/StatusCard.tsx +170 -0
- package/src/cards/TextInputCard.tsx +147 -0
- package/src/cards/index.ts +23 -0
- package/src/coachmarks/CoachmarkOverlayHost.tsx +44 -0
- package/src/coachmarks/CoachmarkProvider.tsx +108 -0
- package/src/coachmarks/GestureHint.tsx +331 -0
- package/src/coachmarks/SpotlightOverlay.tsx +254 -0
- package/src/coachmarks/coachmarkAnchorRegistry.ts +70 -0
- package/src/coachmarks/coachmarkOverlayStore.ts +63 -0
- package/src/coachmarks/index.ts +62 -0
- package/src/coachmarks/runtime.ts +103 -0
- package/src/coachmarks/selectTourSteps.ts +45 -0
- package/src/coachmarks/types.ts +58 -0
- package/src/coachmarks/useCoachmarkAnchor.ts +49 -0
- package/src/coachmarks/useCoachmarkTour.ts +200 -0
- package/src/components/AnimatedSparkle.tsx +101 -0
- package/src/components/Button.tsx +129 -0
- package/src/components/CardHandoff.tsx +212 -0
- package/src/components/CardLayout.tsx +103 -0
- package/src/components/CenteredModal.tsx +184 -0
- package/src/components/CompletionView.tsx +186 -0
- package/src/components/DoneBlock.tsx +37 -0
- package/src/components/ErrorBlock.tsx +42 -0
- package/src/components/Illustration.tsx +36 -0
- package/src/components/LoadingBlock.tsx +182 -0
- package/src/components/LoadingScreen.tsx +35 -0
- package/src/components/OnboardingScaffold.tsx +105 -0
- package/src/components/StepProgress.tsx +85 -0
- package/src/components/loaderChrome.ts +28 -0
- package/src/config/onboardingFlag.ts +39 -0
- package/src/config/wireConfigFromEnv.ts +52 -0
- package/src/device/deviceContext.ts +158 -0
- package/src/features/WireFeaturesProvider.tsx +81 -0
- package/src/features/cache.ts +92 -0
- package/src/features/defaults.ts +67 -0
- package/src/features/fetchWireFeatures.ts +86 -0
- package/src/features/index.ts +39 -0
- package/src/features/types.ts +61 -0
- package/src/features/useWireFeatures.ts +57 -0
- package/src/identity/userIdentity.ts +100 -0
- package/src/illustrations/defaultIllustrations.tsx +99 -0
- package/src/index.ts +159 -0
- package/src/motion/centeredModalMotion.ts +45 -0
- package/src/motion/motionSpec.ts +133 -0
- package/src/motion/useReducedMotion.ts +43 -0
- package/src/questionnaire/QuestionnaireGate.tsx +235 -0
- package/src/questionnaire/decision.ts +63 -0
- package/src/questionnaire/index.ts +54 -0
- package/src/questionnaire/runtime.ts +20 -0
- package/src/questionnaire/transport.ts +83 -0
- package/src/questionnaire/types.ts +182 -0
- package/src/questionnaire/useQuestionnaireGate.ts +159 -0
- package/src/reviews/ReviewGate.tsx +316 -0
- package/src/reviews/ReviewModal.tsx +13 -0
- package/src/reviews/decision.ts +120 -0
- package/src/reviews/equality.ts +54 -0
- package/src/reviews/expo-store-review.d.ts +16 -0
- package/src/reviews/feedbackForm.ts +41 -0
- package/src/reviews/index.ts +78 -0
- package/src/reviews/presentation.ts +29 -0
- package/src/reviews/runtime.ts +45 -0
- package/src/reviews/storeReview.ts +62 -0
- package/src/reviews/transport.ts +89 -0
- package/src/reviews/types.ts +172 -0
- package/src/reviews/useReviewGate.ts +137 -0
- package/src/session/persistedSession.ts +143 -0
- package/src/session-analytics/index.ts +18 -0
- package/src/session-analytics/reportSessionStart.ts +144 -0
- package/src/session-analytics/useSessionStart.ts +114 -0
- package/src/showcase/FeatureShowcase.tsx +233 -0
- package/src/showcase/index.ts +19 -0
- package/src/showcase/selectShowcaseSlides.ts +45 -0
- package/src/showcase/showcaseColors.ts +91 -0
- package/src/showcase/types.ts +74 -0
- package/src/theme/ThemeContext.tsx +38 -0
- package/src/theme/defaultTheme.ts +70 -0
- package/src/theme/themeFromBrand.ts +93 -0
- package/src/theme/types.ts +88 -0
- package/src/theme/typography.ts +46 -0
- package/src/types.ts +215 -0
- package/src/utils/deriveAnswers.ts +43 -0
- package/src/utils/readProgress.ts +33 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the coachmark / guided-tour overlay engine.
|
|
3
|
+
*
|
|
4
|
+
* Lifted from the Myelino app engine and made kit-generic: the app supplies the
|
|
5
|
+
* anchors + catalog + copy, the kit owns the animation/measure/queue mechanics.
|
|
6
|
+
* Dependency-free on purpose so the type surface can be imported anywhere.
|
|
7
|
+
*/
|
|
8
|
+
/** The animated hand/gesture shown over or beside a highlighted target. */
|
|
9
|
+
type GestureKind = "swipe_up" | "swipe_down" | "swipe_left" | "swipe_right" | "tap" | "double_tap" | "pinch" | "zoom" | "none";
|
|
10
|
+
/** Which side of the highlighted target the tooltip pill sits on. */
|
|
11
|
+
type Placement = "top" | "bottom" | "left" | "right" | "center";
|
|
12
|
+
/** A measured on-screen rectangle (window coordinates from measureInWindow). */
|
|
13
|
+
interface TargetRect {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The host-injected gate storage. SYNCHRONOUS on purpose — a coachmark's
|
|
21
|
+
* "seen?" gate must resolve during render with no async flash (otherwise a ring
|
|
22
|
+
* momentarily paints before the read resolves and says "already seen"). MMKV's
|
|
23
|
+
* `getString`/`set` fit as-is; an in-memory `Map` wrapper works for tests. This
|
|
24
|
+
* is deliberately separate from the async `WireOnboardingStorage` used for
|
|
25
|
+
* session persistence.
|
|
26
|
+
*/
|
|
27
|
+
interface CoachmarkStorage {
|
|
28
|
+
getItem(key: string): string | null;
|
|
29
|
+
setItem(key: string, value: string): void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* One step in a guided tour. `anchorId` is looked up in the anchor registry at
|
|
33
|
+
* fire time; omit it for a centered, target-less hint (e.g. a scroll gesture).
|
|
34
|
+
* `id` doubles as the analytics name for the step.
|
|
35
|
+
*/
|
|
36
|
+
interface CoachmarkStep {
|
|
37
|
+
id: string;
|
|
38
|
+
message: string;
|
|
39
|
+
gesture?: GestureKind;
|
|
40
|
+
placement?: Placement;
|
|
41
|
+
anchorId?: string;
|
|
42
|
+
/** Extra action when the step is engaged (e.g. navigate to another tab). */
|
|
43
|
+
onEngage?: () => void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type { CoachmarkStorage as C, GestureKind as G, Placement as P, TargetRect as T, CoachmarkStep as a };
|
package/llms.txt
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# wireai-onboarding
|
|
2
|
+
|
|
3
|
+
> A drop-in AI onboarding kit for React Native / Expo. One component, `<WireOnboarding>`, runs an
|
|
4
|
+
> entire backend-orchestrated, AI-driven onboarding flow (themed cards, progress bar, a mid-flow
|
|
5
|
+
> value screen, per-step validation, completion recap). It sits on top of the open-source
|
|
6
|
+
> [`wireai-rn`](https://github.com/chohra-med/wireai-rn) SDK and talks to a multi-tenant Wire AI
|
|
7
|
+
> backend over A2A. MIT licensed.
|
|
8
|
+
|
|
9
|
+
## What an agent needs to know
|
|
10
|
+
|
|
11
|
+
- **Install:** `npm install wireai-onboarding wireai-rn` (react + react-native are peers).
|
|
12
|
+
- **Metro (required):** `module.exports = withWireOnboarding(getDefaultConfig(__dirname))` from `wireai-onboarding/metro` — pins one copy of react/react-native/wireai-rn/zod (prevents the dual-React crash).
|
|
13
|
+
- **Two secrets:** an app `apiKey` (a `wai_…` key that resolves the tenant server-side) and the backend `serverUrl`. Created in the getwireai console or via the backend's `register_<app>.py`. Nothing renders without both.
|
|
14
|
+
- **Render:** drop `<WireOnboarding config={wireConfigFromEnv({ appId })} theme={...} onComplete={persist} fallbackFlow={<YourStaticOnboarding/>} />` into the signup flow.
|
|
15
|
+
- **Capture is deterministic** — `onComplete` returns `{ answers, raw }`; no second LLM call. Persist all answers through the app's normal profile-update path.
|
|
16
|
+
- **It can never break onboarding** — pass `fallbackFlow` (your existing static onboarding) so a backend error/timeout degrades instead of dead-ending.
|
|
17
|
+
|
|
18
|
+
## Helpers (the reusable substrate)
|
|
19
|
+
|
|
20
|
+
- `wireConfigFromEnv({ appId, metadata? })` → config or null (reads `EXPO_PUBLIC_WIREAI_API_KEY`/`_SERVER_URL`/`_APP_ID`).
|
|
21
|
+
- `isOnboardingEnabled({ remote? })` → the standard gate (transport present: apiKey + serverUrl). No on/off env flag; `remote` is an optional kill-switch the app passes in.
|
|
22
|
+
- `WIRE_ONBOARDING_EVENTS` + `toAnalyticsEvent(event)` → canonical `wire_onboarding_*` funnel names; log via the app's own analytics.
|
|
23
|
+
- `attributionMetadata(a)` → shape install/ad attribution into `config.metadata` (forwarded to the agent).
|
|
24
|
+
- `reportClientEvent` / `makeSessionId` → report device-only funnel events to `POST /v1/events`. `<WireOnboarding>` does this automatically: `dropped` on unmount-without-complete, `client_fallback` on degrade-to-static. Hosts must not double-report fallback.
|
|
25
|
+
- `deriveAnswers(messages)`, `themeFromBrand({ primary })`, `defaultIllustrations`, `DemoOnboarding` (dev/QA, no account).
|
|
26
|
+
|
|
27
|
+
## Files
|
|
28
|
+
|
|
29
|
+
- [README.md](./README.md): full usage, props table, theming, distribution.
|
|
30
|
+
- [INTEGRATION_PROMPT.md](./INTEGRATION_PROMPT.md): a copy-paste prompt to make an AI agent (Claude Code) integrate this into an RN/Expo app end to end.
|
|
31
|
+
- [AGENTS.md](./AGENTS.md): the ordered integration brief for agents.
|
|
32
|
+
- [CHANGELOG.md](./CHANGELOG.md): version history.
|
|
33
|
+
|
|
34
|
+
## Fastest path
|
|
35
|
+
|
|
36
|
+
Run the `wire-rn-integration` Claude skill — it detects the app's conventions, wires Metro, derives a theme, scaffolds the screen, wires a fallback, and type-checks. Otherwise use INTEGRATION_PROMPT.md.
|
package/metro/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type declarations for the `wireai-onboarding/metro` helper. This module runs in
|
|
3
|
+
* Node inside metro.config.js, so the config is loosely typed (`any`-ish) to avoid
|
|
4
|
+
* coupling to a specific Metro/Expo version.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface WithWireOnboardingOptions {
|
|
8
|
+
/**
|
|
9
|
+
* The app dir whose `node_modules` the single-instance deps
|
|
10
|
+
* (react / react-native / wireai-rn / zod) resolve against. Default: process.cwd().
|
|
11
|
+
*/
|
|
12
|
+
appRoot?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Absolute path to the kit's `src/` dir. When set, the `wireai-onboarding`
|
|
15
|
+
* specifier maps here (source consumption) and the dir is added to watchFolders.
|
|
16
|
+
* When omitted, the kit resolves from the installed package.
|
|
17
|
+
*/
|
|
18
|
+
source?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Non-destructively wire the wireai-onboarding kit into an existing Metro config:
|
|
23
|
+
* pins single-instance deps to the app's copy, optionally maps the kit specifier
|
|
24
|
+
* to source + watches it. Mutates and returns the same config object.
|
|
25
|
+
*/
|
|
26
|
+
export function withWireOnboarding<TConfig extends Record<string, any>>(
|
|
27
|
+
config: TConfig,
|
|
28
|
+
options?: WithWireOnboardingOptions,
|
|
29
|
+
): TConfig;
|
|
30
|
+
|
|
31
|
+
/** The deps pinned to the app's single copy. */
|
|
32
|
+
export const SINGLE_INSTANCE_DEPS: readonly ['react', 'react-native', 'wireai-rn', 'zod'];
|
package/metro/index.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* withWireOnboarding — one-call Metro wiring for the wireai-onboarding kit.
|
|
3
|
+
*
|
|
4
|
+
* This file runs in Node inside your app's `metro.config.js` (it is NOT React
|
|
5
|
+
* Native code), so it's plain CommonJS with zero RN imports.
|
|
6
|
+
*
|
|
7
|
+
* It folds the ~25-line hand-written block (pin single-instance deps + map the
|
|
8
|
+
* kit specifier + watch source) into one non-destructive wrapper around your
|
|
9
|
+
* existing Metro config object.
|
|
10
|
+
*
|
|
11
|
+
* // External app (kit installed from git/tarball):
|
|
12
|
+
* const { getDefaultConfig } = require('expo/metro-config');
|
|
13
|
+
* const { withWireOnboarding } = require('wireai-onboarding/metro');
|
|
14
|
+
* module.exports = withWireOnboarding(getDefaultConfig(__dirname));
|
|
15
|
+
*
|
|
16
|
+
* // Source consumer (monorepo app, kit resolved from its src/):
|
|
17
|
+
* const path = require('path');
|
|
18
|
+
* module.exports = withWireOnboarding(getDefaultConfig(__dirname), {
|
|
19
|
+
* source: path.join(__dirname, '../../getwire_ai/wireai-onboarding/src'),
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* @param {object} config An existing Metro config object (e.g. from getDefaultConfig).
|
|
23
|
+
* @param {object} [options]
|
|
24
|
+
* @param {string} [options.appRoot=process.cwd()] The app dir whose node_modules
|
|
25
|
+
* the single-instance deps (react/react-native/wireai-rn/zod) resolve against.
|
|
26
|
+
* @param {string} [options.source] Absolute path to the kit's `src/` dir. When
|
|
27
|
+
* set, the kit specifier maps here (source consumption) and it's added to
|
|
28
|
+
* watchFolders; when omitted, the kit resolves from the installed package.
|
|
29
|
+
* @returns {object} The same config object, mutated in place and returned.
|
|
30
|
+
*/
|
|
31
|
+
'use strict';
|
|
32
|
+
|
|
33
|
+
const path = require('path');
|
|
34
|
+
|
|
35
|
+
/** Deps that MUST resolve to the app's single copy (a 2nd React instance crashes RN). */
|
|
36
|
+
const SINGLE_INSTANCE_DEPS = ['react', 'react-native', 'wireai-rn', 'zod'];
|
|
37
|
+
|
|
38
|
+
function withWireOnboarding(config, options) {
|
|
39
|
+
const opts = options || {};
|
|
40
|
+
const appRoot = opts.appRoot || process.cwd();
|
|
41
|
+
const source = opts.source;
|
|
42
|
+
|
|
43
|
+
if (!config || typeof config !== 'object') {
|
|
44
|
+
throw new Error('withWireOnboarding(config): expected a Metro config object.');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const appNodeModules = path.resolve(appRoot, 'node_modules');
|
|
48
|
+
|
|
49
|
+
// ── extraNodeModules: pin single-instance deps + map the kit specifier ──────
|
|
50
|
+
const resolver = config.resolver || (config.resolver = {});
|
|
51
|
+
const existingExtra = resolver.extraNodeModules || {};
|
|
52
|
+
|
|
53
|
+
const pinned = {};
|
|
54
|
+
for (const dep of SINGLE_INSTANCE_DEPS) {
|
|
55
|
+
pinned[dep] = path.join(appNodeModules, dep);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Source consumption maps the bare specifier to the kit src; otherwise leave it
|
|
59
|
+
// to the installed package (don't set it, so normal node_modules resolution wins).
|
|
60
|
+
const kitMapping = source ? { '@wireai/activation': source } : {};
|
|
61
|
+
|
|
62
|
+
// Helper defaults first, then the app's own explicit entries last so anything
|
|
63
|
+
// the app already set wins on conflict (non-destructive).
|
|
64
|
+
resolver.extraNodeModules = {
|
|
65
|
+
...pinned,
|
|
66
|
+
...kitMapping,
|
|
67
|
+
...existingExtra,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// ── watchFolders: add the kit source so Metro reads + HMRs it ───────────────
|
|
71
|
+
if (source) {
|
|
72
|
+
const existingWatch = Array.isArray(config.watchFolders) ? config.watchFolders : [];
|
|
73
|
+
config.watchFolders = existingWatch.includes(source)
|
|
74
|
+
? existingWatch
|
|
75
|
+
: [...existingWatch, source];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return config;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = { withWireOnboarding };
|
|
82
|
+
module.exports.withWireOnboarding = withWireOnboarding;
|
|
83
|
+
module.exports.SINGLE_INSTANCE_DEPS = SINGLE_INSTANCE_DEPS;
|
package/package.json
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wireai/activation",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Premium, fully-themable drop-in AI onboarding kit for React Native / Expo, on top of the open-source wireai-rn SDK.",
|
|
6
|
+
"author": "Malik Chohra <malik@getwireai.com>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/chohra-med/wireai-onboarding#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/chohra-med/wireai-onboarding.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/chohra-med/wireai-onboarding/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react-native",
|
|
18
|
+
"expo",
|
|
19
|
+
"onboarding",
|
|
20
|
+
"ai",
|
|
21
|
+
"generative-ui",
|
|
22
|
+
"wireai",
|
|
23
|
+
"wireai-rn",
|
|
24
|
+
"dynamic-onboarding"
|
|
25
|
+
],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"main": "dist/index.js",
|
|
31
|
+
"module": "dist/index.mjs",
|
|
32
|
+
"types": "dist/index.d.ts",
|
|
33
|
+
"react-native": "src/index.ts",
|
|
34
|
+
"exports": {
|
|
35
|
+
".": {
|
|
36
|
+
"react-native": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"default": "./src/index.ts"
|
|
39
|
+
},
|
|
40
|
+
"import": {
|
|
41
|
+
"types": "./dist/index.d.mts",
|
|
42
|
+
"default": "./dist/index.mjs"
|
|
43
|
+
},
|
|
44
|
+
"require": {
|
|
45
|
+
"types": "./dist/index.d.ts",
|
|
46
|
+
"default": "./dist/index.js"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"./coachmarks": {
|
|
50
|
+
"react-native": {
|
|
51
|
+
"types": "./dist/coachmarks/index.d.ts",
|
|
52
|
+
"default": "./src/coachmarks/index.ts"
|
|
53
|
+
},
|
|
54
|
+
"import": {
|
|
55
|
+
"types": "./dist/coachmarks/index.d.mts",
|
|
56
|
+
"default": "./dist/coachmarks/index.mjs"
|
|
57
|
+
},
|
|
58
|
+
"require": {
|
|
59
|
+
"types": "./dist/coachmarks/index.d.ts",
|
|
60
|
+
"default": "./dist/coachmarks/index.js"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"./showcase": {
|
|
64
|
+
"react-native": {
|
|
65
|
+
"types": "./dist/showcase/index.d.ts",
|
|
66
|
+
"default": "./src/showcase/index.ts"
|
|
67
|
+
},
|
|
68
|
+
"import": {
|
|
69
|
+
"types": "./dist/showcase/index.d.mts",
|
|
70
|
+
"default": "./dist/showcase/index.mjs"
|
|
71
|
+
},
|
|
72
|
+
"require": {
|
|
73
|
+
"types": "./dist/showcase/index.d.ts",
|
|
74
|
+
"default": "./dist/showcase/index.js"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"./reviews": {
|
|
78
|
+
"react-native": {
|
|
79
|
+
"types": "./dist/reviews/index.d.ts",
|
|
80
|
+
"default": "./src/reviews/index.ts"
|
|
81
|
+
},
|
|
82
|
+
"import": {
|
|
83
|
+
"types": "./dist/reviews/index.d.mts",
|
|
84
|
+
"default": "./dist/reviews/index.mjs"
|
|
85
|
+
},
|
|
86
|
+
"require": {
|
|
87
|
+
"types": "./dist/reviews/index.d.ts",
|
|
88
|
+
"default": "./dist/reviews/index.js"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"./questionnaire": {
|
|
92
|
+
"react-native": {
|
|
93
|
+
"types": "./dist/questionnaire/index.d.ts",
|
|
94
|
+
"default": "./src/questionnaire/index.ts"
|
|
95
|
+
},
|
|
96
|
+
"import": {
|
|
97
|
+
"types": "./dist/questionnaire/index.d.mts",
|
|
98
|
+
"default": "./dist/questionnaire/index.mjs"
|
|
99
|
+
},
|
|
100
|
+
"require": {
|
|
101
|
+
"types": "./dist/questionnaire/index.d.ts",
|
|
102
|
+
"default": "./dist/questionnaire/index.js"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"./metro": {
|
|
106
|
+
"types": "./metro/index.d.ts",
|
|
107
|
+
"default": "./metro/index.js"
|
|
108
|
+
},
|
|
109
|
+
"./package.json": "./package.json"
|
|
110
|
+
},
|
|
111
|
+
"files": [
|
|
112
|
+
"dist",
|
|
113
|
+
"src",
|
|
114
|
+
"!src/**/*.test.ts",
|
|
115
|
+
"!src/**/*.test.tsx",
|
|
116
|
+
"metro",
|
|
117
|
+
"README.md",
|
|
118
|
+
"AGENTS.md",
|
|
119
|
+
"CHANGELOG.md",
|
|
120
|
+
"llms.txt",
|
|
121
|
+
"INTEGRATION_PROMPT.md"
|
|
122
|
+
],
|
|
123
|
+
"scripts": {
|
|
124
|
+
"build": "tsup",
|
|
125
|
+
"prepack": "npm run build",
|
|
126
|
+
"typecheck": "tsc --noEmit",
|
|
127
|
+
"test": "node --test --experimental-strip-types --import ./test/register-ts-resolver.mjs \"src/**/*.test.ts\" \"test/canary/**/*.test.tsx\"",
|
|
128
|
+
"pack:tarball": "npm pack"
|
|
129
|
+
},
|
|
130
|
+
"peerDependencies": {
|
|
131
|
+
"@blazejkustra/react-native-onboarding": ">=1",
|
|
132
|
+
"expo-blur": ">=13",
|
|
133
|
+
"expo-store-review": ">=6",
|
|
134
|
+
"react": ">=18.0.0",
|
|
135
|
+
"react-native": ">=0.73.0",
|
|
136
|
+
"react-native-reanimated": ">=3",
|
|
137
|
+
"react-native-safe-area-context": ">=4.0.0",
|
|
138
|
+
"wireai-rn": ">=0.2.3",
|
|
139
|
+
"zod": ">=3"
|
|
140
|
+
},
|
|
141
|
+
"peerDependenciesMeta": {
|
|
142
|
+
"zod": {
|
|
143
|
+
"optional": false
|
|
144
|
+
},
|
|
145
|
+
"react-native-reanimated": {
|
|
146
|
+
"optional": true
|
|
147
|
+
},
|
|
148
|
+
"expo-blur": {
|
|
149
|
+
"optional": true
|
|
150
|
+
},
|
|
151
|
+
"expo-store-review": {
|
|
152
|
+
"optional": true
|
|
153
|
+
},
|
|
154
|
+
"@blazejkustra/react-native-onboarding": {
|
|
155
|
+
"optional": true
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"devDependencies": {
|
|
159
|
+
"@blazejkustra/react-native-onboarding": "^1.0.1",
|
|
160
|
+
"@types/react": "^19.0.0",
|
|
161
|
+
"expo-blur": "^15.0.0",
|
|
162
|
+
"react": "^19.2.7",
|
|
163
|
+
"react-native": "^0.86.0",
|
|
164
|
+
"react-native-reanimated": "^4.1.1",
|
|
165
|
+
"react-native-safe-area-context": "^4.14.1",
|
|
166
|
+
"react-test-renderer": "^19.2.7",
|
|
167
|
+
"sucrase": "^3.35.1",
|
|
168
|
+
"tsup": "^8.0.0",
|
|
169
|
+
"typescript": "^5.4.0"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DemoOnboarding — a drop-in dev/QA trigger that runs the onboarding flow ON
|
|
3
|
+
* DEMAND in a modal, then closes. No loop, no account, no navigation side-effects:
|
|
4
|
+
* re-runnable infinitely with the same logged-in user. Place it anywhere a host
|
|
5
|
+
* wants (e.g. a __DEV__ row in Settings). If `config` is null (the app hasn't
|
|
6
|
+
* integrated Wire AI yet), it shows a hint instead of the flow.
|
|
7
|
+
*
|
|
8
|
+
* {__DEV__ && (
|
|
9
|
+
* <DemoOnboarding config={wireConfigFromEnv({ appId: "my-app" })} theme={myTheme} />
|
|
10
|
+
* )}
|
|
11
|
+
*
|
|
12
|
+
* It does NOT persist by default (a demo, not a real run) — pass `onComplete` if
|
|
13
|
+
* you want to observe the captured answers.
|
|
14
|
+
*/
|
|
15
|
+
import { useCallback, useMemo, useState, type ReactNode } from "react";
|
|
16
|
+
import { Modal, Pressable, StyleSheet, Text, View } from "react-native";
|
|
17
|
+
|
|
18
|
+
import { WireOnboarding } from "./WireOnboarding";
|
|
19
|
+
import { mergeTheme } from "./theme/defaultTheme";
|
|
20
|
+
import type { OnboardingTheme } from "./theme/types";
|
|
21
|
+
import type { OnboardingResult, WireOnboardingConfig, WireOnboardingProps } from "./types";
|
|
22
|
+
|
|
23
|
+
export type DemoOnboardingProps = {
|
|
24
|
+
/** The Wire AI config, or `null` when the app hasn't integrated Wire AI yet. */
|
|
25
|
+
config: WireOnboardingConfig | null;
|
|
26
|
+
theme?: WireOnboardingProps["theme"];
|
|
27
|
+
illustrations?: WireOnboardingProps["illustrations"];
|
|
28
|
+
validators?: WireOnboardingProps["validators"];
|
|
29
|
+
copy?: WireOnboardingProps["copy"];
|
|
30
|
+
/** Trigger button label. Default "Demo onboarding". */
|
|
31
|
+
label?: string;
|
|
32
|
+
/** Observe the demo result. By default the demo just closes (no persistence). */
|
|
33
|
+
onComplete?: (result: OnboardingResult) => void;
|
|
34
|
+
/** Render your own trigger instead of the default button: `(open) => <YourButton onPress={open} />`. */
|
|
35
|
+
renderTrigger?: (open: () => void) => ReactNode;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function DemoOnboarding({
|
|
39
|
+
config,
|
|
40
|
+
theme,
|
|
41
|
+
illustrations,
|
|
42
|
+
validators,
|
|
43
|
+
copy,
|
|
44
|
+
label = "Demo onboarding",
|
|
45
|
+
onComplete,
|
|
46
|
+
renderTrigger,
|
|
47
|
+
}: DemoOnboardingProps) {
|
|
48
|
+
const [open, setOpen] = useState(false);
|
|
49
|
+
const [runId, setRunId] = useState(0);
|
|
50
|
+
const t = useMemo(() => mergeTheme(theme ?? {}), [theme]);
|
|
51
|
+
const styles = useMemo(() => makeStyles(t), [t]);
|
|
52
|
+
|
|
53
|
+
const openDemo = useCallback(() => {
|
|
54
|
+
setRunId((n) => n + 1); // remount WireOnboarding → a fresh A2A session each open
|
|
55
|
+
setOpen(true);
|
|
56
|
+
}, []);
|
|
57
|
+
const close = useCallback(() => setOpen(false), []);
|
|
58
|
+
const finish = useCallback(
|
|
59
|
+
(result: OnboardingResult) => {
|
|
60
|
+
onComplete?.(result);
|
|
61
|
+
setOpen(false);
|
|
62
|
+
},
|
|
63
|
+
[onComplete],
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<>
|
|
68
|
+
{renderTrigger ? (
|
|
69
|
+
renderTrigger(openDemo)
|
|
70
|
+
) : (
|
|
71
|
+
<Pressable onPress={openDemo} style={styles.trigger} accessibilityRole="button">
|
|
72
|
+
<Text style={styles.triggerText}>{label}</Text>
|
|
73
|
+
</Pressable>
|
|
74
|
+
)}
|
|
75
|
+
|
|
76
|
+
<Modal
|
|
77
|
+
visible={open}
|
|
78
|
+
animationType="slide"
|
|
79
|
+
presentationStyle="fullScreen"
|
|
80
|
+
onRequestClose={close}
|
|
81
|
+
>
|
|
82
|
+
<View style={styles.modal}>
|
|
83
|
+
{config ? (
|
|
84
|
+
<WireOnboarding
|
|
85
|
+
key={runId}
|
|
86
|
+
config={config}
|
|
87
|
+
theme={theme}
|
|
88
|
+
illustrations={illustrations}
|
|
89
|
+
validators={validators}
|
|
90
|
+
copy={copy}
|
|
91
|
+
onComplete={finish}
|
|
92
|
+
onSkip={close}
|
|
93
|
+
onError={close}
|
|
94
|
+
/>
|
|
95
|
+
) : (
|
|
96
|
+
<View style={styles.notice}>
|
|
97
|
+
<Text style={styles.noticeTitle}>Wire AI not configured</Text>
|
|
98
|
+
<Text style={styles.noticeBody}>
|
|
99
|
+
Set the Wire AI key + server URL (e.g. via wireConfigFromEnv) to demo the AI
|
|
100
|
+
onboarding here.
|
|
101
|
+
</Text>
|
|
102
|
+
<Pressable onPress={close} style={styles.trigger} accessibilityRole="button">
|
|
103
|
+
<Text style={styles.triggerText}>Close</Text>
|
|
104
|
+
</Pressable>
|
|
105
|
+
</View>
|
|
106
|
+
)}
|
|
107
|
+
</View>
|
|
108
|
+
</Modal>
|
|
109
|
+
</>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function makeStyles(t: OnboardingTheme) {
|
|
114
|
+
return StyleSheet.create({
|
|
115
|
+
trigger: {
|
|
116
|
+
backgroundColor: t.colors.primary,
|
|
117
|
+
borderRadius: t.button.radius,
|
|
118
|
+
paddingVertical: 14,
|
|
119
|
+
paddingHorizontal: 20,
|
|
120
|
+
alignItems: "center",
|
|
121
|
+
},
|
|
122
|
+
triggerText: { color: t.colors.onPrimary, fontFamily: t.fonts.medium, fontSize: 16 },
|
|
123
|
+
modal: { flex: 1, backgroundColor: t.colors.background },
|
|
124
|
+
notice: { flex: 1, alignItems: "center", justifyContent: "center", padding: 24, gap: 12 },
|
|
125
|
+
noticeTitle: { color: t.colors.text, fontFamily: t.fonts.bold, fontSize: 20 },
|
|
126
|
+
noticeBody: {
|
|
127
|
+
color: t.colors.textMuted,
|
|
128
|
+
fontFamily: t.fonts.regular,
|
|
129
|
+
fontSize: 15,
|
|
130
|
+
textAlign: "center",
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|