rn-backstage 1.4.7 → 1.5.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.
Files changed (52) hide show
  1. package/README.md +43 -0
  2. package/lib/commonjs/Backstage.js +3 -1
  3. package/lib/commonjs/Backstage.js.map +1 -1
  4. package/lib/commonjs/bug-report.js.map +1 -1
  5. package/lib/commonjs/components/BackstagePanel.js +14 -2
  6. package/lib/commonjs/components/BackstagePanel.js.map +1 -1
  7. package/lib/commonjs/components/BugReportComposer.js.map +1 -1
  8. package/lib/commonjs/components/EnvironmentTab.js +746 -0
  9. package/lib/commonjs/components/EnvironmentTab.js.map +1 -0
  10. package/lib/commonjs/components/FlagsTab.js.map +1 -1
  11. package/lib/commonjs/components/FloatingPill.js.map +1 -1
  12. package/lib/commonjs/components/StorageTab.js.map +1 -1
  13. package/lib/commonjs/constants.js +17 -0
  14. package/lib/commonjs/constants.js.map +1 -1
  15. package/lib/commonjs/index.js +7 -0
  16. package/lib/commonjs/index.js.map +1 -1
  17. package/lib/commonjs/types.js +1 -0
  18. package/lib/commonjs/types.js.map +1 -1
  19. package/lib/module/Backstage.js +3 -1
  20. package/lib/module/Backstage.js.map +1 -1
  21. package/lib/module/bug-report.js.map +1 -1
  22. package/lib/module/components/BackstagePanel.js +14 -2
  23. package/lib/module/components/BackstagePanel.js.map +1 -1
  24. package/lib/module/components/BugReportComposer.js.map +1 -1
  25. package/lib/module/components/EnvironmentTab.js +741 -0
  26. package/lib/module/components/EnvironmentTab.js.map +1 -0
  27. package/lib/module/components/FlagsTab.js.map +1 -1
  28. package/lib/module/components/FloatingPill.js.map +1 -1
  29. package/lib/module/components/StorageTab.js.map +1 -1
  30. package/lib/module/constants.js +17 -0
  31. package/lib/module/constants.js.map +1 -1
  32. package/lib/module/index.js +1 -0
  33. package/lib/module/index.js.map +1 -1
  34. package/lib/module/types.js +2 -0
  35. package/lib/module/types.js.map +1 -1
  36. package/lib/typescript/Backstage.d.ts.map +1 -1
  37. package/lib/typescript/bug-report.d.ts.map +1 -1
  38. package/lib/typescript/components/BackstagePanel.d.ts +2 -1
  39. package/lib/typescript/components/BackstagePanel.d.ts.map +1 -1
  40. package/lib/typescript/components/BugReportComposer.d.ts.map +1 -1
  41. package/lib/typescript/components/EnvironmentTab.d.ts +8 -0
  42. package/lib/typescript/components/EnvironmentTab.d.ts.map +1 -0
  43. package/lib/typescript/components/FlagsTab.d.ts.map +1 -1
  44. package/lib/typescript/components/FloatingPill.d.ts.map +1 -1
  45. package/lib/typescript/components/StorageTab.d.ts.map +1 -1
  46. package/lib/typescript/constants.d.ts +16 -0
  47. package/lib/typescript/constants.d.ts.map +1 -1
  48. package/lib/typescript/index.d.ts +2 -1
  49. package/lib/typescript/index.d.ts.map +1 -1
  50. package/lib/typescript/types.d.ts +48 -0
  51. package/lib/typescript/types.d.ts.map +1 -1
  52. package/package.json +2 -2
@@ -0,0 +1,741 @@
1
+ "use strict";
2
+
3
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
4
+ import { ActivityIndicator, Alert, FlatList, KeyboardAvoidingView, Modal, Platform, SafeAreaView, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
5
+ import { MonospaceFont, TestIDs } from '../constants';
6
+ import { useBackstageTheme } from '../ThemeContext';
7
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
8
+ // ─── Constants ───────────────────────────────────────────────────────────────
9
+
10
+ const STORAGE_KEY_PREFIX = 'backstage.env.credentials.';
11
+
12
+ // ─── Credential Editor Modal ─────────────────────────────────────────────────
13
+
14
+ const EditorModal = ({
15
+ visible,
16
+ title,
17
+ credentialName,
18
+ fieldValues,
19
+ credentialFields = [],
20
+ onChangeName,
21
+ onChangeField,
22
+ onSave,
23
+ onCancel,
24
+ theme
25
+ }) => {
26
+ const s = useMemo(() => createStyles(theme), [theme]);
27
+ return /*#__PURE__*/_jsx(Modal, {
28
+ testID: TestIDs.environmentTab.editorModal,
29
+ visible: visible,
30
+ animationType: "slide",
31
+ transparent: false,
32
+ onRequestClose: onCancel,
33
+ children: /*#__PURE__*/_jsxs(SafeAreaView, {
34
+ style: s.modalContainer,
35
+ children: [/*#__PURE__*/_jsxs(View, {
36
+ style: s.modalHeader,
37
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
38
+ testID: TestIDs.environmentTab.editorCancelButton,
39
+ onPress: onCancel,
40
+ hitSlop: {
41
+ top: 8,
42
+ bottom: 8,
43
+ left: 8,
44
+ right: 8
45
+ },
46
+ children: /*#__PURE__*/_jsx(Text, {
47
+ style: s.modalCancelText,
48
+ children: "Cancel"
49
+ })
50
+ }), /*#__PURE__*/_jsx(Text, {
51
+ style: s.modalTitle,
52
+ children: title
53
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
54
+ testID: TestIDs.environmentTab.editorSaveButton,
55
+ onPress: onSave,
56
+ hitSlop: {
57
+ top: 8,
58
+ bottom: 8,
59
+ left: 8,
60
+ right: 8
61
+ },
62
+ children: /*#__PURE__*/_jsx(Text, {
63
+ style: s.modalSaveText,
64
+ children: "Save"
65
+ })
66
+ })]
67
+ }), /*#__PURE__*/_jsx(KeyboardAvoidingView, {
68
+ style: s.modalBody,
69
+ behavior: Platform.OS === 'ios' ? 'padding' : undefined,
70
+ children: /*#__PURE__*/_jsxs(ScrollView, {
71
+ contentContainerStyle: s.modalBodyContent,
72
+ keyboardShouldPersistTaps: "handled",
73
+ children: [/*#__PURE__*/_jsx(Text, {
74
+ style: s.modalLabel,
75
+ children: "Name"
76
+ }), /*#__PURE__*/_jsx(TextInput, {
77
+ testID: TestIDs.environmentTab.editorNameInput,
78
+ style: s.modalInput,
79
+ value: credentialName,
80
+ onChangeText: onChangeName,
81
+ placeholder: "e.g., QA Account, Admin",
82
+ placeholderTextColor: theme.textMuted,
83
+ autoCapitalize: "words",
84
+ autoFocus: true
85
+ }), credentialFields.map(field => /*#__PURE__*/_jsxs(View, {
86
+ style: {
87
+ marginTop: 16
88
+ },
89
+ children: [/*#__PURE__*/_jsx(Text, {
90
+ style: s.modalLabel,
91
+ children: field.label
92
+ }), /*#__PURE__*/_jsx(TextInput, {
93
+ testID: TestIDs.environmentTab.editorFieldInput(field.key),
94
+ style: [s.modalInput, field.secureTextEntry ? undefined : undefined],
95
+ value: fieldValues[field.key] || '',
96
+ onChangeText: val => onChangeField(field.key, val),
97
+ placeholder: field.placeholder || field.label,
98
+ placeholderTextColor: theme.textMuted,
99
+ secureTextEntry: field.secureTextEntry,
100
+ autoCapitalize: field.autoCapitalize ?? 'none',
101
+ autoCorrect: false,
102
+ keyboardType: field.keyboardType
103
+ })]
104
+ }, field.key))]
105
+ })
106
+ })]
107
+ })
108
+ });
109
+ };
110
+
111
+ // ─── Credential Row ──────────────────────────────────────────────────────────
112
+
113
+ const CredentialRow = ({
114
+ envKey,
115
+ index,
116
+ credential,
117
+ envColor,
118
+ onLogin,
119
+ onEdit,
120
+ onDelete,
121
+ loggingIn,
122
+ theme
123
+ }) => {
124
+ const s = useMemo(() => createStyles(theme), [theme]);
125
+ const fieldCount = Object.keys(credential.values).length;
126
+ return /*#__PURE__*/_jsxs(View, {
127
+ testID: TestIDs.environmentTab.credentialRow(envKey, index),
128
+ style: s.credRow,
129
+ children: [/*#__PURE__*/_jsxs(View, {
130
+ style: s.credRowLeft,
131
+ children: [/*#__PURE__*/_jsx(Text, {
132
+ style: s.credName,
133
+ numberOfLines: 1,
134
+ children: credential.name
135
+ }), /*#__PURE__*/_jsxs(Text, {
136
+ style: s.credMeta,
137
+ children: [fieldCount, " field", fieldCount !== 1 ? 's' : '']
138
+ })]
139
+ }), /*#__PURE__*/_jsxs(View, {
140
+ style: s.credRowActions,
141
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
142
+ testID: TestIDs.environmentTab.credentialLogin(envKey, index),
143
+ style: [s.credActionButton, {
144
+ backgroundColor: envColor
145
+ }],
146
+ onPress: onLogin,
147
+ disabled: loggingIn,
148
+ activeOpacity: 0.7,
149
+ hitSlop: {
150
+ top: 4,
151
+ bottom: 4,
152
+ left: 4,
153
+ right: 4
154
+ },
155
+ children: loggingIn ? /*#__PURE__*/_jsx(ActivityIndicator, {
156
+ size: "small",
157
+ color: "#FFF"
158
+ }) : /*#__PURE__*/_jsx(Text, {
159
+ style: s.credActionLoginText,
160
+ children: "Login"
161
+ })
162
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
163
+ testID: TestIDs.environmentTab.credentialEdit(envKey, index),
164
+ onPress: onEdit,
165
+ hitSlop: {
166
+ top: 8,
167
+ bottom: 8,
168
+ left: 8,
169
+ right: 8
170
+ },
171
+ children: /*#__PURE__*/_jsx(Text, {
172
+ style: s.credActionIcon,
173
+ children: "\u270E"
174
+ })
175
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
176
+ testID: TestIDs.environmentTab.credentialDelete(envKey, index),
177
+ onPress: onDelete,
178
+ hitSlop: {
179
+ top: 8,
180
+ bottom: 8,
181
+ left: 8,
182
+ right: 8
183
+ },
184
+ children: /*#__PURE__*/_jsx(Text, {
185
+ style: [s.credActionIcon, s.credDeleteIcon],
186
+ children: "\u2715"
187
+ })
188
+ })]
189
+ })]
190
+ });
191
+ };
192
+
193
+ // ─── Main Component ──────────────────────────────────────────────────────────
194
+
195
+ export const EnvironmentTab = ({
196
+ config
197
+ }) => {
198
+ const {
199
+ environments,
200
+ activeEnvironment,
201
+ onEnvironmentChange,
202
+ credentialFields = [],
203
+ onLogin,
204
+ initialCredentials,
205
+ storageAdapter
206
+ } = config;
207
+ const theme = useBackstageTheme();
208
+ const s = useMemo(() => createStyles(theme), [theme]);
209
+
210
+ // ── Credentials state: Record<envKey, SavedCredential[]> ──
211
+ const [credentials, setCredentials] = useState(() => {
212
+ const init = {};
213
+ for (const env of environments) {
214
+ init[env.key] = initialCredentials?.[env.key] ? [...initialCredentials[env.key]] : [];
215
+ }
216
+ return init;
217
+ });
218
+ const [loadingCredentials, setLoadingCredentials] = useState(!!storageAdapter);
219
+ const [loggingInKey, setLoggingInKey] = useState(null);
220
+
221
+ // ── Editor modal state ─────────────────────────────────────
222
+ const [editorVisible, setEditorVisible] = useState(false);
223
+ const [editorEnvKey, setEditorEnvKey] = useState('');
224
+ const [editorIndex, setEditorIndex] = useState(null); // null = add new
225
+ const [editorName, setEditorName] = useState('');
226
+ const [editorFields, setEditorFields] = useState({});
227
+
228
+ // ── Load persisted credentials on mount ────────────────────
229
+ useEffect(() => {
230
+ if (!storageAdapter) return;
231
+ let cancelled = false;
232
+ const load = async () => {
233
+ try {
234
+ for (const env of environments) {
235
+ const stored = await storageAdapter.getItem(STORAGE_KEY_PREFIX + env.key);
236
+ if (stored && !cancelled) {
237
+ try {
238
+ const parsed = JSON.parse(stored);
239
+ if (Array.isArray(parsed)) {
240
+ setCredentials(prev => ({
241
+ ...prev,
242
+ [env.key]: parsed
243
+ }));
244
+ }
245
+ } catch {
246
+ // Invalid JSON — ignore
247
+ }
248
+ }
249
+ }
250
+ } finally {
251
+ if (!cancelled) setLoadingCredentials(false);
252
+ }
253
+ };
254
+ load();
255
+ return () => {
256
+ cancelled = true;
257
+ };
258
+ }, [storageAdapter, environments]);
259
+
260
+ // ── Persist credentials to storage ─────────────────────────
261
+ const persistCredentials = useCallback((envKey, creds) => {
262
+ if (!storageAdapter) return;
263
+ storageAdapter.setItem(STORAGE_KEY_PREFIX + envKey, JSON.stringify(creds)).catch(() => {});
264
+ }, [storageAdapter]);
265
+
266
+ // ── Editor open/close ──────────────────────────────────────
267
+ const openAddEditor = useCallback(envKey => {
268
+ setEditorEnvKey(envKey);
269
+ setEditorIndex(null);
270
+ setEditorName('');
271
+ setEditorFields({});
272
+ setEditorVisible(true);
273
+ }, []);
274
+ const openEditEditor = useCallback((envKey, index) => {
275
+ const cred = credentials[envKey]?.[index];
276
+ if (!cred) return;
277
+ setEditorEnvKey(envKey);
278
+ setEditorIndex(index);
279
+ setEditorName(cred.name);
280
+ setEditorFields({
281
+ ...cred.values
282
+ });
283
+ setEditorVisible(true);
284
+ }, [credentials]);
285
+ const closeEditor = useCallback(() => {
286
+ setEditorVisible(false);
287
+ setEditorEnvKey('');
288
+ setEditorIndex(null);
289
+ setEditorName('');
290
+ setEditorFields({});
291
+ }, []);
292
+ const saveEditor = useCallback(() => {
293
+ const trimmedName = editorName.trim();
294
+ if (!trimmedName) {
295
+ Alert.alert('Error', 'Credential name cannot be empty');
296
+ return;
297
+ }
298
+ const newCred = {
299
+ name: trimmedName,
300
+ values: {
301
+ ...editorFields
302
+ }
303
+ };
304
+ setCredentials(prev => {
305
+ const envCreds = [...(prev[editorEnvKey] || [])];
306
+ if (editorIndex !== null) {
307
+ // Edit existing
308
+ envCreds[editorIndex] = newCred;
309
+ } else {
310
+ // Add new
311
+ envCreds.push(newCred);
312
+ }
313
+ persistCredentials(editorEnvKey, envCreds);
314
+ return {
315
+ ...prev,
316
+ [editorEnvKey]: envCreds
317
+ };
318
+ });
319
+ closeEditor();
320
+ }, [editorName, editorFields, editorEnvKey, editorIndex, persistCredentials, closeEditor]);
321
+ const updateEditorField = useCallback((fieldKey, value) => {
322
+ setEditorFields(prev => ({
323
+ ...prev,
324
+ [fieldKey]: value
325
+ }));
326
+ }, []);
327
+
328
+ // ── Delete credential ──────────────────────────────────────
329
+ const confirmDelete = useCallback((envKey, index) => {
330
+ const cred = credentials[envKey]?.[index];
331
+ if (!cred) return;
332
+ Alert.alert('Delete Credential', `Remove "${cred.name}"?`, [{
333
+ text: 'Cancel',
334
+ style: 'cancel'
335
+ }, {
336
+ text: 'Delete',
337
+ style: 'destructive',
338
+ onPress: () => {
339
+ setCredentials(prev => {
340
+ const envCreds = [...(prev[envKey] || [])];
341
+ envCreds.splice(index, 1);
342
+ persistCredentials(envKey, envCreds);
343
+ return {
344
+ ...prev,
345
+ [envKey]: envCreds
346
+ };
347
+ });
348
+ }
349
+ }]);
350
+ }, [credentials, persistCredentials]);
351
+
352
+ // ── Handle login ───────────────────────────────────────────
353
+ const handleLogin = useCallback(async (envKey, index) => {
354
+ if (!onLogin) return;
355
+ const cred = credentials[envKey]?.[index];
356
+ if (!cred) return;
357
+ const loginKey = `${envKey}:${index}`;
358
+ setLoggingInKey(loginKey);
359
+ try {
360
+ await onLogin(envKey, cred.values);
361
+ } finally {
362
+ setLoggingInKey(null);
363
+ }
364
+ }, [onLogin, credentials]);
365
+ const activeEnv = environments.find(e => e.key === activeEnvironment);
366
+ return /*#__PURE__*/_jsxs(View, {
367
+ style: s.container,
368
+ children: [/*#__PURE__*/_jsx(FlatList, {
369
+ testID: TestIDs.environmentTab.container,
370
+ data: environments,
371
+ keyExtractor: env => env.key,
372
+ contentContainerStyle: s.contentContainer,
373
+ showsVerticalScrollIndicator: false,
374
+ keyboardShouldPersistTaps: "handled",
375
+ renderItem: ({
376
+ item: env
377
+ }) => {
378
+ const isActive = env.key === activeEnvironment;
379
+ const envColor = env.color || theme.accent;
380
+ const envCreds = credentials[env.key] || [];
381
+ return /*#__PURE__*/_jsxs(View, {
382
+ testID: TestIDs.environmentTab.environmentCard(env.key),
383
+ style: [s.card, isActive && s.cardActive, isActive && {
384
+ borderColor: envColor
385
+ }],
386
+ children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
387
+ testID: TestIDs.environmentTab.radioButton(env.key),
388
+ style: s.cardHeader,
389
+ onPress: () => onEnvironmentChange(env.key),
390
+ activeOpacity: 0.7,
391
+ children: [/*#__PURE__*/_jsxs(View, {
392
+ style: s.radioRow,
393
+ children: [/*#__PURE__*/_jsx(View, {
394
+ style: [s.radio, isActive && s.radioActive, isActive && {
395
+ borderColor: envColor
396
+ }],
397
+ children: isActive && /*#__PURE__*/_jsx(View, {
398
+ style: [s.radioDot, {
399
+ backgroundColor: envColor
400
+ }]
401
+ })
402
+ }), /*#__PURE__*/_jsxs(View, {
403
+ style: s.envInfo,
404
+ children: [/*#__PURE__*/_jsx(Text, {
405
+ style: [s.envLabel, isActive && {
406
+ color: envColor
407
+ }],
408
+ children: env.label
409
+ }), env.baseUrl && /*#__PURE__*/_jsx(Text, {
410
+ style: s.envUrl,
411
+ numberOfLines: 1,
412
+ children: env.baseUrl
413
+ })]
414
+ })]
415
+ }), isActive && /*#__PURE__*/_jsx(View, {
416
+ style: [s.activeBadge, {
417
+ backgroundColor: envColor + '20'
418
+ }],
419
+ children: /*#__PURE__*/_jsx(Text, {
420
+ style: [s.activeBadgeText, {
421
+ color: envColor
422
+ }],
423
+ children: "Active"
424
+ })
425
+ })]
426
+ }), isActive && credentialFields.length > 0 && /*#__PURE__*/_jsx(View, {
427
+ style: s.credentialsContainer,
428
+ children: loadingCredentials ? /*#__PURE__*/_jsxs(View, {
429
+ style: s.loadingContainer,
430
+ children: [/*#__PURE__*/_jsx(ActivityIndicator, {
431
+ size: "small",
432
+ color: theme.textMuted
433
+ }), /*#__PURE__*/_jsx(Text, {
434
+ style: s.loadingText,
435
+ children: "Loading credentials\u2026"
436
+ })]
437
+ }) : /*#__PURE__*/_jsxs(_Fragment, {
438
+ children: [envCreds.length === 0 ? /*#__PURE__*/_jsx(View, {
439
+ style: s.emptyState,
440
+ children: /*#__PURE__*/_jsx(Text, {
441
+ style: s.emptyText,
442
+ children: "No saved credentials"
443
+ })
444
+ }) : envCreds.map((cred, index) => /*#__PURE__*/_jsx(CredentialRow, {
445
+ envKey: env.key,
446
+ index: index,
447
+ credential: cred,
448
+ envColor: envColor,
449
+ onLogin: () => handleLogin(env.key, index),
450
+ onEdit: () => openEditEditor(env.key, index),
451
+ onDelete: () => confirmDelete(env.key, index),
452
+ loggingIn: loggingInKey === `${env.key}:${index}`,
453
+ theme: theme
454
+ }, `${cred.name}-${index}`)), /*#__PURE__*/_jsx(TouchableOpacity, {
455
+ testID: TestIDs.environmentTab.addButton(env.key),
456
+ style: [s.addButton, {
457
+ borderColor: envColor
458
+ }],
459
+ onPress: () => openAddEditor(env.key),
460
+ activeOpacity: 0.7,
461
+ children: /*#__PURE__*/_jsx(Text, {
462
+ style: [s.addButtonText, {
463
+ color: envColor
464
+ }],
465
+ children: "\uFF0B Add Credential"
466
+ })
467
+ })]
468
+ })
469
+ })]
470
+ });
471
+ },
472
+ ListFooterComponent: /*#__PURE__*/_jsx(View, {
473
+ testID: TestIDs.environmentTab.activeLabel,
474
+ style: s.footer,
475
+ children: /*#__PURE__*/_jsxs(Text, {
476
+ style: s.footerText,
477
+ children: ["Active: ", activeEnv?.label ?? activeEnvironment, storageAdapter ? ' · Credentials saved' : '']
478
+ })
479
+ })
480
+ }), /*#__PURE__*/_jsx(EditorModal, {
481
+ visible: editorVisible,
482
+ title: editorIndex !== null ? 'Edit Credential' : 'Add Credential',
483
+ credentialName: editorName,
484
+ fieldValues: editorFields,
485
+ credentialFields: credentialFields,
486
+ onChangeName: setEditorName,
487
+ onChangeField: updateEditorField,
488
+ onSave: saveEditor,
489
+ onCancel: closeEditor,
490
+ theme: theme
491
+ })]
492
+ });
493
+ };
494
+
495
+ // ─── Styles ──────────────────────────────────────────────────────────────────
496
+
497
+ const createStyles = t => StyleSheet.create({
498
+ container: {
499
+ flex: 1
500
+ },
501
+ contentContainer: {
502
+ padding: 14,
503
+ paddingBottom: 40
504
+ },
505
+ // ── Card ────────────────────────
506
+ card: {
507
+ backgroundColor: t.surface,
508
+ borderRadius: 12,
509
+ borderWidth: 1.5,
510
+ borderColor: t.border,
511
+ marginBottom: 12,
512
+ overflow: 'hidden'
513
+ },
514
+ cardActive: {
515
+ backgroundColor: t.surfaceElevated
516
+ },
517
+ cardHeader: {
518
+ flexDirection: 'row',
519
+ alignItems: 'center',
520
+ justifyContent: 'space-between',
521
+ padding: 14
522
+ },
523
+ radioRow: {
524
+ flexDirection: 'row',
525
+ alignItems: 'center',
526
+ flex: 1
527
+ },
528
+ radio: {
529
+ width: 20,
530
+ height: 20,
531
+ borderRadius: 10,
532
+ borderWidth: 2,
533
+ borderColor: t.border,
534
+ alignItems: 'center',
535
+ justifyContent: 'center',
536
+ marginRight: 12
537
+ },
538
+ radioActive: {
539
+ borderWidth: 2
540
+ },
541
+ radioDot: {
542
+ width: 10,
543
+ height: 10,
544
+ borderRadius: 5
545
+ },
546
+ envInfo: {
547
+ flex: 1
548
+ },
549
+ envLabel: {
550
+ fontFamily: MonospaceFont,
551
+ fontSize: 15,
552
+ fontWeight: '700',
553
+ color: t.text
554
+ },
555
+ envUrl: {
556
+ fontFamily: MonospaceFont,
557
+ fontSize: 11,
558
+ color: t.textMuted,
559
+ marginTop: 3
560
+ },
561
+ activeBadge: {
562
+ borderRadius: 6,
563
+ paddingHorizontal: 8,
564
+ paddingVertical: 3,
565
+ marginLeft: 8
566
+ },
567
+ activeBadgeText: {
568
+ fontFamily: MonospaceFont,
569
+ fontSize: 10,
570
+ fontWeight: '700',
571
+ textTransform: 'uppercase',
572
+ letterSpacing: 0.5
573
+ },
574
+ // ── Credentials Section ─────────
575
+ credentialsContainer: {
576
+ paddingHorizontal: 14,
577
+ paddingBottom: 14,
578
+ borderTopWidth: StyleSheet.hairlineWidth,
579
+ borderTopColor: t.border,
580
+ paddingTop: 10
581
+ },
582
+ emptyState: {
583
+ alignItems: 'center',
584
+ paddingVertical: 14
585
+ },
586
+ emptyText: {
587
+ fontFamily: MonospaceFont,
588
+ fontSize: 12,
589
+ color: t.textMuted,
590
+ fontStyle: 'italic'
591
+ },
592
+ // ── Credential Row ──────────────
593
+ credRow: {
594
+ flexDirection: 'row',
595
+ alignItems: 'center',
596
+ justifyContent: 'space-between',
597
+ paddingVertical: 10,
598
+ borderBottomWidth: StyleSheet.hairlineWidth,
599
+ borderBottomColor: t.border
600
+ },
601
+ credRowLeft: {
602
+ flex: 1,
603
+ marginRight: 8
604
+ },
605
+ credName: {
606
+ fontFamily: MonospaceFont,
607
+ fontSize: 13,
608
+ fontWeight: '700',
609
+ color: t.text
610
+ },
611
+ credMeta: {
612
+ fontFamily: MonospaceFont,
613
+ fontSize: 10,
614
+ color: t.textMuted,
615
+ marginTop: 2
616
+ },
617
+ credRowActions: {
618
+ flexDirection: 'row',
619
+ alignItems: 'center',
620
+ gap: 10
621
+ },
622
+ credActionButton: {
623
+ borderRadius: 6,
624
+ paddingHorizontal: 12,
625
+ paddingVertical: 5,
626
+ minWidth: 55,
627
+ alignItems: 'center'
628
+ },
629
+ credActionLoginText: {
630
+ fontFamily: MonospaceFont,
631
+ fontSize: 11,
632
+ fontWeight: '700',
633
+ color: '#FFFFFF'
634
+ },
635
+ credActionIcon: {
636
+ fontSize: 16,
637
+ color: t.textMuted
638
+ },
639
+ credDeleteIcon: {
640
+ color: t.error
641
+ },
642
+ // ── Add Button ──────────────────
643
+ addButton: {
644
+ borderRadius: 8,
645
+ borderWidth: 1,
646
+ borderStyle: 'dashed',
647
+ paddingVertical: 10,
648
+ alignItems: 'center',
649
+ marginTop: 10
650
+ },
651
+ addButtonText: {
652
+ fontFamily: MonospaceFont,
653
+ fontSize: 12,
654
+ fontWeight: '700'
655
+ },
656
+ // ── Footer ──────────────────────
657
+ footer: {
658
+ alignItems: 'center',
659
+ paddingVertical: 12
660
+ },
661
+ footerText: {
662
+ fontFamily: MonospaceFont,
663
+ fontSize: 11,
664
+ color: t.textMuted,
665
+ fontStyle: 'italic'
666
+ },
667
+ // ── Loading ─────────────────────
668
+ loadingContainer: {
669
+ flexDirection: 'row',
670
+ alignItems: 'center',
671
+ justifyContent: 'center',
672
+ gap: 8,
673
+ paddingVertical: 12
674
+ },
675
+ loadingText: {
676
+ fontFamily: MonospaceFont,
677
+ fontSize: 12,
678
+ color: t.textMuted
679
+ },
680
+ // ── Editor Modal ────────────────
681
+ modalContainer: {
682
+ flex: 1,
683
+ backgroundColor: t.background
684
+ },
685
+ modalHeader: {
686
+ flexDirection: 'row',
687
+ alignItems: 'center',
688
+ justifyContent: 'space-between',
689
+ paddingHorizontal: 16,
690
+ paddingVertical: 12,
691
+ borderBottomWidth: 1,
692
+ borderBottomColor: t.border
693
+ },
694
+ modalTitle: {
695
+ fontFamily: MonospaceFont,
696
+ fontSize: 16,
697
+ fontWeight: '700',
698
+ color: t.text,
699
+ flex: 1,
700
+ textAlign: 'center'
701
+ },
702
+ modalCancelText: {
703
+ fontFamily: MonospaceFont,
704
+ fontSize: 14,
705
+ color: t.textSecondary,
706
+ fontWeight: '600'
707
+ },
708
+ modalSaveText: {
709
+ fontFamily: MonospaceFont,
710
+ fontSize: 14,
711
+ color: t.accent,
712
+ fontWeight: '700'
713
+ },
714
+ modalBody: {
715
+ flex: 1
716
+ },
717
+ modalBodyContent: {
718
+ padding: 16
719
+ },
720
+ modalLabel: {
721
+ fontFamily: MonospaceFont,
722
+ fontSize: 12,
723
+ fontWeight: '700',
724
+ color: t.textMuted,
725
+ textTransform: 'uppercase',
726
+ letterSpacing: 0.5,
727
+ marginBottom: 6
728
+ },
729
+ modalInput: {
730
+ fontFamily: MonospaceFont,
731
+ fontSize: 13,
732
+ color: t.text,
733
+ backgroundColor: t.surfaceElevated,
734
+ borderRadius: 8,
735
+ borderWidth: 1,
736
+ borderColor: t.border,
737
+ paddingHorizontal: 12,
738
+ paddingVertical: 10
739
+ }
740
+ });
741
+ //# sourceMappingURL=EnvironmentTab.js.map