@f0rbit/ui 0.1.2
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 +149 -0
- package/dist/components.css +1054 -0
- package/dist/index.d.ts +217 -0
- package/dist/index.js +1137 -0
- package/dist/index.jsx +752 -0
- package/dist/reset.css +93 -0
- package/dist/server.js +794 -0
- package/dist/server.jsx +752 -0
- package/dist/styles.css +1582 -0
- package/dist/tokens.css +121 -0
- package/dist/utilities.css +298 -0
- package/package.json +84 -0
- package/src/components/Badge.tsx +38 -0
- package/src/components/Button.tsx +55 -0
- package/src/components/Card.tsx +82 -0
- package/src/components/Checkbox.tsx +50 -0
- package/src/components/Chevron.tsx +36 -0
- package/src/components/Clamp.tsx +51 -0
- package/src/components/Collapsible.tsx +39 -0
- package/src/components/Dropdown.tsx +114 -0
- package/src/components/Empty.tsx +22 -0
- package/src/components/FormField.tsx +33 -0
- package/src/components/Input.tsx +35 -0
- package/src/components/Modal.tsx +106 -0
- package/src/components/Spinner.tsx +31 -0
- package/src/components/Stat.tsx +18 -0
- package/src/components/Status.tsx +43 -0
- package/src/components/Stepper.tsx +139 -0
- package/src/components/Tabs.tsx +120 -0
- package/src/components/Timeline.tsx +66 -0
- package/src/components/Toggle.tsx +29 -0
- package/src/index.tsx +65 -0
- package/src/styles/components.css +1054 -0
- package/src/styles/reset.css +93 -0
- package/src/styles/tokens.css +121 -0
- package/src/styles/utilities.css +298 -0
package/dist/server.jsx
ADDED
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
// src/components/Button.tsx
|
|
2
|
+
import { splitProps } from "solid-js";
|
|
3
|
+
var variantClasses = {
|
|
4
|
+
primary: "",
|
|
5
|
+
secondary: "btn-secondary",
|
|
6
|
+
ghost: "btn-ghost",
|
|
7
|
+
danger: "btn-danger"
|
|
8
|
+
};
|
|
9
|
+
var sizeClasses = {
|
|
10
|
+
sm: "btn-sm",
|
|
11
|
+
md: "",
|
|
12
|
+
lg: "btn-lg"
|
|
13
|
+
};
|
|
14
|
+
function Button(props) {
|
|
15
|
+
const [local, rest] = splitProps(props, ["variant", "size", "icon", "label", "loading", "class", "disabled", "children"]);
|
|
16
|
+
const classes = () => {
|
|
17
|
+
const parts = ["btn"];
|
|
18
|
+
parts.push(variantClasses[local.variant ?? "primary"]);
|
|
19
|
+
if (local.size && local.size !== "md") {
|
|
20
|
+
parts.push(sizeClasses[local.size]);
|
|
21
|
+
}
|
|
22
|
+
if (local.icon) {
|
|
23
|
+
parts.push("btn-icon");
|
|
24
|
+
}
|
|
25
|
+
if (local.class) {
|
|
26
|
+
parts.push(local.class);
|
|
27
|
+
}
|
|
28
|
+
return parts.join(" ");
|
|
29
|
+
};
|
|
30
|
+
return <button
|
|
31
|
+
class={classes()}
|
|
32
|
+
aria-label={local.icon ? local.label : void 0}
|
|
33
|
+
disabled={local.disabled || local.loading}
|
|
34
|
+
{...rest}
|
|
35
|
+
>
|
|
36
|
+
{local.loading ? <span class="spinner spinner-sm" /> : local.children}
|
|
37
|
+
</button>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/components/Badge.tsx
|
|
41
|
+
import { splitProps as splitProps2 } from "solid-js";
|
|
42
|
+
var variantClasses2 = {
|
|
43
|
+
default: "",
|
|
44
|
+
success: "badge-success",
|
|
45
|
+
error: "badge-error",
|
|
46
|
+
warning: "badge-warning",
|
|
47
|
+
info: "badge-info",
|
|
48
|
+
accent: "badge-accent"
|
|
49
|
+
};
|
|
50
|
+
function Badge(props) {
|
|
51
|
+
const [local, rest] = splitProps2(props, ["variant", "class", "children"]);
|
|
52
|
+
const classes = () => {
|
|
53
|
+
const parts = ["badge"];
|
|
54
|
+
const variant = local.variant ?? "default";
|
|
55
|
+
if (variant !== "default") {
|
|
56
|
+
parts.push(variantClasses2[variant]);
|
|
57
|
+
}
|
|
58
|
+
if (local.class) {
|
|
59
|
+
parts.push(local.class);
|
|
60
|
+
}
|
|
61
|
+
return parts.join(" ");
|
|
62
|
+
};
|
|
63
|
+
return <span class={classes()} {...rest}>
|
|
64
|
+
{local.children}
|
|
65
|
+
</span>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/components/Card.tsx
|
|
69
|
+
import { splitProps as splitProps3 } from "solid-js";
|
|
70
|
+
function Card(props) {
|
|
71
|
+
const [local, rest] = splitProps3(props, ["interactive", "class", "children"]);
|
|
72
|
+
const classes = () => {
|
|
73
|
+
const parts = ["card"];
|
|
74
|
+
if (local.interactive) {
|
|
75
|
+
parts.push("card-interactive");
|
|
76
|
+
}
|
|
77
|
+
if (local.class) {
|
|
78
|
+
parts.push(local.class);
|
|
79
|
+
}
|
|
80
|
+
return parts.join(" ");
|
|
81
|
+
};
|
|
82
|
+
return <div class={classes()} {...rest}>
|
|
83
|
+
{local.children}
|
|
84
|
+
</div>;
|
|
85
|
+
}
|
|
86
|
+
function CardHeader(props) {
|
|
87
|
+
const [local, rest] = splitProps3(props, ["class", "children"]);
|
|
88
|
+
return <div class={`card-header ${local.class ?? ""}`.trim()} {...rest}>
|
|
89
|
+
{local.children}
|
|
90
|
+
</div>;
|
|
91
|
+
}
|
|
92
|
+
function CardTitle(props) {
|
|
93
|
+
const [local, rest] = splitProps3(props, ["class", "children"]);
|
|
94
|
+
return <h3 class={`card-title ${local.class ?? ""}`.trim()} {...rest}>
|
|
95
|
+
{local.children}
|
|
96
|
+
</h3>;
|
|
97
|
+
}
|
|
98
|
+
function CardDescription(props) {
|
|
99
|
+
const [local, rest] = splitProps3(props, ["class", "children"]);
|
|
100
|
+
return <p class={`card-description ${local.class ?? ""}`.trim()} {...rest}>
|
|
101
|
+
{local.children}
|
|
102
|
+
</p>;
|
|
103
|
+
}
|
|
104
|
+
function CardContent(props) {
|
|
105
|
+
const [local, rest] = splitProps3(props, ["class", "children"]);
|
|
106
|
+
return <div class={`card-content ${local.class ?? ""}`.trim()} {...rest}>
|
|
107
|
+
{local.children}
|
|
108
|
+
</div>;
|
|
109
|
+
}
|
|
110
|
+
function CardFooter(props) {
|
|
111
|
+
const [local, rest] = splitProps3(props, ["class", "children"]);
|
|
112
|
+
return <div class={`card-footer ${local.class ?? ""}`.trim()} {...rest}>
|
|
113
|
+
{local.children}
|
|
114
|
+
</div>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/components/Input.tsx
|
|
118
|
+
import { splitProps as splitProps4 } from "solid-js";
|
|
119
|
+
function Input(props) {
|
|
120
|
+
const [local, rest] = splitProps4(props, ["error", "class", "disabled"]);
|
|
121
|
+
const classes = () => `input ${local.error ? "input-error" : ""} ${local.class ?? ""}`.trim();
|
|
122
|
+
return <input class={classes()} disabled={local.disabled} {...rest} />;
|
|
123
|
+
}
|
|
124
|
+
function Textarea(props) {
|
|
125
|
+
const [local, rest] = splitProps4(props, ["error", "class", "disabled"]);
|
|
126
|
+
const classes = () => `textarea ${local.error ? "input-error" : ""} ${local.class ?? ""}`.trim();
|
|
127
|
+
return <textarea class={classes()} disabled={local.disabled} {...rest} />;
|
|
128
|
+
}
|
|
129
|
+
function Select(props) {
|
|
130
|
+
const [local, rest] = splitProps4(props, ["error", "class", "disabled", "children"]);
|
|
131
|
+
const classes = () => `select ${local.error ? "input-error" : ""} ${local.class ?? ""}`.trim();
|
|
132
|
+
return <select class={classes()} disabled={local.disabled} {...rest}>
|
|
133
|
+
{local.children}
|
|
134
|
+
</select>;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/components/Status.tsx
|
|
138
|
+
import { splitProps as splitProps5 } from "solid-js";
|
|
139
|
+
var stateClasses = {
|
|
140
|
+
active: "status-active",
|
|
141
|
+
inactive: "status-inactive",
|
|
142
|
+
error: "status-error",
|
|
143
|
+
pending: "status-pending"
|
|
144
|
+
};
|
|
145
|
+
var defaultLabels = {
|
|
146
|
+
active: "Active",
|
|
147
|
+
inactive: "Inactive",
|
|
148
|
+
error: "Error",
|
|
149
|
+
pending: "Pending"
|
|
150
|
+
};
|
|
151
|
+
function Status(props) {
|
|
152
|
+
const [local, rest] = splitProps5(props, ["state", "label", "class"]);
|
|
153
|
+
const classes = () => {
|
|
154
|
+
const parts = ["status", stateClasses[local.state]];
|
|
155
|
+
if (local.class) {
|
|
156
|
+
parts.push(local.class);
|
|
157
|
+
}
|
|
158
|
+
return parts.join(" ");
|
|
159
|
+
};
|
|
160
|
+
const displayLabel = () => local.label ?? defaultLabels[local.state];
|
|
161
|
+
return <span class={classes()} {...rest}>
|
|
162
|
+
<span class="status-dot" />
|
|
163
|
+
<span>{displayLabel()}</span>
|
|
164
|
+
</span>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// src/components/Stat.tsx
|
|
168
|
+
import { splitProps as splitProps6 } from "solid-js";
|
|
169
|
+
function Stat(props) {
|
|
170
|
+
const [local, rest] = splitProps6(props, ["value", "label", "class"]);
|
|
171
|
+
return <div class={local.class ? `stat ${local.class}` : "stat"} {...rest}>
|
|
172
|
+
<span class="stat-value">{local.value}</span>
|
|
173
|
+
<span class="stat-label">{local.label}</span>
|
|
174
|
+
</div>;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/components/Spinner.tsx
|
|
178
|
+
import { splitProps as splitProps7 } from "solid-js";
|
|
179
|
+
var sizeClasses2 = {
|
|
180
|
+
sm: "spinner-sm",
|
|
181
|
+
md: "",
|
|
182
|
+
lg: "spinner-lg"
|
|
183
|
+
};
|
|
184
|
+
function Spinner(props) {
|
|
185
|
+
const [local, rest] = splitProps7(props, ["size", "class"]);
|
|
186
|
+
const classes = () => {
|
|
187
|
+
const parts = ["spinner"];
|
|
188
|
+
const size = local.size ?? "md";
|
|
189
|
+
if (size !== "md") {
|
|
190
|
+
parts.push(sizeClasses2[size]);
|
|
191
|
+
}
|
|
192
|
+
if (local.class) {
|
|
193
|
+
parts.push(local.class);
|
|
194
|
+
}
|
|
195
|
+
return parts.join(" ");
|
|
196
|
+
};
|
|
197
|
+
return <span class={classes()} {...rest} />;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/components/Chevron.tsx
|
|
201
|
+
import { splitProps as splitProps8 } from "solid-js";
|
|
202
|
+
function Chevron(props) {
|
|
203
|
+
const [local, rest] = splitProps8(props, ["expanded", "facing", "size", "class"]);
|
|
204
|
+
const classes = () => {
|
|
205
|
+
const parts = ["chevron"];
|
|
206
|
+
if (local.facing === "down") {
|
|
207
|
+
parts.push("chevron-down");
|
|
208
|
+
}
|
|
209
|
+
if (local.expanded) {
|
|
210
|
+
parts.push("active");
|
|
211
|
+
}
|
|
212
|
+
if (local.class) {
|
|
213
|
+
parts.push(local.class);
|
|
214
|
+
}
|
|
215
|
+
return parts.join(" ");
|
|
216
|
+
};
|
|
217
|
+
const size = () => local.size ?? "1em";
|
|
218
|
+
return <svg class={classes()} viewBox="0 0 24 24" width={size()} height={size()} fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" {...rest}>
|
|
219
|
+
<path d="m9 18 6-6-6-6" />
|
|
220
|
+
</svg>;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/components/Empty.tsx
|
|
224
|
+
import { splitProps as splitProps9 } from "solid-js";
|
|
225
|
+
function Empty(props) {
|
|
226
|
+
const [local] = splitProps9(props, ["icon", "title", "description", "children"]);
|
|
227
|
+
return <div class="empty">
|
|
228
|
+
{local.icon && <div class="empty-icon">{local.icon}</div>}
|
|
229
|
+
{local.title && <h3 class="empty-title">{local.title}</h3>}
|
|
230
|
+
{local.description && <p class="empty-description">{local.description}</p>}
|
|
231
|
+
{local.children}
|
|
232
|
+
</div>;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/components/Modal.tsx
|
|
236
|
+
import { splitProps as splitProps10, Show, onMount, onCleanup, createContext, useContext } from "solid-js";
|
|
237
|
+
import { Portal, isServer } from "solid-js/web";
|
|
238
|
+
var ModalContext = createContext();
|
|
239
|
+
function Modal(props) {
|
|
240
|
+
const [local, rest] = splitProps10(props, ["open", "onClose", "class", "children"]);
|
|
241
|
+
const handleKeyDown = (e) => {
|
|
242
|
+
if (e.key === "Escape" && local.open) {
|
|
243
|
+
local.onClose();
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const handleOverlayClick = (e) => {
|
|
247
|
+
if (e.target === e.currentTarget) {
|
|
248
|
+
local.onClose();
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
onMount(() => {
|
|
252
|
+
if (isServer) return;
|
|
253
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
254
|
+
});
|
|
255
|
+
onCleanup(() => {
|
|
256
|
+
if (isServer) return;
|
|
257
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
258
|
+
});
|
|
259
|
+
const classes = () => `modal ${local.class ?? ""}`.trim();
|
|
260
|
+
return <Show when={local.open}>
|
|
261
|
+
<Portal>
|
|
262
|
+
<ModalContext.Provider value={{ onClose: local.onClose }}>
|
|
263
|
+
<div class="overlay" onClick={handleOverlayClick} onKeyDown={(e) => e.key === "Escape" && local.onClose()} role="presentation">
|
|
264
|
+
<dialog class={classes()} open aria-modal="true" {...rest}>
|
|
265
|
+
{local.children}
|
|
266
|
+
</dialog>
|
|
267
|
+
</div>
|
|
268
|
+
</ModalContext.Provider>
|
|
269
|
+
</Portal>
|
|
270
|
+
</Show>;
|
|
271
|
+
}
|
|
272
|
+
function ModalHeader(props) {
|
|
273
|
+
const [local, rest] = splitProps10(props, ["class", "children"]);
|
|
274
|
+
const ctx = useContext(ModalContext);
|
|
275
|
+
return <div class={`modal-header ${local.class ?? ""}`.trim()} {...rest}>
|
|
276
|
+
{local.children}
|
|
277
|
+
<Show when={ctx}>
|
|
278
|
+
<button type="button" class="modal-close" onClick={ctx?.onClose} aria-label="Close">
|
|
279
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
280
|
+
<line x1="18" y1="6" x2="6" y2="18" />
|
|
281
|
+
<line x1="6" y1="6" x2="18" y2="18" />
|
|
282
|
+
</svg>
|
|
283
|
+
</button>
|
|
284
|
+
</Show>
|
|
285
|
+
</div>;
|
|
286
|
+
}
|
|
287
|
+
function ModalTitle(props) {
|
|
288
|
+
const [local, rest] = splitProps10(props, ["class", "children"]);
|
|
289
|
+
return <h2 class={`modal-title ${local.class ?? ""}`.trim()} {...rest}>
|
|
290
|
+
{local.children}
|
|
291
|
+
</h2>;
|
|
292
|
+
}
|
|
293
|
+
function ModalBody(props) {
|
|
294
|
+
const [local, rest] = splitProps10(props, ["class", "children"]);
|
|
295
|
+
return <div class={`modal-body ${local.class ?? ""}`.trim()} {...rest}>
|
|
296
|
+
{local.children}
|
|
297
|
+
</div>;
|
|
298
|
+
}
|
|
299
|
+
function ModalFooter(props) {
|
|
300
|
+
const [local, rest] = splitProps10(props, ["class", "children"]);
|
|
301
|
+
return <div class={`modal-footer ${local.class ?? ""}`.trim()} {...rest}>
|
|
302
|
+
{local.children}
|
|
303
|
+
</div>;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// src/components/Dropdown.tsx
|
|
307
|
+
import { splitProps as splitProps11, createSignal, Show as Show2, onMount as onMount2, onCleanup as onCleanup2, createContext as createContext2, useContext as useContext2 } from "solid-js";
|
|
308
|
+
import { isServer as isServer2 } from "solid-js/web";
|
|
309
|
+
var DropdownContext = createContext2();
|
|
310
|
+
function Dropdown(props) {
|
|
311
|
+
const [open, setOpen] = createSignal(false);
|
|
312
|
+
let containerRef;
|
|
313
|
+
const close = () => setOpen(false);
|
|
314
|
+
const handleClickOutside = (e) => {
|
|
315
|
+
if (!containerRef?.contains(e.target)) {
|
|
316
|
+
close();
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
const handleKeyDown = (e) => {
|
|
320
|
+
if (e.key === "Escape" && open()) {
|
|
321
|
+
close();
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
onMount2(() => {
|
|
325
|
+
if (isServer2) return;
|
|
326
|
+
document.addEventListener("click", handleClickOutside);
|
|
327
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
328
|
+
});
|
|
329
|
+
onCleanup2(() => {
|
|
330
|
+
if (isServer2) return;
|
|
331
|
+
document.removeEventListener("click", handleClickOutside);
|
|
332
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
333
|
+
});
|
|
334
|
+
return <DropdownContext.Provider value={{ open, setOpen, close }}>
|
|
335
|
+
<div ref={(el) => containerRef = el} class="dropdown">
|
|
336
|
+
{props.children}
|
|
337
|
+
</div>
|
|
338
|
+
</DropdownContext.Provider>;
|
|
339
|
+
}
|
|
340
|
+
function DropdownTrigger(props) {
|
|
341
|
+
const ctx = useContext2(DropdownContext);
|
|
342
|
+
const handleClick = (e) => {
|
|
343
|
+
e.stopPropagation();
|
|
344
|
+
ctx?.setOpen(!ctx.open());
|
|
345
|
+
};
|
|
346
|
+
return <div class="dropdown-trigger" onClick={handleClick}>
|
|
347
|
+
{props.children}
|
|
348
|
+
</div>;
|
|
349
|
+
}
|
|
350
|
+
function DropdownMenu(props) {
|
|
351
|
+
const ctx = useContext2(DropdownContext);
|
|
352
|
+
return <Show2 when={ctx?.open()}>
|
|
353
|
+
<div class="dropdown-menu">{props.children}</div>
|
|
354
|
+
</Show2>;
|
|
355
|
+
}
|
|
356
|
+
function DropdownItem(props) {
|
|
357
|
+
const [local, rest] = splitProps11(props, ["onClick", "active", "children"]);
|
|
358
|
+
const ctx = useContext2(DropdownContext);
|
|
359
|
+
const handleClick = () => {
|
|
360
|
+
local.onClick?.();
|
|
361
|
+
ctx?.close();
|
|
362
|
+
};
|
|
363
|
+
const classes = () => `dropdown-item ${local.active ? "active" : ""}`.trim();
|
|
364
|
+
return <button type="button" class={classes()} onClick={handleClick} {...rest}>
|
|
365
|
+
{local.children}
|
|
366
|
+
</button>;
|
|
367
|
+
}
|
|
368
|
+
function DropdownDivider() {
|
|
369
|
+
return <div class="dropdown-divider" />;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// src/components/Clamp.tsx
|
|
373
|
+
import { splitProps as splitProps12, createSignal as createSignal2, Show as Show3 } from "solid-js";
|
|
374
|
+
function Clamp(props) {
|
|
375
|
+
const [local, rest] = splitProps12(props, ["lines", "showMoreText", "showLessText", "class", "children"]);
|
|
376
|
+
const lines = () => local.lines ?? 3;
|
|
377
|
+
const showMoreText = () => local.showMoreText ?? "show more";
|
|
378
|
+
const showLessText = () => local.showLessText ?? "show less";
|
|
379
|
+
const [expanded, setExpanded] = createSignal2(false);
|
|
380
|
+
const [overflows, setOverflows] = createSignal2(false);
|
|
381
|
+
let contentRef;
|
|
382
|
+
const checkOverflow = () => {
|
|
383
|
+
if (!contentRef) return;
|
|
384
|
+
setOverflows(contentRef.scrollHeight > contentRef.clientHeight);
|
|
385
|
+
};
|
|
386
|
+
const toggle = () => setExpanded((prev) => !prev);
|
|
387
|
+
const wrapperClasses = () => `clamp ${local.class ?? ""}`.trim();
|
|
388
|
+
const contentClasses = () => expanded() ? "clamp-content" : "clamp-content clamp-clamped";
|
|
389
|
+
return <div class={wrapperClasses()} {...rest}>
|
|
390
|
+
<div
|
|
391
|
+
ref={(el) => {
|
|
392
|
+
contentRef = el;
|
|
393
|
+
requestAnimationFrame(checkOverflow);
|
|
394
|
+
}}
|
|
395
|
+
class={contentClasses()}
|
|
396
|
+
style={`--clamp-lines: ${lines()}`}
|
|
397
|
+
>
|
|
398
|
+
{local.children}
|
|
399
|
+
</div>
|
|
400
|
+
<Show3 when={overflows() || expanded()}>
|
|
401
|
+
<button class="clamp-toggle" onClick={toggle}>
|
|
402
|
+
{expanded() ? showLessText() : showMoreText()}
|
|
403
|
+
</button>
|
|
404
|
+
</Show3>
|
|
405
|
+
</div>;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// src/components/Collapsible.tsx
|
|
409
|
+
import { splitProps as splitProps13, createSignal as createSignal3, Show as Show4 } from "solid-js";
|
|
410
|
+
function Collapsible(props) {
|
|
411
|
+
const [local, rest] = splitProps13(props, ["defaultOpen", "open", "onOpenChange", "children", "trigger"]);
|
|
412
|
+
const [internalOpen, setInternalOpen] = createSignal3(local.defaultOpen ?? false);
|
|
413
|
+
const isControlled = () => local.open !== void 0;
|
|
414
|
+
const isOpen = () => isControlled() ? local.open : internalOpen();
|
|
415
|
+
const toggle = () => {
|
|
416
|
+
const next = !isOpen();
|
|
417
|
+
if (!isControlled()) {
|
|
418
|
+
setInternalOpen(next);
|
|
419
|
+
}
|
|
420
|
+
local.onOpenChange?.(next);
|
|
421
|
+
};
|
|
422
|
+
return <div class="collapsible">
|
|
423
|
+
<button class="collapsible-trigger" onClick={toggle}>
|
|
424
|
+
{local.trigger}
|
|
425
|
+
<Chevron class="collapsible-chevron" expanded={isOpen()} />
|
|
426
|
+
</button>
|
|
427
|
+
<Show4 when={isOpen()}>
|
|
428
|
+
<div class="collapsible-content">{local.children}</div>
|
|
429
|
+
</Show4>
|
|
430
|
+
</div>;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// src/components/Stepper.tsx
|
|
434
|
+
import { splitProps as splitProps14, Show as Show5, createContext as createContext3, useContext as useContext3 } from "solid-js";
|
|
435
|
+
var StepperContext = createContext3();
|
|
436
|
+
var statusClasses = {
|
|
437
|
+
completed: "step-completed",
|
|
438
|
+
current: "step-current",
|
|
439
|
+
upcoming: "step-upcoming"
|
|
440
|
+
};
|
|
441
|
+
function CheckIcon() {
|
|
442
|
+
return <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
443
|
+
<polyline points="13 4 6 12 3 9" />
|
|
444
|
+
</svg>;
|
|
445
|
+
}
|
|
446
|
+
var StepContext = createContext3();
|
|
447
|
+
function Step(props) {
|
|
448
|
+
const [local, rest] = splitProps14(props, ["title", "description", "icon", "status", "class"]);
|
|
449
|
+
const stepperCtx = useContext3(StepperContext);
|
|
450
|
+
const stepCtx = useContext3(StepContext);
|
|
451
|
+
const stepNumber = stepperCtx?.registerStep() ?? 1;
|
|
452
|
+
const orientation = () => stepCtx?.orientation() ?? "horizontal";
|
|
453
|
+
const status = () => local.status ?? "upcoming";
|
|
454
|
+
const isVertical = () => orientation() === "vertical";
|
|
455
|
+
const classes = () => {
|
|
456
|
+
const parts = ["step", statusClasses[status()]];
|
|
457
|
+
if (isVertical()) {
|
|
458
|
+
parts.push("vertical-connector-item");
|
|
459
|
+
}
|
|
460
|
+
if (local.class) {
|
|
461
|
+
parts.push(local.class);
|
|
462
|
+
}
|
|
463
|
+
return parts.join(" ");
|
|
464
|
+
};
|
|
465
|
+
const indicatorClasses = () => {
|
|
466
|
+
const parts = ["step-indicator"];
|
|
467
|
+
if (isVertical()) {
|
|
468
|
+
parts.push("vertical-indicator");
|
|
469
|
+
}
|
|
470
|
+
return parts.join(" ");
|
|
471
|
+
};
|
|
472
|
+
const contentClasses = () => {
|
|
473
|
+
const parts = ["step-content"];
|
|
474
|
+
if (isVertical()) {
|
|
475
|
+
parts.push("vertical-content");
|
|
476
|
+
}
|
|
477
|
+
return parts.join(" ");
|
|
478
|
+
};
|
|
479
|
+
const connectorClasses = () => {
|
|
480
|
+
const parts = ["step-connector"];
|
|
481
|
+
if (isVertical()) {
|
|
482
|
+
parts.push("vertical-connector");
|
|
483
|
+
}
|
|
484
|
+
return parts.join(" ");
|
|
485
|
+
};
|
|
486
|
+
const indicator = () => {
|
|
487
|
+
if (status() === "completed") {
|
|
488
|
+
return <CheckIcon />;
|
|
489
|
+
}
|
|
490
|
+
if (local.icon) {
|
|
491
|
+
return local.icon;
|
|
492
|
+
}
|
|
493
|
+
return stepNumber;
|
|
494
|
+
};
|
|
495
|
+
return <div class={classes()} {...rest}>
|
|
496
|
+
<div class={indicatorClasses()}>{indicator()}</div>
|
|
497
|
+
<div class={contentClasses()}>
|
|
498
|
+
<div class="step-title">{local.title}</div>
|
|
499
|
+
<Show5 when={local.description}>
|
|
500
|
+
<div class="step-description">{local.description}</div>
|
|
501
|
+
</Show5>
|
|
502
|
+
</div>
|
|
503
|
+
<div class={connectorClasses()} />
|
|
504
|
+
</div>;
|
|
505
|
+
}
|
|
506
|
+
function Stepper(props) {
|
|
507
|
+
const [local, rest] = splitProps14(props, ["orientation", "class", "children"]);
|
|
508
|
+
let stepCounter = 0;
|
|
509
|
+
const registerStep = () => ++stepCounter;
|
|
510
|
+
const orientation = () => local.orientation ?? "horizontal";
|
|
511
|
+
const classes = () => {
|
|
512
|
+
const parts = ["stepper", orientation() === "horizontal" ? "stepper-horizontal" : "stepper-vertical"];
|
|
513
|
+
if (local.class) {
|
|
514
|
+
parts.push(local.class);
|
|
515
|
+
}
|
|
516
|
+
return parts.join(" ");
|
|
517
|
+
};
|
|
518
|
+
return <StepperContext.Provider value={{ registerStep }}>
|
|
519
|
+
<StepContext.Provider value={{ orientation }}>
|
|
520
|
+
<div class={classes()} {...rest}>
|
|
521
|
+
{local.children}
|
|
522
|
+
</div>
|
|
523
|
+
</StepContext.Provider>
|
|
524
|
+
</StepperContext.Provider>;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// src/components/Tabs.tsx
|
|
528
|
+
import { splitProps as splitProps15, createSignal as createSignal4, createContext as createContext4, useContext as useContext4, Show as Show6 } from "solid-js";
|
|
529
|
+
var TabsContext = createContext4();
|
|
530
|
+
function Tabs(props) {
|
|
531
|
+
const [local, rest] = splitProps15(props, ["defaultValue", "value", "onValueChange", "children", "class"]);
|
|
532
|
+
const [internalValue, setInternalValue] = createSignal4(local.defaultValue ?? "");
|
|
533
|
+
const isControlled = () => local.value !== void 0;
|
|
534
|
+
const activeTab = () => isControlled() ? local.value : internalValue();
|
|
535
|
+
const setActiveTab = (id) => {
|
|
536
|
+
if (!isControlled()) {
|
|
537
|
+
setInternalValue(id);
|
|
538
|
+
}
|
|
539
|
+
local.onValueChange?.(id);
|
|
540
|
+
};
|
|
541
|
+
const classes = () => `tabs ${local.class ?? ""}`.trim();
|
|
542
|
+
return <TabsContext.Provider value={{ activeTab, setActiveTab }}>
|
|
543
|
+
<div class={classes()} {...rest}>
|
|
544
|
+
{local.children}
|
|
545
|
+
</div>
|
|
546
|
+
</TabsContext.Provider>;
|
|
547
|
+
}
|
|
548
|
+
function TabList(props) {
|
|
549
|
+
const [local, rest] = splitProps15(props, ["children", "class"]);
|
|
550
|
+
const classes = () => `tab-list ${local.class ?? ""}`.trim();
|
|
551
|
+
return <div class={classes()} role="tablist" {...rest}>
|
|
552
|
+
{local.children}
|
|
553
|
+
</div>;
|
|
554
|
+
}
|
|
555
|
+
function Tab(props) {
|
|
556
|
+
const [local, rest] = splitProps15(props, ["value", "children", "class"]);
|
|
557
|
+
const ctx = useContext4(TabsContext);
|
|
558
|
+
const isActive = () => ctx?.activeTab() === local.value;
|
|
559
|
+
const handleClick = () => {
|
|
560
|
+
ctx?.setActiveTab(local.value);
|
|
561
|
+
};
|
|
562
|
+
const classes = () => {
|
|
563
|
+
const parts = ["tab"];
|
|
564
|
+
if (isActive()) {
|
|
565
|
+
parts.push("active");
|
|
566
|
+
}
|
|
567
|
+
if (local.class) {
|
|
568
|
+
parts.push(local.class);
|
|
569
|
+
}
|
|
570
|
+
return parts.join(" ");
|
|
571
|
+
};
|
|
572
|
+
return <button
|
|
573
|
+
type="button"
|
|
574
|
+
role="tab"
|
|
575
|
+
aria-selected={isActive()}
|
|
576
|
+
tabIndex={isActive() ? 0 : -1}
|
|
577
|
+
class={classes()}
|
|
578
|
+
onClick={handleClick}
|
|
579
|
+
{...rest}
|
|
580
|
+
>
|
|
581
|
+
{local.children}
|
|
582
|
+
</button>;
|
|
583
|
+
}
|
|
584
|
+
function TabPanel(props) {
|
|
585
|
+
const [local, rest] = splitProps15(props, ["value", "children", "class"]);
|
|
586
|
+
const ctx = useContext4(TabsContext);
|
|
587
|
+
const isActive = () => ctx?.activeTab() === local.value;
|
|
588
|
+
const classes = () => `tab-panel ${local.class ?? ""}`.trim();
|
|
589
|
+
return <Show6 when={isActive()}>
|
|
590
|
+
<div class={classes()} role="tabpanel" {...rest}>
|
|
591
|
+
{local.children}
|
|
592
|
+
</div>
|
|
593
|
+
</Show6>;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// src/components/Checkbox.tsx
|
|
597
|
+
import { splitProps as splitProps16, createEffect, onMount as onMount3 } from "solid-js";
|
|
598
|
+
function Checkbox(props) {
|
|
599
|
+
const [local, rest] = splitProps16(props, ["label", "description", "indeterminate", "class", "disabled", "id"]);
|
|
600
|
+
let inputRef;
|
|
601
|
+
const setIndeterminate = () => {
|
|
602
|
+
if (inputRef) inputRef.indeterminate = local.indeterminate ?? false;
|
|
603
|
+
};
|
|
604
|
+
onMount3(setIndeterminate);
|
|
605
|
+
createEffect(setIndeterminate);
|
|
606
|
+
const classes = () => `checkbox ${local.disabled ? "checkbox-disabled" : ""} ${local.class ?? ""}`.trim();
|
|
607
|
+
const inputId = () => local.id ?? (local.label ? `checkbox-${local.label.toLowerCase().replace(/\s+/g, "-")}` : void 0);
|
|
608
|
+
return <label class={classes()}>
|
|
609
|
+
<input
|
|
610
|
+
ref={inputRef}
|
|
611
|
+
type="checkbox"
|
|
612
|
+
class="checkbox-input"
|
|
613
|
+
id={inputId()}
|
|
614
|
+
disabled={local.disabled}
|
|
615
|
+
{...rest}
|
|
616
|
+
/>
|
|
617
|
+
<span class="checkbox-box" aria-hidden="true">
|
|
618
|
+
<svg class="checkbox-check" viewBox="0 0 12 12" fill="none">
|
|
619
|
+
<path d="M2 6L5 9L10 3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
|
620
|
+
</svg>
|
|
621
|
+
<span class="checkbox-indeterminate" />
|
|
622
|
+
</span>
|
|
623
|
+
{(local.label || local.description) && <span class="checkbox-content">
|
|
624
|
+
{local.label && <span class="checkbox-label">{local.label}</span>}
|
|
625
|
+
{local.description && <span class="checkbox-description">{local.description}</span>}
|
|
626
|
+
</span>}
|
|
627
|
+
</label>;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// src/components/Toggle.tsx
|
|
631
|
+
import { splitProps as splitProps17 } from "solid-js";
|
|
632
|
+
function Toggle(props) {
|
|
633
|
+
const [local, rest] = splitProps17(props, ["label", "description", "size", "class", "disabled"]);
|
|
634
|
+
const size = () => local.size ?? "md";
|
|
635
|
+
const classes = () => `toggle ${size() === "sm" ? "toggle-sm" : ""} ${local.disabled ? "toggle-disabled" : ""} ${local.class ?? ""}`.trim();
|
|
636
|
+
return <label class={classes()}>
|
|
637
|
+
<input type="checkbox" class="toggle-input" role="switch" disabled={local.disabled} {...rest} />
|
|
638
|
+
<span class="toggle-track">
|
|
639
|
+
<span class="toggle-knob" />
|
|
640
|
+
</span>
|
|
641
|
+
{(local.label || local.description) && <span class="toggle-content">
|
|
642
|
+
{local.label && <span class="toggle-label">{local.label}</span>}
|
|
643
|
+
{local.description && <span class="toggle-description">{local.description}</span>}
|
|
644
|
+
</span>}
|
|
645
|
+
</label>;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// src/components/FormField.tsx
|
|
649
|
+
import { splitProps as splitProps18, Show as Show7 } from "solid-js";
|
|
650
|
+
function FormField(props) {
|
|
651
|
+
const [local, rest] = splitProps18(props, ["label", "error", "description", "required", "children", "id", "class"]);
|
|
652
|
+
const classes = () => `form-field ${local.error ? "form-field-has-error" : ""} ${local.class ?? ""}`.trim();
|
|
653
|
+
return <div class={classes()} {...rest}>
|
|
654
|
+
<label class="form-field-label" for={local.id}>
|
|
655
|
+
{local.label}
|
|
656
|
+
<Show7 when={local.required}>
|
|
657
|
+
<span class="form-field-required" aria-hidden="true">*</span>
|
|
658
|
+
</Show7>
|
|
659
|
+
</label>
|
|
660
|
+
<Show7 when={local.description}>
|
|
661
|
+
<span class="form-field-description">{local.description}</span>
|
|
662
|
+
</Show7>
|
|
663
|
+
{local.children}
|
|
664
|
+
<Show7 when={local.error}>
|
|
665
|
+
<span class="form-field-error" role="alert">{local.error}</span>
|
|
666
|
+
</Show7>
|
|
667
|
+
</div>;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// src/components/Timeline.tsx
|
|
671
|
+
import { splitProps as splitProps19, For as For3, Show as Show8 } from "solid-js";
|
|
672
|
+
var variantClasses3 = {
|
|
673
|
+
default: "",
|
|
674
|
+
success: "timeline-item-success",
|
|
675
|
+
error: "timeline-item-error",
|
|
676
|
+
warning: "timeline-item-warning",
|
|
677
|
+
info: "timeline-item-info"
|
|
678
|
+
};
|
|
679
|
+
function DefaultDot() {
|
|
680
|
+
return <div class="timeline-dot" />;
|
|
681
|
+
}
|
|
682
|
+
function Timeline(props) {
|
|
683
|
+
const [local, rest] = splitProps19(props, ["items", "class"]);
|
|
684
|
+
const classes = () => {
|
|
685
|
+
const parts = ["timeline"];
|
|
686
|
+
if (local.class) parts.push(local.class);
|
|
687
|
+
return parts.join(" ");
|
|
688
|
+
};
|
|
689
|
+
return <div class={classes()} {...rest}>
|
|
690
|
+
<For3 each={local.items}>
|
|
691
|
+
{(item, index) => <div
|
|
692
|
+
class={`timeline-item vertical-connector-item ${variantClasses3[item.variant ?? "default"]}`}
|
|
693
|
+
>
|
|
694
|
+
<div class="timeline-indicator vertical-indicator">
|
|
695
|
+
<Show8 when={item.icon} fallback={<DefaultDot />}>
|
|
696
|
+
{item.icon}
|
|
697
|
+
</Show8>
|
|
698
|
+
</div>
|
|
699
|
+
<div class="vertical-connector" />
|
|
700
|
+
<div class="timeline-content vertical-content">
|
|
701
|
+
<div class="timeline-title">{item.title}</div>
|
|
702
|
+
<Show8 when={item.description}>
|
|
703
|
+
<div class="timeline-description">{item.description}</div>
|
|
704
|
+
</Show8>
|
|
705
|
+
<Show8 when={item.timestamp}>
|
|
706
|
+
<div class="timeline-timestamp">{item.timestamp}</div>
|
|
707
|
+
</Show8>
|
|
708
|
+
</div>
|
|
709
|
+
</div>}
|
|
710
|
+
</For3>
|
|
711
|
+
</div>;
|
|
712
|
+
}
|
|
713
|
+
export {
|
|
714
|
+
Badge,
|
|
715
|
+
Button,
|
|
716
|
+
Card,
|
|
717
|
+
CardContent,
|
|
718
|
+
CardDescription,
|
|
719
|
+
CardFooter,
|
|
720
|
+
CardHeader,
|
|
721
|
+
CardTitle,
|
|
722
|
+
Checkbox,
|
|
723
|
+
Chevron,
|
|
724
|
+
Clamp,
|
|
725
|
+
Collapsible,
|
|
726
|
+
Dropdown,
|
|
727
|
+
DropdownDivider,
|
|
728
|
+
DropdownItem,
|
|
729
|
+
DropdownMenu,
|
|
730
|
+
DropdownTrigger,
|
|
731
|
+
Empty,
|
|
732
|
+
FormField,
|
|
733
|
+
Input,
|
|
734
|
+
Modal,
|
|
735
|
+
ModalBody,
|
|
736
|
+
ModalFooter,
|
|
737
|
+
ModalHeader,
|
|
738
|
+
ModalTitle,
|
|
739
|
+
Select,
|
|
740
|
+
Spinner,
|
|
741
|
+
Stat,
|
|
742
|
+
Status,
|
|
743
|
+
Step,
|
|
744
|
+
Stepper,
|
|
745
|
+
Tab,
|
|
746
|
+
TabList,
|
|
747
|
+
TabPanel,
|
|
748
|
+
Tabs,
|
|
749
|
+
Textarea,
|
|
750
|
+
Timeline,
|
|
751
|
+
Toggle
|
|
752
|
+
};
|