react-pebble 0.1.0 → 0.2.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.
@@ -41,6 +41,12 @@ export interface PebblePiuOptions {
41
41
  settleMs?: number;
42
42
  /** Target platform — sets screen dimensions (default: 'emery') */
43
43
  platform?: string;
44
+ /**
45
+ * Target platforms for multi-platform builds (e.g. ['emery', 'gabbro']).
46
+ * When set, builds once per platform into `{buildDir}-{platform}/`.
47
+ * Overrides the `platform` option.
48
+ */
49
+ targetPlatforms?: string[];
44
50
  /** Directory for the generated Pebble project (default: '.pebble-build') */
45
51
  buildDir?: string;
46
52
  /** Auto-run pebble build + install after compilation */
@@ -63,51 +69,60 @@ export function pebblePiu(options: PebblePiuOptions): Plugin {
63
69
  async closeBundle() {
64
70
  const log = (msg: string) => console.log(`[react-pebble] ${msg}`);
65
71
 
66
- // 1. Compile JSX piu
67
- log(`Compiling ${options.entry}...`);
68
- const result = await compileToPiu({
69
- entry: options.entry,
70
- settleMs: options.settleMs,
71
- platform: options.platform,
72
- logger: log,
73
- });
74
-
75
- // 2. Scaffold pebble project
76
- log(`Scaffolding pebble project in ${buildDir}...`);
77
- scaffoldPebbleProject(buildDir, {
78
- watchface: !result.hasButtons,
79
- messageKeys: result.messageKeys,
80
- });
81
-
82
- // 3. Write compiled output
83
- const outputPath = join(buildDir, 'src', 'embeddedjs', 'main.js');
84
- mkdirSync(dirname(outputPath), { recursive: true });
85
- writeFileSync(outputPath, result.code);
86
- log(`Wrote ${result.code.split('\n').length} lines to ${outputPath}`);
87
-
88
- // 4. Optionally build + deploy
89
- if (options.deploy) {
90
- const emu = options.emulator ?? options.platform ?? 'emery';
91
- log('Running pebble build...');
92
- try {
93
- execSync('pebble build', { cwd: buildDir, stdio: 'inherit' });
94
- log(`Installing to ${emu} emulator...`);
95
- execSync('pebble kill 2>/dev/null; pebble wipe 2>/dev/null; sleep 2', {
96
- cwd: buildDir,
97
- stdio: 'ignore',
98
- });
99
- execSync(`pebble install --emulator ${emu}`, {
100
- cwd: buildDir,
101
- stdio: 'inherit',
102
- timeout: 30000,
103
- });
104
- log(`Deployed to ${emu}. Run 'cd ${buildDir} && pebble logs' for live output.`);
105
- } catch (err) {
106
- log('Deploy failed — is the Pebble SDK installed? (pebble --version)');
107
- throw err;
72
+ const platforms = options.targetPlatforms ?? [options.platform ?? 'emery'];
73
+
74
+ for (const platform of platforms) {
75
+ const platBuildDir = platforms.length > 1
76
+ ? resolve(`${options.buildDir ?? '.pebble-build'}-${platform}`)
77
+ : buildDir;
78
+
79
+ // 1. Compile JSX → piu
80
+ log(`Compiling ${options.entry} for ${platform}...`);
81
+ const result = await compileToPiu({
82
+ entry: options.entry,
83
+ settleMs: options.settleMs,
84
+ platform,
85
+ logger: log,
86
+ });
87
+
88
+ // 2. Scaffold pebble project
89
+ log(`Scaffolding pebble project in ${platBuildDir}...`);
90
+ scaffoldPebbleProject(platBuildDir, {
91
+ watchface: !result.hasButtons,
92
+ messageKeys: result.messageKeys,
93
+ mockDataSource: result.mockDataSource,
94
+ });
95
+
96
+ // 3. Write compiled output
97
+ const outputPath = join(platBuildDir, 'src', 'embeddedjs', 'main.js');
98
+ mkdirSync(dirname(outputPath), { recursive: true });
99
+ writeFileSync(outputPath, result.code);
100
+ log(`Wrote ${result.code.split('\n').length} lines to ${outputPath}`);
101
+
102
+ // 4. Optionally build + deploy
103
+ if (options.deploy) {
104
+ const emu = options.emulator ?? platform;
105
+ log(`Running pebble build for ${platform}...`);
106
+ try {
107
+ execSync('pebble build', { cwd: platBuildDir, stdio: 'inherit' });
108
+ log(`Installing to ${emu} emulator...`);
109
+ execSync('pebble kill 2>/dev/null; pebble wipe 2>/dev/null; sleep 2', {
110
+ cwd: platBuildDir,
111
+ stdio: 'ignore',
112
+ });
113
+ execSync(`pebble install --emulator ${emu}`, {
114
+ cwd: platBuildDir,
115
+ stdio: 'inherit',
116
+ timeout: 30000,
117
+ });
118
+ log(`Deployed to ${emu}. Run 'cd ${platBuildDir} && pebble logs' for live output.`);
119
+ } catch (err) {
120
+ log(`Deploy failed for ${platform} — is the Pebble SDK installed? (pebble --version)`);
121
+ throw err;
122
+ }
123
+ } else {
124
+ log(`Done (${platform}). To deploy:\n cd ${platBuildDir} && pebble build && pebble install --emulator ${platform}`);
108
125
  }
109
- } else {
110
- log(`Done. To deploy:\n cd ${buildDir} && pebble build && pebble install --emulator emery`);
111
126
  }
112
127
  },
113
128
  };
@@ -120,6 +135,8 @@ export function pebblePiu(options: PebblePiuOptions): Plugin {
120
135
  interface ScaffoldOptions {
121
136
  watchface: boolean;
122
137
  messageKeys: string[];
138
+ /** TypeScript source of mock data (for generating phone-side JS) */
139
+ mockDataSource?: string | null;
123
140
  }
124
141
 
125
142
  function scaffoldPebbleProject(dir: string, options: ScaffoldOptions): void {
@@ -207,17 +224,52 @@ int main(void) {
207
224
  // Phone-side JS
208
225
  const pkjsPath = join(dir, 'src', 'pkjs', 'index.js');
209
226
  if (options.messageKeys.length > 0 && options.messageKeys[0] !== 'dummy') {
210
- writeFileSync(
211
- pkjsPath,
212
- `// Phone-side PebbleKit JS — sends data to watch via AppMessage.
227
+ const key = options.messageKeys[0]!;
228
+ const mockSrc = options.mockDataSource;
229
+ if (mockSrc) {
230
+ // Generate working phone-side JS that sends the mock data
231
+ // Strip TypeScript type annotations from the mock data source
232
+ const cleanMockSrc = mockSrc
233
+ .replace(/as\s+const/g, '')
234
+ .replace(/:\s*\w+(\[\])?/g, '')
235
+ .replace(/<[^>]+>/g, '');
236
+ writeFileSync(
237
+ pkjsPath,
238
+ `// Phone-side PebbleKit JS — sends mock data to watch via AppMessage.
213
239
  // Replace the mock data below with a real API fetch.
214
240
 
241
+ Pebble.addEventListener("ready", function () {
242
+ console.log("Phone JS ready — sending data to watch...");
243
+
244
+ // Mock data (from example). Replace with fetch() for real data.
245
+ var data = ${cleanMockSrc};
246
+
247
+ // Send to watch after a short delay (wait for Message subscription)
248
+ setTimeout(function() {
249
+ Pebble.sendAppMessage(
250
+ { "${key}": JSON.stringify(data) },
251
+ function() { console.log("Data sent to watch successfully."); },
252
+ function(e) { console.log("Send failed: " + JSON.stringify(e)); }
253
+ );
254
+ }, 2000);
255
+ });
256
+ `,
257
+ );
258
+ } else {
259
+ writeFileSync(
260
+ pkjsPath,
261
+ `// Phone-side PebbleKit JS — sends data to watch via AppMessage.
262
+ // Replace the placeholder below with a real API fetch.
263
+
215
264
  Pebble.addEventListener("ready", function () {
216
265
  console.log("Phone JS ready.");
217
- // TODO: fetch real data and send via Pebble.sendAppMessage({ ${options.messageKeys[0]}: jsonString });
266
+ // Example: fetch data and send to watch
267
+ // var data = { key: "value" };
268
+ // Pebble.sendAppMessage({ "${key}": JSON.stringify(data) });
218
269
  });
219
270
  `,
220
- );
271
+ );
272
+ }
221
273
  } else if (!existsSync(pkjsPath)) {
222
274
  writeFileSync(
223
275
  pkjsPath,
@@ -44,13 +44,20 @@ interface WatchButtonPayload {
44
44
  [key: string]: unknown;
45
45
  }
46
46
 
47
+ interface WatchConnected {
48
+ /** Whether the Pebble companion app is connected. */
49
+ app: boolean;
50
+ /** Whether PebbleKit JS is available. */
51
+ pebblekit: boolean;
52
+ }
53
+
47
54
  interface ModdableWatch {
48
- addEventListener(event: WatchEvent, handler: (payload?: WatchButtonPayload) => void): void;
49
- removeEventListener(event: WatchEvent, handler: (payload?: WatchButtonPayload) => void): void;
55
+ addEventListener(event: WatchEvent, handler: (...args: any[]) => void): void;
56
+ removeEventListener(event: WatchEvent, handler: (...args: any[]) => void): void;
50
57
  /** Unexplained method on the prototype — possibly the internal dispatch path. */
51
58
  do?: (...args: unknown[]) => unknown;
52
- /** Connection / pairing state — unexplored. */
53
- connected?: unknown;
59
+ /** Connection / pairing state. */
60
+ connected?: WatchConnected;
54
61
  }
55
62
 
56
63
  declare const watch: ModdableWatch | undefined;
@@ -148,6 +155,21 @@ declare module 'commodetto/PocoCore' {
148
155
  export { default } from 'commodetto/Poco';
149
156
  }
150
157
 
158
+ // ---------------------------------------------------------------------------
159
+ // Battery — Alloy provides static properties on a Battery object.
160
+ // ---------------------------------------------------------------------------
161
+
162
+ interface PebbleBattery {
163
+ /** Battery percentage (0–100). */
164
+ readonly percent: number;
165
+ /** Whether the watch is currently charging. */
166
+ readonly charging: boolean;
167
+ /** Whether the watch is plugged in. */
168
+ readonly plugged: boolean;
169
+ }
170
+
171
+ declare const Battery: PebbleBattery | undefined;
172
+
151
173
  // Outline extension module — adds blendOutline / blendPolygon to Poco.prototype.
152
174
  // Importing this module has the side-effect of installing those methods.
153
175
  declare module 'commodetto/outline/PocoOutline' {