@usesidekick/react 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/README.md +246 -0
- package/dist/index.d.mts +358 -0
- package/dist/index.d.ts +358 -0
- package/dist/index.js +2470 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2403 -0
- package/dist/index.mjs.map +1 -0
- package/dist/jsx-dev-runtime.d.mts +21 -0
- package/dist/jsx-dev-runtime.d.ts +21 -0
- package/dist/jsx-dev-runtime.js +160 -0
- package/dist/jsx-dev-runtime.js.map +1 -0
- package/dist/jsx-dev-runtime.mjs +122 -0
- package/dist/jsx-dev-runtime.mjs.map +1 -0
- package/dist/jsx-runtime.d.mts +26 -0
- package/dist/jsx-runtime.d.ts +26 -0
- package/dist/jsx-runtime.js +150 -0
- package/dist/jsx-runtime.js.map +1 -0
- package/dist/jsx-runtime.mjs +109 -0
- package/dist/jsx-runtime.mjs.map +1 -0
- package/dist/server/index.d.mts +235 -0
- package/dist/server/index.d.ts +235 -0
- package/dist/server/index.js +642 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/index.mjs +597 -0
- package/dist/server/index.mjs.map +1 -0
- package/package.json +64 -0
- package/src/components/SidekickPanel.tsx +868 -0
- package/src/components/index.ts +1 -0
- package/src/context.tsx +157 -0
- package/src/flags.ts +47 -0
- package/src/index.ts +71 -0
- package/src/jsx-dev-runtime.ts +138 -0
- package/src/jsx-runtime.ts +159 -0
- package/src/loader.ts +35 -0
- package/src/primitives/behavior.ts +70 -0
- package/src/primitives/data.ts +91 -0
- package/src/primitives/index.ts +3 -0
- package/src/primitives/ui.ts +268 -0
- package/src/provider.tsx +1264 -0
- package/src/runtime-loader.ts +106 -0
- package/src/server/drizzle-adapter.ts +53 -0
- package/src/server/drizzle-schema.ts +16 -0
- package/src/server/generate.ts +578 -0
- package/src/server/handler.ts +343 -0
- package/src/server/index.ts +20 -0
- package/src/server/storage.ts +1 -0
- package/src/server/types.ts +49 -0
- package/src/types.ts +295 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2403 @@
|
|
|
1
|
+
// src/provider.tsx
|
|
2
|
+
import React4, { useCallback, useEffect, useMemo, useState, useRef } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
|
|
5
|
+
// src/context.tsx
|
|
6
|
+
import { createContext, useContext } from "react";
|
|
7
|
+
var SidekickContext = createContext(null);
|
|
8
|
+
function useSidekickSafe() {
|
|
9
|
+
return useContext(SidekickContext);
|
|
10
|
+
}
|
|
11
|
+
function useSidekick() {
|
|
12
|
+
const context = useContext(SidekickContext);
|
|
13
|
+
if (!context) {
|
|
14
|
+
throw new Error("useSidekick must be used within a SidekickProvider");
|
|
15
|
+
}
|
|
16
|
+
return context;
|
|
17
|
+
}
|
|
18
|
+
function useAddedColumns(tableId) {
|
|
19
|
+
const context = useSidekickSafe();
|
|
20
|
+
if (!context) return [];
|
|
21
|
+
return context.getColumns(tableId);
|
|
22
|
+
}
|
|
23
|
+
function useColumnRenames(tableId) {
|
|
24
|
+
const context = useSidekickSafe();
|
|
25
|
+
if (!context) return [];
|
|
26
|
+
return context.getColumnRenames(tableId);
|
|
27
|
+
}
|
|
28
|
+
function useHiddenColumns(tableId) {
|
|
29
|
+
const context = useSidekickSafe();
|
|
30
|
+
if (!context) return [];
|
|
31
|
+
return context.getHiddenColumns(tableId);
|
|
32
|
+
}
|
|
33
|
+
function useColumnOrder(tableId) {
|
|
34
|
+
const context = useSidekickSafe();
|
|
35
|
+
if (!context) return void 0;
|
|
36
|
+
return context.getColumnOrder(tableId);
|
|
37
|
+
}
|
|
38
|
+
function useMenuItems(menuId) {
|
|
39
|
+
const context = useSidekickSafe();
|
|
40
|
+
if (!context) return [];
|
|
41
|
+
return context.getMenuItems(menuId);
|
|
42
|
+
}
|
|
43
|
+
function useTabs(tabGroupId) {
|
|
44
|
+
const context = useSidekickSafe();
|
|
45
|
+
if (!context) return [];
|
|
46
|
+
return context.getTabs(tabGroupId);
|
|
47
|
+
}
|
|
48
|
+
function useActions(actionBarId) {
|
|
49
|
+
const context = useSidekickSafe();
|
|
50
|
+
if (!context) return [];
|
|
51
|
+
return context.getActions(actionBarId);
|
|
52
|
+
}
|
|
53
|
+
function useValidations(formId) {
|
|
54
|
+
const context = useSidekickSafe();
|
|
55
|
+
if (!context) return [];
|
|
56
|
+
return context.getValidations(formId);
|
|
57
|
+
}
|
|
58
|
+
function usePropsModifier(componentId, props) {
|
|
59
|
+
const context = useSidekickSafe();
|
|
60
|
+
if (!context) return props;
|
|
61
|
+
return context.applyPropsModifiers(componentId, props);
|
|
62
|
+
}
|
|
63
|
+
function useComputedField(fieldName, data) {
|
|
64
|
+
const context = useSidekickSafe();
|
|
65
|
+
if (!context) return void 0;
|
|
66
|
+
return context.getComputedValue(fieldName, data);
|
|
67
|
+
}
|
|
68
|
+
function useFilter(filterName, items) {
|
|
69
|
+
const context = useSidekickSafe();
|
|
70
|
+
if (!context) return items;
|
|
71
|
+
return context.applyFilters(filterName, items);
|
|
72
|
+
}
|
|
73
|
+
function useSortOptions(tableId) {
|
|
74
|
+
const context = useSidekickSafe();
|
|
75
|
+
if (!context) return [];
|
|
76
|
+
return context.getSortOptions(tableId);
|
|
77
|
+
}
|
|
78
|
+
function useGroupByOptions(tableId) {
|
|
79
|
+
const context = useSidekickSafe();
|
|
80
|
+
if (!context) return [];
|
|
81
|
+
return context.getGroupByOptions(tableId);
|
|
82
|
+
}
|
|
83
|
+
function useKeyboardShortcuts() {
|
|
84
|
+
const context = useSidekickSafe();
|
|
85
|
+
if (!context) return [];
|
|
86
|
+
return context.getKeyboardShortcuts();
|
|
87
|
+
}
|
|
88
|
+
function useEventEmitter() {
|
|
89
|
+
const context = useSidekickSafe();
|
|
90
|
+
if (!context) return () => {
|
|
91
|
+
};
|
|
92
|
+
return context.emitEvent;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/flags.ts
|
|
96
|
+
var STORAGE_KEY = "sidekick_flags";
|
|
97
|
+
function loadFlags() {
|
|
98
|
+
if (typeof window === "undefined") {
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
103
|
+
return stored ? JSON.parse(stored) : {};
|
|
104
|
+
} catch {
|
|
105
|
+
return {};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function saveFlags(flags) {
|
|
109
|
+
if (typeof window === "undefined") {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(flags));
|
|
114
|
+
} catch {
|
|
115
|
+
console.warn("[Sidekick] Failed to save flags to localStorage");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function getFlag(overrideId) {
|
|
119
|
+
const flags = loadFlags();
|
|
120
|
+
return flags[overrideId] ?? false;
|
|
121
|
+
}
|
|
122
|
+
function setFlag(overrideId, enabled) {
|
|
123
|
+
const flags = loadFlags();
|
|
124
|
+
flags[overrideId] = enabled;
|
|
125
|
+
saveFlags(flags);
|
|
126
|
+
}
|
|
127
|
+
function toggleFlag(overrideId) {
|
|
128
|
+
const current = getFlag(overrideId);
|
|
129
|
+
setFlag(overrideId, !current);
|
|
130
|
+
return !current;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/loader.ts
|
|
134
|
+
var overrideRegistry = /* @__PURE__ */ new Map();
|
|
135
|
+
function registerOverride(module) {
|
|
136
|
+
overrideRegistry.set(module.manifest.id, module);
|
|
137
|
+
}
|
|
138
|
+
function getRegisteredOverrides() {
|
|
139
|
+
return Array.from(overrideRegistry.values());
|
|
140
|
+
}
|
|
141
|
+
function createOverride(manifest, activate) {
|
|
142
|
+
return { manifest, activate };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/primitives/ui.ts
|
|
146
|
+
function generateId() {
|
|
147
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
148
|
+
const r = Math.random() * 16 | 0;
|
|
149
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
150
|
+
return v.toString(16);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function createUIPrimitives(state, currentOverrideId) {
|
|
154
|
+
return {
|
|
155
|
+
wrap(componentName, wrapper, options = {}) {
|
|
156
|
+
const wrapped = {
|
|
157
|
+
id: generateId(),
|
|
158
|
+
overrideId: currentOverrideId,
|
|
159
|
+
wrapper,
|
|
160
|
+
priority: options.priority ?? 0,
|
|
161
|
+
where: options.where
|
|
162
|
+
};
|
|
163
|
+
const existing = state.wrappers.get(componentName) ?? [];
|
|
164
|
+
existing.push(wrapped);
|
|
165
|
+
existing.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
166
|
+
state.wrappers.set(componentName, existing);
|
|
167
|
+
},
|
|
168
|
+
replace(componentName, replacement) {
|
|
169
|
+
state.replacements.set(componentName, replacement);
|
|
170
|
+
},
|
|
171
|
+
addStyles(css) {
|
|
172
|
+
const styles2 = {
|
|
173
|
+
id: generateId(),
|
|
174
|
+
overrideId: currentOverrideId,
|
|
175
|
+
css
|
|
176
|
+
};
|
|
177
|
+
state.styles.push(styles2);
|
|
178
|
+
},
|
|
179
|
+
addColumn(tableId, config) {
|
|
180
|
+
const column = {
|
|
181
|
+
id: generateId(),
|
|
182
|
+
overrideId: currentOverrideId,
|
|
183
|
+
tableId,
|
|
184
|
+
...config
|
|
185
|
+
};
|
|
186
|
+
const existing = state.columns.get(tableId) ?? [];
|
|
187
|
+
existing.push(column);
|
|
188
|
+
existing.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
189
|
+
state.columns.set(tableId, existing);
|
|
190
|
+
},
|
|
191
|
+
renameColumn(tableId, originalHeader, newHeader) {
|
|
192
|
+
const rename = {
|
|
193
|
+
id: generateId(),
|
|
194
|
+
overrideId: currentOverrideId,
|
|
195
|
+
tableId,
|
|
196
|
+
originalHeader,
|
|
197
|
+
newHeader
|
|
198
|
+
};
|
|
199
|
+
const existing = state.columnRenames.get(tableId) ?? [];
|
|
200
|
+
existing.push(rename);
|
|
201
|
+
state.columnRenames.set(tableId, existing);
|
|
202
|
+
},
|
|
203
|
+
hideColumn(tableId, header) {
|
|
204
|
+
const hidden = {
|
|
205
|
+
id: generateId(),
|
|
206
|
+
overrideId: currentOverrideId,
|
|
207
|
+
tableId,
|
|
208
|
+
header
|
|
209
|
+
};
|
|
210
|
+
const existing = state.hiddenColumns.get(tableId) ?? [];
|
|
211
|
+
existing.push(hidden);
|
|
212
|
+
state.hiddenColumns.set(tableId, existing);
|
|
213
|
+
},
|
|
214
|
+
reorderColumns(tableId, order) {
|
|
215
|
+
const columnOrder = {
|
|
216
|
+
id: generateId(),
|
|
217
|
+
overrideId: currentOverrideId,
|
|
218
|
+
tableId,
|
|
219
|
+
order
|
|
220
|
+
};
|
|
221
|
+
state.columnOrders.set(tableId, columnOrder);
|
|
222
|
+
},
|
|
223
|
+
filterRows(tableId, filter) {
|
|
224
|
+
const rowFilter = {
|
|
225
|
+
id: generateId(),
|
|
226
|
+
overrideId: currentOverrideId,
|
|
227
|
+
tableId,
|
|
228
|
+
filter
|
|
229
|
+
};
|
|
230
|
+
const existing = state.rowFilters.get(tableId) ?? [];
|
|
231
|
+
existing.push(rowFilter);
|
|
232
|
+
state.rowFilters.set(tableId, existing);
|
|
233
|
+
},
|
|
234
|
+
addMenuItem(menuId, config) {
|
|
235
|
+
const item = {
|
|
236
|
+
id: generateId(),
|
|
237
|
+
overrideId: currentOverrideId,
|
|
238
|
+
menuId,
|
|
239
|
+
...config
|
|
240
|
+
};
|
|
241
|
+
const existing = state.menuItems.get(menuId) ?? [];
|
|
242
|
+
existing.push(item);
|
|
243
|
+
existing.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
244
|
+
state.menuItems.set(menuId, existing);
|
|
245
|
+
},
|
|
246
|
+
addTab(tabGroupId, config) {
|
|
247
|
+
const tab = {
|
|
248
|
+
id: generateId(),
|
|
249
|
+
overrideId: currentOverrideId,
|
|
250
|
+
tabGroupId,
|
|
251
|
+
...config
|
|
252
|
+
};
|
|
253
|
+
const existing = state.tabs.get(tabGroupId) ?? [];
|
|
254
|
+
existing.push(tab);
|
|
255
|
+
existing.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
256
|
+
state.tabs.set(tabGroupId, existing);
|
|
257
|
+
},
|
|
258
|
+
modifyProps(componentId, modifier) {
|
|
259
|
+
const propsModifier = {
|
|
260
|
+
id: generateId(),
|
|
261
|
+
overrideId: currentOverrideId,
|
|
262
|
+
componentId,
|
|
263
|
+
modifier
|
|
264
|
+
};
|
|
265
|
+
const existing = state.propsModifiers.get(componentId) ?? [];
|
|
266
|
+
existing.push(propsModifier);
|
|
267
|
+
state.propsModifiers.set(componentId, existing);
|
|
268
|
+
},
|
|
269
|
+
addAction(actionBarId, config) {
|
|
270
|
+
const action = {
|
|
271
|
+
id: generateId(),
|
|
272
|
+
overrideId: currentOverrideId,
|
|
273
|
+
actionBarId,
|
|
274
|
+
...config
|
|
275
|
+
};
|
|
276
|
+
const existing = state.actions.get(actionBarId) ?? [];
|
|
277
|
+
existing.push(action);
|
|
278
|
+
existing.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
279
|
+
state.actions.set(actionBarId, existing);
|
|
280
|
+
},
|
|
281
|
+
addValidation(formId, fieldName, validate) {
|
|
282
|
+
const rule = {
|
|
283
|
+
id: generateId(),
|
|
284
|
+
overrideId: currentOverrideId,
|
|
285
|
+
formId,
|
|
286
|
+
fieldName,
|
|
287
|
+
validate
|
|
288
|
+
};
|
|
289
|
+
const existing = state.validations.get(formId) ?? [];
|
|
290
|
+
existing.push(rule);
|
|
291
|
+
state.validations.set(formId, existing);
|
|
292
|
+
},
|
|
293
|
+
setText(selector, text) {
|
|
294
|
+
if (typeof text !== "string") {
|
|
295
|
+
console.warn(`[Sidekick] setText expects a string value, got ${typeof text}. Ignoring.`);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const mod = {
|
|
299
|
+
id: generateId(),
|
|
300
|
+
overrideId: currentOverrideId,
|
|
301
|
+
selector,
|
|
302
|
+
type: "setText",
|
|
303
|
+
value: text
|
|
304
|
+
};
|
|
305
|
+
state.domModifications.push(mod);
|
|
306
|
+
},
|
|
307
|
+
setAttribute(selector, attr, value) {
|
|
308
|
+
const mod = {
|
|
309
|
+
id: generateId(),
|
|
310
|
+
overrideId: currentOverrideId,
|
|
311
|
+
selector,
|
|
312
|
+
type: "setAttribute",
|
|
313
|
+
value: { attr, value }
|
|
314
|
+
};
|
|
315
|
+
state.domModifications.push(mod);
|
|
316
|
+
},
|
|
317
|
+
setStyle(selector, styles2) {
|
|
318
|
+
const mod = {
|
|
319
|
+
id: generateId(),
|
|
320
|
+
overrideId: currentOverrideId,
|
|
321
|
+
selector,
|
|
322
|
+
type: "setStyle",
|
|
323
|
+
value: styles2
|
|
324
|
+
};
|
|
325
|
+
state.domModifications.push(mod);
|
|
326
|
+
},
|
|
327
|
+
addClass(selector, className) {
|
|
328
|
+
const mod = {
|
|
329
|
+
id: generateId(),
|
|
330
|
+
overrideId: currentOverrideId,
|
|
331
|
+
selector,
|
|
332
|
+
type: "addClass",
|
|
333
|
+
value: className
|
|
334
|
+
};
|
|
335
|
+
state.domModifications.push(mod);
|
|
336
|
+
},
|
|
337
|
+
removeClass(selector, className) {
|
|
338
|
+
const mod = {
|
|
339
|
+
id: generateId(),
|
|
340
|
+
overrideId: currentOverrideId,
|
|
341
|
+
selector,
|
|
342
|
+
type: "removeClass",
|
|
343
|
+
value: className
|
|
344
|
+
};
|
|
345
|
+
state.domModifications.push(mod);
|
|
346
|
+
},
|
|
347
|
+
inject(selector, component, position = "after") {
|
|
348
|
+
const injection = {
|
|
349
|
+
id: generateId(),
|
|
350
|
+
overrideId: currentOverrideId,
|
|
351
|
+
selector,
|
|
352
|
+
position,
|
|
353
|
+
component
|
|
354
|
+
};
|
|
355
|
+
state.injections.push(injection);
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// src/primitives/data.ts
|
|
361
|
+
function generateId2() {
|
|
362
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
363
|
+
const r = Math.random() * 16 | 0;
|
|
364
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
365
|
+
return v.toString(16);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
function createDataPrimitives(state, currentOverrideId) {
|
|
369
|
+
return {
|
|
370
|
+
computed(fieldName, compute) {
|
|
371
|
+
const field = {
|
|
372
|
+
id: generateId2(),
|
|
373
|
+
overrideId: currentOverrideId,
|
|
374
|
+
fieldName,
|
|
375
|
+
compute
|
|
376
|
+
};
|
|
377
|
+
state.computedFields.set(fieldName, field);
|
|
378
|
+
},
|
|
379
|
+
addFilter(name, filter) {
|
|
380
|
+
const dataFilter = {
|
|
381
|
+
id: generateId2(),
|
|
382
|
+
overrideId: currentOverrideId,
|
|
383
|
+
name,
|
|
384
|
+
filter
|
|
385
|
+
};
|
|
386
|
+
state.filters.set(name, dataFilter);
|
|
387
|
+
},
|
|
388
|
+
transform(dataKey, transformFn) {
|
|
389
|
+
const transform2 = {
|
|
390
|
+
id: generateId2(),
|
|
391
|
+
overrideId: currentOverrideId,
|
|
392
|
+
dataKey,
|
|
393
|
+
transform: transformFn
|
|
394
|
+
};
|
|
395
|
+
state.transforms.set(dataKey, transform2);
|
|
396
|
+
},
|
|
397
|
+
intercept(pathPattern, handler) {
|
|
398
|
+
const interceptor = {
|
|
399
|
+
id: generateId2(),
|
|
400
|
+
overrideId: currentOverrideId,
|
|
401
|
+
pathPattern,
|
|
402
|
+
handler
|
|
403
|
+
};
|
|
404
|
+
state.interceptors.push(interceptor);
|
|
405
|
+
},
|
|
406
|
+
addSortOption(tableId, config) {
|
|
407
|
+
const sortOption = {
|
|
408
|
+
id: generateId2(),
|
|
409
|
+
overrideId: currentOverrideId,
|
|
410
|
+
tableId,
|
|
411
|
+
...config
|
|
412
|
+
};
|
|
413
|
+
const existing = state.sortOptions.get(tableId) ?? [];
|
|
414
|
+
existing.push(sortOption);
|
|
415
|
+
state.sortOptions.set(tableId, existing);
|
|
416
|
+
},
|
|
417
|
+
addGroupBy(tableId, config) {
|
|
418
|
+
const groupByOption = {
|
|
419
|
+
id: generateId2(),
|
|
420
|
+
overrideId: currentOverrideId,
|
|
421
|
+
tableId,
|
|
422
|
+
...config
|
|
423
|
+
};
|
|
424
|
+
const existing = state.groupByOptions.get(tableId) ?? [];
|
|
425
|
+
existing.push(groupByOption);
|
|
426
|
+
state.groupByOptions.set(tableId, existing);
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// src/primitives/behavior.ts
|
|
432
|
+
function generateId3() {
|
|
433
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
434
|
+
const r = Math.random() * 16 | 0;
|
|
435
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
436
|
+
return v.toString(16);
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
function createBehaviorPrimitives(state, currentOverrideId) {
|
|
440
|
+
return {
|
|
441
|
+
onEvent(eventName, handler, options = {}) {
|
|
442
|
+
const eventHandler = {
|
|
443
|
+
id: generateId3(),
|
|
444
|
+
overrideId: currentOverrideId,
|
|
445
|
+
eventName,
|
|
446
|
+
handler,
|
|
447
|
+
priority: options.priority ?? 0
|
|
448
|
+
};
|
|
449
|
+
const existing = state.eventHandlers.get(eventName) ?? [];
|
|
450
|
+
existing.push(eventHandler);
|
|
451
|
+
existing.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
452
|
+
state.eventHandlers.set(eventName, existing);
|
|
453
|
+
},
|
|
454
|
+
addKeyboardShortcut(keys, action, description) {
|
|
455
|
+
const shortcut = {
|
|
456
|
+
id: generateId3(),
|
|
457
|
+
overrideId: currentOverrideId,
|
|
458
|
+
keys,
|
|
459
|
+
action,
|
|
460
|
+
description
|
|
461
|
+
};
|
|
462
|
+
state.keyboardShortcuts.push(shortcut);
|
|
463
|
+
},
|
|
464
|
+
modifyRoute(pathPattern, handler) {
|
|
465
|
+
const modifier = {
|
|
466
|
+
id: generateId3(),
|
|
467
|
+
overrideId: currentOverrideId,
|
|
468
|
+
pathPattern,
|
|
469
|
+
handler
|
|
470
|
+
};
|
|
471
|
+
state.routeModifiers.push(modifier);
|
|
472
|
+
},
|
|
473
|
+
onDOMEvent(selector, eventType, handler) {
|
|
474
|
+
const listener = {
|
|
475
|
+
id: generateId3(),
|
|
476
|
+
overrideId: currentOverrideId,
|
|
477
|
+
selector,
|
|
478
|
+
eventType,
|
|
479
|
+
handler
|
|
480
|
+
};
|
|
481
|
+
state.domEventListeners.push(listener);
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// src/runtime-loader.ts
|
|
487
|
+
import React from "react";
|
|
488
|
+
import { transform } from "sucrase";
|
|
489
|
+
function compileOverride(overrideData) {
|
|
490
|
+
try {
|
|
491
|
+
const transformed = transform(overrideData.code, {
|
|
492
|
+
transforms: ["typescript", "jsx"],
|
|
493
|
+
jsxRuntime: "classic"
|
|
494
|
+
});
|
|
495
|
+
const exports = {};
|
|
496
|
+
const require2 = (moduleName) => {
|
|
497
|
+
if (moduleName === "react") return React;
|
|
498
|
+
if (moduleName === "@usesidekick/react") {
|
|
499
|
+
return { createOverride, SDK: {} };
|
|
500
|
+
}
|
|
501
|
+
throw new Error(`Module not found: ${moduleName}`);
|
|
502
|
+
};
|
|
503
|
+
const reactDestructure = "var { useState, useEffect, useCallback, useMemo, useRef, useContext, useReducer, memo, forwardRef, createContext, Fragment } = React;\n";
|
|
504
|
+
const moduleFunction = new Function(
|
|
505
|
+
"exports",
|
|
506
|
+
"require",
|
|
507
|
+
"React",
|
|
508
|
+
"createOverride",
|
|
509
|
+
reactDestructure + transformed.code.replace(
|
|
510
|
+
/import\s+.*?from\s+['"].*?['"]/g,
|
|
511
|
+
""
|
|
512
|
+
// Remove import statements, we inject dependencies
|
|
513
|
+
).replace(
|
|
514
|
+
/export\s+default\s+/,
|
|
515
|
+
"exports.default = "
|
|
516
|
+
)
|
|
517
|
+
);
|
|
518
|
+
moduleFunction(exports, require2, React, createOverride);
|
|
519
|
+
if (!exports.default) {
|
|
520
|
+
console.error(`[Sidekick] Override ${overrideData.id} has no default export`);
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
return {
|
|
524
|
+
id: overrideData.id,
|
|
525
|
+
name: overrideData.name,
|
|
526
|
+
description: overrideData.description,
|
|
527
|
+
enabled: overrideData.enabled,
|
|
528
|
+
activate: exports.default.activate
|
|
529
|
+
};
|
|
530
|
+
} catch (error) {
|
|
531
|
+
console.error(`[Sidekick] Failed to compile override ${overrideData.id}:`, error);
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
async function fetchAndCompileOverrides(endpoint) {
|
|
536
|
+
try {
|
|
537
|
+
const response = await fetch(endpoint);
|
|
538
|
+
if (!response.ok) {
|
|
539
|
+
throw new Error(`Failed to fetch overrides: ${response.status}`);
|
|
540
|
+
}
|
|
541
|
+
const data = await response.json();
|
|
542
|
+
if (!data.success || !Array.isArray(data.overrides)) {
|
|
543
|
+
throw new Error("Invalid response format");
|
|
544
|
+
}
|
|
545
|
+
const compiled = [];
|
|
546
|
+
for (const override of data.overrides) {
|
|
547
|
+
const loaded = compileOverride(override);
|
|
548
|
+
if (loaded) {
|
|
549
|
+
compiled.push(loaded);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return compiled;
|
|
553
|
+
} catch (error) {
|
|
554
|
+
console.error("[Sidekick] Failed to fetch overrides:", error);
|
|
555
|
+
return [];
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// src/jsx-runtime.ts
|
|
560
|
+
import React2 from "react";
|
|
561
|
+
var GLOBAL_KEY = "__SIDEKICK_JSX_CONFIG__";
|
|
562
|
+
function getGlobalConfig() {
|
|
563
|
+
const g = globalThis;
|
|
564
|
+
if (!g[GLOBAL_KEY]) {
|
|
565
|
+
g[GLOBAL_KEY] = {
|
|
566
|
+
getWrapper: null,
|
|
567
|
+
getReplacement: null,
|
|
568
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
569
|
+
seenComponents: /* @__PURE__ */ new Set()
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
return g[GLOBAL_KEY];
|
|
573
|
+
}
|
|
574
|
+
var getDebug = () => typeof window !== "undefined" && window.__SIDEKICK_DEBUG__;
|
|
575
|
+
var Fragment = React2.Fragment;
|
|
576
|
+
function configureJsxRuntime(wrapperGetter, replacementGetter) {
|
|
577
|
+
const config = getGlobalConfig();
|
|
578
|
+
config.getWrapper = wrapperGetter;
|
|
579
|
+
config.getReplacement = replacementGetter;
|
|
580
|
+
if (getDebug()) console.log("[Sidekick] JSX runtime configured (global)");
|
|
581
|
+
config.listeners.forEach((listener) => {
|
|
582
|
+
try {
|
|
583
|
+
listener();
|
|
584
|
+
} catch (e) {
|
|
585
|
+
console.error("[Sidekick] Config change listener error:", e);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
function onConfigChange(listener) {
|
|
590
|
+
const config = getGlobalConfig();
|
|
591
|
+
config.listeners.add(listener);
|
|
592
|
+
return () => config.listeners.delete(listener);
|
|
593
|
+
}
|
|
594
|
+
function isJsxRuntimeConfigured() {
|
|
595
|
+
const config = getGlobalConfig();
|
|
596
|
+
return config.getWrapper !== null || config.getReplacement !== null;
|
|
597
|
+
}
|
|
598
|
+
function getSeenComponentsFromJsx() {
|
|
599
|
+
const config = getGlobalConfig();
|
|
600
|
+
return Array.from(config.seenComponents);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// src/jsx-dev-runtime.ts
|
|
604
|
+
import React3 from "react";
|
|
605
|
+
var GLOBAL_KEY2 = "__SIDEKICK_JSX_CONFIG__";
|
|
606
|
+
function getGlobalConfig2() {
|
|
607
|
+
const g = globalThis;
|
|
608
|
+
if (!g[GLOBAL_KEY2]) {
|
|
609
|
+
g[GLOBAL_KEY2] = {
|
|
610
|
+
getWrapper: null,
|
|
611
|
+
getReplacement: null,
|
|
612
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
613
|
+
seenComponents: /* @__PURE__ */ new Set()
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
return g[GLOBAL_KEY2];
|
|
617
|
+
}
|
|
618
|
+
var getDebug2 = () => typeof window !== "undefined" && window.__SIDEKICK_DEBUG__;
|
|
619
|
+
var Fragment2 = React3.Fragment;
|
|
620
|
+
function configureJsxDevRuntime(wrapperGetter, replacementGetter) {
|
|
621
|
+
const config = getGlobalConfig2();
|
|
622
|
+
config.getWrapper = wrapperGetter;
|
|
623
|
+
config.getReplacement = replacementGetter;
|
|
624
|
+
configureJsxRuntime(wrapperGetter, replacementGetter);
|
|
625
|
+
if (getDebug2()) console.log("[Sidekick] JSX dev runtime configured (global)");
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// src/provider.tsx
|
|
629
|
+
import { jsxs } from "react/jsx-runtime";
|
|
630
|
+
function tableIdToComponentName(tableId) {
|
|
631
|
+
return tableId.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
632
|
+
}
|
|
633
|
+
function createAutoColumnWrapper(columns, renames, columnOrder, hiddenColumns, rowFilters) {
|
|
634
|
+
return (Original) => {
|
|
635
|
+
function AutoColumnInjector(props) {
|
|
636
|
+
const containerRef = useRef(null);
|
|
637
|
+
const [cellTargets, setCellTargets] = useState([]);
|
|
638
|
+
const allTasks = props.tasks || [];
|
|
639
|
+
const tasks = useMemo(() => {
|
|
640
|
+
if (!rowFilters || rowFilters.length === 0) return allTasks;
|
|
641
|
+
return allTasks.filter(
|
|
642
|
+
(row) => rowFilters.every((rf) => rf.filter(row))
|
|
643
|
+
);
|
|
644
|
+
}, [allTasks]);
|
|
645
|
+
useEffect(() => {
|
|
646
|
+
const container = containerRef.current;
|
|
647
|
+
if (!container) return;
|
|
648
|
+
const table = container.querySelector("table");
|
|
649
|
+
if (!table) return;
|
|
650
|
+
table.querySelectorAll("[data-sidekick-injected]").forEach((el) => el.remove());
|
|
651
|
+
table.querySelectorAll("[data-sidekick-hidden]").forEach((el) => {
|
|
652
|
+
el.style.display = "";
|
|
653
|
+
el.removeAttribute("data-sidekick-hidden");
|
|
654
|
+
});
|
|
655
|
+
if (renames.length > 0) {
|
|
656
|
+
const headers = table.querySelectorAll("thead th");
|
|
657
|
+
headers.forEach((th) => {
|
|
658
|
+
const text = th.textContent?.trim();
|
|
659
|
+
if (text) {
|
|
660
|
+
const rename = renames.find((r) => r.originalHeader === text);
|
|
661
|
+
if (rename) {
|
|
662
|
+
th.textContent = rename.newHeader;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
if (columnOrder) {
|
|
668
|
+
const headerRow2 = table.querySelector("thead tr");
|
|
669
|
+
if (headerRow2) {
|
|
670
|
+
const ths = Array.from(headerRow2.querySelectorAll("th"));
|
|
671
|
+
const headerToIndex = /* @__PURE__ */ new Map();
|
|
672
|
+
ths.forEach((th, i) => {
|
|
673
|
+
const text = th.textContent?.trim() ?? "";
|
|
674
|
+
headerToIndex.set(text, i);
|
|
675
|
+
});
|
|
676
|
+
const orderedIndices = [];
|
|
677
|
+
const usedIndices = /* @__PURE__ */ new Set();
|
|
678
|
+
for (const headerName of columnOrder.order) {
|
|
679
|
+
const idx = headerToIndex.get(headerName);
|
|
680
|
+
if (idx !== void 0) {
|
|
681
|
+
orderedIndices.push(idx);
|
|
682
|
+
usedIndices.add(idx);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
for (let i = 0; i < ths.length; i++) {
|
|
686
|
+
if (!usedIndices.has(i)) {
|
|
687
|
+
orderedIndices.push(i);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
const sortedThs = orderedIndices.map((i) => ths[i]);
|
|
691
|
+
for (const th of sortedThs) {
|
|
692
|
+
headerRow2.appendChild(th);
|
|
693
|
+
}
|
|
694
|
+
const bodyRows2 = table.querySelectorAll("tbody tr");
|
|
695
|
+
bodyRows2.forEach((row) => {
|
|
696
|
+
const tds = Array.from(row.querySelectorAll("td"));
|
|
697
|
+
const sortedTds = orderedIndices.map((i) => tds[i]).filter(Boolean);
|
|
698
|
+
for (const td of sortedTds) {
|
|
699
|
+
row.appendChild(td);
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
if (hiddenColumns && hiddenColumns.length > 0) {
|
|
705
|
+
const headers = table.querySelectorAll("thead th");
|
|
706
|
+
const hiddenHeaders = new Set(hiddenColumns.map((h) => h.header));
|
|
707
|
+
const hiddenIndices = /* @__PURE__ */ new Set();
|
|
708
|
+
headers.forEach((th, i) => {
|
|
709
|
+
const text = th.textContent?.trim() ?? "";
|
|
710
|
+
if (hiddenHeaders.has(text)) {
|
|
711
|
+
th.style.display = "none";
|
|
712
|
+
th.setAttribute("data-sidekick-hidden", "true");
|
|
713
|
+
hiddenIndices.add(i);
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
if (hiddenIndices.size > 0) {
|
|
717
|
+
const bodyRows2 = table.querySelectorAll("tbody tr");
|
|
718
|
+
bodyRows2.forEach((row) => {
|
|
719
|
+
const tds = row.querySelectorAll("td");
|
|
720
|
+
tds.forEach((td, i) => {
|
|
721
|
+
if (hiddenIndices.has(i)) {
|
|
722
|
+
td.style.display = "none";
|
|
723
|
+
td.setAttribute("data-sidekick-hidden", "true");
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
const headerRow = table.querySelector("thead tr");
|
|
730
|
+
if (headerRow) {
|
|
731
|
+
for (const col of columns) {
|
|
732
|
+
const th = document.createElement("th");
|
|
733
|
+
th.className = "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider";
|
|
734
|
+
th.textContent = col.header;
|
|
735
|
+
th.setAttribute("data-sidekick-injected", "true");
|
|
736
|
+
headerRow.appendChild(th);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
const bodyRows = table.querySelectorAll("tbody tr");
|
|
740
|
+
const targets = [];
|
|
741
|
+
bodyRows.forEach((row, rowIndex) => {
|
|
742
|
+
for (let colIndex = 0; colIndex < columns.length; colIndex++) {
|
|
743
|
+
const td = document.createElement("td");
|
|
744
|
+
td.className = "px-6 py-4 whitespace-nowrap text-sm text-gray-500";
|
|
745
|
+
td.setAttribute("data-sidekick-injected", "true");
|
|
746
|
+
row.appendChild(td);
|
|
747
|
+
targets.push({ element: td, taskIndex: rowIndex, colIndex });
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
setCellTargets(targets);
|
|
751
|
+
return () => {
|
|
752
|
+
table.querySelectorAll("[data-sidekick-injected]").forEach((el) => el.remove());
|
|
753
|
+
table.querySelectorAll("[data-sidekick-hidden]").forEach((el) => {
|
|
754
|
+
el.style.display = "";
|
|
755
|
+
el.removeAttribute("data-sidekick-hidden");
|
|
756
|
+
});
|
|
757
|
+
setCellTargets([]);
|
|
758
|
+
};
|
|
759
|
+
}, [tasks]);
|
|
760
|
+
const filteredProps = rowFilters && rowFilters.length > 0 ? { ...props, tasks } : props;
|
|
761
|
+
return React4.createElement(
|
|
762
|
+
React4.Fragment,
|
|
763
|
+
null,
|
|
764
|
+
React4.createElement(
|
|
765
|
+
"div",
|
|
766
|
+
{ ref: containerRef },
|
|
767
|
+
React4.createElement(Original, filteredProps)
|
|
768
|
+
),
|
|
769
|
+
...cellTargets.map((target, idx) => {
|
|
770
|
+
const task = tasks[target.taskIndex];
|
|
771
|
+
const col = columns[target.colIndex];
|
|
772
|
+
if (!task || !col) return null;
|
|
773
|
+
const accessor = col.accessor;
|
|
774
|
+
const value = typeof accessor === "function" ? accessor(task) : task[accessor];
|
|
775
|
+
const content = col.render ? col.render(value, task) : React4.createElement("span", null, String(value ?? "-"));
|
|
776
|
+
return createPortal(content, target.element, `sidekick-col-${idx}`);
|
|
777
|
+
})
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
AutoColumnInjector.displayName = `AutoColumnInjector(${Original.displayName || Original.name || "Component"})`;
|
|
781
|
+
return AutoColumnInjector;
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
function getComponentName(type) {
|
|
785
|
+
if (!type) return null;
|
|
786
|
+
if (typeof type === "function") {
|
|
787
|
+
const fn = type;
|
|
788
|
+
return fn.displayName || fn.name || null;
|
|
789
|
+
}
|
|
790
|
+
if (typeof type === "object" && type !== null) {
|
|
791
|
+
const obj = type;
|
|
792
|
+
if (obj.displayName) return obj.displayName;
|
|
793
|
+
if (obj.$$typeof?.toString() === "Symbol(react.lazy)") {
|
|
794
|
+
const payload = obj._payload;
|
|
795
|
+
if (payload && payload.status === "fulfilled" && payload.value) {
|
|
796
|
+
return getComponentName(payload.value);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
if (obj.$$typeof) {
|
|
800
|
+
if (obj.type) return getComponentName(obj.type);
|
|
801
|
+
if (obj.render) return getComponentName(obj.render);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
return null;
|
|
805
|
+
}
|
|
806
|
+
function transformElementTree(node, wrappers, replacements, wrapCache) {
|
|
807
|
+
if (node == null || typeof node === "boolean" || typeof node === "string" || typeof node === "number") {
|
|
808
|
+
return node;
|
|
809
|
+
}
|
|
810
|
+
if (Array.isArray(node)) {
|
|
811
|
+
let changed = false;
|
|
812
|
+
const result = node.map((child) => {
|
|
813
|
+
const transformed = transformElementTree(child, wrappers, replacements, wrapCache);
|
|
814
|
+
if (transformed !== child) changed = true;
|
|
815
|
+
return transformed;
|
|
816
|
+
});
|
|
817
|
+
return changed ? result : node;
|
|
818
|
+
}
|
|
819
|
+
if (!React4.isValidElement(node)) return node;
|
|
820
|
+
const element = node;
|
|
821
|
+
const originalType = element.type;
|
|
822
|
+
let newType = originalType;
|
|
823
|
+
let typeChanged = false;
|
|
824
|
+
if (typeof originalType === "function" || typeof originalType === "object" && originalType !== null) {
|
|
825
|
+
const name = getComponentName(originalType);
|
|
826
|
+
if (name) {
|
|
827
|
+
let resolvedType = originalType;
|
|
828
|
+
const maybeObj = originalType;
|
|
829
|
+
if (maybeObj.$$typeof?.toString() === "Symbol(react.lazy)" && maybeObj._payload?.status === "fulfilled" && maybeObj._payload?.value) {
|
|
830
|
+
resolvedType = maybeObj._payload.value;
|
|
831
|
+
}
|
|
832
|
+
const replacement = replacements.get(name);
|
|
833
|
+
if (replacement) {
|
|
834
|
+
newType = replacement;
|
|
835
|
+
typeChanged = true;
|
|
836
|
+
} else {
|
|
837
|
+
const componentWrappers = wrappers.get(name);
|
|
838
|
+
if (componentWrappers && componentWrappers.length > 0) {
|
|
839
|
+
if (!wrapCache.has(resolvedType)) {
|
|
840
|
+
const wrapped = componentWrappers.reduce(
|
|
841
|
+
(comp, { wrapper, where: wherePredicate }) => {
|
|
842
|
+
if (wherePredicate) {
|
|
843
|
+
const Wrapped = wrapper(comp);
|
|
844
|
+
const ConditionalWrapper = (props) => {
|
|
845
|
+
if (wherePredicate(props)) {
|
|
846
|
+
return React4.createElement(Wrapped, props);
|
|
847
|
+
}
|
|
848
|
+
return React4.createElement(comp, props);
|
|
849
|
+
};
|
|
850
|
+
ConditionalWrapper.displayName = `ConditionalWrap(${comp.displayName || comp.name || "Component"})`;
|
|
851
|
+
return ConditionalWrapper;
|
|
852
|
+
}
|
|
853
|
+
return wrapper(comp);
|
|
854
|
+
},
|
|
855
|
+
resolvedType
|
|
856
|
+
);
|
|
857
|
+
wrapCache.set(resolvedType, wrapped);
|
|
858
|
+
}
|
|
859
|
+
newType = wrapCache.get(resolvedType);
|
|
860
|
+
typeChanged = true;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
const childrenProp = element.props.children;
|
|
866
|
+
const transformedChildren = childrenProp != null ? transformElementTree(childrenProp, wrappers, replacements, wrapCache) : childrenProp;
|
|
867
|
+
const childrenChanged = transformedChildren !== childrenProp;
|
|
868
|
+
if (!typeChanged && !childrenChanged) return node;
|
|
869
|
+
const { children: _children, ...restProps } = element.props;
|
|
870
|
+
return React4.createElement(
|
|
871
|
+
newType,
|
|
872
|
+
{ ...restProps, key: element.key },
|
|
873
|
+
transformedChildren
|
|
874
|
+
);
|
|
875
|
+
}
|
|
876
|
+
function createInitialState() {
|
|
877
|
+
return {
|
|
878
|
+
overrides: [],
|
|
879
|
+
// UI state
|
|
880
|
+
wrappers: /* @__PURE__ */ new Map(),
|
|
881
|
+
replacements: /* @__PURE__ */ new Map(),
|
|
882
|
+
styles: [],
|
|
883
|
+
columns: /* @__PURE__ */ new Map(),
|
|
884
|
+
columnRenames: /* @__PURE__ */ new Map(),
|
|
885
|
+
hiddenColumns: /* @__PURE__ */ new Map(),
|
|
886
|
+
columnOrders: /* @__PURE__ */ new Map(),
|
|
887
|
+
rowFilters: /* @__PURE__ */ new Map(),
|
|
888
|
+
menuItems: /* @__PURE__ */ new Map(),
|
|
889
|
+
tabs: /* @__PURE__ */ new Map(),
|
|
890
|
+
propsModifiers: /* @__PURE__ */ new Map(),
|
|
891
|
+
actions: /* @__PURE__ */ new Map(),
|
|
892
|
+
validations: /* @__PURE__ */ new Map(),
|
|
893
|
+
// Data state
|
|
894
|
+
computedFields: /* @__PURE__ */ new Map(),
|
|
895
|
+
filters: /* @__PURE__ */ new Map(),
|
|
896
|
+
transforms: /* @__PURE__ */ new Map(),
|
|
897
|
+
interceptors: [],
|
|
898
|
+
sortOptions: /* @__PURE__ */ new Map(),
|
|
899
|
+
groupByOptions: /* @__PURE__ */ new Map(),
|
|
900
|
+
// Behavior state
|
|
901
|
+
eventHandlers: /* @__PURE__ */ new Map(),
|
|
902
|
+
keyboardShortcuts: [],
|
|
903
|
+
routeModifiers: [],
|
|
904
|
+
// DOM state
|
|
905
|
+
domModifications: [],
|
|
906
|
+
injections: [],
|
|
907
|
+
domEventListeners: []
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
function SidekickProvider({ children, overridesEndpoint }) {
|
|
911
|
+
const [state, setState] = useState(createInitialState);
|
|
912
|
+
const [overrides, setOverrides] = useState([]);
|
|
913
|
+
const [isReady, setIsReady] = useState(false);
|
|
914
|
+
const stateRef = useRef(state);
|
|
915
|
+
stateRef.current = state;
|
|
916
|
+
useEffect(() => {
|
|
917
|
+
const initializeOverrides = async () => {
|
|
918
|
+
const newState = createInitialState();
|
|
919
|
+
const loadedOverrides = [];
|
|
920
|
+
if (overridesEndpoint) {
|
|
921
|
+
console.log("[Sidekick] Fetching overrides from:", overridesEndpoint);
|
|
922
|
+
const apiOverrides = await fetchAndCompileOverrides(overridesEndpoint);
|
|
923
|
+
console.log("[Sidekick] Fetched overrides:", apiOverrides.length);
|
|
924
|
+
for (const override of apiOverrides) {
|
|
925
|
+
loadedOverrides.push({
|
|
926
|
+
id: override.id,
|
|
927
|
+
name: override.name,
|
|
928
|
+
description: override.description,
|
|
929
|
+
version: "1.0.0",
|
|
930
|
+
enabled: override.enabled
|
|
931
|
+
});
|
|
932
|
+
if (override.enabled) {
|
|
933
|
+
console.log(`[Sidekick] Activating override: ${override.id}`);
|
|
934
|
+
const sdk = {
|
|
935
|
+
ui: createUIPrimitives(newState, override.id),
|
|
936
|
+
data: createDataPrimitives(newState, override.id),
|
|
937
|
+
behavior: createBehaviorPrimitives(newState, override.id)
|
|
938
|
+
};
|
|
939
|
+
try {
|
|
940
|
+
override.activate(sdk);
|
|
941
|
+
console.log(`[Sidekick] Activated override: ${override.id}`);
|
|
942
|
+
} catch (error) {
|
|
943
|
+
console.error(`[Sidekick] Failed to activate override ${override.id}:`, error);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
} else {
|
|
948
|
+
const registeredOverrides = getRegisteredOverrides();
|
|
949
|
+
const flags = loadFlags();
|
|
950
|
+
for (const module of registeredOverrides) {
|
|
951
|
+
loadedOverrides.push({
|
|
952
|
+
id: module.manifest.id,
|
|
953
|
+
name: module.manifest.name,
|
|
954
|
+
description: module.manifest.description,
|
|
955
|
+
version: module.manifest.version,
|
|
956
|
+
enabled: flags[module.manifest.id] ?? false
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
for (const module of registeredOverrides) {
|
|
960
|
+
const isEnabled = flags[module.manifest.id] ?? false;
|
|
961
|
+
if (isEnabled) {
|
|
962
|
+
console.log(`[Sidekick] Activating override: ${module.manifest.id}`);
|
|
963
|
+
const sdk = {
|
|
964
|
+
ui: createUIPrimitives(newState, module.manifest.id),
|
|
965
|
+
data: createDataPrimitives(newState, module.manifest.id),
|
|
966
|
+
behavior: createBehaviorPrimitives(newState, module.manifest.id)
|
|
967
|
+
};
|
|
968
|
+
await module.activate(sdk);
|
|
969
|
+
console.log(`[Sidekick] After activation, wrappers:`, Array.from(newState.wrappers.keys()));
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
newState.overrides = loadedOverrides;
|
|
974
|
+
const tableIdsWithMods = /* @__PURE__ */ new Set();
|
|
975
|
+
for (const tableId of newState.columns.keys()) tableIdsWithMods.add(tableId);
|
|
976
|
+
for (const tableId of newState.columnRenames.keys()) tableIdsWithMods.add(tableId);
|
|
977
|
+
for (const tableId of newState.columnOrders.keys()) tableIdsWithMods.add(tableId);
|
|
978
|
+
for (const tableId of newState.hiddenColumns.keys()) tableIdsWithMods.add(tableId);
|
|
979
|
+
for (const tableId of newState.rowFilters.keys()) tableIdsWithMods.add(tableId);
|
|
980
|
+
for (const tableId of tableIdsWithMods) {
|
|
981
|
+
const cols = newState.columns.get(tableId) ?? [];
|
|
982
|
+
const tableRenames = newState.columnRenames.get(tableId) ?? [];
|
|
983
|
+
const tableOrder = newState.columnOrders.get(tableId);
|
|
984
|
+
const tableHidden = newState.hiddenColumns.get(tableId) ?? [];
|
|
985
|
+
const tableRowFilters = newState.rowFilters.get(tableId) ?? [];
|
|
986
|
+
if (cols.length === 0 && tableRenames.length === 0 && !tableOrder && tableHidden.length === 0 && tableRowFilters.length === 0) continue;
|
|
987
|
+
const componentName = tableIdToComponentName(tableId);
|
|
988
|
+
console.log(`[Sidekick] Auto-wrapping ${componentName} with ${cols.length} added columns, ${tableRenames.length} renames, ${tableOrder ? "reorder" : "no reorder"}, ${tableHidden.length} hidden, ${tableRowFilters.length} row filters`);
|
|
989
|
+
const wrapped = {
|
|
990
|
+
id: `auto-columns-${tableId}`,
|
|
991
|
+
overrideId: "__sidekick-internal__",
|
|
992
|
+
wrapper: createAutoColumnWrapper(cols, tableRenames, tableOrder, tableHidden, tableRowFilters),
|
|
993
|
+
priority: -1e3
|
|
994
|
+
// Low priority - runs after user wrappers
|
|
995
|
+
};
|
|
996
|
+
const existing = newState.wrappers.get(componentName) ?? [];
|
|
997
|
+
existing.push(wrapped);
|
|
998
|
+
existing.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
999
|
+
newState.wrappers.set(componentName, existing);
|
|
1000
|
+
}
|
|
1001
|
+
setState(newState);
|
|
1002
|
+
stateRef.current = newState;
|
|
1003
|
+
setOverrides(loadedOverrides);
|
|
1004
|
+
const wrapperGetter = (name) => {
|
|
1005
|
+
const wrappers = stateRef.current.wrappers.get(name);
|
|
1006
|
+
if (!wrappers || wrappers.length === 0) return void 0;
|
|
1007
|
+
return (Component) => {
|
|
1008
|
+
return wrappers.reduce(
|
|
1009
|
+
(wrapped, { wrapper, where: wherePredicate }) => {
|
|
1010
|
+
if (wherePredicate) {
|
|
1011
|
+
const Wrapped = wrapper(wrapped);
|
|
1012
|
+
const ConditionalWrapper = (props) => {
|
|
1013
|
+
if (wherePredicate(props)) {
|
|
1014
|
+
return React4.createElement(Wrapped, props);
|
|
1015
|
+
}
|
|
1016
|
+
return React4.createElement(wrapped, props);
|
|
1017
|
+
};
|
|
1018
|
+
ConditionalWrapper.displayName = `ConditionalWrap(${wrapped.displayName || wrapped.name || "Component"})`;
|
|
1019
|
+
return ConditionalWrapper;
|
|
1020
|
+
}
|
|
1021
|
+
return wrapper(wrapped);
|
|
1022
|
+
},
|
|
1023
|
+
Component
|
|
1024
|
+
);
|
|
1025
|
+
};
|
|
1026
|
+
};
|
|
1027
|
+
const replacementGetter = (name) => {
|
|
1028
|
+
return stateRef.current.replacements.get(name);
|
|
1029
|
+
};
|
|
1030
|
+
console.log("[Sidekick] Configuring JSX runtime with", newState.wrappers.size, "wrappers,", newState.replacements.size, "replacements,", newState.columns.size, "column sets");
|
|
1031
|
+
configureJsxRuntime(wrapperGetter, replacementGetter);
|
|
1032
|
+
configureJsxDevRuntime(wrapperGetter, replacementGetter);
|
|
1033
|
+
console.log("[Sidekick] JSX runtime configured");
|
|
1034
|
+
setIsReady(true);
|
|
1035
|
+
};
|
|
1036
|
+
initializeOverrides();
|
|
1037
|
+
}, [overridesEndpoint]);
|
|
1038
|
+
useEffect(() => {
|
|
1039
|
+
if (!isReady || typeof document === "undefined") return;
|
|
1040
|
+
const styleId = "sidekick-injected-styles";
|
|
1041
|
+
let styleEl = document.getElementById(styleId);
|
|
1042
|
+
if (!styleEl) {
|
|
1043
|
+
styleEl = document.createElement("style");
|
|
1044
|
+
styleEl.id = styleId;
|
|
1045
|
+
document.head.appendChild(styleEl);
|
|
1046
|
+
}
|
|
1047
|
+
styleEl.textContent = state.styles.map((s) => s.css).join("\n");
|
|
1048
|
+
return () => {
|
|
1049
|
+
if (styleEl && styleEl.parentNode) {
|
|
1050
|
+
styleEl.parentNode.removeChild(styleEl);
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
}, [state.styles, isReady]);
|
|
1054
|
+
useEffect(() => {
|
|
1055
|
+
if (!isReady) return;
|
|
1056
|
+
const wrapperGetter = (name) => {
|
|
1057
|
+
const wrappers = state.wrappers.get(name);
|
|
1058
|
+
if (!wrappers || wrappers.length === 0) return void 0;
|
|
1059
|
+
return (Component) => {
|
|
1060
|
+
return wrappers.reduce(
|
|
1061
|
+
(wrapped, { wrapper, where: wherePredicate }) => {
|
|
1062
|
+
if (wherePredicate) {
|
|
1063
|
+
const Wrapped = wrapper(wrapped);
|
|
1064
|
+
const ConditionalWrapper = (props) => {
|
|
1065
|
+
if (wherePredicate(props)) {
|
|
1066
|
+
return React4.createElement(Wrapped, props);
|
|
1067
|
+
}
|
|
1068
|
+
return React4.createElement(wrapped, props);
|
|
1069
|
+
};
|
|
1070
|
+
ConditionalWrapper.displayName = `ConditionalWrap(${wrapped.displayName || wrapped.name || "Component"})`;
|
|
1071
|
+
return ConditionalWrapper;
|
|
1072
|
+
}
|
|
1073
|
+
return wrapper(wrapped);
|
|
1074
|
+
},
|
|
1075
|
+
Component
|
|
1076
|
+
);
|
|
1077
|
+
};
|
|
1078
|
+
};
|
|
1079
|
+
const replacementGetter = (name) => {
|
|
1080
|
+
return state.replacements.get(name);
|
|
1081
|
+
};
|
|
1082
|
+
configureJsxRuntime(wrapperGetter, replacementGetter);
|
|
1083
|
+
configureJsxDevRuntime(wrapperGetter, replacementGetter);
|
|
1084
|
+
}, [state.wrappers, state.replacements, isReady]);
|
|
1085
|
+
useEffect(() => {
|
|
1086
|
+
if (!isReady || typeof document === "undefined" || state.domModifications.length === 0) return;
|
|
1087
|
+
const originals = /* @__PURE__ */ new Map();
|
|
1088
|
+
function applyModifications() {
|
|
1089
|
+
for (const mod of state.domModifications) {
|
|
1090
|
+
let elements;
|
|
1091
|
+
try {
|
|
1092
|
+
elements = document.querySelectorAll(mod.selector);
|
|
1093
|
+
} catch {
|
|
1094
|
+
console.warn(`[Sidekick] Invalid CSS selector: "${mod.selector}"`);
|
|
1095
|
+
continue;
|
|
1096
|
+
}
|
|
1097
|
+
elements.forEach((el) => {
|
|
1098
|
+
const htmlEl = el;
|
|
1099
|
+
if (!originals.has(el)) {
|
|
1100
|
+
switch (mod.type) {
|
|
1101
|
+
case "setText": {
|
|
1102
|
+
const textNodes = [];
|
|
1103
|
+
const tw = document.createTreeWalker(htmlEl, NodeFilter.SHOW_TEXT);
|
|
1104
|
+
let tn;
|
|
1105
|
+
while (tn = tw.nextNode()) {
|
|
1106
|
+
textNodes.push({ node: tn, value: tn.nodeValue || "" });
|
|
1107
|
+
}
|
|
1108
|
+
originals.set(el, { type: "setText", value: textNodes });
|
|
1109
|
+
break;
|
|
1110
|
+
}
|
|
1111
|
+
case "setAttribute": {
|
|
1112
|
+
const { attr } = mod.value;
|
|
1113
|
+
originals.set(el, { type: "setAttribute", value: { attr, value: htmlEl.getAttribute(attr) } });
|
|
1114
|
+
break;
|
|
1115
|
+
}
|
|
1116
|
+
case "setStyle":
|
|
1117
|
+
originals.set(el, { type: "setStyle", value: htmlEl.style.cssText });
|
|
1118
|
+
break;
|
|
1119
|
+
case "addClass":
|
|
1120
|
+
originals.set(el, { type: "addClass", value: mod.value });
|
|
1121
|
+
break;
|
|
1122
|
+
case "removeClass":
|
|
1123
|
+
originals.set(el, { type: "removeClass", value: mod.value });
|
|
1124
|
+
break;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
switch (mod.type) {
|
|
1128
|
+
case "setText": {
|
|
1129
|
+
const walker = document.createTreeWalker(htmlEl, NodeFilter.SHOW_TEXT);
|
|
1130
|
+
const firstTextNode = walker.nextNode();
|
|
1131
|
+
if (firstTextNode) {
|
|
1132
|
+
firstTextNode.nodeValue = mod.value;
|
|
1133
|
+
let extra;
|
|
1134
|
+
while (extra = walker.nextNode()) {
|
|
1135
|
+
extra.nodeValue = "";
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
break;
|
|
1139
|
+
}
|
|
1140
|
+
case "setAttribute": {
|
|
1141
|
+
const { attr, value } = mod.value;
|
|
1142
|
+
htmlEl.setAttribute(attr, value);
|
|
1143
|
+
break;
|
|
1144
|
+
}
|
|
1145
|
+
case "setStyle":
|
|
1146
|
+
Object.assign(htmlEl.style, mod.value);
|
|
1147
|
+
break;
|
|
1148
|
+
case "addClass":
|
|
1149
|
+
htmlEl.classList.add(mod.value);
|
|
1150
|
+
break;
|
|
1151
|
+
case "removeClass":
|
|
1152
|
+
htmlEl.classList.remove(mod.value);
|
|
1153
|
+
break;
|
|
1154
|
+
}
|
|
1155
|
+
htmlEl.setAttribute("data-sidekick-dom-mod", "true");
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
applyModifications();
|
|
1160
|
+
const observer = new MutationObserver(() => {
|
|
1161
|
+
applyModifications();
|
|
1162
|
+
});
|
|
1163
|
+
if (document.body) {
|
|
1164
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
1165
|
+
}
|
|
1166
|
+
return () => {
|
|
1167
|
+
observer.disconnect();
|
|
1168
|
+
originals.forEach((original, el) => {
|
|
1169
|
+
const htmlEl = el;
|
|
1170
|
+
switch (original.type) {
|
|
1171
|
+
case "setText": {
|
|
1172
|
+
const textNodes = original.value;
|
|
1173
|
+
for (const { node, value } of textNodes) {
|
|
1174
|
+
try {
|
|
1175
|
+
node.nodeValue = value;
|
|
1176
|
+
} catch {
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
break;
|
|
1180
|
+
}
|
|
1181
|
+
case "setAttribute": {
|
|
1182
|
+
const { attr, value } = original.value;
|
|
1183
|
+
if (value === null) htmlEl.removeAttribute(attr);
|
|
1184
|
+
else htmlEl.setAttribute(attr, value);
|
|
1185
|
+
break;
|
|
1186
|
+
}
|
|
1187
|
+
case "setStyle":
|
|
1188
|
+
htmlEl.style.cssText = original.value;
|
|
1189
|
+
break;
|
|
1190
|
+
case "addClass":
|
|
1191
|
+
htmlEl.classList.remove(original.value);
|
|
1192
|
+
break;
|
|
1193
|
+
case "removeClass":
|
|
1194
|
+
htmlEl.classList.add(original.value);
|
|
1195
|
+
break;
|
|
1196
|
+
}
|
|
1197
|
+
htmlEl.removeAttribute("data-sidekick-dom-mod");
|
|
1198
|
+
});
|
|
1199
|
+
};
|
|
1200
|
+
}, [state.domModifications, isReady]);
|
|
1201
|
+
useEffect(() => {
|
|
1202
|
+
if (!isReady || typeof document === "undefined" || state.keyboardShortcuts.length === 0) return;
|
|
1203
|
+
function matchesKeys(event, keys) {
|
|
1204
|
+
const parts = keys.toLowerCase().split("+").map((s) => s.trim());
|
|
1205
|
+
const keyName = parts[parts.length - 1];
|
|
1206
|
+
const modifiers = new Set(parts.slice(0, -1));
|
|
1207
|
+
const needsCtrl = modifiers.has("ctrl") || modifiers.has("cmd") || modifiers.has("meta");
|
|
1208
|
+
const needsShift = modifiers.has("shift");
|
|
1209
|
+
const needsAlt = modifiers.has("alt");
|
|
1210
|
+
if (needsCtrl !== (event.ctrlKey || event.metaKey)) return false;
|
|
1211
|
+
if (needsShift !== event.shiftKey) return false;
|
|
1212
|
+
if (needsAlt !== event.altKey) return false;
|
|
1213
|
+
return event.key.toLowerCase() === keyName || event.code.toLowerCase() === keyName;
|
|
1214
|
+
}
|
|
1215
|
+
function handleKeydown(event) {
|
|
1216
|
+
for (const shortcut of state.keyboardShortcuts) {
|
|
1217
|
+
if (matchesKeys(event, shortcut.keys)) {
|
|
1218
|
+
event.preventDefault();
|
|
1219
|
+
try {
|
|
1220
|
+
shortcut.action();
|
|
1221
|
+
} catch (error) {
|
|
1222
|
+
console.error(`[Sidekick] Keyboard shortcut error for "${shortcut.keys}":`, error);
|
|
1223
|
+
}
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
document.addEventListener("keydown", handleKeydown);
|
|
1229
|
+
return () => {
|
|
1230
|
+
document.removeEventListener("keydown", handleKeydown);
|
|
1231
|
+
};
|
|
1232
|
+
}, [state.keyboardShortcuts, isReady]);
|
|
1233
|
+
useEffect(() => {
|
|
1234
|
+
if (!isReady || typeof window === "undefined" || state.interceptors.length === 0) return;
|
|
1235
|
+
const originalFetch = window.fetch;
|
|
1236
|
+
window.fetch = async function sidekickFetch(input, init) {
|
|
1237
|
+
const response = await originalFetch.call(window, input, init);
|
|
1238
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
1239
|
+
const method = init?.method || "GET";
|
|
1240
|
+
for (const interceptor of stateRef.current.interceptors) {
|
|
1241
|
+
const pattern = interceptor.pathPattern;
|
|
1242
|
+
const matches = typeof pattern === "string" ? url.includes(pattern) : pattern.test(url);
|
|
1243
|
+
if (matches) {
|
|
1244
|
+
try {
|
|
1245
|
+
const cloned = response.clone();
|
|
1246
|
+
const json = await cloned.json();
|
|
1247
|
+
const modified = interceptor.handler(json, { path: url, method });
|
|
1248
|
+
return new Response(JSON.stringify(modified), {
|
|
1249
|
+
status: response.status,
|
|
1250
|
+
statusText: response.statusText,
|
|
1251
|
+
headers: response.headers
|
|
1252
|
+
});
|
|
1253
|
+
} catch {
|
|
1254
|
+
return response;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
return response;
|
|
1259
|
+
};
|
|
1260
|
+
return () => {
|
|
1261
|
+
window.fetch = originalFetch;
|
|
1262
|
+
};
|
|
1263
|
+
}, [state.interceptors, isReady]);
|
|
1264
|
+
const [injectionContainers, setInjectionContainers] = useState([]);
|
|
1265
|
+
useEffect(() => {
|
|
1266
|
+
if (!isReady || typeof document === "undefined" || state.injections.length === 0) return;
|
|
1267
|
+
const containers = [];
|
|
1268
|
+
function createContainers() {
|
|
1269
|
+
document.querySelectorAll("[data-sidekick-injection]").forEach((el) => el.remove());
|
|
1270
|
+
containers.length = 0;
|
|
1271
|
+
for (const injection of state.injections) {
|
|
1272
|
+
let target;
|
|
1273
|
+
try {
|
|
1274
|
+
target = document.querySelector(injection.selector);
|
|
1275
|
+
} catch {
|
|
1276
|
+
console.warn(`[Sidekick] Invalid CSS selector: "${injection.selector}"`);
|
|
1277
|
+
continue;
|
|
1278
|
+
}
|
|
1279
|
+
if (!target) continue;
|
|
1280
|
+
const container = document.createElement("div");
|
|
1281
|
+
container.setAttribute("data-sidekick-injection", injection.id);
|
|
1282
|
+
switch (injection.position) {
|
|
1283
|
+
case "before":
|
|
1284
|
+
target.parentNode?.insertBefore(container, target);
|
|
1285
|
+
break;
|
|
1286
|
+
case "after":
|
|
1287
|
+
target.parentNode?.insertBefore(container, target.nextSibling);
|
|
1288
|
+
break;
|
|
1289
|
+
case "prepend":
|
|
1290
|
+
target.insertBefore(container, target.firstChild);
|
|
1291
|
+
break;
|
|
1292
|
+
case "append":
|
|
1293
|
+
target.appendChild(container);
|
|
1294
|
+
break;
|
|
1295
|
+
}
|
|
1296
|
+
containers.push({ injection, container });
|
|
1297
|
+
}
|
|
1298
|
+
setInjectionContainers([...containers]);
|
|
1299
|
+
}
|
|
1300
|
+
createContainers();
|
|
1301
|
+
const observer = new MutationObserver(() => {
|
|
1302
|
+
const needsUpdate = state.injections.some((inj) => {
|
|
1303
|
+
try {
|
|
1304
|
+
const existing = document.querySelector(`[data-sidekick-injection="${inj.id}"]`);
|
|
1305
|
+
if (existing) return false;
|
|
1306
|
+
const target = document.querySelector(inj.selector);
|
|
1307
|
+
return !!target;
|
|
1308
|
+
} catch {
|
|
1309
|
+
return false;
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
if (needsUpdate) createContainers();
|
|
1313
|
+
});
|
|
1314
|
+
if (document.body) {
|
|
1315
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
1316
|
+
}
|
|
1317
|
+
return () => {
|
|
1318
|
+
observer.disconnect();
|
|
1319
|
+
document.querySelectorAll("[data-sidekick-injection]").forEach((el) => el.remove());
|
|
1320
|
+
setInjectionContainers([]);
|
|
1321
|
+
};
|
|
1322
|
+
}, [state.injections, isReady]);
|
|
1323
|
+
useEffect(() => {
|
|
1324
|
+
if (!isReady || typeof document === "undefined" || state.domEventListeners.length === 0) return;
|
|
1325
|
+
const cleanups = [];
|
|
1326
|
+
for (const listener of state.domEventListeners) {
|
|
1327
|
+
const handler = (event) => {
|
|
1328
|
+
const target = event.target;
|
|
1329
|
+
if (!target) return;
|
|
1330
|
+
let matched;
|
|
1331
|
+
try {
|
|
1332
|
+
matched = target.matches(listener.selector) ? target : target.closest(listener.selector);
|
|
1333
|
+
} catch {
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
if (matched) {
|
|
1337
|
+
try {
|
|
1338
|
+
listener.handler(event, matched);
|
|
1339
|
+
} catch (error) {
|
|
1340
|
+
console.error(`[Sidekick] DOM event handler error for "${listener.selector}" ${listener.eventType}:`, error);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
};
|
|
1344
|
+
document.addEventListener(listener.eventType, handler);
|
|
1345
|
+
cleanups.push(() => document.removeEventListener(listener.eventType, handler));
|
|
1346
|
+
}
|
|
1347
|
+
return () => {
|
|
1348
|
+
cleanups.forEach((cleanup) => cleanup());
|
|
1349
|
+
};
|
|
1350
|
+
}, [state.domEventListeners, isReady]);
|
|
1351
|
+
useEffect(() => {
|
|
1352
|
+
if (!isReady || typeof window === "undefined" || state.routeModifiers.length === 0) return;
|
|
1353
|
+
const originalPushState = history.pushState.bind(history);
|
|
1354
|
+
const originalReplaceState = history.replaceState.bind(history);
|
|
1355
|
+
function interceptNavigation(original, data, unused, url) {
|
|
1356
|
+
let finalUrl = url;
|
|
1357
|
+
if (url) {
|
|
1358
|
+
const urlStr = url.toString();
|
|
1359
|
+
for (const modifier of stateRef.current.routeModifiers) {
|
|
1360
|
+
const pattern = modifier.pathPattern;
|
|
1361
|
+
const matches = typeof pattern === "string" ? urlStr.includes(pattern) : pattern.test(urlStr);
|
|
1362
|
+
if (matches) {
|
|
1363
|
+
try {
|
|
1364
|
+
const result = modifier.handler({ path: urlStr, params: {} });
|
|
1365
|
+
if (typeof result === "string") {
|
|
1366
|
+
finalUrl = result;
|
|
1367
|
+
}
|
|
1368
|
+
} catch (error) {
|
|
1369
|
+
console.error(`[Sidekick] Route modifier error:`, error);
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
original(data, unused, finalUrl);
|
|
1375
|
+
}
|
|
1376
|
+
history.pushState = function(data, unused, url) {
|
|
1377
|
+
interceptNavigation(originalPushState, data, unused, url);
|
|
1378
|
+
};
|
|
1379
|
+
history.replaceState = function(data, unused, url) {
|
|
1380
|
+
interceptNavigation(originalReplaceState, data, unused, url);
|
|
1381
|
+
};
|
|
1382
|
+
const handlePopState = () => {
|
|
1383
|
+
const currentPath = window.location.pathname;
|
|
1384
|
+
for (const modifier of stateRef.current.routeModifiers) {
|
|
1385
|
+
const pattern = modifier.pathPattern;
|
|
1386
|
+
const matches = typeof pattern === "string" ? currentPath.includes(pattern) : pattern.test(currentPath);
|
|
1387
|
+
if (matches) {
|
|
1388
|
+
try {
|
|
1389
|
+
modifier.handler({ path: currentPath, params: {} });
|
|
1390
|
+
} catch (error) {
|
|
1391
|
+
console.error(`[Sidekick] Route modifier error on popstate:`, error);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
};
|
|
1396
|
+
window.addEventListener("popstate", handlePopState);
|
|
1397
|
+
return () => {
|
|
1398
|
+
history.pushState = originalPushState;
|
|
1399
|
+
history.replaceState = originalReplaceState;
|
|
1400
|
+
window.removeEventListener("popstate", handlePopState);
|
|
1401
|
+
};
|
|
1402
|
+
}, [state.routeModifiers, isReady]);
|
|
1403
|
+
const isOverrideEnabled = useCallback(
|
|
1404
|
+
(id) => {
|
|
1405
|
+
const override = overrides.find((o) => o.id === id);
|
|
1406
|
+
if (override) return override.enabled;
|
|
1407
|
+
return getFlag(id);
|
|
1408
|
+
},
|
|
1409
|
+
[overrides]
|
|
1410
|
+
);
|
|
1411
|
+
const toggleOverride = useCallback(
|
|
1412
|
+
(id) => {
|
|
1413
|
+
const currentEnabled = getFlag(id);
|
|
1414
|
+
setFlag(id, !currentEnabled);
|
|
1415
|
+
window.location.reload();
|
|
1416
|
+
},
|
|
1417
|
+
[]
|
|
1418
|
+
);
|
|
1419
|
+
const getColumns = useCallback(
|
|
1420
|
+
(tableId) => {
|
|
1421
|
+
return state.columns.get(tableId) ?? [];
|
|
1422
|
+
},
|
|
1423
|
+
[state.columns]
|
|
1424
|
+
);
|
|
1425
|
+
const getColumnRenames = useCallback(
|
|
1426
|
+
(tableId) => {
|
|
1427
|
+
return state.columnRenames.get(tableId) ?? [];
|
|
1428
|
+
},
|
|
1429
|
+
[state.columnRenames]
|
|
1430
|
+
);
|
|
1431
|
+
const getHiddenColumns = useCallback(
|
|
1432
|
+
(tableId) => {
|
|
1433
|
+
return state.hiddenColumns.get(tableId) ?? [];
|
|
1434
|
+
},
|
|
1435
|
+
[state.hiddenColumns]
|
|
1436
|
+
);
|
|
1437
|
+
const getColumnOrder = useCallback(
|
|
1438
|
+
(tableId) => {
|
|
1439
|
+
return state.columnOrders.get(tableId);
|
|
1440
|
+
},
|
|
1441
|
+
[state.columnOrders]
|
|
1442
|
+
);
|
|
1443
|
+
const getMenuItems = useCallback(
|
|
1444
|
+
(menuId) => {
|
|
1445
|
+
return state.menuItems.get(menuId) ?? [];
|
|
1446
|
+
},
|
|
1447
|
+
[state.menuItems]
|
|
1448
|
+
);
|
|
1449
|
+
const getTabs = useCallback(
|
|
1450
|
+
(tabGroupId) => {
|
|
1451
|
+
return state.tabs.get(tabGroupId) ?? [];
|
|
1452
|
+
},
|
|
1453
|
+
[state.tabs]
|
|
1454
|
+
);
|
|
1455
|
+
const getActions = useCallback(
|
|
1456
|
+
(actionBarId) => {
|
|
1457
|
+
return state.actions.get(actionBarId) ?? [];
|
|
1458
|
+
},
|
|
1459
|
+
[state.actions]
|
|
1460
|
+
);
|
|
1461
|
+
const getValidations = useCallback(
|
|
1462
|
+
(formId) => {
|
|
1463
|
+
return state.validations.get(formId) ?? [];
|
|
1464
|
+
},
|
|
1465
|
+
[state.validations]
|
|
1466
|
+
);
|
|
1467
|
+
const applyPropsModifiers = useCallback(
|
|
1468
|
+
(componentId, props) => {
|
|
1469
|
+
const modifiers = state.propsModifiers.get(componentId) ?? [];
|
|
1470
|
+
return modifiers.reduce((acc, { modifier }) => modifier(acc), props);
|
|
1471
|
+
},
|
|
1472
|
+
[state.propsModifiers]
|
|
1473
|
+
);
|
|
1474
|
+
const getComputedValue = useCallback(
|
|
1475
|
+
(fieldName, data) => {
|
|
1476
|
+
const field = state.computedFields.get(fieldName);
|
|
1477
|
+
if (!field) return void 0;
|
|
1478
|
+
return field.compute(data);
|
|
1479
|
+
},
|
|
1480
|
+
[state.computedFields]
|
|
1481
|
+
);
|
|
1482
|
+
const applyFilters = useCallback(
|
|
1483
|
+
(filterName, items) => {
|
|
1484
|
+
const filter = state.filters.get(filterName);
|
|
1485
|
+
if (!filter) return items;
|
|
1486
|
+
return filter.filter(items);
|
|
1487
|
+
},
|
|
1488
|
+
[state.filters]
|
|
1489
|
+
);
|
|
1490
|
+
const applyTransform = useCallback(
|
|
1491
|
+
(dataKey, data) => {
|
|
1492
|
+
const transform2 = state.transforms.get(dataKey);
|
|
1493
|
+
if (!transform2) return data;
|
|
1494
|
+
return transform2.transform(data);
|
|
1495
|
+
},
|
|
1496
|
+
[state.transforms]
|
|
1497
|
+
);
|
|
1498
|
+
const getSortOptions = useCallback(
|
|
1499
|
+
(tableId) => {
|
|
1500
|
+
return state.sortOptions.get(tableId) ?? [];
|
|
1501
|
+
},
|
|
1502
|
+
[state.sortOptions]
|
|
1503
|
+
);
|
|
1504
|
+
const getGroupByOptions = useCallback(
|
|
1505
|
+
(tableId) => {
|
|
1506
|
+
return state.groupByOptions.get(tableId) ?? [];
|
|
1507
|
+
},
|
|
1508
|
+
[state.groupByOptions]
|
|
1509
|
+
);
|
|
1510
|
+
const getKeyboardShortcuts = useCallback(
|
|
1511
|
+
() => {
|
|
1512
|
+
return state.keyboardShortcuts;
|
|
1513
|
+
},
|
|
1514
|
+
[state.keyboardShortcuts]
|
|
1515
|
+
);
|
|
1516
|
+
const emitEvent = useCallback(
|
|
1517
|
+
(eventName, payload) => {
|
|
1518
|
+
const handlers = state.eventHandlers.get(eventName) ?? [];
|
|
1519
|
+
for (const handler of handlers) {
|
|
1520
|
+
try {
|
|
1521
|
+
handler.handler(payload);
|
|
1522
|
+
} catch (error) {
|
|
1523
|
+
console.error(`[Sidekick] Event handler error for ${eventName}:`, error);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
},
|
|
1527
|
+
[state.eventHandlers]
|
|
1528
|
+
);
|
|
1529
|
+
const getWrapper = useCallback(
|
|
1530
|
+
(componentName) => {
|
|
1531
|
+
const wrappers = state.wrappers.get(componentName);
|
|
1532
|
+
if (!wrappers || wrappers.length === 0) return void 0;
|
|
1533
|
+
return (Component) => {
|
|
1534
|
+
return wrappers.reduce(
|
|
1535
|
+
(wrapped, { wrapper }) => wrapper(wrapped),
|
|
1536
|
+
Component
|
|
1537
|
+
);
|
|
1538
|
+
};
|
|
1539
|
+
},
|
|
1540
|
+
[state.wrappers]
|
|
1541
|
+
);
|
|
1542
|
+
const getReplacement = useCallback(
|
|
1543
|
+
(componentName) => {
|
|
1544
|
+
return state.replacements.get(componentName);
|
|
1545
|
+
},
|
|
1546
|
+
[state.replacements]
|
|
1547
|
+
);
|
|
1548
|
+
const contextValue = useMemo(
|
|
1549
|
+
() => ({
|
|
1550
|
+
state,
|
|
1551
|
+
overrides,
|
|
1552
|
+
isOverrideEnabled,
|
|
1553
|
+
toggleOverride,
|
|
1554
|
+
// UI
|
|
1555
|
+
getColumns,
|
|
1556
|
+
getColumnRenames,
|
|
1557
|
+
getHiddenColumns,
|
|
1558
|
+
getColumnOrder,
|
|
1559
|
+
getMenuItems,
|
|
1560
|
+
getTabs,
|
|
1561
|
+
getActions,
|
|
1562
|
+
getValidations,
|
|
1563
|
+
getWrapper,
|
|
1564
|
+
getReplacement,
|
|
1565
|
+
applyPropsModifiers,
|
|
1566
|
+
// Data
|
|
1567
|
+
getComputedValue,
|
|
1568
|
+
applyFilters,
|
|
1569
|
+
applyTransform,
|
|
1570
|
+
getSortOptions,
|
|
1571
|
+
getGroupByOptions,
|
|
1572
|
+
// Behavior
|
|
1573
|
+
getKeyboardShortcuts,
|
|
1574
|
+
emitEvent
|
|
1575
|
+
}),
|
|
1576
|
+
[
|
|
1577
|
+
state,
|
|
1578
|
+
overrides,
|
|
1579
|
+
isOverrideEnabled,
|
|
1580
|
+
toggleOverride,
|
|
1581
|
+
getColumns,
|
|
1582
|
+
getColumnRenames,
|
|
1583
|
+
getHiddenColumns,
|
|
1584
|
+
getColumnOrder,
|
|
1585
|
+
getMenuItems,
|
|
1586
|
+
getTabs,
|
|
1587
|
+
getActions,
|
|
1588
|
+
getValidations,
|
|
1589
|
+
getWrapper,
|
|
1590
|
+
getReplacement,
|
|
1591
|
+
applyPropsModifiers,
|
|
1592
|
+
getComputedValue,
|
|
1593
|
+
applyFilters,
|
|
1594
|
+
applyTransform,
|
|
1595
|
+
getSortOptions,
|
|
1596
|
+
getGroupByOptions,
|
|
1597
|
+
getKeyboardShortcuts,
|
|
1598
|
+
emitEvent
|
|
1599
|
+
]
|
|
1600
|
+
);
|
|
1601
|
+
const wrapCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
1602
|
+
const transformedChildren = useMemo(() => {
|
|
1603
|
+
if (!isReady) return null;
|
|
1604
|
+
if (state.wrappers.size === 0 && state.replacements.size === 0) return children;
|
|
1605
|
+
return transformElementTree(children, state.wrappers, state.replacements, wrapCacheRef.current);
|
|
1606
|
+
}, [children, isReady, state.wrappers, state.replacements]);
|
|
1607
|
+
return /* @__PURE__ */ jsxs(SidekickContext.Provider, { value: contextValue, children: [
|
|
1608
|
+
isReady ? transformedChildren : null,
|
|
1609
|
+
injectionContainers.map(
|
|
1610
|
+
({ injection, container }) => createPortal(
|
|
1611
|
+
React4.createElement(injection.component, {}),
|
|
1612
|
+
container,
|
|
1613
|
+
`sidekick-injection-${injection.id}`
|
|
1614
|
+
)
|
|
1615
|
+
)
|
|
1616
|
+
] });
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
// src/components/SidekickPanel.tsx
|
|
1620
|
+
import { useState as useState2, useCallback as useCallback2, useEffect as useEffect2 } from "react";
|
|
1621
|
+
import { Fragment as Fragment3, jsx, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1622
|
+
function SidekickPanel({ apiEndpoint, deleteEndpoint, toggleEndpoint, onGenerate, onDelete, onToggle }) {
|
|
1623
|
+
const [isOpen, setIsOpen] = useState2(() => {
|
|
1624
|
+
if (typeof window === "undefined") return false;
|
|
1625
|
+
return sessionStorage.getItem("sidekick_panel_open") === "true";
|
|
1626
|
+
});
|
|
1627
|
+
const [activeTab, setActiveTab] = useState2(() => {
|
|
1628
|
+
if (typeof window === "undefined") return "chat";
|
|
1629
|
+
return sessionStorage.getItem("sidekick_panel_tab") || "chat";
|
|
1630
|
+
});
|
|
1631
|
+
const [messages, setMessages] = useState2([]);
|
|
1632
|
+
const [input, setInput] = useState2("");
|
|
1633
|
+
const [isGenerating, setIsGenerating] = useState2(false);
|
|
1634
|
+
const [deletingId, setDeletingId] = useState2(null);
|
|
1635
|
+
const [togglingId, setTogglingId] = useState2(null);
|
|
1636
|
+
const [editingOverrideId, setEditingOverrideId] = useState2(null);
|
|
1637
|
+
const context = useSidekickSafe();
|
|
1638
|
+
const overrides = context?.overrides ?? [];
|
|
1639
|
+
const effectiveDeleteEndpoint = deleteEndpoint || (apiEndpoint ? apiEndpoint.replace("/generate", "/delete") : void 0);
|
|
1640
|
+
const effectiveToggleEndpoint = toggleEndpoint || (apiEndpoint ? apiEndpoint.replace("/generate", "/toggle") : void 0);
|
|
1641
|
+
useEffect2(() => {
|
|
1642
|
+
if (typeof window === "undefined") return;
|
|
1643
|
+
sessionStorage.setItem("sidekick_panel_open", isOpen ? "true" : "false");
|
|
1644
|
+
}, [isOpen]);
|
|
1645
|
+
useEffect2(() => {
|
|
1646
|
+
if (typeof window === "undefined") return;
|
|
1647
|
+
sessionStorage.setItem("sidekick_panel_tab", activeTab);
|
|
1648
|
+
}, [activeTab]);
|
|
1649
|
+
const messagesStorageKey = editingOverrideId ? `sidekick_edit_messages_${editingOverrideId}` : "sidekick_messages";
|
|
1650
|
+
useEffect2(() => {
|
|
1651
|
+
if (typeof window === "undefined") return;
|
|
1652
|
+
const stored = sessionStorage.getItem(messagesStorageKey);
|
|
1653
|
+
if (stored) {
|
|
1654
|
+
try {
|
|
1655
|
+
const parsed = JSON.parse(stored);
|
|
1656
|
+
setMessages(parsed.map((m) => ({ ...m, timestamp: new Date(m.timestamp) })));
|
|
1657
|
+
} catch {
|
|
1658
|
+
setMessages([]);
|
|
1659
|
+
}
|
|
1660
|
+
} else {
|
|
1661
|
+
setMessages([]);
|
|
1662
|
+
}
|
|
1663
|
+
}, [messagesStorageKey]);
|
|
1664
|
+
useEffect2(() => {
|
|
1665
|
+
if (typeof window === "undefined" || messages.length === 0) return;
|
|
1666
|
+
sessionStorage.setItem(messagesStorageKey, JSON.stringify(messages));
|
|
1667
|
+
}, [messages, messagesStorageKey]);
|
|
1668
|
+
const handleSubmit = useCallback2(async (e) => {
|
|
1669
|
+
e.preventDefault();
|
|
1670
|
+
if (!input.trim() || isGenerating) return;
|
|
1671
|
+
const userMessage = {
|
|
1672
|
+
id: generateId4(),
|
|
1673
|
+
role: "user",
|
|
1674
|
+
content: input.trim(),
|
|
1675
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1676
|
+
};
|
|
1677
|
+
const assistantMessage = {
|
|
1678
|
+
id: generateId4(),
|
|
1679
|
+
role: "assistant",
|
|
1680
|
+
content: "Generating your customization...",
|
|
1681
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
1682
|
+
status: "generating"
|
|
1683
|
+
};
|
|
1684
|
+
setMessages((prev) => [...prev, userMessage, assistantMessage]);
|
|
1685
|
+
setInput("");
|
|
1686
|
+
setIsGenerating(true);
|
|
1687
|
+
try {
|
|
1688
|
+
let result;
|
|
1689
|
+
const requestBody = { request: userMessage.content };
|
|
1690
|
+
if (editingOverrideId) {
|
|
1691
|
+
requestBody.overrideId = editingOverrideId;
|
|
1692
|
+
}
|
|
1693
|
+
if (onGenerate) {
|
|
1694
|
+
result = await onGenerate(userMessage.content);
|
|
1695
|
+
} else if (apiEndpoint) {
|
|
1696
|
+
const response = await fetch(apiEndpoint, {
|
|
1697
|
+
method: "POST",
|
|
1698
|
+
headers: { "Content-Type": "application/json" },
|
|
1699
|
+
body: JSON.stringify(requestBody)
|
|
1700
|
+
});
|
|
1701
|
+
result = await response.json();
|
|
1702
|
+
} else {
|
|
1703
|
+
result = {
|
|
1704
|
+
success: false,
|
|
1705
|
+
error: "No API endpoint or onGenerate handler configured"
|
|
1706
|
+
};
|
|
1707
|
+
}
|
|
1708
|
+
const verb = editingOverrideId ? "Updated" : "Created";
|
|
1709
|
+
const successMessage = result.success ? `${verb} "${result.name || result.overrideId}"!
|
|
1710
|
+
|
|
1711
|
+
${result.description || ""}
|
|
1712
|
+
|
|
1713
|
+
Reload the page to apply changes.` : `Failed to generate: ${result.error}`;
|
|
1714
|
+
setMessages(
|
|
1715
|
+
(prev) => prev.map(
|
|
1716
|
+
(m) => m.id === assistantMessage.id ? {
|
|
1717
|
+
...m,
|
|
1718
|
+
content: successMessage,
|
|
1719
|
+
status: result.success ? "success" : "error",
|
|
1720
|
+
overrideId: result.overrideId
|
|
1721
|
+
} : m
|
|
1722
|
+
)
|
|
1723
|
+
);
|
|
1724
|
+
} catch (error) {
|
|
1725
|
+
setMessages(
|
|
1726
|
+
(prev) => prev.map(
|
|
1727
|
+
(m) => m.id === assistantMessage.id ? {
|
|
1728
|
+
...m,
|
|
1729
|
+
content: `Error: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1730
|
+
status: "error"
|
|
1731
|
+
} : m
|
|
1732
|
+
)
|
|
1733
|
+
);
|
|
1734
|
+
} finally {
|
|
1735
|
+
setIsGenerating(false);
|
|
1736
|
+
}
|
|
1737
|
+
}, [input, isGenerating, onGenerate, apiEndpoint, editingOverrideId]);
|
|
1738
|
+
const handleToggleOverride = useCallback2(async (overrideId, enabled) => {
|
|
1739
|
+
setTogglingId(overrideId);
|
|
1740
|
+
try {
|
|
1741
|
+
if (onToggle) {
|
|
1742
|
+
await onToggle(overrideId, enabled);
|
|
1743
|
+
} else if (effectiveToggleEndpoint) {
|
|
1744
|
+
const response = await fetch(effectiveToggleEndpoint, {
|
|
1745
|
+
method: "POST",
|
|
1746
|
+
headers: { "Content-Type": "application/json" },
|
|
1747
|
+
body: JSON.stringify({ overrideId, enabled })
|
|
1748
|
+
});
|
|
1749
|
+
const result = await response.json();
|
|
1750
|
+
if (!result.success) {
|
|
1751
|
+
throw new Error(result.error || "Toggle failed");
|
|
1752
|
+
}
|
|
1753
|
+
} else {
|
|
1754
|
+
setFlag(overrideId, enabled);
|
|
1755
|
+
}
|
|
1756
|
+
window.location.reload();
|
|
1757
|
+
} catch (error) {
|
|
1758
|
+
alert(`Failed to toggle: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1759
|
+
setTogglingId(null);
|
|
1760
|
+
}
|
|
1761
|
+
}, [onToggle, effectiveToggleEndpoint]);
|
|
1762
|
+
const handleDeleteOverride = useCallback2(async (overrideId) => {
|
|
1763
|
+
if (!confirm(`Are you sure you want to delete this override? This cannot be undone.`)) {
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
setDeletingId(overrideId);
|
|
1767
|
+
try {
|
|
1768
|
+
let result;
|
|
1769
|
+
if (onDelete) {
|
|
1770
|
+
result = await onDelete(overrideId);
|
|
1771
|
+
} else if (effectiveDeleteEndpoint) {
|
|
1772
|
+
const response = await fetch(effectiveDeleteEndpoint, {
|
|
1773
|
+
method: "POST",
|
|
1774
|
+
headers: { "Content-Type": "application/json" },
|
|
1775
|
+
body: JSON.stringify({ overrideId })
|
|
1776
|
+
});
|
|
1777
|
+
result = await response.json();
|
|
1778
|
+
} else {
|
|
1779
|
+
result = { success: false, error: "No delete endpoint configured" };
|
|
1780
|
+
}
|
|
1781
|
+
if (result.success) {
|
|
1782
|
+
setFlag(overrideId, false);
|
|
1783
|
+
window.location.reload();
|
|
1784
|
+
} else {
|
|
1785
|
+
alert(`Failed to delete: ${result.error}`);
|
|
1786
|
+
}
|
|
1787
|
+
} catch (error) {
|
|
1788
|
+
alert(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1789
|
+
} finally {
|
|
1790
|
+
setDeletingId(null);
|
|
1791
|
+
}
|
|
1792
|
+
}, [onDelete, effectiveDeleteEndpoint]);
|
|
1793
|
+
const handleRegenerateOverride = useCallback2((overrideId) => {
|
|
1794
|
+
setEditingOverrideId(overrideId);
|
|
1795
|
+
setActiveTab("chat");
|
|
1796
|
+
setInput("");
|
|
1797
|
+
}, []);
|
|
1798
|
+
const handleEditOverride = useCallback2((overrideId) => {
|
|
1799
|
+
setEditingOverrideId(overrideId);
|
|
1800
|
+
setActiveTab("chat");
|
|
1801
|
+
setInput("");
|
|
1802
|
+
}, []);
|
|
1803
|
+
const handleExitEditMode = useCallback2(() => {
|
|
1804
|
+
setEditingOverrideId(null);
|
|
1805
|
+
setInput("");
|
|
1806
|
+
}, []);
|
|
1807
|
+
const handleClearHistory = useCallback2(() => {
|
|
1808
|
+
setMessages([]);
|
|
1809
|
+
sessionStorage.removeItem(messagesStorageKey);
|
|
1810
|
+
}, [messagesStorageKey]);
|
|
1811
|
+
if (!isOpen) {
|
|
1812
|
+
return /* @__PURE__ */ jsx(
|
|
1813
|
+
"button",
|
|
1814
|
+
{
|
|
1815
|
+
onClick: () => setIsOpen(true),
|
|
1816
|
+
style: styles.trigger,
|
|
1817
|
+
"aria-label": "Open Sidekick Panel",
|
|
1818
|
+
children: /* @__PURE__ */ jsx(SidekickIcon, {})
|
|
1819
|
+
}
|
|
1820
|
+
);
|
|
1821
|
+
}
|
|
1822
|
+
return /* @__PURE__ */ jsx("div", { style: styles.overlay, onWheel: (e) => e.stopPropagation(), onTouchMove: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxs2("div", { style: styles.panel, children: [
|
|
1823
|
+
/* @__PURE__ */ jsxs2("div", { style: styles.header, children: [
|
|
1824
|
+
/* @__PURE__ */ jsx("h2", { style: styles.title, children: "Sidekick" }),
|
|
1825
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setIsOpen(false), style: styles.closeButton, children: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
1826
|
+
] }),
|
|
1827
|
+
/* @__PURE__ */ jsxs2("div", { style: styles.tabs, children: [
|
|
1828
|
+
/* @__PURE__ */ jsx(
|
|
1829
|
+
"button",
|
|
1830
|
+
{
|
|
1831
|
+
onClick: () => setActiveTab("chat"),
|
|
1832
|
+
style: {
|
|
1833
|
+
...styles.tab,
|
|
1834
|
+
...activeTab === "chat" ? styles.tabActive : {}
|
|
1835
|
+
},
|
|
1836
|
+
children: "Customize"
|
|
1837
|
+
}
|
|
1838
|
+
),
|
|
1839
|
+
/* @__PURE__ */ jsxs2(
|
|
1840
|
+
"button",
|
|
1841
|
+
{
|
|
1842
|
+
onClick: () => setActiveTab("overrides"),
|
|
1843
|
+
style: {
|
|
1844
|
+
...styles.tab,
|
|
1845
|
+
...activeTab === "overrides" ? styles.tabActive : {}
|
|
1846
|
+
},
|
|
1847
|
+
children: [
|
|
1848
|
+
"Overrides (",
|
|
1849
|
+
overrides.length,
|
|
1850
|
+
")"
|
|
1851
|
+
]
|
|
1852
|
+
}
|
|
1853
|
+
)
|
|
1854
|
+
] }),
|
|
1855
|
+
/* @__PURE__ */ jsx("div", { style: styles.content, children: activeTab === "chat" ? /* @__PURE__ */ jsx(
|
|
1856
|
+
ChatTab,
|
|
1857
|
+
{
|
|
1858
|
+
messages,
|
|
1859
|
+
input,
|
|
1860
|
+
isGenerating,
|
|
1861
|
+
onInputChange: setInput,
|
|
1862
|
+
onSubmit: handleSubmit,
|
|
1863
|
+
onClearHistory: handleClearHistory,
|
|
1864
|
+
editingOverride: editingOverrideId ? overrides.find((o) => o.id === editingOverrideId) : void 0,
|
|
1865
|
+
onExitEditMode: handleExitEditMode
|
|
1866
|
+
}
|
|
1867
|
+
) : /* @__PURE__ */ jsx(
|
|
1868
|
+
OverridesTab,
|
|
1869
|
+
{
|
|
1870
|
+
overrides,
|
|
1871
|
+
onToggle: handleToggleOverride,
|
|
1872
|
+
onDelete: handleDeleteOverride,
|
|
1873
|
+
onRegenerate: handleRegenerateOverride,
|
|
1874
|
+
onEdit: handleEditOverride,
|
|
1875
|
+
deletingId,
|
|
1876
|
+
togglingId
|
|
1877
|
+
}
|
|
1878
|
+
) })
|
|
1879
|
+
] }) });
|
|
1880
|
+
}
|
|
1881
|
+
function ChatTab({
|
|
1882
|
+
messages,
|
|
1883
|
+
input,
|
|
1884
|
+
isGenerating,
|
|
1885
|
+
onInputChange,
|
|
1886
|
+
onSubmit,
|
|
1887
|
+
onClearHistory,
|
|
1888
|
+
editingOverride,
|
|
1889
|
+
onExitEditMode
|
|
1890
|
+
}) {
|
|
1891
|
+
return /* @__PURE__ */ jsxs2("div", { style: styles.chatContainer, children: [
|
|
1892
|
+
editingOverride && /* @__PURE__ */ jsxs2("div", { style: styles.editHeader, children: [
|
|
1893
|
+
/* @__PURE__ */ jsxs2("span", { style: styles.editHeaderText, children: [
|
|
1894
|
+
"Editing: ",
|
|
1895
|
+
editingOverride.name
|
|
1896
|
+
] }),
|
|
1897
|
+
/* @__PURE__ */ jsx("button", { onClick: onExitEditMode, style: styles.editHeaderClose, children: "\u2715" })
|
|
1898
|
+
] }),
|
|
1899
|
+
/* @__PURE__ */ jsx("div", { style: styles.messages, children: messages.length === 0 ? editingOverride ? /* @__PURE__ */ jsxs2("div", { style: styles.emptyState, children: [
|
|
1900
|
+
/* @__PURE__ */ jsxs2("p", { style: styles.emptyTitle, children: [
|
|
1901
|
+
'Edit "',
|
|
1902
|
+
editingOverride.name,
|
|
1903
|
+
'"'
|
|
1904
|
+
] }),
|
|
1905
|
+
/* @__PURE__ */ jsx("p", { style: styles.emptyDescription, children: "Describe what you want to change about this override, and I'll modify the existing code." }),
|
|
1906
|
+
/* @__PURE__ */ jsxs2("div", { style: styles.examples, children: [
|
|
1907
|
+
/* @__PURE__ */ jsx("p", { style: styles.examplesTitle, children: "Try saying:" }),
|
|
1908
|
+
/* @__PURE__ */ jsxs2("ul", { style: styles.examplesList, children: [
|
|
1909
|
+
/* @__PURE__ */ jsx("li", { children: '"Change the color to red"' }),
|
|
1910
|
+
/* @__PURE__ */ jsx("li", { children: '"Make it only apply to high priority items"' }),
|
|
1911
|
+
/* @__PURE__ */ jsx("li", { children: '"Add a hover effect"' })
|
|
1912
|
+
] })
|
|
1913
|
+
] })
|
|
1914
|
+
] }) : /* @__PURE__ */ jsxs2("div", { style: styles.emptyState, children: [
|
|
1915
|
+
/* @__PURE__ */ jsx("p", { style: styles.emptyTitle, children: "Customize your app" }),
|
|
1916
|
+
/* @__PURE__ */ jsx("p", { style: styles.emptyDescription, children: "Describe what you want to change in natural language, and I'll generate the code." }),
|
|
1917
|
+
/* @__PURE__ */ jsxs2("div", { style: styles.examples, children: [
|
|
1918
|
+
/* @__PURE__ */ jsx("p", { style: styles.examplesTitle, children: "Try saying:" }),
|
|
1919
|
+
/* @__PURE__ */ jsxs2("ul", { style: styles.examplesList, children: [
|
|
1920
|
+
/* @__PURE__ */ jsx("li", { children: '"Add a column showing days until due date"' }),
|
|
1921
|
+
/* @__PURE__ */ jsx("li", { children: '"Add a banner at the top of the sidebar"' }),
|
|
1922
|
+
/* @__PURE__ */ jsx("li", { children: '"Highlight overdue tasks in red"' })
|
|
1923
|
+
] })
|
|
1924
|
+
] })
|
|
1925
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
1926
|
+
messages.map((message) => /* @__PURE__ */ jsxs2(
|
|
1927
|
+
"div",
|
|
1928
|
+
{
|
|
1929
|
+
style: {
|
|
1930
|
+
...styles.message,
|
|
1931
|
+
...message.role === "user" ? styles.userMessage : styles.assistantMessage
|
|
1932
|
+
},
|
|
1933
|
+
children: [
|
|
1934
|
+
/* @__PURE__ */ jsxs2("div", { style: styles.messageContent, children: [
|
|
1935
|
+
message.content,
|
|
1936
|
+
message.status === "generating" && /* @__PURE__ */ jsx("span", { style: styles.spinner, children: "\u27F3" })
|
|
1937
|
+
] }),
|
|
1938
|
+
message.status === "success" && /* @__PURE__ */ jsxs2("div", { style: styles.successContainer, children: [
|
|
1939
|
+
/* @__PURE__ */ jsxs2("div", { style: styles.successBadge, children: [
|
|
1940
|
+
"\u2713 ",
|
|
1941
|
+
editingOverride ? "Updated" : "Created"
|
|
1942
|
+
] }),
|
|
1943
|
+
/* @__PURE__ */ jsx(
|
|
1944
|
+
"button",
|
|
1945
|
+
{
|
|
1946
|
+
onClick: () => window.location.reload(),
|
|
1947
|
+
style: styles.reloadButton,
|
|
1948
|
+
children: "Reload to Apply"
|
|
1949
|
+
}
|
|
1950
|
+
)
|
|
1951
|
+
] }),
|
|
1952
|
+
message.status === "error" && /* @__PURE__ */ jsx("div", { style: styles.errorBadge, children: "\u2715 Failed" })
|
|
1953
|
+
]
|
|
1954
|
+
},
|
|
1955
|
+
message.id
|
|
1956
|
+
)),
|
|
1957
|
+
/* @__PURE__ */ jsx("button", { onClick: onClearHistory, style: styles.clearButton, children: "Clear history" })
|
|
1958
|
+
] }) }),
|
|
1959
|
+
/* @__PURE__ */ jsxs2("form", { onSubmit, style: styles.inputForm, children: [
|
|
1960
|
+
/* @__PURE__ */ jsx(
|
|
1961
|
+
"input",
|
|
1962
|
+
{
|
|
1963
|
+
type: "text",
|
|
1964
|
+
value: input,
|
|
1965
|
+
onChange: (e) => onInputChange(e.target.value),
|
|
1966
|
+
placeholder: "Describe your customization...",
|
|
1967
|
+
disabled: isGenerating,
|
|
1968
|
+
style: styles.input
|
|
1969
|
+
}
|
|
1970
|
+
),
|
|
1971
|
+
/* @__PURE__ */ jsx(
|
|
1972
|
+
"button",
|
|
1973
|
+
{
|
|
1974
|
+
type: "submit",
|
|
1975
|
+
disabled: !input.trim() || isGenerating,
|
|
1976
|
+
style: {
|
|
1977
|
+
...styles.submitButton,
|
|
1978
|
+
...!input.trim() || isGenerating ? styles.submitButtonDisabled : {}
|
|
1979
|
+
},
|
|
1980
|
+
children: isGenerating ? "..." : "\u2192"
|
|
1981
|
+
}
|
|
1982
|
+
)
|
|
1983
|
+
] })
|
|
1984
|
+
] });
|
|
1985
|
+
}
|
|
1986
|
+
function OverridesTab({ overrides, onToggle, onDelete, onRegenerate, onEdit, deletingId, togglingId }) {
|
|
1987
|
+
const handleToggle = (override) => {
|
|
1988
|
+
onToggle(override.id, !override.enabled);
|
|
1989
|
+
};
|
|
1990
|
+
if (overrides.length === 0) {
|
|
1991
|
+
return /* @__PURE__ */ jsxs2("div", { style: styles.emptyState, children: [
|
|
1992
|
+
/* @__PURE__ */ jsx("p", { style: styles.emptyTitle, children: "No overrides yet" }),
|
|
1993
|
+
/* @__PURE__ */ jsx("p", { style: styles.emptyDescription, children: "Use the Customize tab to create your first customization." })
|
|
1994
|
+
] });
|
|
1995
|
+
}
|
|
1996
|
+
return /* @__PURE__ */ jsx("div", { style: styles.overridesList, children: overrides.map((override) => /* @__PURE__ */ jsxs2("div", { style: styles.overrideItem, children: [
|
|
1997
|
+
/* @__PURE__ */ jsxs2("div", { style: styles.overrideInfo, children: [
|
|
1998
|
+
/* @__PURE__ */ jsx("h3", { style: styles.overrideName, children: override.name }),
|
|
1999
|
+
/* @__PURE__ */ jsx("p", { style: styles.overrideDescription, children: override.description }),
|
|
2000
|
+
/* @__PURE__ */ jsxs2("div", { style: styles.overrideActions, children: [
|
|
2001
|
+
/* @__PURE__ */ jsx(
|
|
2002
|
+
"button",
|
|
2003
|
+
{
|
|
2004
|
+
onClick: () => onEdit(override.id),
|
|
2005
|
+
style: styles.actionButton,
|
|
2006
|
+
children: "Edit"
|
|
2007
|
+
}
|
|
2008
|
+
),
|
|
2009
|
+
/* @__PURE__ */ jsx(
|
|
2010
|
+
"button",
|
|
2011
|
+
{
|
|
2012
|
+
onClick: () => onRegenerate(override.id),
|
|
2013
|
+
style: styles.actionButton,
|
|
2014
|
+
children: "Regenerate"
|
|
2015
|
+
}
|
|
2016
|
+
),
|
|
2017
|
+
/* @__PURE__ */ jsx(
|
|
2018
|
+
"button",
|
|
2019
|
+
{
|
|
2020
|
+
onClick: () => onDelete(override.id),
|
|
2021
|
+
disabled: deletingId === override.id,
|
|
2022
|
+
style: {
|
|
2023
|
+
...styles.actionButton,
|
|
2024
|
+
...styles.deleteButton,
|
|
2025
|
+
...deletingId === override.id ? styles.actionButtonDisabled : {}
|
|
2026
|
+
},
|
|
2027
|
+
children: deletingId === override.id ? "Deleting..." : "Delete"
|
|
2028
|
+
}
|
|
2029
|
+
)
|
|
2030
|
+
] })
|
|
2031
|
+
] }),
|
|
2032
|
+
/* @__PURE__ */ jsx(
|
|
2033
|
+
"button",
|
|
2034
|
+
{
|
|
2035
|
+
onClick: () => handleToggle(override),
|
|
2036
|
+
disabled: togglingId === override.id,
|
|
2037
|
+
style: {
|
|
2038
|
+
...styles.toggle,
|
|
2039
|
+
...override.enabled ? styles.toggleOn : styles.toggleOff,
|
|
2040
|
+
...togglingId === override.id ? styles.toggleDisabled : {}
|
|
2041
|
+
},
|
|
2042
|
+
children: togglingId === override.id ? "..." : override.enabled ? "ON" : "OFF"
|
|
2043
|
+
}
|
|
2044
|
+
)
|
|
2045
|
+
] }, override.id)) });
|
|
2046
|
+
}
|
|
2047
|
+
function SidekickIcon() {
|
|
2048
|
+
return /* @__PURE__ */ jsxs2("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
2049
|
+
/* @__PURE__ */ jsx("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }),
|
|
2050
|
+
/* @__PURE__ */ jsx("path", { d: "M2 17l10 5 10-5" }),
|
|
2051
|
+
/* @__PURE__ */ jsx("path", { d: "M2 12l10 5 10-5" })
|
|
2052
|
+
] });
|
|
2053
|
+
}
|
|
2054
|
+
function CloseIcon() {
|
|
2055
|
+
return /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" }) });
|
|
2056
|
+
}
|
|
2057
|
+
function generateId4() {
|
|
2058
|
+
return Math.random().toString(36).substring(2, 11);
|
|
2059
|
+
}
|
|
2060
|
+
var styles = {
|
|
2061
|
+
trigger: {
|
|
2062
|
+
position: "fixed",
|
|
2063
|
+
bottom: "24px",
|
|
2064
|
+
right: "24px",
|
|
2065
|
+
width: "56px",
|
|
2066
|
+
height: "56px",
|
|
2067
|
+
borderRadius: "50%",
|
|
2068
|
+
backgroundColor: "#3B82F6",
|
|
2069
|
+
color: "white",
|
|
2070
|
+
border: "none",
|
|
2071
|
+
cursor: "pointer",
|
|
2072
|
+
display: "flex",
|
|
2073
|
+
alignItems: "center",
|
|
2074
|
+
justifyContent: "center",
|
|
2075
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
2076
|
+
zIndex: 9999
|
|
2077
|
+
},
|
|
2078
|
+
overlay: {
|
|
2079
|
+
position: "fixed",
|
|
2080
|
+
top: 0,
|
|
2081
|
+
right: 0,
|
|
2082
|
+
bottom: 0,
|
|
2083
|
+
width: "400px",
|
|
2084
|
+
zIndex: 9999,
|
|
2085
|
+
boxShadow: "-4px 0 24px rgba(0, 0, 0, 0.15)",
|
|
2086
|
+
overscrollBehavior: "contain"
|
|
2087
|
+
},
|
|
2088
|
+
panel: {
|
|
2089
|
+
height: "100%",
|
|
2090
|
+
backgroundColor: "white",
|
|
2091
|
+
display: "flex",
|
|
2092
|
+
flexDirection: "column"
|
|
2093
|
+
},
|
|
2094
|
+
header: {
|
|
2095
|
+
display: "flex",
|
|
2096
|
+
alignItems: "center",
|
|
2097
|
+
justifyContent: "space-between",
|
|
2098
|
+
padding: "16px 20px",
|
|
2099
|
+
borderBottom: "1px solid #E5E7EB"
|
|
2100
|
+
},
|
|
2101
|
+
title: {
|
|
2102
|
+
margin: 0,
|
|
2103
|
+
fontSize: "18px",
|
|
2104
|
+
fontWeight: 600,
|
|
2105
|
+
color: "#111827"
|
|
2106
|
+
},
|
|
2107
|
+
closeButton: {
|
|
2108
|
+
background: "none",
|
|
2109
|
+
border: "none",
|
|
2110
|
+
cursor: "pointer",
|
|
2111
|
+
padding: "4px",
|
|
2112
|
+
color: "#6B7280"
|
|
2113
|
+
},
|
|
2114
|
+
tabs: {
|
|
2115
|
+
display: "flex",
|
|
2116
|
+
borderBottom: "1px solid #E5E7EB"
|
|
2117
|
+
},
|
|
2118
|
+
tab: {
|
|
2119
|
+
flex: 1,
|
|
2120
|
+
padding: "12px 16px",
|
|
2121
|
+
background: "none",
|
|
2122
|
+
border: "none",
|
|
2123
|
+
cursor: "pointer",
|
|
2124
|
+
fontSize: "14px",
|
|
2125
|
+
fontWeight: 500,
|
|
2126
|
+
color: "#6B7280",
|
|
2127
|
+
borderBottom: "2px solid transparent"
|
|
2128
|
+
},
|
|
2129
|
+
tabActive: {
|
|
2130
|
+
color: "#3B82F6",
|
|
2131
|
+
borderBottomColor: "#3B82F6"
|
|
2132
|
+
},
|
|
2133
|
+
content: {
|
|
2134
|
+
flex: 1,
|
|
2135
|
+
overflow: "hidden",
|
|
2136
|
+
display: "flex",
|
|
2137
|
+
flexDirection: "column"
|
|
2138
|
+
},
|
|
2139
|
+
chatContainer: {
|
|
2140
|
+
flex: 1,
|
|
2141
|
+
display: "flex",
|
|
2142
|
+
flexDirection: "column",
|
|
2143
|
+
overflow: "hidden"
|
|
2144
|
+
},
|
|
2145
|
+
messages: {
|
|
2146
|
+
flex: 1,
|
|
2147
|
+
overflowY: "auto",
|
|
2148
|
+
padding: "16px",
|
|
2149
|
+
overscrollBehavior: "contain"
|
|
2150
|
+
},
|
|
2151
|
+
emptyState: {
|
|
2152
|
+
textAlign: "center",
|
|
2153
|
+
padding: "40px 20px"
|
|
2154
|
+
},
|
|
2155
|
+
emptyTitle: {
|
|
2156
|
+
margin: "0 0 8px 0",
|
|
2157
|
+
fontSize: "16px",
|
|
2158
|
+
fontWeight: 600,
|
|
2159
|
+
color: "#111827"
|
|
2160
|
+
},
|
|
2161
|
+
emptyDescription: {
|
|
2162
|
+
margin: "0 0 24px 0",
|
|
2163
|
+
fontSize: "14px",
|
|
2164
|
+
color: "#6B7280"
|
|
2165
|
+
},
|
|
2166
|
+
examples: {
|
|
2167
|
+
textAlign: "left",
|
|
2168
|
+
backgroundColor: "#F9FAFB",
|
|
2169
|
+
borderRadius: "8px",
|
|
2170
|
+
padding: "16px"
|
|
2171
|
+
},
|
|
2172
|
+
examplesTitle: {
|
|
2173
|
+
margin: "0 0 8px 0",
|
|
2174
|
+
fontSize: "13px",
|
|
2175
|
+
fontWeight: 500,
|
|
2176
|
+
color: "#374151"
|
|
2177
|
+
},
|
|
2178
|
+
examplesList: {
|
|
2179
|
+
margin: 0,
|
|
2180
|
+
padding: "0 0 0 20px",
|
|
2181
|
+
fontSize: "13px",
|
|
2182
|
+
color: "#6B7280",
|
|
2183
|
+
lineHeight: 1.8
|
|
2184
|
+
},
|
|
2185
|
+
message: {
|
|
2186
|
+
marginBottom: "12px",
|
|
2187
|
+
padding: "12px 16px",
|
|
2188
|
+
borderRadius: "12px",
|
|
2189
|
+
fontSize: "14px",
|
|
2190
|
+
lineHeight: 1.5
|
|
2191
|
+
},
|
|
2192
|
+
userMessage: {
|
|
2193
|
+
backgroundColor: "#3B82F6",
|
|
2194
|
+
color: "white",
|
|
2195
|
+
marginLeft: "40px"
|
|
2196
|
+
},
|
|
2197
|
+
assistantMessage: {
|
|
2198
|
+
backgroundColor: "#F3F4F6",
|
|
2199
|
+
color: "#111827",
|
|
2200
|
+
marginRight: "40px"
|
|
2201
|
+
},
|
|
2202
|
+
messageContent: {
|
|
2203
|
+
whiteSpace: "pre-wrap"
|
|
2204
|
+
},
|
|
2205
|
+
spinner: {
|
|
2206
|
+
display: "inline-block",
|
|
2207
|
+
animation: "spin 1s linear infinite"
|
|
2208
|
+
},
|
|
2209
|
+
successContainer: {
|
|
2210
|
+
marginTop: "12px",
|
|
2211
|
+
display: "flex",
|
|
2212
|
+
flexDirection: "column",
|
|
2213
|
+
gap: "8px"
|
|
2214
|
+
},
|
|
2215
|
+
successBadge: {
|
|
2216
|
+
fontSize: "12px",
|
|
2217
|
+
color: "#059669",
|
|
2218
|
+
fontWeight: 500
|
|
2219
|
+
},
|
|
2220
|
+
reloadButton: {
|
|
2221
|
+
padding: "8px 16px",
|
|
2222
|
+
backgroundColor: "#059669",
|
|
2223
|
+
color: "white",
|
|
2224
|
+
border: "none",
|
|
2225
|
+
borderRadius: "6px",
|
|
2226
|
+
fontSize: "13px",
|
|
2227
|
+
fontWeight: 500,
|
|
2228
|
+
cursor: "pointer"
|
|
2229
|
+
},
|
|
2230
|
+
errorBadge: {
|
|
2231
|
+
marginTop: "8px",
|
|
2232
|
+
fontSize: "12px",
|
|
2233
|
+
color: "#DC2626",
|
|
2234
|
+
fontWeight: 500
|
|
2235
|
+
},
|
|
2236
|
+
clearButton: {
|
|
2237
|
+
background: "none",
|
|
2238
|
+
border: "none",
|
|
2239
|
+
color: "#6B7280",
|
|
2240
|
+
fontSize: "12px",
|
|
2241
|
+
cursor: "pointer",
|
|
2242
|
+
padding: "8px",
|
|
2243
|
+
textAlign: "center",
|
|
2244
|
+
width: "100%"
|
|
2245
|
+
},
|
|
2246
|
+
inputForm: {
|
|
2247
|
+
display: "flex",
|
|
2248
|
+
gap: "8px",
|
|
2249
|
+
padding: "16px",
|
|
2250
|
+
borderTop: "1px solid #E5E7EB"
|
|
2251
|
+
},
|
|
2252
|
+
input: {
|
|
2253
|
+
flex: 1,
|
|
2254
|
+
padding: "12px 16px",
|
|
2255
|
+
border: "1px solid #E5E7EB",
|
|
2256
|
+
borderRadius: "8px",
|
|
2257
|
+
fontSize: "14px",
|
|
2258
|
+
outline: "none"
|
|
2259
|
+
},
|
|
2260
|
+
submitButton: {
|
|
2261
|
+
padding: "12px 20px",
|
|
2262
|
+
backgroundColor: "#3B82F6",
|
|
2263
|
+
color: "white",
|
|
2264
|
+
border: "none",
|
|
2265
|
+
borderRadius: "8px",
|
|
2266
|
+
fontSize: "16px",
|
|
2267
|
+
cursor: "pointer",
|
|
2268
|
+
fontWeight: 600
|
|
2269
|
+
},
|
|
2270
|
+
submitButtonDisabled: {
|
|
2271
|
+
backgroundColor: "#93C5FD",
|
|
2272
|
+
cursor: "not-allowed"
|
|
2273
|
+
},
|
|
2274
|
+
overridesList: {
|
|
2275
|
+
padding: "16px",
|
|
2276
|
+
flex: 1,
|
|
2277
|
+
overflowY: "auto",
|
|
2278
|
+
overscrollBehavior: "contain"
|
|
2279
|
+
},
|
|
2280
|
+
overrideItem: {
|
|
2281
|
+
display: "flex",
|
|
2282
|
+
alignItems: "center",
|
|
2283
|
+
justifyContent: "space-between",
|
|
2284
|
+
padding: "16px",
|
|
2285
|
+
backgroundColor: "#F9FAFB",
|
|
2286
|
+
borderRadius: "8px",
|
|
2287
|
+
marginBottom: "12px"
|
|
2288
|
+
},
|
|
2289
|
+
overrideInfo: {
|
|
2290
|
+
flex: 1,
|
|
2291
|
+
marginRight: "16px"
|
|
2292
|
+
},
|
|
2293
|
+
overrideName: {
|
|
2294
|
+
margin: "0 0 4px 0",
|
|
2295
|
+
fontSize: "14px",
|
|
2296
|
+
fontWeight: 600,
|
|
2297
|
+
color: "#111827"
|
|
2298
|
+
},
|
|
2299
|
+
overrideDescription: {
|
|
2300
|
+
margin: 0,
|
|
2301
|
+
fontSize: "13px",
|
|
2302
|
+
color: "#6B7280"
|
|
2303
|
+
},
|
|
2304
|
+
toggle: {
|
|
2305
|
+
padding: "6px 12px",
|
|
2306
|
+
borderRadius: "4px",
|
|
2307
|
+
border: "none",
|
|
2308
|
+
fontSize: "12px",
|
|
2309
|
+
fontWeight: 600,
|
|
2310
|
+
cursor: "pointer"
|
|
2311
|
+
},
|
|
2312
|
+
toggleOn: {
|
|
2313
|
+
backgroundColor: "#059669",
|
|
2314
|
+
color: "white"
|
|
2315
|
+
},
|
|
2316
|
+
toggleOff: {
|
|
2317
|
+
backgroundColor: "#E5E7EB",
|
|
2318
|
+
color: "#6B7280"
|
|
2319
|
+
},
|
|
2320
|
+
toggleDisabled: {
|
|
2321
|
+
opacity: 0.5,
|
|
2322
|
+
cursor: "not-allowed"
|
|
2323
|
+
},
|
|
2324
|
+
overrideActions: {
|
|
2325
|
+
display: "flex",
|
|
2326
|
+
gap: "8px",
|
|
2327
|
+
marginTop: "8px"
|
|
2328
|
+
},
|
|
2329
|
+
actionButton: {
|
|
2330
|
+
padding: "4px 8px",
|
|
2331
|
+
fontSize: "11px",
|
|
2332
|
+
fontWeight: 500,
|
|
2333
|
+
border: "1px solid #E5E7EB",
|
|
2334
|
+
borderRadius: "4px",
|
|
2335
|
+
backgroundColor: "white",
|
|
2336
|
+
color: "#6B7280",
|
|
2337
|
+
cursor: "pointer"
|
|
2338
|
+
},
|
|
2339
|
+
actionButtonDisabled: {
|
|
2340
|
+
opacity: 0.5,
|
|
2341
|
+
cursor: "not-allowed"
|
|
2342
|
+
},
|
|
2343
|
+
deleteButton: {
|
|
2344
|
+
color: "#DC2626",
|
|
2345
|
+
borderColor: "#FCA5A5"
|
|
2346
|
+
},
|
|
2347
|
+
editHeader: {
|
|
2348
|
+
display: "flex",
|
|
2349
|
+
alignItems: "center",
|
|
2350
|
+
justifyContent: "space-between",
|
|
2351
|
+
padding: "8px 16px",
|
|
2352
|
+
backgroundColor: "#EFF6FF",
|
|
2353
|
+
borderBottom: "1px solid #BFDBFE"
|
|
2354
|
+
},
|
|
2355
|
+
editHeaderText: {
|
|
2356
|
+
fontSize: "13px",
|
|
2357
|
+
fontWeight: 600,
|
|
2358
|
+
color: "#1D4ED8"
|
|
2359
|
+
},
|
|
2360
|
+
editHeaderClose: {
|
|
2361
|
+
background: "none",
|
|
2362
|
+
border: "none",
|
|
2363
|
+
cursor: "pointer",
|
|
2364
|
+
fontSize: "14px",
|
|
2365
|
+
color: "#1D4ED8",
|
|
2366
|
+
padding: "2px 6px",
|
|
2367
|
+
borderRadius: "4px"
|
|
2368
|
+
}
|
|
2369
|
+
};
|
|
2370
|
+
export {
|
|
2371
|
+
SidekickPanel,
|
|
2372
|
+
SidekickProvider,
|
|
2373
|
+
configureJsxRuntime,
|
|
2374
|
+
createOverride,
|
|
2375
|
+
getFlag,
|
|
2376
|
+
getRegisteredOverrides,
|
|
2377
|
+
getSeenComponentsFromJsx,
|
|
2378
|
+
isJsxRuntimeConfigured,
|
|
2379
|
+
loadFlags,
|
|
2380
|
+
onConfigChange,
|
|
2381
|
+
registerOverride,
|
|
2382
|
+
saveFlags,
|
|
2383
|
+
setFlag,
|
|
2384
|
+
toggleFlag,
|
|
2385
|
+
useActions,
|
|
2386
|
+
useAddedColumns,
|
|
2387
|
+
useColumnOrder,
|
|
2388
|
+
useColumnRenames,
|
|
2389
|
+
useComputedField,
|
|
2390
|
+
useEventEmitter,
|
|
2391
|
+
useFilter,
|
|
2392
|
+
useGroupByOptions,
|
|
2393
|
+
useHiddenColumns,
|
|
2394
|
+
useKeyboardShortcuts,
|
|
2395
|
+
useMenuItems,
|
|
2396
|
+
usePropsModifier,
|
|
2397
|
+
useSidekick,
|
|
2398
|
+
useSidekickSafe,
|
|
2399
|
+
useSortOptions,
|
|
2400
|
+
useTabs,
|
|
2401
|
+
useValidations
|
|
2402
|
+
};
|
|
2403
|
+
//# sourceMappingURL=index.mjs.map
|