@kondeio/kdf 0.1.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/CONTRIBUTING.md +57 -0
  3. package/LICENSE +21 -0
  4. package/README.md +374 -0
  5. package/SECURITY.md +53 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +58 -0
  8. package/dist/css-generator.d.ts +17 -0
  9. package/dist/css-generator.js +59 -0
  10. package/dist/index.d.ts +48 -0
  11. package/dist/index.js +62 -0
  12. package/dist/plugin.d.ts +30 -0
  13. package/dist/plugin.js +40 -0
  14. package/dist/postinstall.d.ts +1 -0
  15. package/dist/postinstall.js +48 -0
  16. package/dist/resolver.d.ts +11 -0
  17. package/dist/resolver.js +184 -0
  18. package/dist/types.d.ts +44 -0
  19. package/dist/types.js +1 -0
  20. package/docs/kdf-doc.md +653 -0
  21. package/docs/kdf-skill.md +374 -0
  22. package/example/bootstrap/globals.css +12 -0
  23. package/example/bootstrap/hero-section.tsx +38 -0
  24. package/example/bootstrap/kdf/homepage.json +35 -0
  25. package/example/bootstrap/kdf/shared/button.json +10 -0
  26. package/example/bootstrap/kdf/shared/card.json +4 -0
  27. package/example/bootstrap/kdf/shared/color.json +17 -0
  28. package/example/bootstrap/kdf/shared/layout.json +7 -0
  29. package/example/bootstrap/kdf/shared/typography.json +8 -0
  30. package/example/bootstrap/konde-server.css +3 -0
  31. package/example/bootstrap/konde.css +3 -0
  32. package/example/preview.ts +428 -0
  33. package/example/pure-css/hero-section.tsx +40 -0
  34. package/example/pure-css/kdf/homepage.json +20 -0
  35. package/example/pure-css/kdf/shared/button.json +10 -0
  36. package/example/pure-css/kdf/shared/card.json +4 -0
  37. package/example/pure-css/kdf/shared/color.json +11 -0
  38. package/example/pure-css/kdf/shared/typography.json +8 -0
  39. package/example/pure-css/konde-server.css +3 -0
  40. package/example/pure-css/konde.css +3 -0
  41. package/example/pure-css/styles.css +34 -0
  42. package/example/sample-pages/about.json +30 -0
  43. package/example/sample-pages/dashboard.json +12 -0
  44. package/example/sample-pages/pricing.json +28 -0
  45. package/example/shadcn/globals.css +15 -0
  46. package/example/shadcn/hero-section.tsx +34 -0
  47. package/example/shadcn/konde-server.css +3 -0
  48. package/example/shadcn/konde.css +3 -0
  49. package/example/tailwind/globals.css +5 -0
  50. package/example/tailwind/hero-section.tsx +34 -0
  51. package/example/tailwind/konde-server.css +3 -0
  52. package/example/tailwind/konde.css +3 -0
  53. package/kdf/homepage.json +25 -0
  54. package/kdf/shared/button.json +10 -0
  55. package/kdf/shared/card.json +4 -0
  56. package/kdf/shared/color.json +17 -0
  57. package/kdf/shared/layout.json +7 -0
  58. package/kdf/shared/typography.json +8 -0
  59. package/package.json +77 -0
@@ -0,0 +1,374 @@
1
+ # KDF Skill
2
+
3
+ Use this skill whenever you build, review, or modify UI that uses Konde Design Framework.
4
+
5
+ Package: `@kondeio/kdf`
6
+ Runtime target: Node/server-side JavaScript. Tested with Next.js, Astro, and Hono.
7
+ Primary API: `getDesign`, `cn`, `cx`, `composeClasses`, `dedupeClasses`, `createClassComposer`, `clearKdfCache`
8
+ Required convention: every `d()` usage must have matching `data-kdf`
9
+
10
+ ## Goal
11
+
12
+ Build UI from KDF JSON instead of improvising styles in JSX.
13
+
14
+ KDF is the design source of truth. Code should render the design. Agents should not invent spacing, colors, typography, or section order when a KDF token exists or should exist.
15
+
16
+ ## Install Behavior
17
+
18
+ Check whether the host app already has `@kondeio/kdf` installed before adding it.
19
+
20
+ Default install:
21
+
22
+ ```bash
23
+ npm install @kondeio/kdf
24
+ ```
25
+
26
+ This scaffolds starter `kdf/` through `postinstall` if the folder does not exist.
27
+
28
+ Opt out:
29
+
30
+ ```bash
31
+ npm install @kondeio/kdf --ignore-scripts
32
+ ```
33
+
34
+ Manual init:
35
+
36
+ ```bash
37
+ npx kdf init
38
+ ```
39
+
40
+ Do not document fake custom npm flags such as `--noinit`. Use `--ignore-scripts`.
41
+
42
+ ## Before You Edit
43
+
44
+ 1. Locate the relevant design file:
45
+
46
+ ```text
47
+ kdf/<page>.json
48
+ kdf/shared/*.json
49
+ ```
50
+
51
+ 2. Locate the relevant UI component or page.
52
+
53
+ 3. Confirm package import:
54
+
55
+ ```ts
56
+ import { getDesign, cn } from "@kondeio/kdf";
57
+ ```
58
+
59
+ 4. Confirm page accessor:
60
+
61
+ ```ts
62
+ const d = getDesign("homepage");
63
+ ```
64
+
65
+ 5. Confirm the styling framework scans KDF JSON if it generates CSS by scanning source files:
66
+
67
+ ```css
68
+ @source "../kdf/**/*.json";
69
+ ```
70
+
71
+ or equivalent framework/source scanning config.
72
+
73
+ ## Non-negotiable Rules
74
+
75
+ ### 1. Do Not Guess Design
76
+
77
+ If a class belongs to the design system, put it in JSON and read it with `d()`.
78
+
79
+ Wrong:
80
+
81
+ ```tsx
82
+ <h1 className="text-5xl font-semibold tracking-tight">
83
+ ```
84
+
85
+ Right:
86
+
87
+ ```tsx
88
+ <h1 data-kdf="hero.title" className={d("hero.title")}>
89
+ ```
90
+
91
+ ### 2. Always Add `data-kdf`
92
+
93
+ Every token usage must be traceable.
94
+
95
+ Wrong:
96
+
97
+ ```tsx
98
+ <h1 className={d("hero.title")}>
99
+ ```
100
+
101
+ Right:
102
+
103
+ ```tsx
104
+ <h1 data-kdf="hero.title" className={d("hero.title")}>
105
+ ```
106
+
107
+ The `data-kdf` value must match the `d()` path.
108
+
109
+ ### 3. Keep Component Logic in Code
110
+
111
+ KDF controls design, not business logic.
112
+
113
+ Keep these in code:
114
+
115
+ - data fetching
116
+ - state
117
+ - event handlers
118
+ - conditional rendering
119
+ - permissions
120
+ - accessibility behavior
121
+ - component implementation
122
+
123
+ Keep these in KDF JSON:
124
+
125
+ - classes
126
+ - page section order
127
+ - visibility via `$layout`
128
+ - shared style references
129
+ - CSS custom properties
130
+ - component design metadata such as `$`, `variant`, and `size`
131
+
132
+ ### 4. Prefer Shared Tokens
133
+
134
+ If a style repeats across pages, move it into `kdf/shared`.
135
+
136
+ Example:
137
+
138
+ ```json
139
+ {
140
+ "hero": {
141
+ "cta": "@button.cta"
142
+ }
143
+ }
144
+ ```
145
+
146
+ Avoid copying the same long button class into many page files.
147
+
148
+ ### 5. Use KDF Class Composition
149
+
150
+ Use `cn()` when combining KDF tokens with conditional classes or caller-provided `className`.
151
+
152
+ ```tsx
153
+ className={cn(d("button.base"), active && d("button.active"), className)}
154
+ ```
155
+
156
+ Do not concatenate class strings manually when conditional classes can drift or duplicate.
157
+
158
+ KDF provides universal class helpers:
159
+
160
+ - `cn()` joins conditional classes, drops falsy values, normalizes whitespace,
161
+ and removes exact duplicate classes.
162
+ - `cx()` is an alias of `cn()`.
163
+ - `composeClasses()` is the same default composer with a more explicit name.
164
+ - `dedupeClasses()` removes exact duplicate class names from an existing string.
165
+ - `createClassComposer({ merge })` lets the app inject project-specific class
166
+ rules.
167
+
168
+ Default KDF composition is semantic-free. It does not resolve color, spacing,
169
+ variant, or framework-specific conflicts. If an app needs those rules, define
170
+ them at app level:
171
+
172
+ ```ts
173
+ import { createClassComposer } from "@kondeio/kdf";
174
+
175
+ export const cn = createClassComposer({
176
+ merge(className) {
177
+ return applyProjectClassRules(className);
178
+ }
179
+ });
180
+ ```
181
+
182
+ ### 6. Resolve Design Server-Side
183
+
184
+ `getDesign()` / `d()` / `d.css()` read JSON via Node `fs` — server-only. Never
185
+ call them in a Client Component (`"use client"`); the browser has no filesystem.
186
+ Resolve in server-rendered code such as a Next.js Server Component, Astro
187
+ server render, or Hono server handler, then pass the resulting className string
188
+ down to browser/client components as a prop.
189
+
190
+ ```tsx
191
+ // Server Component
192
+ const d = getDesign("homepage");
193
+ return <ClientThing className={d("hero.cta")} />;
194
+ ```
195
+
196
+ ## JSON Patterns
197
+
198
+ ### String Token
199
+
200
+ ```json
201
+ {
202
+ "hero": {
203
+ "wrapper": "mx-auto max-w-6xl px-6 py-20"
204
+ }
205
+ }
206
+ ```
207
+
208
+ ```tsx
209
+ <section data-kdf="hero.wrapper" className={d("hero.wrapper")} />
210
+ ```
211
+
212
+ ### Object Token
213
+
214
+ ```json
215
+ {
216
+ "hero": {
217
+ "title": {
218
+ "$": "h1",
219
+ "className": "@typography.h1"
220
+ }
221
+ }
222
+ }
223
+ ```
224
+
225
+ ```tsx
226
+ <h1 data-kdf="hero.title" className={d("hero.title")} />
227
+ ```
228
+
229
+ ### CSS Properties
230
+
231
+ ```json
232
+ {
233
+ "hero": {
234
+ "title": {
235
+ "className": "text-3xl",
236
+ "css": {
237
+ "--kdf-accent": "oklch(0.546 0.245 262)"
238
+ }
239
+ }
240
+ }
241
+ }
242
+ ```
243
+
244
+ ```tsx
245
+ <h1
246
+ data-kdf="hero.title"
247
+ className={d("hero.title")}
248
+ style={d.css("hero.title")}
249
+ />
250
+ ```
251
+
252
+ ## References
253
+
254
+ Use `@` for shared style references.
255
+
256
+ ```json
257
+ {
258
+ "hero": {
259
+ "cta": "@button.cta"
260
+ }
261
+ }
262
+ ```
263
+
264
+ Extend a shared reference:
265
+
266
+ ```json
267
+ {
268
+ "hero": {
269
+ "cta": "@button.cta shadow-xl"
270
+ }
271
+ }
272
+ ```
273
+
274
+ Use multiple references:
275
+
276
+ ```json
277
+ {
278
+ "hero": {
279
+ "login": "@button.base @button.ghost @button.sm"
280
+ }
281
+ }
282
+ ```
283
+
284
+ ## Page Layout
285
+
286
+ Use `$layout` for section order and visibility.
287
+
288
+ ```json
289
+ {
290
+ "$layout": ["hero", "features", "footer"],
291
+ "hero": {},
292
+ "features": {},
293
+ "footer": {}
294
+ }
295
+ ```
296
+
297
+ Rules:
298
+
299
+ - render sections in `$layout` order
300
+ - hide sections missing from `$layout`
301
+ - keep section token data even when hidden if it may be reused later
302
+
303
+ ## Cache Behavior
304
+
305
+ KDF caches JSON by default.
306
+
307
+ Development mode revalidates with file `mtimeMs` and `size` checks to avoid disk-read storms during HMR.
308
+
309
+ Use explicit cache options only when needed:
310
+
311
+ ```ts
312
+ const d = getDesign("homepage", {
313
+ cache: "auto",
314
+ maxAgeMs: 250
315
+ });
316
+ ```
317
+
318
+ Use custom invalidation only for tooling:
319
+
320
+ ```ts
321
+ clearKdfCache();
322
+ ```
323
+
324
+ ## Implementation Checklist
325
+
326
+ Use this checklist before finishing KDF-related UI work.
327
+
328
+ - [ ] Page imports `getDesign` from `@kondeio/kdf`.
329
+ - [ ] Page creates one accessor per design page, for example `getDesign("homepage")`.
330
+ - [ ] Every `d()` usage has matching `data-kdf`.
331
+ - [ ] Shared repeated styles live in `kdf/shared`.
332
+ - [ ] One-off page styles live in `kdf/<page>.json`.
333
+ - [ ] Conditional class composition uses `cn()`, `cx()`, or `composeClasses()`.
334
+ - [ ] Exact duplicate class cleanup uses `dedupeClasses()` when operating on an existing class string.
335
+ - [ ] App-specific semantic merge rules use `createClassComposer({ merge })`, not hardcoded KDF internals.
336
+ - [ ] CSS custom properties use `d.css(path)`.
337
+ - [ ] The app's styling framework scans KDF JSON files when required.
338
+ - [ ] No large design class strings are hardcoded in JSX when a token should exist.
339
+ - [ ] `$layout` is respected if the page uses section ordering.
340
+
341
+ ## Review Checklist
342
+
343
+ Use this when reviewing code written by another agent.
344
+
345
+ - [ ] No legacy `@konde/kdf` imports remain; use `@kondeio/kdf`.
346
+ - [ ] No element uses `d("...")` without `data-kdf`.
347
+ - [ ] `data-kdf` values match the token paths exactly.
348
+ - [ ] No design drift through arbitrary inline styling classes.
349
+ - [ ] KDF JSON remains valid JSON.
350
+ - [ ] Shared refs point to existing shared token files.
351
+ - [ ] `@` refs are not used for business logic.
352
+ - [ ] No non-English or informal comments are introduced into user-facing app source.
353
+
354
+ ## Validation Commands
355
+
356
+ From the host app:
357
+
358
+ ```bash
359
+ bun run build
360
+ ```
361
+
362
+ Use the host app's existing lint, typecheck, test, and build commands when they
363
+ exist.
364
+
365
+ ## Agent Behavior
366
+
367
+ If a user asks for a KDF UI change:
368
+
369
+ 1. Inspect current JSON.
370
+ 2. Inspect the rendered component/page.
371
+ 3. Update JSON first when the change is design-only.
372
+ 4. Update TSX only when structure, behavior, or data flow changes.
373
+ 5. Verify `data-kdf` coverage.
374
+ 6. Run the smallest relevant validation.
@@ -0,0 +1,12 @@
1
+ /* Bootstrap 5 — via CDN */
2
+ @import url("https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css");
3
+
4
+ /* Bridge: KDF CSS variables → Bootstrap CSS variables */
5
+ .btn-primary {
6
+ --bs-btn-bg: var(--kdf-primary, #0d6efd);
7
+ --bs-btn-border-color: var(--kdf-primary, #0d6efd);
8
+ --bs-btn-hover-bg: var(--kdf-primary, #0d6efd);
9
+ --bs-btn-hover-border-color: var(--kdf-primary, #0d6efd);
10
+ }
11
+
12
+ /* Load konde.css after framework CSS in the host app. withKDF() only exposes paths. */
@@ -0,0 +1,38 @@
1
+ import { getDesign } from "@kondeio/kdf";
2
+
3
+ export function HeroSection() {
4
+ const d = getDesign("homepage");
5
+
6
+ return (
7
+ <section data-kdf="hero.wrapper" className={d("hero.wrapper")}>
8
+ <div data-kdf="hero.content" className={d("hero.content")}>
9
+ <h1 data-kdf="hero.title" className={d("hero.title")}>
10
+ Build websites with AI
11
+ </h1>
12
+ <p data-kdf="hero.description" className={d("hero.description")}>
13
+ The AI orchestration platform for web development teams.
14
+ </p>
15
+ <div data-kdf="hero.actions" className={d("hero.actions")}>
16
+ <a href="/about" data-kdf="hero.cta-secondary" className={d("hero.cta-secondary")}>
17
+ Learn more
18
+ </a>
19
+ <a href="/pricing" data-kdf="hero.cta-primary" className={d("hero.cta-primary")}>
20
+ Get started
21
+ </a>
22
+ </div>
23
+ </div>
24
+ </section>
25
+ );
26
+ }
27
+
28
+ /*
29
+ kdf/shared/button.json (Bootstrap version):
30
+ "base": "btn",
31
+ "cta": "btn btn-primary btn-lg shadow",
32
+ "outline": "btn btn-outline-secondary"
33
+
34
+ kdf/homepage.json:
35
+ "hero.cta-primary": "@button.cta"
36
+
37
+ Same JSON structure, different class values.
38
+ */
@@ -0,0 +1,35 @@
1
+ {
2
+ "hero": {
3
+ "wrapper": "row align-items-center g-5",
4
+ "content": "col-lg-6",
5
+ "title": {
6
+ "className": "@typography.h1",
7
+ "css": {
8
+ "color": "orange",
9
+ "font-size": "3.5rem",
10
+ "--kdf-title-accent": "blue"
11
+ }
12
+ },
13
+ "description": {
14
+ "className": "mt-3 @typography.body",
15
+ "css": { "color": "#6c757d" }
16
+ },
17
+ "actions": "mt-4 d-flex gap-3",
18
+ "cta-primary": "@button.base @button.cta @button.lg",
19
+ "cta-secondary": "@button.base @button.outline",
20
+ "slider": "col-lg-6"
21
+ },
22
+ "template-grid": {
23
+ "wrapper": "row row-cols-1 row-cols-sm-2 row-cols-lg-3 g-4 mt-5",
24
+ "card": "@card.base @card.hover",
25
+ "card-image": "card-img-top",
26
+ "card-body": "card-body",
27
+ "card-title": "card-title fw-medium fs-6",
28
+ "card-category": "@typography.small"
29
+ },
30
+ "pagination": {
31
+ "wrapper": "mt-4 d-flex justify-content-center gap-2",
32
+ "button": "@button.base @button.ghost @button.sm",
33
+ "active": "@button.base @button.primary @button.sm"
34
+ }
35
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "base": "btn",
3
+ "primary": "btn-primary",
4
+ "outline": "btn-outline-secondary",
5
+ "ghost": "btn-link text-decoration-none",
6
+ "cta": "btn-primary shadow",
7
+ "sm": "btn-sm",
8
+ "md": "",
9
+ "lg": "btn-lg"
10
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "base": "card",
3
+ "hover": "shadow-sm"
4
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "primary": {
3
+ "css": { "--kdf-primary": "red" }
4
+ },
5
+ "danger": {
6
+ "css": { "--kdf-danger": "#dc3545" }
7
+ },
8
+ "success": {
9
+ "css": { "--kdf-success": "#198754" }
10
+ },
11
+ "warning": {
12
+ "css": { "--kdf-warning": "#ffc107" }
13
+ },
14
+ "accent": {
15
+ "css": { "--kdf-accent": "#fd7e14" }
16
+ }
17
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "header": "sticky-top bg-white border-bottom py-2 px-4",
3
+ "sidebar": "position-fixed top-0 start-0 vh-100 bg-white border-end d-none d-lg-block",
4
+ "content": "flex-grow-1 p-4",
5
+ "main": "d-flex flex-column",
6
+ "footer": "border-top py-4 px-4"
7
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "h1": "display-4 fw-bold",
3
+ "h2": "display-6 fw-bold",
4
+ "h3": "h4 fw-semibold",
5
+ "body": "lead",
6
+ "muted": "small",
7
+ "small": "fs-6"
8
+ }
@@ -0,0 +1,3 @@
1
+ /* konde-server.css — Critical design overrides (server-rendered) */
2
+ /* Imported in layout.tsx — inlined in HTML, no FOUC */
3
+ /* Edit freely — KDF will never overwrite this file */
@@ -0,0 +1,3 @@
1
+ /* konde.css — Custom design overrides */
2
+ /* Loaded LAST in <head> for highest specificity */
3
+ /* Edit freely — KDF will never overwrite this file */