@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 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