@solidxai/core-ui 0.1.7-beta.9 → 0.1.7

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.
@@ -1,20 +1,32 @@
1
- import React from "react";
2
- import { SolidInput, SolidSelect, SolidSwitch, SolidTextarea } from "../../../shad-cn-ui";
1
+ import React, { useState } from "react";
2
+ import {
3
+ SolidButton,
4
+ SolidDialog,
5
+ SolidDialogBody,
6
+ SolidDialogFooter,
7
+ SolidDialogHeader,
8
+ SolidDialogTitle,
9
+ SolidInput,
10
+ SolidSelect,
11
+ SolidSwitch,
12
+ SolidTextarea,
13
+ } from "../../../shad-cn-ui";
14
+
3
15
 
4
16
  export interface ModelBehavior {
5
17
  streaming: boolean;
6
18
  custom: string;
7
19
  }
8
20
 
9
- export interface ProviderConfig {
10
- provider: string;
21
+ export interface ProviderEntry {
22
+ type: string;
11
23
  apiKey: string;
12
- model: string;
13
24
  baseUrl?: string;
14
25
  }
15
26
 
16
27
  export interface ModelEntry {
17
- providerKey: string;
28
+ providerId: string;
29
+ model: string;
18
30
  behavior: ModelBehavior;
19
31
  }
20
32
 
@@ -23,125 +35,353 @@ export interface SolidAiConfig {
23
35
  default: ModelEntry;
24
36
  fast: ModelEntry;
25
37
  };
26
- providers: Record<string, ProviderConfig>;
38
+ providers: Record<string, ProviderEntry>;
27
39
  }
28
40
 
29
- interface Props {
30
- providerKey: string;
31
- providerConfig: ProviderConfig;
32
- behavior: ModelBehavior;
33
- allProviders: Record<string, ProviderConfig>;
34
- onProviderKeyChange: (newProviderKey: string, config: ProviderConfig) => void;
35
- onProviderConfigChange: (providerKey: string, config: ProviderConfig) => void;
36
- onBehaviorChange: (behavior: ModelBehavior) => void;
37
- }
38
41
 
39
- const PROVIDER_OPTIONS = [
42
+ const PROVIDER_TYPE_OPTIONS = [
40
43
  { label: "OpenAI", value: "openai" },
41
44
  { label: "Anthropic", value: "anthropic" },
42
45
  { label: "OpenAI Compatible", value: "openai-compatible" },
43
46
  { label: "Anthropic Compatible", value: "anthropic-compatible" },
44
47
  ];
45
48
 
46
- const COMPATIBLE_PROVIDERS = ["openai-compatible", "anthropic-compatible"];
49
+ const COMPATIBLE_TYPES = ["openai-compatible", "anthropic-compatible"];
47
50
 
48
- const DEFAULT_PROVIDER_CONFIGS: Record<string, ProviderConfig> = {
49
- openai: { provider: "openai", apiKey: "", model: "" },
50
- anthropic: { provider: "anthropic", apiKey: "", model: "" },
51
- "openai-compatible": { provider: "openai-compatible", apiKey: "", model: "", baseUrl: "" },
52
- "anthropic-compatible": { provider: "anthropic-compatible", apiKey: "", model: "", baseUrl: "" },
51
+ const BUILT_IN_TYPES = ["openai", "anthropic"];
52
+
53
+ const DEFAULT_BUILT_IN_PROVIDERS: Record<string, ProviderEntry> = {
54
+ openai: { type: "openai", apiKey: "" },
55
+ anthropic: { type: "anthropic", apiKey: "" },
53
56
  };
54
57
 
55
- export const AiModelConfigTab = ({
56
- providerKey,
57
- providerConfig,
58
- behavior,
59
- allProviders,
60
- onProviderKeyChange,
61
- onProviderConfigChange,
62
- onBehaviorChange,
63
- }: Props) => {
64
- const isCompatible = COMPATIBLE_PROVIDERS.includes(providerKey);
65
-
66
- const handleProviderSelect = (value: string) => {
67
- const existingConfig = allProviders[value];
68
- const newConfig = existingConfig ?? DEFAULT_PROVIDER_CONFIGS[value] ?? { provider: value, apiKey: "", model: "" };
69
- onProviderKeyChange(value, newConfig);
70
- };
58
+ export const ensureBuiltInProviders = (providers: Record<string, ProviderEntry>): Record<string, ProviderEntry> => ({
59
+ ...DEFAULT_BUILT_IN_PROVIDERS,
60
+ ...providers,
61
+ });
62
+
63
+ const cardStyle: React.CSSProperties = {
64
+ border: "1px solid var(--solid-border-color, #e2e8f0)",
65
+ borderRadius: "0.5rem",
66
+ padding: "1.25rem",
67
+ background: "var(--solid-card-bg, var(--solid-surface-bg, transparent))",
68
+ };
69
+
70
+
71
+ interface ProviderModalProps {
72
+ visible: boolean;
73
+ onHide: () => void;
74
+ providers: Record<string, ProviderEntry>;
75
+ onProvidersChange: (providers: Record<string, ProviderEntry>) => void;
76
+ editKey?: string | null; // null = add mode, string = edit mode
77
+ }
78
+
79
+ const ProviderModal = ({ visible, onHide, providers, onProvidersChange, editKey }: ProviderModalProps) => {
80
+ const isEdit = !!editKey;
81
+ const existingEntry = isEdit ? providers[editKey] : null;
82
+
83
+ const [providerType, setProviderType] = useState(existingEntry?.type ?? "");
84
+ const [providerName, setProviderName] = useState(editKey && !BUILT_IN_TYPES.includes(editKey) ? editKey : "");
85
+ const [providerBaseUrl, setProviderBaseUrl] = useState(existingEntry?.baseUrl ?? "");
86
+ const [providerApiKey, setProviderApiKey] = useState(existingEntry?.apiKey ?? "");
87
+
88
+ const isCompatible = COMPATIBLE_TYPES.includes(providerType);
89
+
90
+ // Reset state when modal opens with new data
91
+ React.useEffect(() => {
92
+ if (visible) {
93
+ const entry = editKey ? providers[editKey] : null;
94
+ setProviderType(entry?.type ?? "");
95
+ setProviderName(editKey && !BUILT_IN_TYPES.includes(editKey) ? editKey : "");
96
+ setProviderBaseUrl(entry?.baseUrl ?? "");
97
+ setProviderApiKey(entry?.apiKey ?? "");
98
+ }
99
+ }, [visible, editKey]);
100
+
101
+ // In add mode, only show compatible types (built-ins are always pre-added)
102
+ // In edit mode, show all types but lock the value
103
+ const typeOptions = isEdit
104
+ ? PROVIDER_TYPE_OPTIONS
105
+ : PROVIDER_TYPE_OPTIONS.filter((opt) => COMPATIBLE_TYPES.includes(opt.value));
106
+
107
+ const handleSave = () => {
108
+ if (!providerType) return;
71
109
 
72
- const handleConfigUpdate = (key: keyof ProviderConfig, value: string) => {
73
- onProviderConfigChange(providerKey, { ...providerConfig, [key]: value });
110
+ let key: string;
111
+ const entry: ProviderEntry = { type: providerType, apiKey: providerApiKey };
112
+
113
+ if (isCompatible) {
114
+ if (!providerName.trim()) return;
115
+ key = providerName.trim();
116
+ entry.baseUrl = providerBaseUrl;
117
+ } else {
118
+ key = providerType;
119
+ }
120
+
121
+ // In add mode, don't overwrite existing
122
+ if (!isEdit && providers[key]) return;
123
+
124
+ const next = { ...providers };
125
+
126
+ // If editing and key changed (shouldn't happen for built-in), remove old
127
+ if (isEdit && editKey !== key) {
128
+ delete next[editKey!];
129
+ }
130
+
131
+ next[key] = entry;
132
+ onProvidersChange(next);
133
+ onHide();
74
134
  };
75
135
 
76
- const cardStyle: React.CSSProperties = {
77
- border: "1px solid var(--solid-border-color, #e2e8f0)",
78
- borderRadius: "0.5rem",
79
- padding: "1.25rem",
80
- background: "var(--solid-card-bg, var(--solid-surface-bg, transparent))",
136
+ const handleRemove = () => {
137
+ if (!editKey) return;
138
+ const next = { ...providers };
139
+ delete next[editKey];
140
+ onProvidersChange(next);
141
+ onHide();
81
142
  };
82
143
 
144
+ const canSave = providerType && (isCompatible ? providerName.trim() : true);
145
+
83
146
  return (
84
- <div className="flex flex-column gap-4">
85
- <div style={cardStyle}>
86
- <p className="solid-settings-subheading">Provider Config</p>
87
- <div className="flex flex-column gap-3 mt-3">
88
- <div className="flex flex-column gap-2">
89
- <label className="form-field-label">Provider</label>
90
- <SolidSelect
91
- className="w-full"
92
- value={providerKey}
93
- options={PROVIDER_OPTIONS}
94
- onChange={(e) => handleProviderSelect(e.value)}
95
- placeholder="Select Provider"
96
- />
97
- </div>
98
- {isCompatible && (
99
- <div className="flex flex-column gap-2">
100
- <label className="form-field-label">Base URL</label>
101
- <SolidInput
102
- placeholder="http://localhost:8000"
103
- value={providerConfig?.baseUrl || ""}
104
- onChange={(e) => handleConfigUpdate("baseUrl", e.target.value)}
147
+ <SolidDialog open={visible} onOpenChange={(open) => !open && onHide()} style={{ width: "500px" }}>
148
+ <SolidDialogHeader>
149
+ <SolidDialogTitle>
150
+ {isEdit
151
+ ? `Edit Provider — ${BUILT_IN_TYPES.includes(editKey!) ? PROVIDER_TYPE_OPTIONS.find((o) => o.value === editKey)?.label : editKey}`
152
+ : "Add Provider"}
153
+ </SolidDialogTitle>
154
+ </SolidDialogHeader>
155
+ <SolidDialogBody>
156
+ <div className="flex flex-column gap-3">
157
+ {!(isEdit && BUILT_IN_TYPES.includes(editKey!)) && (
158
+ <div>
159
+ <label className="form-field-label">Provider Type</label>
160
+ <SolidSelect
105
161
  className="w-full"
162
+ value={providerType}
163
+ options={typeOptions}
164
+ onChange={(e) => {
165
+ setProviderType(e.value);
166
+ if (!isEdit) {
167
+ setProviderName("");
168
+ setProviderBaseUrl("");
169
+ }
170
+ }}
171
+ placeholder="Select Provider Type"
172
+ disabled={isEdit}
106
173
  />
107
174
  </div>
108
175
  )}
109
- <div className="flex flex-column gap-2">
176
+ {isCompatible && (
177
+ <>
178
+ {!isEdit && (
179
+ <div>
180
+ <label className="form-field-label">Name (unique identifier)</label>
181
+ <SolidInput
182
+ placeholder="e.g. openrouter, together-ai"
183
+ value={providerName}
184
+ onChange={(e) => setProviderName(e.target.value)}
185
+ className="w-full"
186
+ />
187
+ </div>
188
+ )}
189
+ <div>
190
+ <label className="form-field-label">Base URL</label>
191
+ <SolidInput
192
+ placeholder="https://openrouter.ai/api/v1"
193
+ value={providerBaseUrl}
194
+ onChange={(e) => setProviderBaseUrl(e.target.value)}
195
+ className="w-full"
196
+ />
197
+ </div>
198
+ </>
199
+ )}
200
+ <div>
110
201
  <label className="form-field-label">API Key</label>
111
202
  <SolidInput
112
203
  type="password"
204
+ value={providerApiKey}
205
+ onChange={(e) => setProviderApiKey(e.target.value)}
206
+ className="w-full"
207
+ />
208
+ </div>
209
+ </div>
210
+ </SolidDialogBody>
211
+ <SolidDialogFooter>
212
+ <div className="flex justify-content-between w-full">
213
+ <div>
214
+ {isEdit && !BUILT_IN_TYPES.includes(editKey!) && (
215
+ <SolidButton variant="ghost" onClick={handleRemove} style={{ color: "var(--solid-danger-color, #ef4444)" }}>
216
+ Remove
217
+ </SolidButton>
218
+ )}
219
+ </div>
220
+ <div className="flex gap-2">
221
+ <SolidButton variant="outline" onClick={onHide}>
222
+ Cancel
223
+ </SolidButton>
224
+ <SolidButton onClick={handleSave} disabled={!canSave}>
225
+ {isEdit ? "Save" : "Add"}
226
+ </SolidButton>
227
+ </div>
228
+ </div>
229
+ </SolidDialogFooter>
230
+ </SolidDialog>
231
+ );
232
+ };
233
+
234
+ // --- Providers Tab (List View) ---
235
+
236
+ interface ProvidersTabProps {
237
+ providers: Record<string, ProviderEntry>;
238
+ onProvidersChange: (providers: Record<string, ProviderEntry>) => void;
239
+ showAddModal?: boolean;
240
+ onAddModalClose?: () => void;
241
+ }
242
+
243
+ export const ProvidersTab = ({ providers, onProvidersChange, showAddModal, onAddModalClose }: ProvidersTabProps) => {
244
+ const [editKey, setEditKey] = useState<string | null>(null);
245
+ const [modalVisible, setModalVisible] = useState(false);
246
+
247
+ // Ensure built-in providers are always present
248
+ const allProviders = ensureBuiltInProviders(providers);
249
+
250
+ // Open modal when parent triggers add
251
+ React.useEffect(() => {
252
+ if (showAddModal) {
253
+ setEditKey(null);
254
+ setModalVisible(true);
255
+ }
256
+ }, [showAddModal]);
257
+
258
+ const providerEntries = Object.entries(allProviders);
259
+
260
+ const handleRowClick = (key: string) => {
261
+ setEditKey(key);
262
+ setModalVisible(true);
263
+ };
264
+
265
+ return (
266
+ <>
267
+ <div className="solid-simple-table">
268
+ <table style={{ width: "100%" }}>
269
+ <thead>
270
+ <tr>
271
+ <th style={{ textAlign: "left", padding: "0.75rem 1rem" }}>Name</th>
272
+ <th style={{ textAlign: "left", padding: "0.75rem 1rem" }}>Type</th>
273
+ <th style={{ textAlign: "left", padding: "0.75rem 1rem" }}>API Key</th>
274
+ <th style={{ textAlign: "left", padding: "0.75rem 1rem" }}>Base URL</th>
275
+ </tr>
276
+ </thead>
277
+ <tbody>
278
+ {providerEntries.length === 0 && (
279
+ <tr>
280
+ <td colSpan={4} style={{ textAlign: "center", padding: "2rem 1rem", opacity: 0.5 }}>
281
+ No providers configured.
282
+ </td>
283
+ </tr>
284
+ )}
285
+ {providerEntries.map(([key, entry]) => {
286
+ const typeLabel = PROVIDER_TYPE_OPTIONS.find((o) => o.value === entry.type)?.label ?? entry.type;
287
+ const isBuiltIn = BUILT_IN_TYPES.includes(key);
288
+ const displayName = isBuiltIn ? typeLabel : key;
289
+ const maskedKey = entry.apiKey ? "\u2022".repeat(Math.min(entry.apiKey.length, 8)) : "-";
290
+
291
+ return (
292
+ <tr
293
+ key={key}
294
+ onClick={() => handleRowClick(key)}
295
+ style={{ cursor: "pointer" }}
296
+ className="solid-table-row-hover"
297
+ >
298
+ <td style={{ padding: "0.75rem 1rem", fontWeight: 500 }}>{displayName}</td>
299
+ <td style={{ padding: "0.75rem 1rem" }}>{typeLabel}</td>
300
+ <td style={{ padding: "0.75rem 1rem" }}>{maskedKey}</td>
301
+ <td style={{ padding: "0.75rem 1rem" }}>{entry.baseUrl || "-"}</td>
302
+ </tr>
303
+ );
304
+ })}
305
+ </tbody>
306
+ </table>
307
+ </div>
308
+
309
+ <ProviderModal
310
+ visible={modalVisible}
311
+ onHide={() => {
312
+ setModalVisible(false);
313
+ setEditKey(null);
314
+ onAddModalClose?.();
315
+ }}
316
+ providers={allProviders}
317
+ onProvidersChange={onProvidersChange}
318
+ editKey={editKey}
319
+ />
320
+ </>
321
+ );
322
+ };
323
+
324
+ // --- Model Config Tab (used for Intelligent Model & Fast Model) ---
325
+
326
+ interface ModelConfigTabProps {
327
+ modelEntry: ModelEntry;
328
+ providers: Record<string, ProviderEntry>;
329
+ onModelEntryChange: (entry: ModelEntry) => void;
330
+ }
331
+
332
+ export const ModelConfigTab = ({ modelEntry, providers, onModelEntryChange }: ModelConfigTabProps) => {
333
+ const providerOptions = Object.entries(providers).map(([key, entry]) => {
334
+ const typeLabel = PROVIDER_TYPE_OPTIONS.find((o) => o.value === entry.type)?.label ?? entry.type;
335
+ const label = BUILT_IN_TYPES.includes(key) ? typeLabel : `${key} (${typeLabel})`;
336
+ return { label, value: key };
337
+ });
338
+
339
+ return (
340
+ <div className="flex flex-column gap-4">
341
+ <div style={{ ...cardStyle, width: "50%" }}>
342
+ <p className="solid-settings-subheading">Model Config</p>
343
+ <div className="flex flex-column gap-3 mt-3">
344
+ <div>
345
+ <label className="form-field-label">Provider</label>
346
+ <SolidSelect
113
347
  className="w-full"
114
- value={providerConfig?.apiKey || ""}
115
- onChange={(e) => handleConfigUpdate("apiKey", e.target.value)}
348
+ value={modelEntry.providerId}
349
+ options={providerOptions}
350
+ onChange={(e) => onModelEntryChange({ ...modelEntry, providerId: e.value })}
351
+ placeholder="Select Provider"
116
352
  />
117
353
  </div>
118
- <div className="flex flex-column gap-2">
354
+ <div>
119
355
  <label className="form-field-label">Model</label>
120
356
  <SolidInput
121
357
  placeholder="e.g. gpt-4o-mini"
122
- value={providerConfig?.model || ""}
123
- onChange={(e) => handleConfigUpdate("model", e.target.value)}
358
+ value={modelEntry.model || ""}
359
+ onChange={(e) => onModelEntryChange({ ...modelEntry, model: e.target.value })}
124
360
  className="w-full"
125
361
  />
126
362
  </div>
127
363
  </div>
128
364
  </div>
129
365
 
130
- <div style={cardStyle}>
366
+ <div style={{ ...cardStyle, width: "50%" }}>
131
367
  <p className="solid-settings-subheading">Behavior</p>
132
368
  <div className="flex flex-column gap-3 mt-3">
133
369
  <div className="flex align-items-center gap-2">
134
370
  <SolidSwitch
135
- checked={behavior.streaming}
136
- onChange={(val) => onBehaviorChange({ ...behavior, streaming: val })}
371
+ checked={modelEntry.behavior.streaming}
372
+ onChange={(val) =>
373
+ onModelEntryChange({ ...modelEntry, behavior: { ...modelEntry.behavior, streaming: val } })
374
+ }
137
375
  />
138
376
  <label className="form-field-label" style={{ marginBottom: 0 }}>Streaming</label>
139
377
  </div>
140
- <div className="flex flex-column gap-2">
378
+ <div>
141
379
  <label className="form-field-label">Custom Params (JSON)</label>
142
380
  <SolidTextarea
143
- value={behavior.custom}
144
- onChange={(e) => onBehaviorChange({ ...behavior, custom: e.target.value })}
381
+ value={modelEntry.behavior.custom}
382
+ onChange={(e) =>
383
+ onModelEntryChange({ ...modelEntry, behavior: { ...modelEntry.behavior, custom: e.target.value } })
384
+ }
145
385
  placeholder='{ "temperature": 0.7, "maxTokens": 1000 }'
146
386
  rows={4}
147
387
  className="w-full"
@@ -149,7 +389,6 @@ export const AiModelConfigTab = ({
149
389
  </div>
150
390
  </div>
151
391
  </div>
152
-
153
392
  </div>
154
393
  );
155
394
  };
@@ -13,8 +13,9 @@ type SolidTabGroupProps = {
13
13
  listClassName?: string;
14
14
  panelClassName?: string;
15
15
  tabPosition?: "left" | "center" | "right";
16
+ extra?: React.ReactNode;
16
17
  };
17
18
  export declare function SolidTab(_props: SolidTabProps): null;
18
- export declare function SolidTabGroup({ tabs, value, onValueChange, className, listClassName, panelClassName, tabPosition, }: SolidTabGroupProps): import("react/jsx-runtime").JSX.Element;
19
+ export declare function SolidTabGroup({ tabs, value, onValueChange, className, listClassName, panelClassName, tabPosition, extra, }: SolidTabGroupProps): import("react/jsx-runtime").JSX.Element;
19
20
  export {};
20
21
  //# sourceMappingURL=SolidTabs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SolidTabs.d.ts","sourceRoot":"","sources":["../../../src/components/shad-cn-ui/SolidTabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;CAC3C,CAAC;AAMF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,aAAa,QAE7C;AAED,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,cAAc,EACd,WAAoB,GACrB,EAAE,kBAAkB,2CAiDpB"}
1
+ {"version":3,"file":"SolidTabs.d.ts","sourceRoot":"","sources":["../../../src/components/shad-cn-ui/SolidTabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC1C,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACzB,CAAC;AAMF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,aAAa,QAE7C;AAED,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,cAAc,EACd,WAAoB,EACpB,KAAK,GACN,EAAE,kBAAkB,2CAqDpB"}
@@ -10,11 +10,11 @@ export function SolidTab(_props) {
10
10
  return null;
11
11
  }
12
12
  export function SolidTabGroup(_a) {
13
- var tabs = _a.tabs, value = _a.value, onValueChange = _a.onValueChange, className = _a.className, listClassName = _a.listClassName, panelClassName = _a.panelClassName, _b = _a.tabPosition, tabPosition = _b === void 0 ? "left" : _b;
14
- return (_jsxs("div", { className: cx("solid-notebook", "solid-tabs", "solid-tabs--".concat(tabPosition), className), children: [_jsx("div", { className: cx("solid-notebook-tablist", "solid-tabs-list", listClassName), role: "tablist", children: tabs.map(function (tab) {
15
- var isActive = tab.value === value;
16
- return (_jsx("button", { type: "button", role: "tab", "aria-selected": isActive, "aria-controls": "solid-tab-panel-".concat(tab.value), id: "solid-tab-".concat(tab.value), className: cx("solid-notebook-tab-trigger", "solid-tabs-trigger", tab.hasError && "error", isActive && "active", isActive && "is-active"), onClick: function () { return onValueChange(tab.value); }, children: tab.label }, tab.value));
17
- }) }), tabs.map(function (tab) {
13
+ var tabs = _a.tabs, value = _a.value, onValueChange = _a.onValueChange, className = _a.className, listClassName = _a.listClassName, panelClassName = _a.panelClassName, _b = _a.tabPosition, tabPosition = _b === void 0 ? "left" : _b, extra = _a.extra;
14
+ return (_jsxs("div", { className: cx("solid-notebook", "solid-tabs", "solid-tabs--".concat(tabPosition), className), children: [_jsxs("div", { className: cx("solid-notebook-tablist", "solid-tabs-list", listClassName), role: "tablist", style: extra ? { display: "flex", alignItems: "center", justifyContent: "space-between" } : undefined, children: [_jsx("div", { style: extra ? { display: "flex" } : undefined, children: tabs.map(function (tab) {
15
+ var isActive = tab.value === value;
16
+ return (_jsx("button", { type: "button", role: "tab", "aria-selected": isActive, "aria-controls": "solid-tab-panel-".concat(tab.value), id: "solid-tab-".concat(tab.value), className: cx("solid-notebook-tab-trigger", "solid-tabs-trigger", tab.hasError && "error", isActive && "active", isActive && "is-active"), onClick: function () { return onValueChange(tab.value); }, children: tab.label }, tab.value));
17
+ }) }), extra && _jsx("div", { children: extra })] }), tabs.map(function (tab) {
18
18
  var isActive = tab.value === value;
19
19
  return (_jsx("div", { role: "tabpanel", id: "solid-tab-panel-".concat(tab.value), "aria-labelledby": "solid-tab-".concat(tab.value), hidden: !isActive, className: cx("solid-notebook-content", "solid-tabs-panel", panelClassName), children: isActive ? tab.content : null }, tab.value));
20
20
  })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"SolidTabs.js","sourceRoot":"","sources":["../../../src/components/shad-cn-ui/SolidTabs.tsx"],"names":[],"mappings":";AAmBA,SAAS,EAAE;IAAC,eAA2C;SAA3C,UAA2C,EAA3C,qBAA2C,EAA3C,IAA2C;QAA3C,0BAA2C;;IACrD,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAqB;IAC5C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAQT;QAPnB,IAAI,UAAA,EACJ,KAAK,WAAA,EACL,aAAa,mBAAA,EACb,SAAS,eAAA,EACT,aAAa,mBAAA,EACb,cAAc,oBAAA,EACd,mBAAoB,EAApB,WAAW,mBAAG,MAAM,KAAA;IAEpB,OAAO,CACL,eAAK,SAAS,EAAE,EAAE,CAAC,gBAAgB,EAAE,YAAY,EAAE,sBAAe,WAAW,CAAE,EAAE,SAAS,CAAC,aACzF,cACE,SAAS,EAAE,EAAE,CAAC,wBAAwB,EAAE,iBAAiB,EAAE,aAAa,CAAC,EACzE,IAAI,EAAC,SAAS,YAEb,IAAI,CAAC,GAAG,CAAC,UAAC,GAAG;oBACZ,IAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC;oBACrC,OAAO,CACL,iBAEE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,KAAK,mBACK,QAAQ,mBACR,0BAAmB,GAAG,CAAC,KAAK,CAAE,EAC7C,EAAE,EAAE,oBAAa,GAAG,CAAC,KAAK,CAAE,EAC5B,SAAS,EAAE,EAAE,CACX,4BAA4B,EAC5B,oBAAoB,EACpB,GAAG,CAAC,QAAQ,IAAI,OAAO,EACvB,QAAQ,IAAI,QAAQ,EACpB,QAAQ,IAAI,WAAW,CACxB,EACD,OAAO,EAAE,cAAM,OAAA,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAxB,CAAwB,YAEtC,GAAG,CAAC,KAAK,IAfL,GAAG,CAAC,KAAK,CAgBP,CACV,CAAC;gBACJ,CAAC,CAAC,GACE,EAEL,IAAI,CAAC,GAAG,CAAC,UAAC,GAAG;gBACZ,IAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC;gBACrC,OAAO,CACL,cAEE,IAAI,EAAC,UAAU,EACf,EAAE,EAAE,0BAAmB,GAAG,CAAC,KAAK,CAAE,qBACjB,oBAAa,GAAG,CAAC,KAAK,CAAE,EACzC,MAAM,EAAE,CAAC,QAAQ,EACjB,SAAS,EAAE,EAAE,CAAC,wBAAwB,EAAE,kBAAkB,EAAE,cAAc,CAAC,YAE1E,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,IAPzB,GAAG,CAAC,KAAK,CAQV,CACP,CAAC;YACJ,CAAC,CAAC,IACE,CACP,CAAC;AACJ,CAAC","sourcesContent":["import React from \"react\";\n\ntype SolidTabProps = {\n value: string;\n label: React.ReactNode;\n content: React.ReactNode;\n hasError?: boolean;\n};\n\ntype SolidTabGroupProps = {\n tabs: SolidTabProps[];\n value: string;\n onValueChange: (value: string) => void;\n className?: string;\n listClassName?: string;\n panelClassName?: string;\n tabPosition?: \"left\" | \"center\" | \"right\";\n};\n\nfunction cx(...parts: Array<string | false | undefined>) {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport function SolidTab(_props: SolidTabProps) {\n return null;\n}\n\nexport function SolidTabGroup({\n tabs,\n value,\n onValueChange,\n className,\n listClassName,\n panelClassName,\n tabPosition = \"left\",\n}: SolidTabGroupProps) {\n return (\n <div className={cx(\"solid-notebook\", \"solid-tabs\", `solid-tabs--${tabPosition}`, className)}>\n <div\n className={cx(\"solid-notebook-tablist\", \"solid-tabs-list\", listClassName)}\n role=\"tablist\"\n >\n {tabs.map((tab) => {\n const isActive = tab.value === value;\n return (\n <button\n key={tab.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={`solid-tab-panel-${tab.value}`}\n id={`solid-tab-${tab.value}`}\n className={cx(\n \"solid-notebook-tab-trigger\",\n \"solid-tabs-trigger\",\n tab.hasError && \"error\",\n isActive && \"active\",\n isActive && \"is-active\",\n )}\n onClick={() => onValueChange(tab.value)}\n >\n {tab.label}\n </button>\n );\n })}\n </div>\n\n {tabs.map((tab) => {\n const isActive = tab.value === value;\n return (\n <div\n key={tab.value}\n role=\"tabpanel\"\n id={`solid-tab-panel-${tab.value}`}\n aria-labelledby={`solid-tab-${tab.value}`}\n hidden={!isActive}\n className={cx(\"solid-notebook-content\", \"solid-tabs-panel\", panelClassName)}\n >\n {isActive ? tab.content : null}\n </div>\n );\n })}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"SolidTabs.js","sourceRoot":"","sources":["../../../src/components/shad-cn-ui/SolidTabs.tsx"],"names":[],"mappings":";AAoBA,SAAS,EAAE;IAAC,eAA2C;SAA3C,UAA2C,EAA3C,qBAA2C,EAA3C,IAA2C;QAA3C,0BAA2C;;IACrD,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAqB;IAC5C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAST;QARnB,IAAI,UAAA,EACJ,KAAK,WAAA,EACL,aAAa,mBAAA,EACb,SAAS,eAAA,EACT,aAAa,mBAAA,EACb,cAAc,oBAAA,EACd,mBAAoB,EAApB,WAAW,mBAAG,MAAM,KAAA,EACpB,KAAK,WAAA;IAEL,OAAO,CACL,eAAK,SAAS,EAAE,EAAE,CAAC,gBAAgB,EAAE,YAAY,EAAE,sBAAe,WAAW,CAAE,EAAE,SAAS,CAAC,aACzF,eACE,SAAS,EAAE,EAAE,CAAC,wBAAwB,EAAE,iBAAiB,EAAE,aAAa,CAAC,EACzE,IAAI,EAAC,SAAS,EACd,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,SAAS,aAErG,cAAK,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,YAClD,IAAI,CAAC,GAAG,CAAC,UAAC,GAAG;4BACZ,IAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC;4BACrC,OAAO,CACL,iBAEE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,KAAK,mBACK,QAAQ,mBACR,0BAAmB,GAAG,CAAC,KAAK,CAAE,EAC7C,EAAE,EAAE,oBAAa,GAAG,CAAC,KAAK,CAAE,EAC5B,SAAS,EAAE,EAAE,CACX,4BAA4B,EAC5B,oBAAoB,EACpB,GAAG,CAAC,QAAQ,IAAI,OAAO,EACvB,QAAQ,IAAI,QAAQ,EACpB,QAAQ,IAAI,WAAW,CACxB,EACD,OAAO,EAAE,cAAM,OAAA,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAxB,CAAwB,YAEtC,GAAG,CAAC,KAAK,IAfL,GAAG,CAAC,KAAK,CAgBP,CACV,CAAC;wBACJ,CAAC,CAAC,GACI,EACL,KAAK,IAAI,wBAAM,KAAK,GAAO,IACxB,EAEL,IAAI,CAAC,GAAG,CAAC,UAAC,GAAG;gBACZ,IAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC;gBACrC,OAAO,CACL,cAEE,IAAI,EAAC,UAAU,EACf,EAAE,EAAE,0BAAmB,GAAG,CAAC,KAAK,CAAE,qBACjB,oBAAa,GAAG,CAAC,KAAK,CAAE,EACzC,MAAM,EAAE,CAAC,QAAQ,EACjB,SAAS,EAAE,EAAE,CAAC,wBAAwB,EAAE,kBAAkB,EAAE,cAAc,CAAC,YAE1E,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,IAPzB,GAAG,CAAC,KAAK,CAQV,CACP,CAAC;YACJ,CAAC,CAAC,IACE,CACP,CAAC;AACJ,CAAC","sourcesContent":["import React from \"react\";\n\ntype SolidTabProps = {\n value: string;\n label: React.ReactNode;\n content: React.ReactNode;\n hasError?: boolean;\n};\n\ntype SolidTabGroupProps = {\n tabs: SolidTabProps[];\n value: string;\n onValueChange: (value: string) => void;\n className?: string;\n listClassName?: string;\n panelClassName?: string;\n tabPosition?: \"left\" | \"center\" | \"right\";\n extra?: React.ReactNode;\n};\n\nfunction cx(...parts: Array<string | false | undefined>) {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport function SolidTab(_props: SolidTabProps) {\n return null;\n}\n\nexport function SolidTabGroup({\n tabs,\n value,\n onValueChange,\n className,\n listClassName,\n panelClassName,\n tabPosition = \"left\",\n extra,\n}: SolidTabGroupProps) {\n return (\n <div className={cx(\"solid-notebook\", \"solid-tabs\", `solid-tabs--${tabPosition}`, className)}>\n <div\n className={cx(\"solid-notebook-tablist\", \"solid-tabs-list\", listClassName)}\n role=\"tablist\"\n style={extra ? { display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\" } : undefined}\n >\n <div style={extra ? { display: \"flex\" } : undefined}>\n {tabs.map((tab) => {\n const isActive = tab.value === value;\n return (\n <button\n key={tab.value}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={`solid-tab-panel-${tab.value}`}\n id={`solid-tab-${tab.value}`}\n className={cx(\n \"solid-notebook-tab-trigger\",\n \"solid-tabs-trigger\",\n tab.hasError && \"error\",\n isActive && \"active\",\n isActive && \"is-active\",\n )}\n onClick={() => onValueChange(tab.value)}\n >\n {tab.label}\n </button>\n );\n })}\n </div>\n {extra && <div>{extra}</div>}\n </div>\n\n {tabs.map((tab) => {\n const isActive = tab.value === value;\n return (\n <div\n key={tab.value}\n role=\"tabpanel\"\n id={`solid-tab-panel-${tab.value}`}\n aria-labelledby={`solid-tab-${tab.value}`}\n hidden={!isActive}\n className={cx(\"solid-notebook-content\", \"solid-tabs-panel\", panelClassName)}\n >\n {isActive ? tab.content : null}\n </div>\n );\n })}\n </div>\n );\n}\n"]}
@@ -15,6 +15,7 @@ type SolidTabGroupProps = {
15
15
  listClassName?: string;
16
16
  panelClassName?: string;
17
17
  tabPosition?: "left" | "center" | "right";
18
+ extra?: React.ReactNode;
18
19
  };
19
20
 
20
21
  function cx(...parts: Array<string | false | undefined>) {
@@ -33,13 +34,16 @@ export function SolidTabGroup({
33
34
  listClassName,
34
35
  panelClassName,
35
36
  tabPosition = "left",
37
+ extra,
36
38
  }: SolidTabGroupProps) {
37
39
  return (
38
40
  <div className={cx("solid-notebook", "solid-tabs", `solid-tabs--${tabPosition}`, className)}>
39
41
  <div
40
42
  className={cx("solid-notebook-tablist", "solid-tabs-list", listClassName)}
41
43
  role="tablist"
44
+ style={extra ? { display: "flex", alignItems: "center", justifyContent: "space-between" } : undefined}
42
45
  >
46
+ <div style={extra ? { display: "flex" } : undefined}>
43
47
  {tabs.map((tab) => {
44
48
  const isActive = tab.value === value;
45
49
  return (
@@ -63,6 +67,8 @@ export function SolidTabGroup({
63
67
  </button>
64
68
  );
65
69
  })}
70
+ </div>
71
+ {extra && <div>{extra}</div>}
66
72
  </div>
67
73
 
68
74
  {tabs.map((tab) => {
@@ -1 +1 @@
1
- {"version":3,"file":"GuestGuard.d.ts","sourceRoot":"","sources":["../../../src/routes/guards/GuestGuard.tsx"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,4CAmBzB"}
1
+ {"version":3,"file":"GuestGuard.d.ts","sourceRoot":"","sources":["../../../src/routes/guards/GuestGuard.tsx"],"names":[],"mappings":"AAIA,wBAAgB,UAAU,4CAezB"}
@@ -6,13 +6,8 @@ export function GuestGuard() {
6
6
  var status = useSession().status;
7
7
  var navigate = useNavigate();
8
8
  useEffect(function () {
9
- if (status === "authenticated") {
10
- if (window.history.length > 1) {
11
- navigate(-1);
12
- }
13
- else {
14
- navigate("/admin", { replace: true });
15
- }
9
+ if (status === "authenticated" && location.pathname.startsWith("/auth")) {
10
+ navigate("/admin", { replace: true });
16
11
  }
17
12
  }, [status, navigate]);
18
13
  if (status === "loading" || status === "authenticated") {
@@ -1 +1 @@
1
- {"version":3,"file":"GuestGuard.js","sourceRoot":"","sources":["../../../src/routes/guards/GuestGuard.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,MAAM,UAAU,UAAU;IAChB,IAAA,MAAM,GAAK,UAAU,EAAE,OAAjB,CAAkB;IAChC,IAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,SAAS,CAAC;QACR,IAAI,MAAM,KAAK,eAAe,EAAE;YAC9B,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;gBAC7B,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;aACd;iBAAM;gBACL,QAAQ,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;aACvC;SACF;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEvB,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,eAAe,EAAE;QACtD,OAAO,uCAAqB,CAAC;KAC9B;IAED,OAAO,KAAC,MAAM,KAAG,CAAC;AACpB,CAAC","sourcesContent":["import { useEffect } from \"react\";\nimport { Outlet, useNavigate } from \"react-router-dom\";\nimport { useSession } from \"../../hooks/useSession\";\n\nexport function GuestGuard() {\n const { status } = useSession();\n const navigate = useNavigate();\n\n useEffect(() => {\n if (status === \"authenticated\") {\n if (window.history.length > 1) {\n navigate(-1);\n } else {\n navigate(\"/admin\", { replace: true });\n }\n }\n }, [status, navigate]);\n\n if (status === \"loading\" || status === \"authenticated\") {\n return <div>Loading...</div>;\n }\n\n return <Outlet />;\n}"]}
1
+ {"version":3,"file":"GuestGuard.js","sourceRoot":"","sources":["../../../src/routes/guards/GuestGuard.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,MAAM,UAAU,UAAU;IAChB,IAAA,MAAM,GAAK,UAAU,EAAE,OAAjB,CAAkB;IAChC,IAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,SAAS,CAAC;QACR,IAAI,MAAM,KAAK,eAAe,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;YACvE,QAAQ,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;SACvC;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEvB,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,eAAe,EAAE;QACtD,OAAO,uCAAqB,CAAC;KAC9B;IAED,OAAO,KAAC,MAAM,KAAG,CAAC;AACpB,CAAC","sourcesContent":["import { useEffect } from \"react\";\nimport { Outlet, useNavigate } from \"react-router-dom\";\nimport { useSession } from \"../../hooks/useSession\";\n\nexport function GuestGuard() {\n const { status } = useSession();\n const navigate = useNavigate();\n\n useEffect(() => {\n if (status === \"authenticated\" && location.pathname.startsWith(\"/auth\")) {\n navigate(\"/admin\", { replace: true });\n }\n }, [status, navigate]);\n\n if (status === \"loading\" || status === \"authenticated\") {\n return <div>Loading...</div>;\n }\n\n return <Outlet />;\n}"]}
@@ -7,12 +7,8 @@ export function GuestGuard() {
7
7
  const navigate = useNavigate();
8
8
 
9
9
  useEffect(() => {
10
- if (status === "authenticated") {
11
- if (window.history.length > 1) {
12
- navigate(-1);
13
- } else {
14
- navigate("/admin", { replace: true });
15
- }
10
+ if (status === "authenticated" && location.pathname.startsWith("/auth")) {
11
+ navigate("/admin", { replace: true });
16
12
  }
17
13
  }, [status, navigate]);
18
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidxai/core-ui",
3
- "version": "0.1.7-beta.9",
3
+ "version": "0.1.7",
4
4
  "scripts": {
5
5
  "prebuild": "npm run copy-resources && npm run copy-styles",
6
6
  "build": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",