@buoy-gg/zustand 7.0.40 → 7.0.42
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/README.md +11 -72
- package/lib/commonjs/index.js +1 -105
- package/lib/commonjs/preset.js +1 -102
- package/lib/commonjs/zustand/components/ZustandActionButton.js +1 -118
- package/lib/commonjs/zustand/components/ZustandDetailViewToggle.js +1 -48
- package/lib/commonjs/zustand/components/ZustandEventFilterView.js +1 -43
- package/lib/commonjs/zustand/components/ZustandIcon.js +1 -18
- package/lib/commonjs/zustand/components/ZustandModal.js +1 -772
- package/lib/commonjs/zustand/components/ZustandStateChangeItem.js +1 -117
- package/lib/commonjs/zustand/components/ZustandStateDetailContent.js +1 -372
- package/lib/commonjs/zustand/components/ZustandStateInfoView.js +1 -488
- package/lib/commonjs/zustand/components/ZustandStoreBrowser.js +1 -204
- package/lib/commonjs/zustand/components/ZustandStoreDetailContent.js +1 -471
- package/lib/commonjs/zustand/hooks/useZustandStateChanges.js +1 -74
- package/lib/commonjs/zustand/sync/zustandSyncAdapter.js +1 -382
- package/lib/commonjs/zustand/types/index.js +1 -1
- package/lib/commonjs/zustand/utils/buoyZustandMiddleware.js +1 -284
- package/lib/commonjs/zustand/utils/editableState.js +1 -146
- package/lib/commonjs/zustand/utils/snapshotProvider.js +1 -209
- package/lib/commonjs/zustand/utils/testIDs.js +1 -82
- package/lib/commonjs/zustand/utils/zustandStateStore.js +1 -379
- package/lib/module/index.js +1 -90
- package/lib/module/preset.js +1 -98
- package/lib/module/zustand/components/ZustandActionButton.js +1 -114
- package/lib/module/zustand/components/ZustandDetailViewToggle.js +1 -43
- package/lib/module/zustand/components/ZustandEventFilterView.js +1 -39
- package/lib/module/zustand/components/ZustandIcon.js +1 -11
- package/lib/module/zustand/components/ZustandModal.js +1 -767
- package/lib/module/zustand/components/ZustandStateChangeItem.js +1 -113
- package/lib/module/zustand/components/ZustandStateDetailContent.js +1 -368
- package/lib/module/zustand/components/ZustandStateInfoView.js +1 -483
- package/lib/module/zustand/components/ZustandStoreBrowser.js +1 -200
- package/lib/module/zustand/components/ZustandStoreDetailContent.js +1 -469
- package/lib/module/zustand/hooks/useZustandStateChanges.js +1 -70
- package/lib/module/zustand/sync/zustandSyncAdapter.js +1 -380
- package/lib/module/zustand/types/index.js +1 -1
- package/lib/module/zustand/utils/buoyZustandMiddleware.js +1 -278
- package/lib/module/zustand/utils/editableState.js +1 -138
- package/lib/module/zustand/utils/snapshotProvider.js +1 -209
- package/lib/module/zustand/utils/testIDs.js +1 -74
- package/lib/module/zustand/utils/zustandStateStore.js +1 -375
- package/lib/web/index.mjs +2 -0
- package/package.json +35 -12
- package/lib/commonjs/zustand/components/ZustandStoreEditorScreen.js +0 -393
- package/lib/module/zustand/components/ZustandStoreEditorScreen.js +0 -389
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
- package/lib/typescript/zustand/components/ZustandActionButton.d.ts.map +0 -1
- package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts.map +0 -1
- package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts.map +0 -1
- package/lib/typescript/zustand/components/ZustandIcon.d.ts.map +0 -1
- package/lib/typescript/zustand/components/ZustandModal.d.ts.map +0 -1
- package/lib/typescript/zustand/components/ZustandStateChangeItem.d.ts.map +0 -1
- package/lib/typescript/zustand/components/ZustandStateDetailContent.d.ts.map +0 -1
- package/lib/typescript/zustand/components/ZustandStateInfoView.d.ts.map +0 -1
- package/lib/typescript/zustand/components/ZustandStoreBrowser.d.ts.map +0 -1
- package/lib/typescript/zustand/components/ZustandStoreDetailContent.d.ts.map +0 -1
- package/lib/typescript/zustand/components/ZustandStoreEditorScreen.d.ts +0 -42
- package/lib/typescript/zustand/components/ZustandStoreEditorScreen.d.ts.map +0 -1
- package/lib/typescript/zustand/hooks/useZustandStateChanges.d.ts.map +0 -1
- package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/zustand/types/index.d.ts.map +0 -1
- package/lib/typescript/zustand/utils/buoyZustandMiddleware.d.ts.map +0 -1
- package/lib/typescript/zustand/utils/editableState.d.ts.map +0 -1
- package/lib/typescript/zustand/utils/snapshotProvider.d.ts.map +0 -1
- package/lib/typescript/zustand/utils/testIDs.d.ts.map +0 -1
- package/lib/typescript/zustand/utils/zustandStateStore.d.ts.map +0 -1
|
@@ -1,379 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.zustandStateStore = void 0;
|
|
7
|
-
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
8
|
-
/**
|
|
9
|
-
* Zustand state store - captures and stores Zustand state changes
|
|
10
|
-
*
|
|
11
|
-
* The generic event-log half (ring buffer, listeners, clear-forwarding for
|
|
12
|
-
* the desktop mirror, pause/suppress flags, hydrate-by-id) is the shared
|
|
13
|
-
* `ChangeLog`; this file owns the zustand-specific half — the store registry,
|
|
14
|
-
* snapshots, mirror rebuild, filters and stats.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
// ============================================
|
|
18
|
-
// Store Color Palette
|
|
19
|
-
// ============================================
|
|
20
|
-
|
|
21
|
-
const STORE_COLORS = {
|
|
22
|
-
counter: "#10B981",
|
|
23
|
-
// emerald
|
|
24
|
-
auth: "#8B5CF6",
|
|
25
|
-
// purple
|
|
26
|
-
user: "#3B82F6",
|
|
27
|
-
// blue
|
|
28
|
-
cart: "#EC4899",
|
|
29
|
-
// pink
|
|
30
|
-
app: "#6366F1",
|
|
31
|
-
// indigo
|
|
32
|
-
ui: "#F59E0B",
|
|
33
|
-
// amber
|
|
34
|
-
settings: "#14B8A6",
|
|
35
|
-
// teal
|
|
36
|
-
theme: "#06B6D4",
|
|
37
|
-
// cyan
|
|
38
|
-
navigation: "#F97316",
|
|
39
|
-
// orange
|
|
40
|
-
form: "#EF4444" // red
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Get consistent color for a store based on its name
|
|
45
|
-
*/
|
|
46
|
-
function getStoreColor(storeName) {
|
|
47
|
-
return (0, _sharedUi.entityColor)(storeName, STORE_COLORS);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Format payload preview for display
|
|
52
|
-
*/
|
|
53
|
-
function formatPartialPreview(partial, maxLength = 40) {
|
|
54
|
-
return (0, _sharedUi.formatValuePreview)(partial, {
|
|
55
|
-
maxLength,
|
|
56
|
-
undefinedLabel: "",
|
|
57
|
-
functionLabel: "(updater fn)"
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// ============================================
|
|
62
|
-
// Zustand State Store
|
|
63
|
-
// ============================================
|
|
64
|
-
|
|
65
|
-
class ZustandStateStore extends _sharedUi.ChangeLog {
|
|
66
|
-
stores = new Map();
|
|
67
|
-
storeListeners = new Set();
|
|
68
|
-
remoteSetStateHandler = null;
|
|
69
|
-
|
|
70
|
-
// ---- State Change Tracking ----
|
|
71
|
-
|
|
72
|
-
addStateChange(params) {
|
|
73
|
-
if (!this.canRecord()) return;
|
|
74
|
-
const {
|
|
75
|
-
storeName,
|
|
76
|
-
partial,
|
|
77
|
-
replace,
|
|
78
|
-
prevState,
|
|
79
|
-
nextState,
|
|
80
|
-
duration,
|
|
81
|
-
category,
|
|
82
|
-
isPersisted = false
|
|
83
|
-
} = params;
|
|
84
|
-
const hasStateChange = prevState !== nextState;
|
|
85
|
-
// `changedCount` counts the keys in `changedKeys` and nothing else, so the
|
|
86
|
-
// row's "N keys changed" and the detail page's CHANGED KEYS card agree —
|
|
87
|
-
// including the persist-rehydrate case where the object is replaced
|
|
88
|
-
// without any top-level value moving.
|
|
89
|
-
const {
|
|
90
|
-
summary,
|
|
91
|
-
changedKeys,
|
|
92
|
-
changedCount
|
|
93
|
-
} = (0, _sharedUi.shallowDiffSummary)(prevState, nextState);
|
|
94
|
-
const partialPreview = formatPartialPreview(partial);
|
|
95
|
-
const isSlowUpdate = (duration ?? 0) > 16;
|
|
96
|
-
const resolvedCategory = category ?? (replace ? "replace" : "setState");
|
|
97
|
-
const stateChange = {
|
|
98
|
-
id: this.nextId(),
|
|
99
|
-
storeName,
|
|
100
|
-
timestamp: Date.now(),
|
|
101
|
-
prevState,
|
|
102
|
-
nextState,
|
|
103
|
-
partial,
|
|
104
|
-
duration,
|
|
105
|
-
hasStateChange,
|
|
106
|
-
replace,
|
|
107
|
-
category: resolvedCategory,
|
|
108
|
-
changedKeys,
|
|
109
|
-
changedKeysCount: changedCount,
|
|
110
|
-
diffSummary: summary,
|
|
111
|
-
partialPreview,
|
|
112
|
-
isSlowUpdate,
|
|
113
|
-
isPersisted
|
|
114
|
-
};
|
|
115
|
-
this.push(stateChange);
|
|
116
|
-
|
|
117
|
-
// Update store change count
|
|
118
|
-
const storeInfo = this.stores.get(storeName);
|
|
119
|
-
if (storeInfo) {
|
|
120
|
-
storeInfo.stateChangeCount++;
|
|
121
|
-
}
|
|
122
|
-
this.notifyListeners();
|
|
123
|
-
}
|
|
124
|
-
getStateChanges() {
|
|
125
|
-
return this.getAll();
|
|
126
|
-
}
|
|
127
|
-
getStateChangeById(id) {
|
|
128
|
-
return this.getById(id);
|
|
129
|
-
}
|
|
130
|
-
clearStateChanges() {
|
|
131
|
-
// Reset counts
|
|
132
|
-
for (const store of this.stores.values()) {
|
|
133
|
-
store.stateChangeCount = 0;
|
|
134
|
-
}
|
|
135
|
-
this.clear();
|
|
136
|
-
// The browser keeps its store list in React state and only re-reads it
|
|
137
|
-
// on a store notification — `clear()` above only tells the change-log
|
|
138
|
-
// listeners, so without this the cards kept their old counts after Clear.
|
|
139
|
-
this.notifyStoreListeners();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// ---- Remote Mirror Mode ----
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Replace the change log without touching the store registry. Used when a
|
|
146
|
-
* host keeps real registered stores (JUMP / RESET stay wired) but needs to
|
|
147
|
-
* reseed the event list — the docs live tour, or any mirror that already
|
|
148
|
-
* called `registerStore`. Does not fire `onClear`. Respects the enabled
|
|
149
|
-
* flag so the UI's pause button freezes the reseed.
|
|
150
|
-
*/
|
|
151
|
-
replaceStateChanges(changes) {
|
|
152
|
-
if (!this.getEnabled()) return;
|
|
153
|
-
for (const store of this.stores.values()) {
|
|
154
|
-
store.stateChangeCount = 0;
|
|
155
|
-
}
|
|
156
|
-
const kept = changes.slice(0, this.max);
|
|
157
|
-
for (const change of kept) {
|
|
158
|
-
const store = this.stores.get(change.storeName);
|
|
159
|
-
if (store) store.stateChangeCount++;
|
|
160
|
-
}
|
|
161
|
-
this.setItems(kept);
|
|
162
|
-
this.notifyStoreListeners();
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Serializable snapshot of the tracked stores (registry metadata plus each
|
|
167
|
-
* store's current state). Used by the sync adapter on the device side —
|
|
168
|
-
* the live `api` handles can't go over the wire.
|
|
169
|
-
*/
|
|
170
|
-
getStoreSnapshots() {
|
|
171
|
-
return Array.from(this.stores.values()).map(store => {
|
|
172
|
-
let currentState;
|
|
173
|
-
try {
|
|
174
|
-
currentState = store.api.getState();
|
|
175
|
-
} catch {
|
|
176
|
-
currentState = undefined;
|
|
177
|
-
}
|
|
178
|
-
return {
|
|
179
|
-
name: store.name,
|
|
180
|
-
stateChangeCount: store.stateChangeCount,
|
|
181
|
-
isPersisted: store.isPersisted,
|
|
182
|
-
persistName: store.persistName,
|
|
183
|
-
// Persisted is not the same as re-readable: a store registered before
|
|
184
|
-
// its persist middleware attached has a name but no handle. The
|
|
185
|
-
// Storage tool needs the difference to decide between offering "apply"
|
|
186
|
-
// and telling the user to restart.
|
|
187
|
-
canRehydrate: typeof store.rehydrate === "function",
|
|
188
|
-
color: store.color,
|
|
189
|
-
currentState
|
|
190
|
-
};
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Handler invoked when the UI calls setState on a mirrored store (e.g.
|
|
196
|
-
* time-travel from the dashboard). Forward it to the synced device.
|
|
197
|
-
*/
|
|
198
|
-
setRemoteSetStateHandler(handler) {
|
|
199
|
-
this.remoteSetStateHandler = handler;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Replace the entire mirror contents from a synced device snapshot. The
|
|
204
|
-
* rebuilt registry entries get stub `api` handles: getState() serves the
|
|
205
|
-
* snapshotted state, setState() forwards to the remote handler. Respects
|
|
206
|
-
* the enabled flag so the UI's pause button freezes the mirror.
|
|
207
|
-
*/
|
|
208
|
-
replaceFromSnapshot(changes, storeSnapshots) {
|
|
209
|
-
if (!this.getEnabled()) return;
|
|
210
|
-
|
|
211
|
-
// Preserve trees a remote mirror already hydrated — wire-form snapshots
|
|
212
|
-
// always carry markers, and a later snapshot must not blank the detail pane.
|
|
213
|
-
const hydrated = new Map();
|
|
214
|
-
for (const existing of this.items) {
|
|
215
|
-
const prev = existing.prevState;
|
|
216
|
-
if (!prev || prev.__buoyStateOnDevice !== true) {
|
|
217
|
-
hydrated.set(existing.id, existing);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
const merged = changes.slice(0, this.max).map(change => {
|
|
221
|
-
const kept = hydrated.get(change.id);
|
|
222
|
-
const incoming = change.prevState;
|
|
223
|
-
return kept && incoming?.__buoyStateOnDevice === true ? {
|
|
224
|
-
...change,
|
|
225
|
-
prevState: kept.prevState,
|
|
226
|
-
nextState: kept.nextState,
|
|
227
|
-
partial: kept.partial
|
|
228
|
-
} : change;
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
// Preserve currentState a remote mirror already hydrated — oversized
|
|
232
|
-
// stores arrive as STATE_ON_DEVICE markers on every snapshot.
|
|
233
|
-
const hydratedStores = new Map();
|
|
234
|
-
for (const [name, store] of this.stores) {
|
|
235
|
-
try {
|
|
236
|
-
const state = store.api.getState();
|
|
237
|
-
const marker = state;
|
|
238
|
-
if (!marker || marker.__buoyStateOnDevice !== true) {
|
|
239
|
-
hydratedStores.set(name, state);
|
|
240
|
-
}
|
|
241
|
-
} catch {
|
|
242
|
-
// ignore
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
this.stores = new Map(storeSnapshots.map(snapshot => {
|
|
246
|
-
const incoming = snapshot.currentState;
|
|
247
|
-
const kept = hydratedStores.get(snapshot.name);
|
|
248
|
-
const currentState = kept !== undefined && incoming?.__buoyStateOnDevice === true ? kept : snapshot.currentState;
|
|
249
|
-
return [snapshot.name, {
|
|
250
|
-
name: snapshot.name,
|
|
251
|
-
api: {
|
|
252
|
-
getState: () => currentState,
|
|
253
|
-
setState: (partial, replace) => {
|
|
254
|
-
this.remoteSetStateHandler?.(snapshot.name, partial, replace);
|
|
255
|
-
},
|
|
256
|
-
subscribe: () => () => {}
|
|
257
|
-
},
|
|
258
|
-
stateChangeCount: snapshot.stateChangeCount,
|
|
259
|
-
isPersisted: snapshot.isPersisted,
|
|
260
|
-
persistName: snapshot.persistName,
|
|
261
|
-
color: snapshot.color
|
|
262
|
-
}];
|
|
263
|
-
}));
|
|
264
|
-
this.setItems(merged);
|
|
265
|
-
this.notifyStoreListeners();
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Hydrate one mirrored change with real trees fetched on demand from the
|
|
270
|
-
* device via the adapter's `getChangeDetail`. Remote-mirror (desktop) only.
|
|
271
|
-
*/
|
|
272
|
-
hydrateChange(id, patch) {
|
|
273
|
-
this.hydrateById(id, patch);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Hydrate one mirrored store's currentState fetched on demand from the
|
|
278
|
-
* device via the adapter's `getStoreState`. Remote-mirror (desktop) only.
|
|
279
|
-
*/
|
|
280
|
-
hydrateStoreState(storeName, currentState) {
|
|
281
|
-
const store = this.stores.get(storeName);
|
|
282
|
-
if (!store) return;
|
|
283
|
-
this.stores.set(storeName, {
|
|
284
|
-
...store,
|
|
285
|
-
api: {
|
|
286
|
-
...store.api,
|
|
287
|
-
getState: () => currentState
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
this.notifyStoreListeners();
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// ---- Store Registry ----
|
|
294
|
-
|
|
295
|
-
registerStore(name, api, options) {
|
|
296
|
-
if (this.stores.has(name)) return;
|
|
297
|
-
const storeInfo = {
|
|
298
|
-
name,
|
|
299
|
-
api,
|
|
300
|
-
stateChangeCount: 0,
|
|
301
|
-
isPersisted: options?.isPersisted ?? false,
|
|
302
|
-
persistName: options?.persistName,
|
|
303
|
-
rehydrate: options?.rehydrate,
|
|
304
|
-
color: getStoreColor(name)
|
|
305
|
-
};
|
|
306
|
-
this.stores.set(name, storeInfo);
|
|
307
|
-
this.notifyStoreListeners();
|
|
308
|
-
}
|
|
309
|
-
unregisterStore(name) {
|
|
310
|
-
this.stores.delete(name);
|
|
311
|
-
this.notifyStoreListeners();
|
|
312
|
-
}
|
|
313
|
-
getStores() {
|
|
314
|
-
return Array.from(this.stores.values());
|
|
315
|
-
}
|
|
316
|
-
getStore(name) {
|
|
317
|
-
return this.stores.get(name);
|
|
318
|
-
}
|
|
319
|
-
getStoreColor(name) {
|
|
320
|
-
return this.stores.get(name)?.color ?? getStoreColor(name);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// ---- Filtering ----
|
|
324
|
-
|
|
325
|
-
filterStateChanges(filter) {
|
|
326
|
-
let filtered = this.getAll();
|
|
327
|
-
if (filter.searchText) {
|
|
328
|
-
const search = filter.searchText.toLowerCase();
|
|
329
|
-
filtered = filtered.filter(c => c.storeName.toLowerCase().includes(search) || c.partialPreview.toLowerCase().includes(search) || c.changedKeys.some(k => k.toLowerCase().includes(search)));
|
|
330
|
-
}
|
|
331
|
-
if (filter.storeNames && filter.storeNames.length > 0) {
|
|
332
|
-
filtered = filtered.filter(c => filter.storeNames.includes(c.storeName));
|
|
333
|
-
}
|
|
334
|
-
if (filter.onlyWithChanges) {
|
|
335
|
-
filtered = filtered.filter(c => c.hasStateChange);
|
|
336
|
-
}
|
|
337
|
-
return filtered;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// ---- Stats ----
|
|
341
|
-
|
|
342
|
-
getStats() {
|
|
343
|
-
const total = this.items.length;
|
|
344
|
-
const withChanges = this.items.filter(c => c.hasStateChange).length;
|
|
345
|
-
const storeCount = this.stores.size;
|
|
346
|
-
const durations = this.items.filter(c => c.duration !== undefined).map(c => c.duration);
|
|
347
|
-
const avgDuration = durations.length > 0 ? durations.reduce((sum, d) => sum + d, 0) / durations.length : 0;
|
|
348
|
-
return {
|
|
349
|
-
totalChanges: total,
|
|
350
|
-
changesWithStateChange: withChanges,
|
|
351
|
-
changesWithoutStateChange: total - withChanges,
|
|
352
|
-
storeCount,
|
|
353
|
-
averageDuration: Math.round(avgDuration * 100) / 100
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
getUniqueStoreNames() {
|
|
357
|
-
return Array.from(this.stores.keys()).sort();
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// ---- Enable / Disable ----
|
|
361
|
-
|
|
362
|
-
setMaxChanges(max) {
|
|
363
|
-
this.setMax(max);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// ---- Subscriptions ----
|
|
367
|
-
|
|
368
|
-
subscribeToStores(listener) {
|
|
369
|
-
this.storeListeners.add(listener);
|
|
370
|
-
return () => {
|
|
371
|
-
this.storeListeners.delete(listener);
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
notifyStoreListeners() {
|
|
375
|
-
const stores = this.getStores();
|
|
376
|
-
this.storeListeners.forEach(listener => listener(stores));
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
const zustandStateStore = exports.zustandStateStore = new ZustandStateStore();
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.zustandStateStore=void 0;var _sharedUi=require("@buoy-gg/shared-ui");const STORE_COLORS={counter:"#10B981",auth:"#8B5CF6",user:"#3B82F6",cart:"#EC4899",app:"#6366F1",ui:"#F59E0B",settings:"#14B8A6",theme:"#06B6D4",navigation:"#F97316",form:"#EF4444"};function getStoreColor(u){return(0,_sharedUi.entityColor)(u,STORE_COLORS)}function formatPartialPreview(u,t=40){return(0,_sharedUi.formatValuePreview)(u,{maxLength:t,undefinedLabel:"",functionLabel:"(updater fn)"})}class ZustandStateStore extends _sharedUi.ChangeLog{stores=new Map;storeListeners=new Set;remoteSetStateHandler=null;addStateChange(t){if(!this.canRecord())return;const{storeName:s,partial:r,replace:a,prevState:o,nextState:e,duration:n,category:i,isPersisted:h=false}=t;const c=o!==e;const{summary:g,changedKeys:d,changedCount:l}=(0,_sharedUi.shallowDiffSummary)(o,e);const f=formatPartialPreview(r);const m=(n??0)>16;const C=i??(a?"replace":"setState");const y={id:this.nextId(),storeName:s,timestamp:Date.now(),prevState:o,nextState:e,partial:r,duration:n,hasStateChange:c,replace:a,category:C,changedKeys:d,changedKeysCount:l,diffSummary:g,partialPreview:f,isSlowUpdate:m,isPersisted:h};this.push(y);const S=this.stores.get(s);if(S){S.stateChangeCount++}this.notifyListeners()}getStateChanges(){return this.getAll()}getStateChangeById(t){return this.getById(t)}clearStateChanges(){for(const t of this.stores.values()){t.stateChangeCount=0}this.clear();this.notifyStoreListeners()}replaceStateChanges(t){if(!this.getEnabled())return;for(const r of this.stores.values()){r.stateChangeCount=0}const s=t.slice(0,this.max);for(const r of s){const a=this.stores.get(r.storeName);if(a)a.stateChangeCount++}this.setItems(s);this.notifyStoreListeners()}getStoreSnapshots(){return Array.from(this.stores.values()).map(t=>{let s;try{s=t.api.getState()}catch{s=void 0}return{name:t.name,stateChangeCount:t.stateChangeCount,isPersisted:t.isPersisted,persistName:t.persistName,canRehydrate:typeof t.rehydrate==="function",color:t.color,currentState:s}})}setRemoteSetStateHandler(t){this.remoteSetStateHandler=t}replaceFromSnapshot(t,s){if(!this.getEnabled())return;const r=new Map;for(const e of this.items){const n=e.prevState;if(!n||n.__buoyStateOnDevice!==true){r.set(e.id,e)}}const a=t.slice(0,this.max).map(e=>{const n=r.get(e.id);const i=e.prevState;return n&&i?.__buoyStateOnDevice===true?{...e,prevState:n.prevState,nextState:n.nextState,partial:n.partial}:e});const o=new Map;for(const[e,n]of this.stores){try{const i=n.api.getState();const h=i;if(!h||h.__buoyStateOnDevice!==true){o.set(e,i)}}catch{}}this.stores=new Map(s.map(e=>{const n=e.currentState;const i=o.get(e.name);const h=i!==void 0&&n?.__buoyStateOnDevice===true?i:e.currentState;return[e.name,{name:e.name,api:{getState:()=>h,setState:(c,g)=>{this.remoteSetStateHandler?.(e.name,c,g)},subscribe:()=>()=>{}},stateChangeCount:e.stateChangeCount,isPersisted:e.isPersisted,persistName:e.persistName,color:e.color}]}));this.setItems(a);this.notifyStoreListeners()}hydrateChange(t,s){this.hydrateById(t,s)}hydrateStoreState(t,s){const r=this.stores.get(t);if(!r)return;this.stores.set(t,{...r,api:{...r.api,getState:()=>s}});this.notifyStoreListeners()}registerStore(t,s,r){if(this.stores.has(t))return;const a={name:t,api:s,stateChangeCount:0,isPersisted:r?.isPersisted??false,persistName:r?.persistName,rehydrate:r?.rehydrate,color:getStoreColor(t)};this.stores.set(t,a);this.notifyStoreListeners()}unregisterStore(t){this.stores.delete(t);this.notifyStoreListeners()}getStores(){return Array.from(this.stores.values())}getStore(t){return this.stores.get(t)}getStoreColor(t){return this.stores.get(t)?.color??getStoreColor(t)}filterStateChanges(t){let s=this.getAll();if(t.searchText){const r=t.searchText.toLowerCase();s=s.filter(a=>a.storeName.toLowerCase().includes(r)||a.partialPreview.toLowerCase().includes(r)||a.changedKeys.some(o=>o.toLowerCase().includes(r)))}if(t.storeNames&&t.storeNames.length>0){s=s.filter(r=>t.storeNames.includes(r.storeName))}if(t.onlyWithChanges){s=s.filter(r=>r.hasStateChange)}return s}getStats(){const t=this.items.length;const s=this.items.filter(e=>e.hasStateChange).length;const r=this.stores.size;const a=this.items.filter(e=>e.duration!==void 0).map(e=>e.duration);const o=a.length>0?a.reduce((e,n)=>e+n,0)/a.length:0;return{totalChanges:t,changesWithStateChange:s,changesWithoutStateChange:t-s,storeCount:r,averageDuration:Math.round(o*100)/100}}getUniqueStoreNames(){return Array.from(this.stores.keys()).sort()}setMaxChanges(t){this.setMax(t)}subscribeToStores(t){this.storeListeners.add(t);return()=>{this.storeListeners.delete(t)}}notifyStoreListeners(){const t=this.getStores();this.storeListeners.forEach(s=>s(t))}}const zustandStateStore=exports.zustandStateStore=new ZustandStateStore;
|
package/lib/module/index.js
CHANGED
|
@@ -1,90 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @buoy-gg/zustand
|
|
5
|
-
*
|
|
6
|
-
* Zustand Store DevTools for React Native
|
|
7
|
-
*
|
|
8
|
-
* PUBLIC API - Only these exports are supported for external use.
|
|
9
|
-
*
|
|
10
|
-
* @example Recommended setup (one line, zero store modifications)
|
|
11
|
-
* ```tsx
|
|
12
|
-
* import { watchStores } from '@buoy-gg/zustand';
|
|
13
|
-
* import { useCounterStore } from './stores/counter';
|
|
14
|
-
* import { useAuthStore } from './stores/auth';
|
|
15
|
-
*
|
|
16
|
-
* // One call, anywhere at module scope or in your root layout:
|
|
17
|
-
* watchStores({
|
|
18
|
-
* counterStore: useCounterStore,
|
|
19
|
-
* authStore: useAuthStore,
|
|
20
|
-
* });
|
|
21
|
-
* ```
|
|
22
|
-
*
|
|
23
|
-
* @example Advanced: middleware for extra detail (partial + timing)
|
|
24
|
-
* ```tsx
|
|
25
|
-
* import { create } from 'zustand';
|
|
26
|
-
* import { buoyDevTools } from '@buoy-gg/zustand';
|
|
27
|
-
*
|
|
28
|
-
* const useCounterStore = create(
|
|
29
|
-
* buoyDevTools(
|
|
30
|
-
* (set) => ({
|
|
31
|
-
* count: 0,
|
|
32
|
-
* increment: () => set((s) => ({ count: s.count + 1 })),
|
|
33
|
-
* }),
|
|
34
|
-
* { name: 'counterStore' }
|
|
35
|
-
* )
|
|
36
|
-
* );
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
// Side-effect: registers the Time Machine snapshot provider
|
|
41
|
-
import "./zustand/utils/snapshotProvider";
|
|
42
|
-
|
|
43
|
-
// =============================================================================
|
|
44
|
-
// PRESET (Primary entry point for FloatingDevTools)
|
|
45
|
-
// =============================================================================
|
|
46
|
-
export { zustandToolPreset, createZustandTool } from "./preset";
|
|
47
|
-
|
|
48
|
-
// =============================================================================
|
|
49
|
-
// WATCH STORES (Recommended — non-intrusive, subscribe-only)
|
|
50
|
-
// =============================================================================
|
|
51
|
-
export { watchStores } from "./zustand/utils/buoyZustandMiddleware";
|
|
52
|
-
|
|
53
|
-
// =============================================================================
|
|
54
|
-
// MIDDLEWARE (Advanced — wraps setState for partial + timing capture)
|
|
55
|
-
// =============================================================================
|
|
56
|
-
export { buoyDevTools } from "./zustand/utils/buoyZustandMiddleware";
|
|
57
|
-
|
|
58
|
-
// =============================================================================
|
|
59
|
-
// UTILITIES
|
|
60
|
-
// =============================================================================
|
|
61
|
-
export { isStoreInstrumented } from "./zustand/utils/buoyZustandMiddleware";
|
|
62
|
-
|
|
63
|
-
// =============================================================================
|
|
64
|
-
// HOOKS (For consuming Zustand state data)
|
|
65
|
-
// =============================================================================
|
|
66
|
-
export { useZustandStateChanges } from "./zustand/hooks/useZustandStateChanges";
|
|
67
|
-
// =============================================================================
|
|
68
|
-
// COMPONENTS (For custom UI implementations)
|
|
69
|
-
// =============================================================================
|
|
70
|
-
// `ZustandToolView` is the same tool rendered inline (header bar + body + footer)
|
|
71
|
-
// instead of inside a JsModal — for hosts that show tools in a panel.
|
|
72
|
-
export { ZustandModal, ZustandToolView } from "./zustand/components/ZustandModal";
|
|
73
|
-
export { ZustandStateChangeItem } from "./zustand/components/ZustandStateChangeItem";
|
|
74
|
-
export { ZustandStateDetailContent, ZustandStateDetailFooter } from "./zustand/components/ZustandStateDetailContent";
|
|
75
|
-
export { ZustandIcon, ZUSTAND_ICON_COLOR } from "./zustand/components/ZustandIcon";
|
|
76
|
-
|
|
77
|
-
// =============================================================================
|
|
78
|
-
// EXTERNAL SYNC (Adapter for @buoy-gg/external-sync's useExternalSync)
|
|
79
|
-
// =============================================================================
|
|
80
|
-
export { zustandSyncAdapter } from "./zustand/sync/zustandSyncAdapter";
|
|
81
|
-
|
|
82
|
-
// =============================================================================
|
|
83
|
-
// TYPES
|
|
84
|
-
// =============================================================================
|
|
85
|
-
|
|
86
|
-
// =============================================================================
|
|
87
|
-
// INTERNAL EXPORTS (For @buoy-gg/* packages only - not part of public API)
|
|
88
|
-
// =============================================================================
|
|
89
|
-
/** @internal */
|
|
90
|
-
export { zustandStateStore } from "./zustand/utils/zustandStateStore";
|
|
1
|
+
"use strict";import"./zustand/utils/snapshotProvider";export{zustandToolPreset,createZustandTool}from"./preset";export{watchStores}from"./zustand/utils/buoyZustandMiddleware";export{buoyDevTools}from"./zustand/utils/buoyZustandMiddleware";export{isStoreInstrumented}from"./zustand/utils/buoyZustandMiddleware";export{useZustandStateChanges}from"./zustand/hooks/useZustandStateChanges";export{ZustandModal,ZustandToolView}from"./zustand/components/ZustandModal";export{ZustandStateChangeItem}from"./zustand/components/ZustandStateChangeItem";export{ZustandStateDetailContent,ZustandStateDetailFooter}from"./zustand/components/ZustandStateDetailContent";export{ZustandIcon,ZUSTAND_ICON_COLOR}from"./zustand/components/ZustandIcon";export{zustandSyncAdapter}from"./zustand/sync/zustandSyncAdapter";export{zustandStateStore}from"./zustand/utils/zustandStateStore";
|
package/lib/module/preset.js
CHANGED
|
@@ -1,98 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Pre-configured Zustand DevTools preset for FloatingDevTools
|
|
5
|
-
*
|
|
6
|
-
* ZERO-CONFIG: This preset is auto-discovered by FloatingDevTools!
|
|
7
|
-
* Just install @buoy-gg/zustand and wrap your stores with buoyDevTools().
|
|
8
|
-
*
|
|
9
|
-
* @example Automatic (recommended)
|
|
10
|
-
* ```tsx
|
|
11
|
-
* import { create } from 'zustand';
|
|
12
|
-
* import { buoyDevTools } from '@buoy-gg/zustand';
|
|
13
|
-
*
|
|
14
|
-
* const useCounterStore = create(
|
|
15
|
-
* buoyDevTools(
|
|
16
|
-
* (set) => ({ count: 0, increment: () => set((s) => ({ count: s.count + 1 })) }),
|
|
17
|
-
* { name: 'counterStore' }
|
|
18
|
-
* )
|
|
19
|
-
* );
|
|
20
|
-
*
|
|
21
|
-
* // The Zustand tool appears automatically in FloatingDevTools!
|
|
22
|
-
* <FloatingDevTools />
|
|
23
|
-
* ```
|
|
24
|
-
*
|
|
25
|
-
* @example Manual (only for custom configuration)
|
|
26
|
-
* ```tsx
|
|
27
|
-
* import { createZustandTool } from '@buoy-gg/zustand';
|
|
28
|
-
*
|
|
29
|
-
* const customZustandTool = createZustandTool({
|
|
30
|
-
* name: "STATE",
|
|
31
|
-
* iconColor: "#463B3F",
|
|
32
|
-
* });
|
|
33
|
-
*
|
|
34
|
-
* <FloatingDevTools apps={[customZustandTool]} />
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
import { ZustandModal } from "./zustand/components/ZustandModal";
|
|
39
|
-
import { ZustandIcon } from "./zustand/components/ZustandIcon";
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Pre-configured Zustand DevTools preset for FloatingDevTools.
|
|
43
|
-
* Includes:
|
|
44
|
-
* - Live state change monitoring
|
|
45
|
-
* - State inspection (JSON viewer)
|
|
46
|
-
* - State diff visualization (tree + split)
|
|
47
|
-
* - Filter by store name
|
|
48
|
-
* - Changed keys tracking
|
|
49
|
-
*/
|
|
50
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
51
|
-
export const zustandToolPreset = {
|
|
52
|
-
id: "zustand",
|
|
53
|
-
name: "ZUSTAND",
|
|
54
|
-
description: "Zustand store & state inspector",
|
|
55
|
-
slot: "both",
|
|
56
|
-
icon: ({
|
|
57
|
-
size
|
|
58
|
-
}) => /*#__PURE__*/_jsx(ZustandIcon, {
|
|
59
|
-
size: size
|
|
60
|
-
}),
|
|
61
|
-
component: ZustandModal,
|
|
62
|
-
props: {
|
|
63
|
-
enableSharedModalDimensions: false
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Create a custom Zustand DevTools configuration.
|
|
69
|
-
* Use this if you want to override default settings.
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* ```tsx
|
|
73
|
-
* import { createZustandTool } from '@buoy-gg/zustand';
|
|
74
|
-
*
|
|
75
|
-
* const myZustandTool = createZustandTool({
|
|
76
|
-
* name: "STATE",
|
|
77
|
-
* iconColor: "#463B3F",
|
|
78
|
-
* });
|
|
79
|
-
* ```
|
|
80
|
-
*/
|
|
81
|
-
export function createZustandTool(options) {
|
|
82
|
-
return {
|
|
83
|
-
id: options?.id || "zustand",
|
|
84
|
-
name: options?.name || "ZUSTAND",
|
|
85
|
-
description: options?.description || "Zustand store & state inspector",
|
|
86
|
-
slot: "both",
|
|
87
|
-
icon: ({
|
|
88
|
-
size
|
|
89
|
-
}) => /*#__PURE__*/_jsx(ZustandIcon, {
|
|
90
|
-
size: size,
|
|
91
|
-
color: options?.iconColor
|
|
92
|
-
}),
|
|
93
|
-
component: ZustandModal,
|
|
94
|
-
props: {
|
|
95
|
-
enableSharedModalDimensions: options?.enableSharedModalDimensions !== undefined ? options.enableSharedModalDimensions : false
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
}
|
|
1
|
+
"use strict";import{ZustandModal as o}from"./zustand/components/ZustandModal";import{ZustandIcon as n}from"./zustand/components/ZustandIcon";import{jsx as s}from"react/jsx-runtime";export const zustandToolPreset={id:"zustand",name:"ZUSTAND",description:"Zustand store & state inspector",slot:"both",icon:({size:e})=>s(n,{size:e}),component:o,props:{enableSharedModalDimensions:false}};export function createZustandTool(e){return{id:e?.id||"zustand",name:e?.name||"ZUSTAND",description:e?.description||"Zustand store & state inspector",slot:"both",icon:({size:t})=>s(n,{size:t,color:e?.iconColor}),component:o,props:{enableSharedModalDimensions:e?.enableSharedModalDimensions!==void 0?e.enableSharedModalDimensions:false}}}
|
|
@@ -1,114 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* ZustandActionButton
|
|
5
|
-
*
|
|
6
|
-
* Generic action button for Zustand DevTools footer.
|
|
7
|
-
* Mirrors ReduxActionButton.tsx
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { TouchableOpacity, Text, View, StyleSheet } from "react-native";
|
|
11
|
-
import { night, monoFont } from "@buoy-gg/shared-ui";
|
|
12
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
-
const buttonConfigs = {
|
|
14
|
-
copy: {
|
|
15
|
-
color: night.color.accent,
|
|
16
|
-
backgroundColor: night.color.accentSoft,
|
|
17
|
-
borderColor: night.color.accentBorder,
|
|
18
|
-
textColor: night.color.accent
|
|
19
|
-
},
|
|
20
|
-
reset: {
|
|
21
|
-
color: night.color.warning,
|
|
22
|
-
backgroundColor: night.color.warningSoft,
|
|
23
|
-
borderColor: night.color.warning + "40",
|
|
24
|
-
textColor: night.color.warning
|
|
25
|
-
},
|
|
26
|
-
clear: {
|
|
27
|
-
color: night.color.danger,
|
|
28
|
-
backgroundColor: night.color.dangerSoft,
|
|
29
|
-
borderColor: night.color.danger + "40",
|
|
30
|
-
textColor: night.color.danger
|
|
31
|
-
},
|
|
32
|
-
jump: {
|
|
33
|
-
color: night.color.warning,
|
|
34
|
-
backgroundColor: night.color.warningSoft,
|
|
35
|
-
borderColor: night.color.warning + "40",
|
|
36
|
-
textColor: night.color.warning
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
export function ZustandActionButton({
|
|
40
|
-
onPress,
|
|
41
|
-
text,
|
|
42
|
-
type,
|
|
43
|
-
disabled = false,
|
|
44
|
-
testID
|
|
45
|
-
}) {
|
|
46
|
-
const config = buttonConfigs[type];
|
|
47
|
-
return /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
48
|
-
disabled: disabled,
|
|
49
|
-
onPress: onPress,
|
|
50
|
-
style: [styles.button, {
|
|
51
|
-
backgroundColor: disabled ? night.color.textTertiary + "1A" : config.backgroundColor,
|
|
52
|
-
borderColor: disabled ? night.color.textTertiary + "33" : config.borderColor,
|
|
53
|
-
opacity: disabled ? 0.5 : 1
|
|
54
|
-
}],
|
|
55
|
-
activeOpacity: 0.7,
|
|
56
|
-
testID: testID,
|
|
57
|
-
accessibilityRole: "button",
|
|
58
|
-
accessibilityLabel: text,
|
|
59
|
-
accessibilityState: {
|
|
60
|
-
disabled
|
|
61
|
-
},
|
|
62
|
-
children: [/*#__PURE__*/_jsx(View, {
|
|
63
|
-
style: [styles.dot, {
|
|
64
|
-
backgroundColor: disabled ? night.color.textTertiary : config.color
|
|
65
|
-
}]
|
|
66
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
67
|
-
style: [styles.text, {
|
|
68
|
-
color: disabled ? night.color.textTertiary : config.textColor
|
|
69
|
-
}],
|
|
70
|
-
children: text
|
|
71
|
-
})]
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
const styles = StyleSheet.create({
|
|
75
|
-
button: {
|
|
76
|
-
flexDirection: "row",
|
|
77
|
-
alignItems: "center",
|
|
78
|
-
justifyContent: "center",
|
|
79
|
-
borderRadius: 6,
|
|
80
|
-
borderWidth: 1,
|
|
81
|
-
paddingHorizontal: 12,
|
|
82
|
-
paddingVertical: 6,
|
|
83
|
-
height: 25,
|
|
84
|
-
minWidth: 80,
|
|
85
|
-
shadowOffset: {
|
|
86
|
-
width: 0,
|
|
87
|
-
height: 1
|
|
88
|
-
},
|
|
89
|
-
shadowOpacity: 0.2,
|
|
90
|
-
shadowRadius: 2,
|
|
91
|
-
elevation: 2
|
|
92
|
-
},
|
|
93
|
-
dot: {
|
|
94
|
-
width: 5,
|
|
95
|
-
height: 5,
|
|
96
|
-
borderRadius: 3,
|
|
97
|
-
marginRight: 6,
|
|
98
|
-
shadowColor: night.color.text,
|
|
99
|
-
shadowOffset: {
|
|
100
|
-
width: 0,
|
|
101
|
-
height: 0
|
|
102
|
-
},
|
|
103
|
-
shadowOpacity: 0.6,
|
|
104
|
-
shadowRadius: 2
|
|
105
|
-
},
|
|
106
|
-
text: {
|
|
107
|
-
fontSize: 10,
|
|
108
|
-
fontWeight: "600",
|
|
109
|
-
letterSpacing: 0.5,
|
|
110
|
-
textTransform: "uppercase",
|
|
111
|
-
fontFamily: monoFont,
|
|
112
|
-
height: 12
|
|
113
|
-
}
|
|
114
|
-
});
|
|
1
|
+
"use strict";import{TouchableOpacity as s,Text as d,View as g,StyleSheet as h}from"react-native";import{night as o,monoFont as u}from"@buoy-gg/shared-ui";import{jsx as n,jsxs as f}from"react/jsx-runtime";const C={copy:{color:o.color.accent,backgroundColor:o.color.accentSoft,borderColor:o.color.accentBorder,textColor:o.color.accent},reset:{color:o.color.warning,backgroundColor:o.color.warningSoft,borderColor:o.color.warning+"40",textColor:o.color.warning},clear:{color:o.color.danger,backgroundColor:o.color.dangerSoft,borderColor:o.color.danger+"40",textColor:o.color.danger},jump:{color:o.color.warning,backgroundColor:o.color.warningSoft,borderColor:o.color.warning+"40",textColor:o.color.warning}};export function ZustandActionButton({onPress:i,text:c,type:l,disabled:r=false,testID:a}){const t=C[l];return f(s,{disabled:r,onPress:i,style:[e.button,{backgroundColor:r?o.color.textTertiary+"1A":t.backgroundColor,borderColor:r?o.color.textTertiary+"33":t.borderColor,opacity:r?.5:1}],activeOpacity:.7,testID:a,accessibilityRole:"button",accessibilityLabel:c,accessibilityState:{disabled:r},children:[n(g,{style:[e.dot,{backgroundColor:r?o.color.textTertiary:t.color}]}),n(d,{style:[e.text,{color:r?o.color.textTertiary:t.textColor}],children:c})]})}const e=h.create({button:{flexDirection:"row",alignItems:"center",justifyContent:"center",borderRadius:6,borderWidth:1,paddingHorizontal:12,paddingVertical:6,height:25,minWidth:80,shadowOffset:{width:0,height:1},shadowOpacity:.2,shadowRadius:2,elevation:2},dot:{width:5,height:5,borderRadius:3,marginRight:6,shadowColor:o.color.text,shadowOffset:{width:0,height:0},shadowOpacity:.6,shadowRadius:2},text:{fontSize:10,fontWeight:"600",letterSpacing:.5,textTransform:"uppercase",fontFamily:u,height:12}});
|