@loykin/designkit 0.0.2 → 0.0.4

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.
@@ -0,0 +1,20 @@
1
+ # DesignKit Implementation Guides
2
+
3
+ The Playground's **Guides** group contains complete product flows. Existing template groups remain visual API references; they do not receive an AI guide merely because a workflow uses that template.
4
+
5
+ | Workflow | Pattern ID | Connected destinations | Contract |
6
+ | ------------------- | --------------------- | -------------------------------------- | ----------------------------------------------- |
7
+ | Resource Management | `managed-table` | table → detail Sheet; create/edit page | [Managed Table](./managed-table.md) |
8
+ | Forms | `form-workflow` | create, edit, and settings pages | [Stacked Form](./form-workflow.md) |
9
+ | Publishing | `publishing-workflow` | blog collection → article route | [Publishing Workflow](./publishing-workflow.md) |
10
+ | Commerce | `commerce-workflow` | filtered catalog → product route | [Commerce Workflow](./commerce-workflow.md) |
11
+
12
+ ## How to use these guides
13
+
14
+ 1. Choose the guide by the product workflow, not by a component name or sample entity.
15
+ 2. Give the complete guide Markdown and its Playground source to the AI.
16
+ 3. Preserve route, query, action-placement, loading, and page-template boundaries.
17
+ 4. Replace mock API functions and sample records with application code.
18
+ 5. Use existing template demos only to compare supported visual variants.
19
+
20
+ Each route renders exactly one page-level template. A workflow may connect different templates across routes, but must never nest one page-level template inside another.
@@ -0,0 +1,47 @@
1
+ # Commerce Workflow Contract for AI
2
+
3
+ Use this guide to build a discovery-to-decision commerce experience. The executable reference is **Guides / Commerce / Catalog → Product**.
4
+
5
+ ## Identity
6
+
7
+ - Pattern ID: `commerce-workflow`
8
+ - Catalog route template: `BrowseBodyTemplate`
9
+ - Product route template: `DetailBodyTemplate`
10
+ - Server state: TanStack Query
11
+ - Executable source: `playground/src/templates/demos/guides/CommerceWorkflowGuide.tsx`
12
+
13
+ The existing **Browse / Catalog** and product detail template demos remain visual references. This Guide defines their behavioral connection.
14
+
15
+ ## Route contract
16
+
17
+ ```text
18
+ /products → filterable and sortable catalog
19
+ /products/:productSlug → linkable product destination
20
+ ```
21
+
22
+ Selecting a product card navigates to the product route. Browser Back and the product breadcrumb return to the catalog. A product decision page is not a Sheet and must not be rendered inside the catalog template.
23
+
24
+ ## Query and filter ownership
25
+
26
+ - `CatalogPage` owns category, search, sort, pagination, and `['commerce', 'products', ...inputs]`.
27
+ - Every server-state input belongs in the query key.
28
+ - `ProductPage` owns `['commerce', 'product', slug]`.
29
+ - Filters stay in `BrowseBodyTemplate.sidebar`; sort and result count stay in `toolbar`.
30
+ - Initial loading replaces only catalog cards. Background refetch keeps current cards mounted.
31
+
32
+ ## Layout and action rules
33
+
34
+ - Catalog discovery actions and filters remain on the catalog route.
35
+ - Product-specific status, price, variants, purchase action, and delivery information belong on the detail route.
36
+ - Use `DetailBodyTemplate` media layout when product media is a primary decision input.
37
+ - Render exactly one page-level template per route.
38
+
39
+ ## AI reconstruction checklist
40
+
41
+ - [ ] Real catalog and product routes
42
+ - [ ] `BrowseBodyTemplate` catalog and `DetailBodyTemplate` product
43
+ - [ ] Filters and sort included in the catalog query key
44
+ - [ ] Product card click navigates to a slug route
45
+ - [ ] Product breadcrumb returns to catalog
46
+ - [ ] Purchase action exists only on the product route
47
+ - [ ] No nested page templates and no product Sheet
@@ -0,0 +1,212 @@
1
+ # Stacked Form Workflow Contract for AI
2
+
3
+ Use this contract for create, edit, and settings forms. It standardizes the visual structure and component boundaries. It does not prescribe a form-state, validation, routing, or data-fetching library.
4
+
5
+ ## Canonical reference
6
+
7
+ - Pattern ID: `form-workflow`
8
+ - Playground: **Guides / Forms / Stacked Form**
9
+ - Page template: `DataBodyTemplate`
10
+ - Section primitive: `DataBodyTemplate.Group layout="stacked"`
11
+
12
+ The existing **DataBodyTemplate / Form / Horizontal**, **Stacked**, and **Inline** entries are visual API references. When generating a product form, follow this guide instead of selecting among those demos.
13
+
14
+ The executable Playground example uses React Hook Form to demonstrate shared state across modular section components, controlled DesignKit inputs, and field-level errors. React Hook Form is a Playground implementation choice, not a DesignKit dependency or part of this visual contract.
15
+
16
+ ## Non-negotiable visual contract
17
+
18
+ 1. Render the form as a full route page by default. Do not use a Sheet for ordinary create, edit, or settings work.
19
+ 2. Keep the route hierarchy in `PageTopBar`: for example, `Resources / Members / Add member`.
20
+ 3. Use one `DataBodyTemplate` page root.
21
+ 4. Use the stacked form shape for create, edit, and settings pages. Do not switch to `horizontal` or `inline` because the domain changed.
22
+ 5. Divide the form into one or more `DataBodyTemplate.Group layout="stacked"` sections according to meaning, not visual preference.
23
+ 6. Keep field spacing at `space-y-3`; keep each label/control/help block at `space-y-1.5`.
24
+ 7. Use DesignKit controls and the established compact control sizing: `h-8 text-sm` for inputs and selects, `size="sm"` with `h-8 text-xs` for actions.
25
+ 8. Put Cancel before the primary submit action. Keep the action cluster right-aligned at the bottom of its save boundary.
26
+ 9. Show validation text directly below its field. Show form-level failure above the bottom actions, inside the same form boundary.
27
+ 10. A submitting, refreshing, or validation state must not replace or flash the page header or unrelated groups.
28
+
29
+ ## Module boundary contract
30
+
31
+ Treat each semantic group like tab-scoped content: implement it as a named component instead of one large page function.
32
+
33
+ - The route component owns only `DataBodyTemplate`, breadcrumb, title, and route-level description.
34
+ - A form component owns the submit boundary and bottom actions.
35
+ - Each section component returns one stacked `DataBodyTemplate.Group`.
36
+ - Section-only state and asynchronous work stay in that section component when possible.
37
+ - Shared form state may be provided by the form component through props, context, React Hook Form, or another application-selected mechanism.
38
+ - Do not lift section-only pending, error, or refresh state into the page header.
39
+ - Do not nest another page-level template inside the form or a Group.
40
+
41
+ Separating components is a behavior boundary, not permission to change their layout. Every section still uses the same stacked Group contract.
42
+
43
+ ## Save boundaries
44
+
45
+ The visual system remains the same; only form ownership changes.
46
+
47
+ | Workflow | Form ownership | Actions |
48
+ | -------------------------------------------- | ---------------------------------------- | --------------------------------------------------------------- |
49
+ | Create or edit one record | One form owns all stacked sections | One bottom action row after the final section |
50
+ | Settings saved as one document | One form owns all stacked sections | One bottom action row after the final section |
51
+ | Settings with independently saved categories | Each section component owns its own form | Each stacked section ends with its own right-aligned action row |
52
+
53
+ Do not create separate forms merely because the screen contains multiple Groups. Split forms only when the server-side save boundaries are genuinely independent.
54
+
55
+ ## Canonical composition
56
+
57
+ The following is the concrete React Hook Form composition used by the Playground. Applications may replace React Hook Form, but must preserve the same component and visual boundaries.
58
+
59
+ ```tsx
60
+ import { Controller, FormProvider, useForm, useFormContext } from 'react-hook-form'
61
+
62
+ interface MemberFormValues {
63
+ name: string
64
+ email: string
65
+ role: string
66
+ active: boolean
67
+ }
68
+
69
+ function IdentitySection() {
70
+ const {
71
+ register,
72
+ formState: { errors },
73
+ } = useFormContext<MemberFormValues>()
74
+
75
+ return (
76
+ <DataBodyTemplate.Group
77
+ layout="stacked"
78
+ title="Identity"
79
+ description="Basic account information."
80
+ >
81
+ <div className="space-y-3">
82
+ <div className="space-y-1.5">
83
+ <Label htmlFor="member-name" className="text-xs">
84
+ Name
85
+ </Label>
86
+ <Input
87
+ id="member-name"
88
+ {...register('name', { required: 'Enter a member name.' })}
89
+ aria-invalid={Boolean(errors.name)}
90
+ className="h-8 text-sm"
91
+ />
92
+ {errors.name && <p className="text-xs text-destructive">{errors.name.message}</p>}
93
+ </div>
94
+ </div>
95
+ </DataBodyTemplate.Group>
96
+ )
97
+ }
98
+
99
+ function AccessSection() {
100
+ const { control } = useFormContext<MemberFormValues>()
101
+
102
+ return (
103
+ <DataBodyTemplate.Group
104
+ layout="stacked"
105
+ title="Role & access"
106
+ description="Default workspace permissions."
107
+ >
108
+ <div className="space-y-3">
109
+ <div className="space-y-1.5">
110
+ <Label htmlFor="member-role" className="text-xs">
111
+ Role
112
+ </Label>
113
+ <Controller
114
+ control={control}
115
+ name="role"
116
+ render={({ field }) => (
117
+ <Select value={field.value} onValueChange={field.onChange}>
118
+ <SelectTrigger id="member-role" className="h-8 text-sm">
119
+ <SelectValue />
120
+ </SelectTrigger>
121
+ <SelectContent>{/* roles */}</SelectContent>
122
+ </Select>
123
+ )}
124
+ />
125
+ </div>
126
+ <Controller
127
+ control={control}
128
+ name="active"
129
+ render={({ field }) => <Switch checked={field.value} onCheckedChange={field.onChange} />}
130
+ />
131
+ </div>
132
+ </DataBodyTemplate.Group>
133
+ )
134
+ }
135
+
136
+ function MemberForm() {
137
+ const form = useForm<MemberFormValues>({
138
+ defaultValues: {
139
+ name: '',
140
+ email: '',
141
+ role: 'viewer',
142
+ active: true,
143
+ },
144
+ })
145
+
146
+ const submitMember = (values: MemberFormValues) => {
147
+ // Application-owned mutation or submit behavior.
148
+ }
149
+
150
+ return (
151
+ <FormProvider {...form}>
152
+ <form className="contents" onSubmit={form.handleSubmit(submitMember)}>
153
+ <IdentitySection />
154
+ <AccessSection />
155
+ <div className="flex justify-end gap-2 border-t border-border pt-(--designkit-panel-gap)">
156
+ <Button type="button" variant="outline" size="sm" className="h-8 text-xs">
157
+ Cancel
158
+ </Button>
159
+ <Button type="submit" size="sm" className="h-8 text-xs">
160
+ Save
161
+ </Button>
162
+ </div>
163
+ </form>
164
+ </FormProvider>
165
+ )
166
+ }
167
+
168
+ export function MemberCreatePage() {
169
+ return (
170
+ <DataBodyTemplate
171
+ topBar={<PageTopBar left="Resources / Members / Add member" />}
172
+ title="Add member"
173
+ description="Create a workspace member."
174
+ >
175
+ <MemberForm />
176
+ </DataBodyTemplate>
177
+ )
178
+ }
179
+ ```
180
+
181
+ React Hook Form is used here to prove that independently implemented Group components can share one form boundary. It remains a Playground-only dependency. Replacing it with ordinary React state, Formik, or another form tool must not change the rendered structure.
182
+
183
+ ## Settings with independent saves
184
+
185
+ When settings categories save independently, retain the same stacked appearance and move each form boundary into its section component.
186
+
187
+ ```tsx
188
+ function ProfileSettingsSection() {
189
+ return (
190
+ <DataBodyTemplate.Group layout="stacked" title="Profile">
191
+ <form className="space-y-3" onSubmit={saveProfile}>
192
+ {/* profile fields */}
193
+ <div className="flex justify-end">
194
+ <Button type="submit" size="sm" className="h-8 text-xs">
195
+ Save profile
196
+ </Button>
197
+ </div>
198
+ </form>
199
+ </DataBodyTemplate.Group>
200
+ )
201
+ }
202
+ ```
203
+
204
+ ## Review checklist
205
+
206
+ - Create, edit, and settings screens all use the stacked shape.
207
+ - The page is a route rather than a Sheet unless the task explicitly requires a constrained secondary edit.
208
+ - Breadcrumb, title, Groups, fields, and actions follow the same vertical order.
209
+ - Groups are named components and unrelated section state is not owned by the route header.
210
+ - Group count follows the information model; it does not select a different layout.
211
+ - Form and validation libraries remain application choices.
212
+ - Bottom actions belong to the form that they submit.