ReviewOS

also looking at this

craft-native/craft

fix(ios): hand the page the answers native was already sending

#222
Merged glennmichael123 wants to merge fix/ios-unanswered-posts into main
18 files +597 -164

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

docs/api/mobile/haptics.mdmodified+7-0
Changes to docs/api/mobile/haptics.md
@@ -2,6 +2,13 @@
22
33Provide tactile feedback through device vibrations.
44
5Haptics are feedback, so these methods never stop a flow for a capability the
6app left off. On iOS, with `enableHaptics` off in `craft.config.json`, they
7resolve without playing anything, the way the web fallback does on a device
8with no vibration motor. They reject only when the native call itself fails.
9The raw `window.craft.haptic()` is different: it rejects with
10`CAPABILITY_DISABLED`, for code that needs to know.
11
512## Import
613
714```typescript
packages/ios/README.mdmodified+11-8
Changes to packages/ios/README.md
@@ -159,14 +159,17 @@ window.addEventListener('craftReady', (e) => {
159159 console.log('Capabilities:', e.detail.capabilities);
160160});
161161
162// Haptic feedback
163window.craft.haptic('light'); // light, medium, heavy
164window.craft.haptic('success'); // success, warning, error
165window.craft.haptic('selection');
166
167// Speech recognition
168window.craft.startListening();
169window.craft.stopListening();
162// Haptic feedback. Resolves true, and rejects with CAPABILITY_DISABLED when
163// enableHaptics is off.
164await window.craft.haptic('light'); // light, medium, heavy
165await window.craft.haptic('success'); // success, warning, error
166await window.craft.haptic('selection');
167
168// Speech recognition. startListening resolves true once the request is
169// taken; whether listening actually began arrives as the events below
170// (craftSpeechError for a declined prompt or no recognizer).
171await window.craft.startListening();
172await window.craft.stopListening();
170173
171174// Listen for speech events
172175window.addEventListener('craftSpeechStart', () => { /* recording started */ });
packages/react/src/index.tsmodified+8-1
Changes to packages/react/src/index.ts
@@ -127,7 +127,14 @@ export function useHaptic() {
127127 console.warn('Craft not ready');
128128 return;
129129 }
130 await craft.haptic(type);
130 try {
131 await craft.haptic(type);
132 }
133 catch (error) {
134 // Feedback: an app built with haptics off plays nothing, the same as
135 // Craft not being ready. Any other failure still reaches the caller.
136 if ((error as { code?: string } | null)?.code !== 'CAPABILITY_DISABLED') throw error;
137 }
131138 },
132139 [craft, isReady]
133140 );
packages/svelte/src/actions/haptic.tsmodified+8-1
Changes to packages/svelte/src/actions/haptic.ts
@@ -5,7 +5,14 @@ export function haptic(node: HTMLElement, type: string = 'selection') {
55 const handleClick = async () => {
66 const _$craft = get(craft);
77 if (!_$craft) return;
8 await _$craft.haptic(type);
8 try {
9 await _$craft.haptic(type);
10 }
11 catch (error) {
12 // Feedback: an app built with haptics off plays nothing on click, rather
13 // than an unhandled rejection. Any other failure still surfaces.
14 if ((error as { code?: string } | null)?.code !== 'CAPABILITY_DISABLED') throw error;
15 }
916 };
1017
1118 node.addEventListener('click', handleClick);
packages/vue/src/index.tsmodified+8-1
Changes to packages/vue/src/index.ts
@@ -128,7 +128,14 @@ export function useHaptic() {
128128 console.warn('Craft not ready');
129129 return;
130130 }
131 await craft.value.haptic(type);
131 try {
132 await craft.value.haptic(type);
133 }
134 catch (error) {
135 // Feedback: an app built with haptics off plays nothing, the same as
136 // Craft not being ready. Any other failure still reaches the caller.
137 if ((error as { code?: string } | null)?.code !== 'CAPABILITY_DISABLED') throw error;
138 }
132139 };
133140
134141 return { haptic };