@devalok/shilp-sutra 0.40.1 → 0.41.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/AGENTS.md CHANGED
@@ -25,6 +25,7 @@ If you are a human, read [README.md](./README.md) instead.
25
25
  3. **`packages/core/docs/recipes/<framework>.md`** — copy-paste install + setup for the user's framework.
26
26
  4. **`packages/core/llms-full.txt`** — exhaustive per-component reference (~140K tokens, props/variants/examples). Read only when `llms.txt` is insufficient.
27
27
  5. **`packages/core/docs/recipes/upgrading.md`** + **`MIGRATION.md`** — read BOTH before any version bump. See the hard constraint below.
28
+ 6. **`node_modules/@devalok/shilp-sutra/BREAKING.json`** — machine-readable manifest of every breaking change per version (moves, type narrowings, removals, renames). Read this programmatically when planning an upgrade — schema in `BREAKING.schema.json`. Lets you answer "does my code import any of these moved symbols?" without parsing CHANGELOG prose.
28
29
 
29
30
  When the package is installed in a consumer project, the same files live at:
30
31
 
@@ -60,7 +61,7 @@ If the framework is not in the table, fall back to **`install-vite.md`** (closes
60
61
 
61
62
  ## Hard constraints (these break things if violated)
62
63
 
63
- - **On any version bump, do not report it safe before reading the COMPLETE changelog + `MIGRATION.md` for the target version.** Breaking entries are often ordered last (changesets sorts by file, not severity), and breaks are frequently type-level — a prop type narrowed (`React.ReactNode` → a tighter type fails `tsc` for values that compiled before) or a symbol moved from a barrel to a per-component subpath. Grep your codebase for the moved/narrowed symbols, run `typecheck` + `build`, and use the `@devalok/eslint-plugin-shilp-sutra` migration preset for the mechanical edits. Full procedure: `packages/core/docs/recipes/upgrading.md`.
64
+ - **On any version bump, do not report it safe before reading the COMPLETE changelog + `MIGRATION.md` for the target version.** Breaking entries are often ordered last (changesets sorts by file, not severity), and breaks are frequently type-level — a prop type narrowed (`React.ReactNode` → a tighter type fails `tsc` for values that compiled before) or a symbol moved from a barrel to a per-component subpath. **Fastest path: parse `node_modules/@devalok/shilp-sutra/BREAKING.json` for the version range** — it has the structured break data so you can grep your codebase for affected symbols deterministically. Then run `typecheck` + `build` and use the `@devalok/eslint-plugin-shilp-sutra` `migration` preset for the mechanical edits. Full procedure: `packages/core/docs/recipes/upgrading.md`.
64
65
  - **Tailwind 4 only.** Do NOT create `tailwind.config.ts` with `presets: [shilpSutra]`. The JS preset was removed in 0.38. Setup uses CSS imports:
65
66
  ```css
66
67
  @import "tailwindcss";
@@ -74,6 +75,27 @@ If the framework is not in the table, fall back to **`install-vite.md`** (closes
74
75
  - **Do not invent variant names.** Variant names live in CVA source. Grep `packages/core/src/ui/<component>.tsx` or check `llms-full.txt` for the authoritative list.
75
76
  - **Default to `variant="soft"`** over `variant="outline"` for non-primary Button actions.
76
77
 
78
+ ## Spacing cadence (when building layouts — forms, settings, login, anything with vertical rhythm)
79
+
80
+ The `--spacing-ds-*` scale runs `ds-01`→`ds-09` (2px→48px) with many adjacent steps. It is a *primitive* scale, not a layout recipe. When you compose a UI, **do not reach for every adjacent token** — that produces 5-6 near-identical gaps the eye can't group, and rhythm reads muddy.
81
+
82
+ **Pick a 3-tier cadence — each tier visibly ~1.5-2× the previous, so each gap is distinct:**
83
+
84
+ | Tier | Token (px) | Use for |
85
+ |---|---|---|
86
+ | Related (one unit) | `ds-03` (8) | label ↔ field, eyebrow ↔ title, items inside one micro-cluster |
87
+ | Grouped (a section's items) | `ds-05` (16) | header-stack → form, between stacked field-groups, multi-line footers |
88
+ | Section (independent blocks) | `ds-07` (32) | between page sections, form ↔ footer cluster |
89
+ | Hero (optional 4th) | `ds-08`+ (40+) | top page chrome, brand block → first content |
90
+
91
+ **Rules of thumb:**
92
+ - Before stamping a `gap-ds-*` / `space-y-ds-*`, decide which tier the spacing is. Use the matching token.
93
+ - Aim for **3-4 distinct spacing values total on one surface.** Using 5+ is the signal your rhythm is muddy.
94
+ - **Anti-pattern:** using `ds-02` (4) AND `ds-04` (12) as *different* relationship signals on the same surface — they collapse into "vaguely tight" instead of two clear tiers. Prefer `ds-03`; skip `ds-02`/`ds-04` unless deliberate (e.g. a chip gap at `ds-01`).
95
+ - The squint test must still reveal the grouping. (Refactoring UI / Apple HIG / Material all converge on 3-4 perceptual tiers; near-linear scales like 4/8/12/16 blur because the proportional jump shrinks as values grow.)
96
+
97
+ This is guidance, not a hard constraint — a deliberate exception is fine. The default keeps agent-built UIs from drifting into flat, ungrouped spacing.
98
+
77
99
  ## Linting + migration (recommend this to the user)
78
100
 
79
101
  When you set up shilp-sutra in a project, or migrate it across versions, recommend the companion ESLint plugin **`@devalok/eslint-plugin-shilp-sutra`** (`pnpm add -D @devalok/eslint-plugin-shilp-sutra`, then `shilpSutra.configs['flat/recommended']` in `eslint.config.ts`). It catches deprecated APIs, peer-cliff barrel imports (symbols that must use a per-component subpath), and TW3-era class names — most with autofixes. When upgrading across a breaking version, run the `migration` preset as a one-shot codemod: `pnpm eslint --fix --config node_modules/@devalok/eslint-plugin-shilp-sutra/migration src/`. Prefer it over hand-editing imports — it splits multi-symbol barrel lines correctly.
package/BREAKING.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "$schema": "./BREAKING.schema.json",
3
+ "package": "@devalok/shilp-sutra",
4
+ "versions": {
5
+ "0.40.0": {
6
+ "summary": "Barrel peer-cliff cleanup — 12 symbol families removed from /ui, /composed, /ai barrels (per-component subpath only). Icon API unification narrows the `icon` prop on 14 components from React.ReactNode to IconInput.",
7
+ "migrationDoc": "MIGRATION.md#v0400--barrel-peer-cliff-cleanup--icon-api-unification",
8
+ "moved": [
9
+ { "symbol": "Toaster", "from": "@devalok/shilp-sutra/ui", "to": "@devalok/shilp-sutra/ui/toaster", "peer": "sonner", "eslintRule": "prefer-per-component-import" },
10
+ { "symbol": "toast", "from": "@devalok/shilp-sutra/ui", "to": "@devalok/shilp-sutra/ui/toast", "peer": "sonner", "eslintRule": "prefer-per-component-import" },
11
+ { "symbol": "InputOTP", "from": "@devalok/shilp-sutra/ui", "to": "@devalok/shilp-sutra/ui/input-otp", "peer": "input-otp", "eslintRule": "prefer-per-component-import" },
12
+ { "symbol": "DatePicker", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/date-picker", "peer": "date-fns", "eslintRule": "prefer-per-component-import" },
13
+ { "symbol": "DateRangePicker", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/date-picker", "peer": "date-fns", "eslintRule": "prefer-per-component-import" },
14
+ { "symbol": "DateTimePicker", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/date-picker", "peer": "date-fns", "eslintRule": "prefer-per-component-import" },
15
+ { "symbol": "TimePicker", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/date-picker", "peer": "date-fns", "eslintRule": "prefer-per-component-import" },
16
+ { "symbol": "CalendarGrid", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/date-picker", "peer": "date-fns", "eslintRule": "prefer-per-component-import" },
17
+ { "symbol": "MonthPicker", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/date-picker", "peer": "date-fns", "eslintRule": "prefer-per-component-import" },
18
+ { "symbol": "YearPicker", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/date-picker", "peer": "date-fns", "eslintRule": "prefer-per-component-import" },
19
+ { "symbol": "Presets", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/date-picker", "peer": "date-fns", "eslintRule": "prefer-per-component-import" },
20
+ { "symbol": "useCalendar", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/date-picker", "peer": "date-fns", "eslintRule": "prefer-per-component-import" },
21
+ { "symbol": "EmojiPicker", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/emoji-picker", "peer": "@emoji-mart/data", "eslintRule": "prefer-per-component-import" },
22
+ { "symbol": "EmojiPickerPopover", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/emoji-picker", "peer": "@emoji-mart/data", "eslintRule": "prefer-per-component-import" },
23
+ { "symbol": "EmojiNode", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/extensions/emoji-node", "peer": "@tiptap/react", "eslintRule": "prefer-per-component-import" },
24
+ { "symbol": "createEmojiSuggestion", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/extensions/emoji-suggestion", "peer": "@tiptap/react", "eslintRule": "prefer-per-component-import" },
25
+ { "symbol": "FilePreview", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/file-preview", "peer": "react-pdf", "eslintRule": "prefer-per-component-import" },
26
+ { "symbol": "MarkdownViewer", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/markdown-viewer", "peer": "react-markdown", "eslintRule": "prefer-per-component-import" },
27
+ { "symbol": "RichTextEditor", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/rich-text-editor", "peer": "@tiptap/react", "eslintRule": "prefer-per-component-import" },
28
+ { "symbol": "RichTextViewer", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/rich-text-editor", "peer": "@tiptap/react", "eslintRule": "prefer-per-component-import" },
29
+ { "symbol": "RichChatInput", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/rich-chat-input", "peer": "@tiptap/react", "eslintRule": "prefer-per-component-import" },
30
+ { "symbol": "AudioPlayer", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/rich-chat-input", "peer": "@tiptap/react", "eslintRule": "prefer-per-component-import" },
31
+ { "symbol": "AudioWaveform", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/rich-chat-input", "peer": "@tiptap/react", "eslintRule": "prefer-per-component-import" },
32
+ { "symbol": "useVoiceRecorder", "from": "@devalok/shilp-sutra/composed", "to": "@devalok/shilp-sutra/composed/rich-chat-input", "peer": "@tiptap/react", "eslintRule": "prefer-per-component-import" },
33
+ { "symbol": "BlockRenderer", "from": "@devalok/shilp-sutra/ai", "to": "@devalok/shilp-sutra/ai/block-renderer", "peer": "react-markdown", "eslintRule": "prefer-per-component-import" },
34
+ { "symbol": "ErrorBlock", "from": "@devalok/shilp-sutra/ai/blocks", "to": "@devalok/shilp-sutra/ai/blocks/error", "peer": "react-markdown", "eslintRule": "prefer-per-component-import" },
35
+ { "symbol": "TextBlock", "from": "@devalok/shilp-sutra/ai/blocks", "to": "@devalok/shilp-sutra/ai/blocks/text", "peer": "react-markdown", "eslintRule": "prefer-per-component-import" }
36
+ ],
37
+ "narrowed": [
38
+ {
39
+ "prop": "icon",
40
+ "components": [
41
+ "Combobox option",
42
+ "Stepper step",
43
+ "TreeItem",
44
+ "OAuthButton",
45
+ "AppCommandPalette",
46
+ "CommandRegistry",
47
+ "BottomNavbar",
48
+ "Sidebar NavItem",
49
+ "Sidebar NavSubItem",
50
+ "Sidebar footer.promo",
51
+ "TopBar UserMenuItem",
52
+ "Chat.Message.Avatar",
53
+ "Chat.SystemMessage",
54
+ "AIConversation agent",
55
+ "ActivityFeed item",
56
+ "CommandPalette item",
57
+ "CommandBar item"
58
+ ],
59
+ "from": "React.ReactNode",
60
+ "to": "IconInput",
61
+ "fix": "Retype the icon source from React.ReactNode to React.ReactElement (or import the IconInput type). Build-time only; runtime JSX is unaffected."
62
+ }
63
+ ]
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,184 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://shilp-sutra.devalok.in/breaking-manifest.schema.json",
4
+ "title": "shilp-sutra BREAKING manifest",
5
+ "description": "Machine-readable record of breaking changes per published version. Lets AI agents and migration tools answer 'what breaks between X and Y?' programmatically instead of parsing CHANGELOG prose. Cumulative — every prior version's breaks remain so a consumer jumping 0.37 → 0.41 can see every break in range.",
6
+ "type": "object",
7
+ "required": ["package", "versions"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "$schema": { "type": "string" },
11
+ "package": {
12
+ "type": "string",
13
+ "description": "npm package name this manifest covers.",
14
+ "examples": ["@devalok/shilp-sutra"]
15
+ },
16
+ "versions": {
17
+ "type": "object",
18
+ "description": "Map of semver version → breaking-change record. A version only appears if it had at least one breaking change. Non-breaking releases are absent (an empty object would falsely signal 'this version had breaks I forgot to document').",
19
+ "patternProperties": {
20
+ "^\\d+\\.\\d+\\.\\d+$": { "$ref": "#/$defs/versionEntry" }
21
+ },
22
+ "additionalProperties": false
23
+ }
24
+ },
25
+ "$defs": {
26
+ "versionEntry": {
27
+ "type": "object",
28
+ "additionalProperties": false,
29
+ "description": "All breaks shipped in this version. Every present field is an array; omit empty fields entirely. A consumer planning an upgrade reads the union of all entries between current and target version.",
30
+ "properties": {
31
+ "summary": {
32
+ "type": "string",
33
+ "description": "One-line human summary of the version's breaks. Mirrors the `> ⚠️ Breaking in X.Y.Z` callout in CHANGELOG."
34
+ },
35
+ "migrationDoc": {
36
+ "type": "string",
37
+ "description": "Relative path inside the package tarball to the human migration guide for this version.",
38
+ "examples": ["MIGRATION.md#v0400--barrel-peer-cliff-cleanup--icon-api-unification"]
39
+ },
40
+ "moved": {
41
+ "type": "array",
42
+ "description": "Symbols whose import path changed. Old path no longer exports the symbol; new path does. Consumer fix is a search-and-replace of the import path; prop/type signatures are unchanged.",
43
+ "items": { "$ref": "#/$defs/move" }
44
+ },
45
+ "narrowed": {
46
+ "type": "array",
47
+ "description": "Prop types that accept LESS than before. A consumer value valid under the old type may now fail tsc. Not a runtime break. The fix is typically retyping the value's source.",
48
+ "items": { "$ref": "#/$defs/narrowing" }
49
+ },
50
+ "removed": {
51
+ "type": "array",
52
+ "description": "Symbols (components, props, variants, exports) deleted with no replacement on the same path. If a renamed-with-deprecation, list under `renamed` instead.",
53
+ "items": { "$ref": "#/$defs/removal" }
54
+ },
55
+ "renamed": {
56
+ "type": "array",
57
+ "description": "Symbols whose name changed in place (same import path, new export name) or whose prop name changed (same component, new prop name).",
58
+ "items": { "$ref": "#/$defs/rename" }
59
+ },
60
+ "notes": {
61
+ "type": "array",
62
+ "description": "Free-form breaking changes that don't fit the structured categories above (e.g. visual-only changes, DOM structure shifts, default-value flips). Reader must check these manually — the migration is NOT one-shot autofixable.",
63
+ "items": { "type": "string" }
64
+ }
65
+ }
66
+ },
67
+ "move": {
68
+ "type": "object",
69
+ "required": ["symbol", "from", "to"],
70
+ "additionalProperties": false,
71
+ "properties": {
72
+ "symbol": {
73
+ "type": "string",
74
+ "description": "Exported name as it appears in an import statement.",
75
+ "examples": ["Toaster", "DatePicker"]
76
+ },
77
+ "from": {
78
+ "type": "string",
79
+ "description": "Old import path (no longer exports this symbol after this version).",
80
+ "examples": ["@devalok/shilp-sutra/ui"]
81
+ },
82
+ "to": {
83
+ "type": "string",
84
+ "description": "New import path (exports this symbol going forward).",
85
+ "examples": ["@devalok/shilp-sutra/ui/toaster"]
86
+ },
87
+ "peer": {
88
+ "type": "string",
89
+ "description": "Optional. If this move was driven by a peer-cliff cleanup, the peer dependency the new subpath pulls.",
90
+ "examples": ["sonner", "input-otp", "date-fns"]
91
+ },
92
+ "eslintRule": {
93
+ "type": "string",
94
+ "description": "Optional. The `@devalok/eslint-plugin-shilp-sutra` rule that autofixes this move.",
95
+ "examples": ["prefer-per-component-import"]
96
+ }
97
+ }
98
+ },
99
+ "narrowing": {
100
+ "type": "object",
101
+ "required": ["prop", "components", "from", "to", "fix"],
102
+ "additionalProperties": false,
103
+ "properties": {
104
+ "prop": {
105
+ "type": "string",
106
+ "description": "Prop name whose type narrowed.",
107
+ "examples": ["icon", "startIcon"]
108
+ },
109
+ "components": {
110
+ "type": "array",
111
+ "description": "Components whose this-prop narrowed. List each affected component explicitly — the same prop name on a component whose type was already narrower than the new type is NOT affected.",
112
+ "items": { "type": "string" },
113
+ "examples": [["CommandItem", "ActivityItem", "Chat.Message.Avatar"]]
114
+ },
115
+ "from": {
116
+ "type": "string",
117
+ "description": "Previous TypeScript type, as a string. Use the exact source form.",
118
+ "examples": ["React.ReactNode"]
119
+ },
120
+ "to": {
121
+ "type": "string",
122
+ "description": "New TypeScript type, as a string. Must be a subset of `from` (otherwise it's a widening, not a narrowing).",
123
+ "examples": ["IconInput"]
124
+ },
125
+ "fix": {
126
+ "type": "string",
127
+ "description": "One-line consumer fix. Should be actionable from the type alone.",
128
+ "examples": ["Retype the icon source from React.ReactNode to React.ReactElement."]
129
+ }
130
+ }
131
+ },
132
+ "removal": {
133
+ "type": "object",
134
+ "required": ["symbol", "where"],
135
+ "additionalProperties": false,
136
+ "properties": {
137
+ "symbol": {
138
+ "type": "string",
139
+ "examples": ["variant=\"filled\""]
140
+ },
141
+ "where": {
142
+ "type": "string",
143
+ "description": "What the symbol was on — a component, an import path, or a token namespace.",
144
+ "examples": ["Alert", "@devalok/shilp-sutra/tailwind"]
145
+ },
146
+ "replacement": {
147
+ "type": "string",
148
+ "description": "Optional. If a replacement exists at the same site, name it. If there is none, omit.",
149
+ "examples": ["variant=\"solid\""]
150
+ },
151
+ "deprecatedSince": {
152
+ "type": "string",
153
+ "description": "Optional. The version that first emitted a deprecation warning, if a cycle was observed.",
154
+ "examples": ["0.32.0"]
155
+ }
156
+ }
157
+ },
158
+ "rename": {
159
+ "type": "object",
160
+ "required": ["from", "to", "where"],
161
+ "additionalProperties": false,
162
+ "properties": {
163
+ "from": {
164
+ "type": "string",
165
+ "examples": ["isLoadingMore"]
166
+ },
167
+ "to": {
168
+ "type": "string",
169
+ "examples": ["loadingMore"]
170
+ },
171
+ "where": {
172
+ "type": "string",
173
+ "description": "Component or import path the rename applies to.",
174
+ "examples": ["MessageList"]
175
+ },
176
+ "kind": {
177
+ "type": "string",
178
+ "enum": ["prop", "export", "variant"],
179
+ "default": "prop"
180
+ }
181
+ }
182
+ }
183
+ }
184
+ }
package/MIGRATION.md CHANGED
@@ -4,6 +4,14 @@ This page indexes all breaking changes across `@devalok/shilp-sutra` versions. F
4
4
 
5
5
  > **Upgrading from &lt; 0.36?** Start here, then read each intermediate version section. Breaking changes stack — skipping versions means stacking migrations.
6
6
 
7
+ ## v0.41.0 — `BREAKING.json` manifest + recipe polish (no migration needed)
8
+
9
+ **Non-breaking minor.** No consumer code changes required.
10
+
11
+ - **New:** `packages/core/BREAKING.json` ships in the tarball — a machine-readable record of every breaking change per version. AI agents and migration tooling can `import manifest from '@devalok/shilp-sutra/BREAKING.json'` instead of parsing this file. Schema at `BREAKING.schema.json`.
12
+ - **Docs:** Next.js App Router install recipe gained a Tested-on matrix, explicit replace-the-whole-scaffold-globals.css guidance, Turbopack note, and three new gotchas (`pnpm-workspace.yaml`, auto-generated `AGENTS.md` markers, scaffold body-font cascade). No setup change required for existing consumers.
13
+ - **Internals:** release.yml now regenerates Agent Skill references before the pre-publish audit (kills the skill-drift email spam class). No impact on the published tarball.
14
+
7
15
  ## v0.40.0 — Barrel peer-cliff cleanup + Icon API unification
8
16
 
9
17
  This release pairs one breaking change (barrel peer-cliff cleanup) with one non-breaking type widening (Icon API unification). Read the breaking section first.
@@ -2,6 +2,8 @@
2
2
 
3
3
  > Setup recipe for adding `@devalok/shilp-sutra` to a Next.js 13+ App Router project.
4
4
 
5
+ > **Tested cold-install on:** Next 16.2.6 + React 19.2 + Turbopack + pnpm 10.30 + Node 22 + Windows 11 (2026-05-25). Earlier versions of Next 13/14/15 are still supported on this recipe; deltas called out inline.
6
+
5
7
  ## 1. Detect the framework
6
8
 
7
9
  You are in this recipe if **all** of these are true:
@@ -59,27 +61,35 @@ Some components depend on third-party libraries that ship as optional peers. **I
59
61
 
60
62
  ## 3. Configure PostCSS
61
63
 
62
- Create or update `postcss.config.mjs` at the project root:
64
+ **Next 14+ scaffolds this for you.** Verify `postcss.config.mjs` (or `.js` / `.cjs` / `.json`) at the project root contains:
63
65
 
64
66
  ```js
65
- export default {
67
+ const config = {
66
68
  plugins: {
67
69
  "@tailwindcss/postcss": {},
68
70
  },
69
71
  };
72
+
73
+ export default config;
70
74
  ```
71
75
 
72
- If a `postcss.config.{js,cjs,json}` already exists, merge the plugin in. Do not delete the existing file.
76
+ If the file is missing, create it with the contents above. If another PostCSS file exists with different plugins, merge `@tailwindcss/postcss` in do not delete the existing file.
73
77
 
74
78
  ## 4. Wire Tailwind 4 + design tokens
75
79
 
76
- Locate the global CSS file. Common paths in priority order:
80
+ ### 4a. Locate the global CSS file
81
+
82
+ Next 13+ default location depends on the `--src-dir` choice at scaffold time:
83
+
84
+ - `src/app/globals.css` — default since Next 14 when scaffolded without `--src-dir false`. **Most common in Next 16+ defaults.**
85
+ - `app/globals.css` — when scaffolded with `--src-dir false` (no `src/`).
86
+ - `app/global.css` — older Next 13 scaffolds.
77
87
 
78
- - `app/globals.css`
79
- - `src/app/globals.css`
80
- - `app/global.css`
88
+ If none exists, create at whichever path matches the project's existing `app/` location.
81
89
 
82
- If none exists, create `app/globals.css`. Set the file contents to (or merge into):
90
+ ### 4b. Replace the scaffold's CSS with the shilp-sutra setup
91
+
92
+ A fresh `create-next-app` scaffold writes a `globals.css` with `:root` color vars, an `@theme inline` block linked to Geist font vars, a `prefers-color-scheme` dark override, and a `body { font-family: Arial }` block. **Replace the entire file** with the shilp-sutra setup unless you have a specific reason to keep scaffold styles:
83
93
 
84
94
  ```css
85
95
  @import "tailwindcss";
@@ -88,7 +98,11 @@ If none exists, create `app/globals.css`. Set the file contents to (or merge int
88
98
 
89
99
  **Order matters.** `tailwindcss` MUST come first. The shilp-sutra `/css` entry registers `@theme` blocks that the Tailwind import must process.
90
100
 
91
- If the project has its own theme overrides, place them AFTER both imports:
101
+ If you want to keep the scaffold's color/font vars alongside shilp-sutra tokens (rare — usually you want one or the other), put scaffold's `@theme inline` / `:root` / `body` blocks AFTER the shilp-sutra import. Otherwise the scaffold's `body { font-family: Arial }` will compete with shilp-sutra's font setup.
102
+
103
+ ### 4c. Optional: add your own theme overrides
104
+
105
+ Place after both imports:
92
106
 
93
107
  ```css
94
108
  @import "tailwindcss";
@@ -99,12 +113,16 @@ If the project has its own theme overrides, place them AFTER both imports:
99
113
  }
100
114
  ```
101
115
 
102
- Import the CSS file once from `app/layout.tsx` (it should already be imported in a fresh `create-next-app` project):
116
+ ### 4d. Ensure CSS is imported from the layout
117
+
118
+ The CSS import in `app/layout.tsx` (or `src/app/layout.tsx`) should already exist in a fresh scaffold:
103
119
 
104
120
  ```tsx
105
121
  import "./globals.css";
106
122
  ```
107
123
 
124
+ If you removed the Geist-font import from layout.tsx (see § 6), keep this CSS import line.
125
+
108
126
  ## 5. Configure `transpilePackages`
109
127
 
110
128
  Edit `next.config.{ts,js,mjs}`. Add the `transpilePackages` field:
@@ -123,6 +141,8 @@ If a `transpilePackages` array already exists, append to it. Do not replace.
123
141
 
124
142
  Without `transpilePackages`, Next will refuse to load our pre-built `dist/*.js` because it ships native ESM that does not match Next's CJS-leaning loader for `node_modules`.
125
143
 
144
+ **Turbopack:** as of Next 16, Turbopack is the default bundler (`next dev` and `next build`). `transpilePackages` is respected by both Turbopack and the Webpack backend. Tested on Turbopack 16.2 cold-install (2026-05-25); no extra config needed.
145
+
126
146
  ## 6. Scaffold the Providers wrapper
127
147
 
128
148
  Create `app/providers.tsx`:
@@ -149,13 +169,21 @@ export function Providers({ children }: { children: ReactNode }) {
149
169
  - Drop the `Toaster` import and its JSX usage
150
170
  - Skip installing `sonner`
151
171
 
152
- Mount `<Providers>` from `app/layout.tsx`:
172
+ Mount `<Providers>` from `app/layout.tsx` (or `src/app/layout.tsx`). **Replace the scaffold's layout** with the version below — the scaffold imports `next/font/google` (Geist) and applies font-variable classes to `<html>`, which you don't need when shilp-sutra ships its own fonts:
153
173
 
154
174
  ```tsx
175
+ import type { Metadata } from "next";
155
176
  import "./globals.css";
156
177
  import { Providers } from "./providers";
157
178
 
158
- export default function RootLayout({ children }: { children: React.ReactNode }) {
179
+ export const metadata: Metadata = {
180
+ title: "Your app",
181
+ description: "Built with shilp-sutra",
182
+ };
183
+
184
+ export default function RootLayout({
185
+ children,
186
+ }: Readonly<{ children: React.ReactNode }>) {
159
187
  return (
160
188
  <html lang="en" suppressHydrationWarning>
161
189
  <body>
@@ -166,11 +194,20 @@ export default function RootLayout({ children }: { children: React.ReactNode })
166
194
  }
167
195
  ```
168
196
 
197
+ Specifically, **remove these scaffold lines**:
198
+
199
+ - `import { Geist, Geist_Mono } from "next/font/google";`
200
+ - The `const geistSans = Geist({...})` and `const geistMono = Geist_Mono({...})` blocks
201
+ - The `className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}` on `<html>`
202
+ - The `className="min-h-full flex flex-col"` on `<body>`
203
+
204
+ If you want to keep Geist alongside shilp-sutra's fonts, leave the `Geist` imports — but know that shilp-sutra's `font-sans` token resolves to Inter (body) and Ranade (display), not to the scaffold's `--font-geist-sans`. Loading both is wasted bytes.
205
+
169
206
  `suppressHydrationWarning` on `<html>` is required because `next-themes` writes the `class` attribute before React hydrates. Without it, every page logs a hydration warning.
170
207
 
171
208
  ## 7. Verify the install
172
209
 
173
- Replace the contents of `app/page.tsx`:
210
+ Replace the contents of `app/page.tsx` (or `src/app/page.tsx`). The scaffold's `page.tsx` imports `next/image` and renders the Vercel marketing layout — replace the whole file:
174
211
 
175
212
  ```tsx
176
213
  import { Button } from "@devalok/shilp-sutra/ui/button";
@@ -209,6 +246,7 @@ If anything is off, see [troubleshoot.md](./troubleshoot.md).
209
246
  ## 8. Common gotchas
210
247
 
211
248
  - **CSS import order.** `tailwindcss` BEFORE `@devalok/shilp-sutra/css`. Reversing the order silently produces a build with no design-system utilities.
249
+ - **Scaffold's `body { font-family: Arial }` overrides shilp-sutra fonts.** The `create-next-app` `globals.css` template sets `font-family: Arial, Helvetica, sans-serif` on `<body>`. If you kept the scaffold's body styles, they win the cascade over shilp-sutra's `font-sans`. § 4b says to replace the whole file — follow it.
212
250
  - **Multiple `framer-motion` copies.** Run `pnpm why framer-motion`. If it shows more than one resolved version, contexts (`MotionConfig`, `LayoutGroup`, `AnimatePresence`) silently break. Fix:
213
251
  ```jsonc
214
252
  // package.json
@@ -222,7 +260,9 @@ If anything is off, see [troubleshoot.md](./troubleshoot.md).
222
260
  ```
223
261
  For npm/yarn/bun equivalents, see [troubleshoot.md](./troubleshoot.md).
224
262
  - **Per-component imports keep RSC fast AND avoid peer-dep cliffs.** Inside Server Components, prefer `@devalok/shilp-sutra/ui/text`, `…/composed/page-header`, etc. The barrel `@devalok/shilp-sutra/ui` re-exports many client components — including some with hard peer-dep imports (e.g. `input-otp`) — so it both inflates the client bundle and forces those peers to be installed even when you never render those components. See [server-components.md](./server-components.md) for the full RSC-safety matrix.
225
- - **`p-3` vs `p-ds-03` — both are valid.** DS spacing uses the `--spacing-ds-*` namespace (`p-ds-04`, `gap-ds-03`); Tailwind 4's default numeric scale (`p-4`, `gap-2`) coexists by design. Pick `p-ds-*` for values that should track DS theme changes (card padding, form gaps); pick `p-N` for one-off layout values (section breathing room). Do NOT mass-codemod `p-4` → `p-ds-04` — that is not what the package intends.
263
+ - **`p-3` vs `p-ds-03` — both are valid.** DS spacing uses the `--spacing-ds-*` namespace (`p-ds-04`, `gap-ds-03`); Tailwind 4's default numeric scale (`p-4`, `gap-2`) coexists by design. Pick `p-ds-*` for values that should track DS theme changes (card padding, form gaps); pick `p-N` for one-off layout values (section breathing room). Do NOT mass-codemod `p-4` → `p-ds-04` — that is not what the package intends. For layout rhythm, pick a 3-tier cadence (`ds-03` related / `ds-05` grouped / `ds-07` section), not every adjacent token.
264
+ - **Auto-generated `pnpm-workspace.yaml`.** `pnpm 10+` writes a `pnpm-workspace.yaml` at the project root on first install with `ignoredBuiltDependencies` entries. This is harmless for a standalone app, but if you're nesting this project inside a larger monorepo, delete this file and use the parent monorepo's workspace config instead.
265
+ - **Auto-generated `AGENTS.md`.** `create-next-app` writes an `AGENTS.md` with managed `<!-- BEGIN:nextjs-agent-rules -->` / `<!-- END:nextjs-agent-rules -->` markers. Shilp Sutra's agent rules use `<!-- BEGIN:shilp-sutra-agent-rules -->` markers — they coexist cleanly. If you install the shilp-sutra Agent Skill (see the repo root `AGENTS.md` for the one-liner), it adds its block alongside Next's, not over it.
226
266
  - **Bare `shadow` is dead.** Tailwind 4 has no `--shadow-DEFAULT`. Use `shadow-raised`, `shadow-overlay`, or `shadow-floating`.
227
267
 
228
268
  ## 9. What you should NOT do
@@ -16,6 +16,25 @@ A version bump is **not** safe-by-default. Breaking changes in this design syste
16
16
 
17
17
  ## Step 2 — find affected call sites in your code
18
18
 
19
+ **Fastest path — read the machine-readable manifest:**
20
+
21
+ ```bash
22
+ # Lists every break per version as structured data (moves, narrowings, removals)
23
+ cat node_modules/@devalok/shilp-sutra/BREAKING.json
24
+ ```
25
+
26
+ Or programmatically:
27
+
28
+ ```js
29
+ import manifest from '@devalok/shilp-sutra/BREAKING.json'
30
+ // manifest.versions["0.40.0"].moved → [{ symbol, from, to, peer, eslintRule }, …]
31
+ // manifest.versions["0.40.0"].narrowed → [{ prop, components, from, to, fix }, …]
32
+ ```
33
+
34
+ Schema: `@devalok/shilp-sutra/BREAKING.schema.json`. AI agents should prefer this over prose-parsing CHANGELOG.
35
+
36
+ **Or grep manually:**
37
+
19
38
  ```bash
20
39
  # Symbols moved out of barrels (0.40.0 peer-cliff cleanup example):
21
40
  grep -rn "from '@devalok/shilp-sutra/ui'" src/ | grep -E "Toaster|toast|InputOTP"
package/llms-full.txt CHANGED
@@ -5,7 +5,7 @@
5
5
  > All variant values and props verified from source CVA definitions.
6
6
  >
7
7
  > Package: @devalok/shilp-sutra
8
- > Version: 0.40.1
8
+ > Version: 0.41.0
9
9
  >
10
10
  > **If you are an AI agent reading this file top-to-bottom:** the Setup
11
11
  > section below is authoritative. If any later per-component doc or a
package/llms-quick.txt CHANGED
@@ -47,6 +47,8 @@ Per-framework recipes: `node_modules/@devalok/shilp-sutra/docs/recipes/install-<
47
47
 
48
48
  **Lint + migrate:** `pnpm add -D @devalok/eslint-plugin-shilp-sutra`, then `shilpSutra.configs['flat/recommended']`. Catches deprecated APIs, peer-cliff barrel imports, TW3 classes — most autofixable. Use the `migration` preset (`pnpm eslint --fix`) when upgrading across breaking versions.
49
49
 
50
+ **Machine-readable breaks:** `node_modules/@devalok/shilp-sutra/BREAKING.json` lists every breaking change per version as structured data (moves, narrowings, removals). Read this for programmatic upgrade planning instead of parsing CHANGELOG prose. Schema: `BREAKING.schema.json`.
51
+
50
52
  ## OPTIONAL PEER DEPENDENCIES (install BEFORE first import)
51
53
 
52
54
  | When you import… | Install |
@@ -67,7 +69,7 @@ Per-framework recipes: `node_modules/@devalok/shilp-sutra/docs/recipes/install-<
67
69
  2. **`framer-motion@^12` required peer.** Single copy — configure pnpm/yarn overrides if you see duplicates.
68
70
  3. **`sonner@^2`** required only when you render `<Toaster />` or call `toast.*`. Optional otherwise.
69
71
  4. **Per-component imports keep RSC fast AND avoid peer-dep cliffs.** Barrel `@devalok/shilp-sutra/ui` works in client contexts but inflates client bundle and forces optional peers to be installed. Prefer `…/ui/text`, `…/ui/dialog`, etc. The barrel **no longer** re-exports peer-cliff symbols (`Toaster`, `toast`, `InputOTP`, `DatePicker`, `RichTextEditor`, `EmojiPicker`, `FilePreview`, `MarkdownViewer`, `BlockRenderer`, `ErrorBlock`, `TextBlock`) as of 0.40.0 — import per-component.
70
- 5. **Spacing namespace is `--spacing-ds-*`.** `p-ds-04`, `gap-ds-03` — these DO NOT replace TW4 default `p-4`, `gap-2`. Both coexist by design. Pick `p-ds-*` for values that should track DS theme changes, `p-N` for one-off layout values.
72
+ 5. **Spacing namespace is `--spacing-ds-*`.** `p-ds-04`, `gap-ds-03` — these DO NOT replace TW4 default `p-4`, `gap-2`. Both coexist by design. Pick `p-ds-*` for values that should track DS theme changes, `p-N` for one-off layout values. **Cadence when building layouts:** pick a 3-tier scale, not every adjacent token — `ds-03` (related: label↔field), `ds-05` (grouped: between field-groups), `ds-07` (section: between blocks), optional `ds-08`+ (hero). 3-4 distinct gaps per surface max; 5+ = muddy rhythm. Anti-pattern: `ds-02` + `ds-04` as different signals on one surface (they collapse). Squint test must still show grouping.
71
73
  6. **Bare `shadow` class renders no shadow in TW4.** Use `shadow-raised` (cards), `shadow-floating` (dropdowns), `shadow-overlay` (dialogs), `shadow-ring` (focus).
72
74
  7. **Variant names must match CVA source exactly** — invented variant names silently no-op (CVA falls back to defaults). Grep `packages/core/src/ui/<component>.tsx` if in doubt.
73
75
  8. **Default to `variant="soft"`** over `variant="outline"` for non-primary Button actions. Outline only on colored backgrounds or where primary/secondary hierarchy needs a hard border.
package/llms.txt CHANGED
@@ -49,6 +49,7 @@ The repo URL for these files is `https://github.com/devalok-design/shilp-sutra/t
49
49
  - **Agent-friendly install experience.** `AGENTS.md` now ships in the tarball (`node_modules/@devalok/shilp-sutra/AGENTS.md`), discoverable by 25+ agent tools. `package.json` declares an `agents` field (npm-agentskills convention) so `pnpm dlx @codemcp/agentskills export` auto-installs the bundled skill. New postinstall welcome banner (silent in CI / non-TTY / `SHILP_SUTRA_NO_WELCOME=1`). `troubleshoot.md` gained peer-cliff symptom entries.
50
50
  - **`llms-quick.txt`.** New ≤15K-token fast-path summary in the tarball — fits in one Read on any agent. Read order is now `llms-quick.txt` → `llms.txt` → `llms-full.txt`.
51
51
  - **Companion package `@devalok/eslint-plugin-shilp-sutra`** (first release). 12 rules — deprecated-API catches, peer-cliff barrel-import detection, TW3→TW4 classname autofixes. `pnpm add -D @devalok/eslint-plugin-shilp-sutra`, then `shilpSutra.configs['flat/recommended']`. Three presets: `recommended`, `strict`, `migration` (one-shot codemod).
52
+ - **Machine-readable `BREAKING.json` manifest** (v0.40.2+). Structured record of every breaking change per version (moves, narrowings, removals, renames). At `node_modules/@devalok/shilp-sutra/BREAKING.json` after install; subpath export `@devalok/shilp-sutra/BREAKING.json`. AI agents and migration tooling read this instead of parsing CHANGELOG prose. Schema at `BREAKING.schema.json`. Pre-publish-audit gate enforces a manifest entry for every release with a breaking CHANGELOG signal.
52
53
 
53
54
  ## BREAKING CHANGES (v0.40.0)
54
55
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devalok/shilp-sutra",
3
- "version": "0.40.1",
3
+ "version": "0.41.0",
4
4
  "description": "Devalok Design System — accessible React components, OKLCH design tokens, and Tailwind 4 CSS-first setup. Ships with AI-agent setup recipes.",
5
5
  "license": "MIT",
6
6
  "author": "Devalok Design & Strategy Studios <shilp-sutra@devalok.in>",
@@ -65,6 +65,8 @@
65
65
  },
66
66
  "./css": "./dist/tokens/shilp-sutra.css",
67
67
  "./tokens": "./dist/tokens/index.css",
68
+ "./BREAKING.json": "./BREAKING.json",
69
+ "./BREAKING.schema.json": "./BREAKING.schema.json",
68
70
  "./ui": {
69
71
  "types": "./dist/ui/index.d.ts",
70
72
  "import": "./dist/ui/index.js",
@@ -802,6 +804,8 @@
802
804
  "skill",
803
805
  "scripts/welcome.mjs",
804
806
  "AGENTS.md",
807
+ "BREAKING.json",
808
+ "BREAKING.schema.json",
805
809
  "MIGRATION.md",
806
810
  "README.md",
807
811
  "llms.txt",
package/skill/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: shilp-sutra
3
3
  description: Add, configure, and use components from Devalok's shilp-sutra design system (@devalok/shilp-sutra) — a Tailwind 4 + React 19 + CVA library with 110+ accessible components, OKLCH design tokens, framer-motion animations, and per-component RSC-safe entry points. Use this skill whenever the user mentions shilp-sutra, Devalok, the @devalok npm scope, or asks to install/add/style/theme UI in any React project that already depends on the package — even if they don't name it explicitly. Use it instead of generic shadcn/ui, MUI, or Chakra knowledge when shilp-sutra is in the project. Covers Next.js (App + Pages), Vite, Astro, Remix, TanStack Start setup playbooks; component API and variant reference; brand token customization; Server Component import patterns; and a troubleshoot tree for the thirteen most common breakages.
4
4
  license: MIT
5
5
  metadata:
6
- version: "0.40.1"
6
+ version: "0.41.0"
7
7
  author: Devalok Design & Strategy Studios
8
8
  homepage: https://github.com/devalok-design/shilp-sutra
9
9
  npm: https://www.npmjs.com/package/@devalok/shilp-sutra
@@ -64,8 +64,8 @@ These are non-negotiable. Violating any of them produces runtime errors that loo
64
64
  ```
65
65
  2. **`framer-motion@^12` is a required peer dep.** The consumer must install it. Module-scoped contexts (`MotionConfig`, `LayoutGroup`, `AnimatePresence`) silently break if two copies of framer-motion resolve. Configure pnpm/yarn to dedupe.
66
66
  3. **`sonner@^2` is an optional peer dep.** Install only when rendering `<Toaster />`.
67
- 4. **Per-component imports are mandatory for React Server Components.** `@devalok/shilp-sutra/ui/text` is server-safe; the barrel `@devalok/shilp-sutra/ui` pulls client code and crashes RSC. See `references/server-components.md` for the per-component matrix.
68
- 5. **Spacing namespace is `--spacing-ds-*`.** Write `p-ds-04`, not `p-4`. Same for typography: `text-ds-body-md`, not `text-base`.
67
+ 4. **Prefer per-component imports they keep RSC bundles small and avoid peer-dep cliffs.** `@devalok/shilp-sutra/ui/text` is server-safe and pulls only its own peers. The barrel `@devalok/shilp-sutra/ui` re-exports every component (including ones with hard peer deps like `input-otp`), so it forces those peers to install even when unused. With all peers installed the barrel also works in RSC (per-component `"use client"` is honoured), but the client bundle is larger. Prefer per-component for new code; existing barrel usage is not an emergency. See `references/server-components.md`.
68
+ 5. **Spacing uses the `--spacing-ds-*` namespace** (`p-ds-04`, `gap-ds-03`); typography uses `text-ds-body-md`. These **coexist with** Tailwind 4's numeric scale (`p-4`, `gap-2`) by design — both valid. Pick `p-ds-*` for values that should track DS theme changes, `p-N` for one-off layout. Do NOT mass-codemod `p-4` → `p-ds-04`. **Cadence when building layouts:** pick a 3-tier scale, not every adjacent token — `ds-03` (related: label↔field), `ds-05` (grouped: between field-groups), `ds-07` (section: between blocks), optional `ds-08`+ (hero). 3-4 distinct gaps per surface; 5+ reads muddy. Anti-pattern: `ds-02` + `ds-04` as different signals on one surface — they collapse. The squint test must still reveal grouping.
69
69
  6. **Bare `shadow` does not exist in Tailwind 4.** Use `shadow-raised`, `shadow-overlay`, `shadow-floating`. Bare `rounded` is fine (maps to `--radius`); `rounded-ds-lg` etc. for sized variants.
70
70
  7. **Do not invent variant names.** CVA source files at `node_modules/@devalok/shilp-sutra/dist/ui/*.d.ts` (or `packages/core/src/ui/*.tsx` in the DS repo) are authoritative. When in doubt, check `references/components-full.md` for the enumerated list. If you guess a variant that doesn't exist, the prop is silently dropped and the default applies.
71
71
  8. **Default `variant="soft"` over `variant="outline"` for non-primary Button actions.** Soft (tinted bg + tinted text, no border) reads warmer in data-dense UIs. Use outline only when soft would disappear on a colored background or when a primary/secondary hierarchy needs a visible border.
@@ -7,7 +7,7 @@
7
7
  > All variant values and props verified from source CVA definitions.
8
8
  >
9
9
  > Package: @devalok/shilp-sutra
10
- > Version: 0.40.1
10
+ > Version: 0.41.0
11
11
  >
12
12
  > **If you are an AI agent reading this file top-to-bottom:** the Setup
13
13
  > section below is authoritative. If any later per-component doc or a
@@ -51,6 +51,7 @@ The repo URL for these files is `https://github.com/devalok-design/shilp-sutra/t
51
51
  - **Agent-friendly install experience.** `AGENTS.md` now ships in the tarball (`node_modules/@devalok/shilp-sutra/AGENTS.md`), discoverable by 25+ agent tools. `package.json` declares an `agents` field (npm-agentskills convention) so `pnpm dlx @codemcp/agentskills export` auto-installs the bundled skill. New postinstall welcome banner (silent in CI / non-TTY / `SHILP_SUTRA_NO_WELCOME=1`). `troubleshoot.md` gained peer-cliff symptom entries.
52
52
  - **`llms-quick.txt`.** New ≤15K-token fast-path summary in the tarball — fits in one Read on any agent. Read order is now `llms-quick.txt` → `llms.txt` → `llms-full.txt`.
53
53
  - **Companion package `@devalok/eslint-plugin-shilp-sutra`** (first release). 12 rules — deprecated-API catches, peer-cliff barrel-import detection, TW3→TW4 classname autofixes. `pnpm add -D @devalok/eslint-plugin-shilp-sutra`, then `shilpSutra.configs['flat/recommended']`. Three presets: `recommended`, `strict`, `migration` (one-shot codemod).
54
+ - **Machine-readable `BREAKING.json` manifest** (v0.40.2+). Structured record of every breaking change per version (moves, narrowings, removals, renames). At `node_modules/@devalok/shilp-sutra/BREAKING.json` after install; subpath export `@devalok/shilp-sutra/BREAKING.json`. AI agents and migration tooling read this instead of parsing CHANGELOG prose. Schema at `BREAKING.schema.json`. Pre-publish-audit gate enforces a manifest entry for every release with a breaking CHANGELOG signal.
54
55
 
55
56
  ## BREAKING CHANGES (v0.40.0)
56
57
 
@@ -4,6 +4,8 @@
4
4
 
5
5
  > Setup recipe for adding `@devalok/shilp-sutra` to a Next.js 13+ App Router project.
6
6
 
7
+ > **Tested cold-install on:** Next 16.2.6 + React 19.2 + Turbopack + pnpm 10.30 + Node 22 + Windows 11 (2026-05-25). Earlier versions of Next 13/14/15 are still supported on this recipe; deltas called out inline.
8
+
7
9
  ## 1. Detect the framework
8
10
 
9
11
  You are in this recipe if **all** of these are true:
@@ -61,27 +63,35 @@ Some components depend on third-party libraries that ship as optional peers. **I
61
63
 
62
64
  ## 3. Configure PostCSS
63
65
 
64
- Create or update `postcss.config.mjs` at the project root:
66
+ **Next 14+ scaffolds this for you.** Verify `postcss.config.mjs` (or `.js` / `.cjs` / `.json`) at the project root contains:
65
67
 
66
68
  ```js
67
- export default {
69
+ const config = {
68
70
  plugins: {
69
71
  "@tailwindcss/postcss": {},
70
72
  },
71
73
  };
74
+
75
+ export default config;
72
76
  ```
73
77
 
74
- If a `postcss.config.{js,cjs,json}` already exists, merge the plugin in. Do not delete the existing file.
78
+ If the file is missing, create it with the contents above. If another PostCSS file exists with different plugins, merge `@tailwindcss/postcss` in do not delete the existing file.
75
79
 
76
80
  ## 4. Wire Tailwind 4 + design tokens
77
81
 
78
- Locate the global CSS file. Common paths in priority order:
82
+ ### 4a. Locate the global CSS file
83
+
84
+ Next 13+ default location depends on the `--src-dir` choice at scaffold time:
85
+
86
+ - `src/app/globals.css` — default since Next 14 when scaffolded without `--src-dir false`. **Most common in Next 16+ defaults.**
87
+ - `app/globals.css` — when scaffolded with `--src-dir false` (no `src/`).
88
+ - `app/global.css` — older Next 13 scaffolds.
79
89
 
80
- - `app/globals.css`
81
- - `src/app/globals.css`
82
- - `app/global.css`
90
+ If none exists, create at whichever path matches the project's existing `app/` location.
83
91
 
84
- If none exists, create `app/globals.css`. Set the file contents to (or merge into):
92
+ ### 4b. Replace the scaffold's CSS with the shilp-sutra setup
93
+
94
+ A fresh `create-next-app` scaffold writes a `globals.css` with `:root` color vars, an `@theme inline` block linked to Geist font vars, a `prefers-color-scheme` dark override, and a `body { font-family: Arial }` block. **Replace the entire file** with the shilp-sutra setup unless you have a specific reason to keep scaffold styles:
85
95
 
86
96
  ```css
87
97
  @import "tailwindcss";
@@ -90,7 +100,11 @@ If none exists, create `app/globals.css`. Set the file contents to (or merge int
90
100
 
91
101
  **Order matters.** `tailwindcss` MUST come first. The shilp-sutra `/css` entry registers `@theme` blocks that the Tailwind import must process.
92
102
 
93
- If the project has its own theme overrides, place them AFTER both imports:
103
+ If you want to keep the scaffold's color/font vars alongside shilp-sutra tokens (rare — usually you want one or the other), put scaffold's `@theme inline` / `:root` / `body` blocks AFTER the shilp-sutra import. Otherwise the scaffold's `body { font-family: Arial }` will compete with shilp-sutra's font setup.
104
+
105
+ ### 4c. Optional: add your own theme overrides
106
+
107
+ Place after both imports:
94
108
 
95
109
  ```css
96
110
  @import "tailwindcss";
@@ -101,12 +115,16 @@ If the project has its own theme overrides, place them AFTER both imports:
101
115
  }
102
116
  ```
103
117
 
104
- Import the CSS file once from `app/layout.tsx` (it should already be imported in a fresh `create-next-app` project):
118
+ ### 4d. Ensure CSS is imported from the layout
119
+
120
+ The CSS import in `app/layout.tsx` (or `src/app/layout.tsx`) should already exist in a fresh scaffold:
105
121
 
106
122
  ```tsx
107
123
  import "./globals.css";
108
124
  ```
109
125
 
126
+ If you removed the Geist-font import from layout.tsx (see § 6), keep this CSS import line.
127
+
110
128
  ## 5. Configure `transpilePackages`
111
129
 
112
130
  Edit `next.config.{ts,js,mjs}`. Add the `transpilePackages` field:
@@ -125,6 +143,8 @@ If a `transpilePackages` array already exists, append to it. Do not replace.
125
143
 
126
144
  Without `transpilePackages`, Next will refuse to load our pre-built `dist/*.js` because it ships native ESM that does not match Next's CJS-leaning loader for `node_modules`.
127
145
 
146
+ **Turbopack:** as of Next 16, Turbopack is the default bundler (`next dev` and `next build`). `transpilePackages` is respected by both Turbopack and the Webpack backend. Tested on Turbopack 16.2 cold-install (2026-05-25); no extra config needed.
147
+
128
148
  ## 6. Scaffold the Providers wrapper
129
149
 
130
150
  Create `app/providers.tsx`:
@@ -151,13 +171,21 @@ export function Providers({ children }: { children: ReactNode }) {
151
171
  - Drop the `Toaster` import and its JSX usage
152
172
  - Skip installing `sonner`
153
173
 
154
- Mount `<Providers>` from `app/layout.tsx`:
174
+ Mount `<Providers>` from `app/layout.tsx` (or `src/app/layout.tsx`). **Replace the scaffold's layout** with the version below — the scaffold imports `next/font/google` (Geist) and applies font-variable classes to `<html>`, which you don't need when shilp-sutra ships its own fonts:
155
175
 
156
176
  ```tsx
177
+ import type { Metadata } from "next";
157
178
  import "./globals.css";
158
179
  import { Providers } from "./providers";
159
180
 
160
- export default function RootLayout({ children }: { children: React.ReactNode }) {
181
+ export const metadata: Metadata = {
182
+ title: "Your app",
183
+ description: "Built with shilp-sutra",
184
+ };
185
+
186
+ export default function RootLayout({
187
+ children,
188
+ }: Readonly<{ children: React.ReactNode }>) {
161
189
  return (
162
190
  <html lang="en" suppressHydrationWarning>
163
191
  <body>
@@ -168,11 +196,20 @@ export default function RootLayout({ children }: { children: React.ReactNode })
168
196
  }
169
197
  ```
170
198
 
199
+ Specifically, **remove these scaffold lines**:
200
+
201
+ - `import { Geist, Geist_Mono } from "next/font/google";`
202
+ - The `const geistSans = Geist({...})` and `const geistMono = Geist_Mono({...})` blocks
203
+ - The `className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}` on `<html>`
204
+ - The `className="min-h-full flex flex-col"` on `<body>`
205
+
206
+ If you want to keep Geist alongside shilp-sutra's fonts, leave the `Geist` imports — but know that shilp-sutra's `font-sans` token resolves to Inter (body) and Ranade (display), not to the scaffold's `--font-geist-sans`. Loading both is wasted bytes.
207
+
171
208
  `suppressHydrationWarning` on `<html>` is required because `next-themes` writes the `class` attribute before React hydrates. Without it, every page logs a hydration warning.
172
209
 
173
210
  ## 7. Verify the install
174
211
 
175
- Replace the contents of `app/page.tsx`:
212
+ Replace the contents of `app/page.tsx` (or `src/app/page.tsx`). The scaffold's `page.tsx` imports `next/image` and renders the Vercel marketing layout — replace the whole file:
176
213
 
177
214
  ```tsx
178
215
  import { Button } from "@devalok/shilp-sutra/ui/button";
@@ -211,6 +248,7 @@ If anything is off, see [troubleshoot.md](./troubleshoot.md).
211
248
  ## 8. Common gotchas
212
249
 
213
250
  - **CSS import order.** `tailwindcss` BEFORE `@devalok/shilp-sutra/css`. Reversing the order silently produces a build with no design-system utilities.
251
+ - **Scaffold's `body { font-family: Arial }` overrides shilp-sutra fonts.** The `create-next-app` `globals.css` template sets `font-family: Arial, Helvetica, sans-serif` on `<body>`. If you kept the scaffold's body styles, they win the cascade over shilp-sutra's `font-sans`. § 4b says to replace the whole file — follow it.
214
252
  - **Multiple `framer-motion` copies.** Run `pnpm why framer-motion`. If it shows more than one resolved version, contexts (`MotionConfig`, `LayoutGroup`, `AnimatePresence`) silently break. Fix:
215
253
  ```jsonc
216
254
  // package.json
@@ -224,7 +262,9 @@ If anything is off, see [troubleshoot.md](./troubleshoot.md).
224
262
  ```
225
263
  For npm/yarn/bun equivalents, see [troubleshoot.md](./troubleshoot.md).
226
264
  - **Per-component imports keep RSC fast AND avoid peer-dep cliffs.** Inside Server Components, prefer `@devalok/shilp-sutra/ui/text`, `…/composed/page-header`, etc. The barrel `@devalok/shilp-sutra/ui` re-exports many client components — including some with hard peer-dep imports (e.g. `input-otp`) — so it both inflates the client bundle and forces those peers to be installed even when you never render those components. See [server-components.md](./server-components.md) for the full RSC-safety matrix.
227
- - **`p-3` vs `p-ds-03` — both are valid.** DS spacing uses the `--spacing-ds-*` namespace (`p-ds-04`, `gap-ds-03`); Tailwind 4's default numeric scale (`p-4`, `gap-2`) coexists by design. Pick `p-ds-*` for values that should track DS theme changes (card padding, form gaps); pick `p-N` for one-off layout values (section breathing room). Do NOT mass-codemod `p-4` → `p-ds-04` — that is not what the package intends.
265
+ - **`p-3` vs `p-ds-03` — both are valid.** DS spacing uses the `--spacing-ds-*` namespace (`p-ds-04`, `gap-ds-03`); Tailwind 4's default numeric scale (`p-4`, `gap-2`) coexists by design. Pick `p-ds-*` for values that should track DS theme changes (card padding, form gaps); pick `p-N` for one-off layout values (section breathing room). Do NOT mass-codemod `p-4` → `p-ds-04` — that is not what the package intends. For layout rhythm, pick a 3-tier cadence (`ds-03` related / `ds-05` grouped / `ds-07` section), not every adjacent token.
266
+ - **Auto-generated `pnpm-workspace.yaml`.** `pnpm 10+` writes a `pnpm-workspace.yaml` at the project root on first install with `ignoredBuiltDependencies` entries. This is harmless for a standalone app, but if you're nesting this project inside a larger monorepo, delete this file and use the parent monorepo's workspace config instead.
267
+ - **Auto-generated `AGENTS.md`.** `create-next-app` writes an `AGENTS.md` with managed `<!-- BEGIN:nextjs-agent-rules -->` / `<!-- END:nextjs-agent-rules -->` markers. Shilp Sutra's agent rules use `<!-- BEGIN:shilp-sutra-agent-rules -->` markers — they coexist cleanly. If you install the shilp-sutra Agent Skill (see the repo root `AGENTS.md` for the one-liner), it adds its block alongside Next's, not over it.
228
268
  - **Bare `shadow` is dead.** Tailwind 4 has no `--shadow-DEFAULT`. Use `shadow-raised`, `shadow-overlay`, or `shadow-floating`.
229
269
 
230
270
  ## 9. What you should NOT do
@@ -18,6 +18,25 @@ A version bump is **not** safe-by-default. Breaking changes in this design syste
18
18
 
19
19
  ## Step 2 — find affected call sites in your code
20
20
 
21
+ **Fastest path — read the machine-readable manifest:**
22
+
23
+ ```bash
24
+ # Lists every break per version as structured data (moves, narrowings, removals)
25
+ cat node_modules/@devalok/shilp-sutra/BREAKING.json
26
+ ```
27
+
28
+ Or programmatically:
29
+
30
+ ```js
31
+ import manifest from '@devalok/shilp-sutra/BREAKING.json'
32
+ // manifest.versions["0.40.0"].moved → [{ symbol, from, to, peer, eslintRule }, …]
33
+ // manifest.versions["0.40.0"].narrowed → [{ prop, components, from, to, fix }, …]
34
+ ```
35
+
36
+ Schema: `@devalok/shilp-sutra/BREAKING.schema.json`. AI agents should prefer this over prose-parsing CHANGELOG.
37
+
38
+ **Or grep manually:**
39
+
21
40
  ```bash
22
41
  # Symbols moved out of barrels (0.40.0 peer-cliff cleanup example):
23
42
  grep -rn "from '@devalok/shilp-sutra/ui'" src/ | grep -E "Toaster|toast|InputOTP"