@loykin/designkit 0.0.1-dev.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 +408 -0
- package/dist/index.cjs +5839 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +667 -0
- package/dist/index.d.ts +667 -0
- package/dist/index.js +5681 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +136 -0
- package/dist/styles.d.ts +1 -0
- package/package.json +75 -0
package/README.md
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
# @loykin/designkit
|
|
2
|
+
|
|
3
|
+
React page template library. Provides ready-to-use page layouts for admin and dashboard applications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @loykin/designkit @loykin/gridkit
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires React 19 and Tailwind CSS v4. UI components are based on [shadcn/ui](https://ui.shadcn.com) — if your app has shadcn set up, theming integrates automatically via shared CSS variables (`--primary`, `--background`, `--radius`, etc.). You can customize every token through shadcn's theme without touching designkit directly.
|
|
12
|
+
|
|
13
|
+
Add the following to your global CSS so Tailwind scans the designkit bundle:
|
|
14
|
+
|
|
15
|
+
```css
|
|
16
|
+
/* globals.css */
|
|
17
|
+
@source "node_modules/@loykin/designkit/dist/index.js";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
import { DataBodyTemplate, DataGridView, PageTopBar, type DataGridColumnDef } from '@loykin/designkit'
|
|
24
|
+
import '@loykin/designkit/styles'
|
|
25
|
+
|
|
26
|
+
type User = { id: string; name: string; email: string }
|
|
27
|
+
|
|
28
|
+
const columns: DataGridColumnDef<User>[] = [
|
|
29
|
+
{ id: 'name', accessorKey: 'name', header: 'Name' },
|
|
30
|
+
{ id: 'email', accessorKey: 'email', header: 'Email' },
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
export function UsersPage() {
|
|
34
|
+
return (
|
|
35
|
+
<DataBodyTemplate
|
|
36
|
+
topBar={<PageTopBar left="Admin / Users" />}
|
|
37
|
+
title="Users"
|
|
38
|
+
>
|
|
39
|
+
<DataBodyTemplate.Body>
|
|
40
|
+
<DataGridView data={data} columns={columns} getRowId={(row) => row.id} />
|
|
41
|
+
</DataBodyTemplate.Body>
|
|
42
|
+
</DataBodyTemplate>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Templates
|
|
50
|
+
|
|
51
|
+
### DataBodyTemplate
|
|
52
|
+
|
|
53
|
+
The general-purpose page shell. Accepts three kinds of child slots — `.Body`, `.Tab`, and `.Section` — which determine the layout mode automatically.
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
<DataBodyTemplate
|
|
57
|
+
topBar={<PageTopBar left="Admin / Users" />}
|
|
58
|
+
title="Users"
|
|
59
|
+
description="Manage your team members."
|
|
60
|
+
actions={<Button>Add User</Button>}
|
|
61
|
+
>
|
|
62
|
+
{/* .Body | .Tab | .Section */}
|
|
63
|
+
</DataBodyTemplate>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
| Prop | Type | Description |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `topBar` | `ReactNode` | Top breadcrumb bar. Pass `<PageTopBar left="..." />` or omit. |
|
|
69
|
+
| `title` | `ReactNode` | Page title |
|
|
70
|
+
| `description` | `ReactNode` | Subtitle below the title |
|
|
71
|
+
| `actions` | `ReactNode` | Page-level actions (Add, Export, etc.) next to the title. Not for form Save buttons. |
|
|
72
|
+
| `toolbarLeft` / `toolbarRight` | `ReactNode` | Toolbar slots above the content area |
|
|
73
|
+
| `theme` | `CSSProperties` | Inline CSS variable overrides |
|
|
74
|
+
| `className` | `string` | Class applied to the page root |
|
|
75
|
+
|
|
76
|
+
#### DataBodyTemplate.Body
|
|
77
|
+
|
|
78
|
+
Single-pane content. No navigation. Use for full-height grid or custom layouts.
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
<DataBodyTemplate title="Users">
|
|
82
|
+
<DataBodyTemplate.Body>
|
|
83
|
+
<DataGridView data={data} columns={columns} getRowId={(row) => row.id} />
|
|
84
|
+
</DataBodyTemplate.Body>
|
|
85
|
+
</DataBodyTemplate>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
> Passing children directly without any slot wrapper also renders as a body, but `.Body` makes the layout intent explicit.
|
|
89
|
+
|
|
90
|
+
#### DataBodyTemplate.Tab
|
|
91
|
+
|
|
92
|
+
Creates a tabbed page layout. Add multiple `.Tab` children to enable the tab bar.
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
<DataBodyTemplate title="Users">
|
|
96
|
+
<DataBodyTemplate.Tab id="list" label="List" count={42}>
|
|
97
|
+
<DataGridView data={data} columns={columns} getRowId={(row) => row.id} />
|
|
98
|
+
</DataBodyTemplate.Tab>
|
|
99
|
+
<DataBodyTemplate.Tab id="settings" label="Settings">
|
|
100
|
+
<SettingsForm />
|
|
101
|
+
</DataBodyTemplate.Tab>
|
|
102
|
+
</DataBodyTemplate>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### DataBodyTemplate.Section
|
|
106
|
+
|
|
107
|
+
Settings-style layout with left navigation and right content panel. Add multiple `.Section` children to enable the side nav.
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
<DataBodyTemplate title="Settings">
|
|
111
|
+
<DataBodyTemplate.Section id="general" label="General" description="Workspace basics">
|
|
112
|
+
<DataBodyTemplate.Group layout="stacked" title="Workspace">
|
|
113
|
+
<form onSubmit={handleSubmit} className="space-y-3">
|
|
114
|
+
<Label htmlFor="name">Name</Label>
|
|
115
|
+
<Input id="name" defaultValue="Acme Corp" />
|
|
116
|
+
<Button type="submit" size="sm">Save</Button>
|
|
117
|
+
</form>
|
|
118
|
+
</DataBodyTemplate.Group>
|
|
119
|
+
</DataBodyTemplate.Section>
|
|
120
|
+
<DataBodyTemplate.Section id="security" label="Security">
|
|
121
|
+
<SecuritySettings />
|
|
122
|
+
</DataBodyTemplate.Section>
|
|
123
|
+
</DataBodyTemplate>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### DataBodyTemplate.Group
|
|
127
|
+
|
|
128
|
+
Groups content within a tab or section. The `layout` prop controls the visual structure.
|
|
129
|
+
|
|
130
|
+
| layout | Use case | Default wrapper |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `horizontal` | Label on left, input on right (settings form) | Card |
|
|
133
|
+
| `stacked` | Label above, input below | plain |
|
|
134
|
+
| `inline` | Table-style rows (detail view, inline form) | bordered |
|
|
135
|
+
| `split` | Left list + right detail | bordered |
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
<DataBodyTemplate.Tab id="settings" label="Settings">
|
|
139
|
+
<DataBodyTemplate.Group layout="horizontal" title="Identity" description="Basic information">
|
|
140
|
+
<DataBodyTemplate.Row label="Name" required>
|
|
141
|
+
<Input defaultValue="Sarah Kim" />
|
|
142
|
+
</DataBodyTemplate.Row>
|
|
143
|
+
<DataBodyTemplate.Row label="Email">
|
|
144
|
+
<Input type="email" defaultValue="sarah@acme.com" />
|
|
145
|
+
</DataBodyTemplate.Row>
|
|
146
|
+
</DataBodyTemplate.Group>
|
|
147
|
+
</DataBodyTemplate.Tab>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### DataBodyTemplate.Field
|
|
151
|
+
|
|
152
|
+
Read-only key-value display. Use with `Group layout="inline"` for detail pages.
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
<DataBodyTemplate.Group layout="inline" title="Identity">
|
|
156
|
+
<DataBodyTemplate.Field label="Email">sarah@acme.com</DataBodyTemplate.Field>
|
|
157
|
+
<DataBodyTemplate.Field label="Role"><Badge>Admin</Badge></DataBodyTemplate.Field>
|
|
158
|
+
</DataBodyTemplate.Group>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### DataBodyTemplate.Summary
|
|
162
|
+
|
|
163
|
+
A pinned summary area below the header, above tabs.
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
<DataBodyTemplate title="Overview">
|
|
167
|
+
<DataBodyTemplate.Summary>
|
|
168
|
+
<StatCards />
|
|
169
|
+
</DataBodyTemplate.Summary>
|
|
170
|
+
<DataBodyTemplate.Tab id="details" label="Details">...</DataBodyTemplate.Tab>
|
|
171
|
+
</DataBodyTemplate>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### DataGridView
|
|
177
|
+
|
|
178
|
+
Data table component. Use inside `DataBodyTemplate.Body` or any `.Tab` / `.Section`.
|
|
179
|
+
|
|
180
|
+
| variant | Description |
|
|
181
|
+
|---|---|
|
|
182
|
+
| `standard` (default) | Standard data table with pagination |
|
|
183
|
+
| `infinity` | Infinite scroll |
|
|
184
|
+
| `drag` | Row drag-to-reorder |
|
|
185
|
+
| `card` | Card grid |
|
|
186
|
+
| `card-list` | Card list |
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
import { DataBodyTemplate, DataGridView, PageTopBar, type DataGridColumnDef } from '@loykin/designkit'
|
|
190
|
+
|
|
191
|
+
type User = { id: string; name: string; email: string }
|
|
192
|
+
|
|
193
|
+
const columns: DataGridColumnDef<User>[] = [
|
|
194
|
+
{ id: 'name', accessorKey: 'name', header: 'Name' },
|
|
195
|
+
{ id: 'email', accessorKey: 'email', header: 'Email' },
|
|
196
|
+
]
|
|
197
|
+
|
|
198
|
+
export function UsersPage() {
|
|
199
|
+
return (
|
|
200
|
+
<DataBodyTemplate topBar={<PageTopBar left="Admin / Users" />} title="Users">
|
|
201
|
+
<DataBodyTemplate.Body>
|
|
202
|
+
<DataGridView
|
|
203
|
+
data={data}
|
|
204
|
+
columns={columns}
|
|
205
|
+
getRowId={(row) => row.id}
|
|
206
|
+
tableHeight={420}
|
|
207
|
+
/>
|
|
208
|
+
</DataBodyTemplate.Body>
|
|
209
|
+
</DataBodyTemplate>
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### FormWizardBodyTemplate
|
|
217
|
+
|
|
218
|
+
Multi-step input wizard. The template wraps each step's `content` in a `<form>` element automatically, so the Continue / Finish button acts as a submit trigger. Press Enter or click Continue to advance.
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
import { useState } from 'react'
|
|
222
|
+
import { FormWizardBodyTemplate, type FormWizardStep } from '@loykin/designkit'
|
|
223
|
+
|
|
224
|
+
const steps: FormWizardStep[] = [
|
|
225
|
+
{ key: 'info', title: 'Basic Info', content: <BasicInfoForm /> },
|
|
226
|
+
{ key: 'config', title: 'Configuration', content: <ConfigForm /> },
|
|
227
|
+
{ key: 'review', title: 'Review', content: <ReviewStep /> },
|
|
228
|
+
]
|
|
229
|
+
|
|
230
|
+
export function OnboardingPage() {
|
|
231
|
+
const [step, setStep] = useState(0)
|
|
232
|
+
return (
|
|
233
|
+
<FormWizardBodyTemplate
|
|
234
|
+
title="Setup Wizard"
|
|
235
|
+
steps={steps}
|
|
236
|
+
activeStep={step}
|
|
237
|
+
onNext={() => setStep((s) => Math.min(s + 1, steps.length - 1))}
|
|
238
|
+
onBack={() => setStep((s) => Math.max(s - 1, 0))}
|
|
239
|
+
onFinish={() => router.push('/dashboard')}
|
|
240
|
+
/>
|
|
241
|
+
)
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
For per-step validation with `react-hook-form`, call `trigger()` inside `onNext` before advancing:
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
onNext={async () => {
|
|
249
|
+
const ok = await trigger(['email', 'password'])
|
|
250
|
+
if (ok) setStep((s) => s + 1)
|
|
251
|
+
}}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
The `variant` prop switches between `'plain'` (default) and `'card'` to wrap each step in a Card.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
### LoginBodyTemplate
|
|
259
|
+
|
|
260
|
+
Authentication page shell. Renders centered or split-panel login layouts.
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
import { LoginBodyTemplate } from '@loykin/designkit'
|
|
264
|
+
|
|
265
|
+
export function SignInPage() {
|
|
266
|
+
return (
|
|
267
|
+
<LoginBodyTemplate layout="centered" card="card">
|
|
268
|
+
<form onSubmit={handleSubmit} className="space-y-4">
|
|
269
|
+
<div className="space-y-1.5">
|
|
270
|
+
<Label htmlFor="email">Email</Label>
|
|
271
|
+
<Input id="email" type="email" />
|
|
272
|
+
</div>
|
|
273
|
+
<div className="space-y-1.5">
|
|
274
|
+
<Label htmlFor="password">Password</Label>
|
|
275
|
+
<Input id="password" type="password" />
|
|
276
|
+
</div>
|
|
277
|
+
<Button type="submit" className="w-full">Sign In</Button>
|
|
278
|
+
</form>
|
|
279
|
+
</LoginBodyTemplate>
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
| Prop | Type | Default | Description |
|
|
285
|
+
|---|---|---|---|
|
|
286
|
+
| `layout` | `'centered' \| 'split'` | `'centered'` | Centered card or split-panel with brand side |
|
|
287
|
+
| `card` | `'card' \| 'plain'` | `'plain'` | Wrap the form content in a card border |
|
|
288
|
+
| `cardWidth` | `'sm' \| 'md' \| 'lg'` | `'md'` | Width of the form card |
|
|
289
|
+
| `bg` | `'default' \| 'subtle' \| 'none'` | `'default'` | Background style |
|
|
290
|
+
| `side` | `'left' \| 'right'` | `'left'` | Side the brand panel appears on (split layout only) |
|
|
291
|
+
| `brand` | `ReactNode` | built-in | Custom brand/logo panel content |
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## UI Components
|
|
296
|
+
|
|
297
|
+
Base components for use within page templates.
|
|
298
|
+
|
|
299
|
+
```tsx
|
|
300
|
+
import {
|
|
301
|
+
Badge, Button, Card, CardContent,
|
|
302
|
+
Input, Label, Select, SelectTrigger, SelectValue, SelectContent, SelectItem,
|
|
303
|
+
Switch, Checkbox, Slider,
|
|
304
|
+
EmptyState,
|
|
305
|
+
Tabs, TabsList, TabsTrigger, TabsContent,
|
|
306
|
+
Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger,
|
|
307
|
+
Tooltip, TooltipContent, TooltipProvider, TooltipTrigger,
|
|
308
|
+
Avatar, AvatarFallback, AvatarImage,
|
|
309
|
+
Separator, Skeleton,
|
|
310
|
+
Breadcrumb, DropdownMenu, NavigationMenu,
|
|
311
|
+
Popover, ScrollArea, Sidebar, Table,
|
|
312
|
+
PageTopBar,
|
|
313
|
+
} from '@loykin/designkit'
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### EmptyState
|
|
317
|
+
|
|
318
|
+
Displays empty data, no search results, or error states.
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
import { EmptyState } from '@loykin/designkit'
|
|
322
|
+
import { Users } from 'lucide-react'
|
|
323
|
+
|
|
324
|
+
<EmptyState
|
|
325
|
+
icon={Users}
|
|
326
|
+
title="No users yet"
|
|
327
|
+
description="Add your first user to get started."
|
|
328
|
+
action={{ label: 'Add User', onClick: () => openModal() }}
|
|
329
|
+
/>
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Theming
|
|
335
|
+
|
|
336
|
+
Designkit maps shadcn/ui CSS variables (`--primary`, `--background`, `--radius`, etc.) onto its own `--dk-*` tokens. Changing your shadcn theme automatically updates all designkit components.
|
|
337
|
+
|
|
338
|
+
For additional control, override `--dk-*` variables directly in `globals.css`.
|
|
339
|
+
|
|
340
|
+
### Customization scope
|
|
341
|
+
|
|
342
|
+
CSS variables are the customization layer. The library is opinionated about structure and ships its own UI components — visual appearance is controlled entirely through tokens.
|
|
343
|
+
|
|
344
|
+
| What | How |
|
|
345
|
+
|---|---|
|
|
346
|
+
| Colors, radius, typography | shadcn/ui theme variables (`--primary`, `--radius`, etc.) |
|
|
347
|
+
| Spacing, density, padding | `--dk-density`, `--dk-page-padding-*`, `--dk-panel-gap` |
|
|
348
|
+
| Per-page overrides | `className` or `theme` prop |
|
|
349
|
+
|
|
350
|
+
```css
|
|
351
|
+
:root {
|
|
352
|
+
--dk-radius: 0.375rem;
|
|
353
|
+
--dk-primary: oklch(0.52 0.2 250);
|
|
354
|
+
|
|
355
|
+
--dk-density: 1; /* 0.85 compact / 1 default / 1.15 comfortable */
|
|
356
|
+
--dk-page-padding-x: 1.5rem;
|
|
357
|
+
--dk-page-padding-y: 1rem;
|
|
358
|
+
--dk-panel-gap: 1rem;
|
|
359
|
+
--dk-toolbar-height: 2.75rem;
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
To override per page, combine with `className`:
|
|
364
|
+
|
|
365
|
+
```css
|
|
366
|
+
.layout-settings {
|
|
367
|
+
--dk-radius: 0.5rem;
|
|
368
|
+
--dk-density: 1.15;
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
<DataBodyTemplate className="layout-settings" title="Settings">
|
|
374
|
+
...
|
|
375
|
+
</DataBodyTemplate>
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Or use the `theme` prop for inline overrides:
|
|
379
|
+
|
|
380
|
+
```tsx
|
|
381
|
+
<DataBodyTemplate
|
|
382
|
+
theme={{ '--dk-radius': '0.5rem', '--dk-density': '1.15' } as React.CSSProperties}
|
|
383
|
+
title="Settings"
|
|
384
|
+
>
|
|
385
|
+
...
|
|
386
|
+
</DataBodyTemplate>
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Playground
|
|
392
|
+
|
|
393
|
+
An interactive development tool to preview templates and generate CSS/component code.
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
git clone https://github.com/loykin/designkit
|
|
397
|
+
cd designkit
|
|
398
|
+
pnpm install
|
|
399
|
+
pnpm dev
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Open `http://localhost:5173` to browse templates and export code.
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## License
|
|
407
|
+
|
|
408
|
+
MIT
|