@vadimcomanescu/nadicode-design-system 4.0.0 → 4.0.2

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 (49) hide show
  1. package/.agents/skills/seed/SKILL.md +38 -166
  2. package/.agents/skills/seed/references/animation.md +2 -2
  3. package/.agents/skills/seed/references/responsive.md +1 -1
  4. package/README.md +2 -2
  5. package/dist/catalog/components.js +4 -4
  6. package/dist/{chunk-7A2RXKGH.js → chunk-GJ557DGH.js} +1 -1
  7. package/dist/{chunk-7XLZCXUL.js → chunk-K4U67BVG.js} +1 -1
  8. package/dist/{chunk-TUJZMJXW.js → chunk-LK2L3C7D.js} +1 -1
  9. package/dist/{chunk-DSMGCFMJ.js → chunk-POFFOUQW.js} +2 -5
  10. package/dist/components/blocks/HeroBlock.js +2 -2
  11. package/dist/components/page-kits/LandingPageKit.js +3 -3
  12. package/dist/components/page-kits/ServiceSuitePageKit.js +3 -3
  13. package/dist/components/ui/AvatarUpload.js +1 -1
  14. package/dist/components/ui/MouseEffect.js +1 -1
  15. package/eslint-rules/nadicode/config.js +1 -0
  16. package/eslint-rules/nadicode/index.js +2 -0
  17. package/eslint-rules/nadicode/rules/__tests__/require-catalog-import.test.js +111 -0
  18. package/eslint-rules/nadicode/rules/no-has-svg-selector.js +1 -1
  19. package/eslint-rules/nadicode/rules/require-catalog-import.js +59 -0
  20. package/package.json +1 -338
  21. package/scripts/ds-check.mjs +0 -10
  22. package/scripts/sync-seed-skill.mjs +0 -3
  23. package/.agents/skills/seed/contract.md +0 -104
  24. package/.agents/skills/seed/intent-map.md +0 -320
  25. package/.agents/skills/seed/recipes/agency-home.md +0 -311
  26. package/.agents/skills/seed/recipes/agents-chat.md +0 -305
  27. package/.agents/skills/seed/recipes/analytics.md +0 -253
  28. package/.agents/skills/seed/recipes/auth.md +0 -254
  29. package/.agents/skills/seed/recipes/blog-content.md +0 -307
  30. package/.agents/skills/seed/recipes/checkout.md +0 -311
  31. package/.agents/skills/seed/recipes/company-about.md +0 -276
  32. package/.agents/skills/seed/recipes/company-contact.md +0 -234
  33. package/.agents/skills/seed/recipes/crud-form.md +0 -233
  34. package/.agents/skills/seed/recipes/crud-list-detail.md +0 -230
  35. package/.agents/skills/seed/recipes/dashboard.md +0 -354
  36. package/.agents/skills/seed/recipes/digital-workers.md +0 -314
  37. package/.agents/skills/seed/recipes/error-pages.md +0 -199
  38. package/.agents/skills/seed/recipes/marketing-landing.md +0 -293
  39. package/.agents/skills/seed/recipes/marketing-shell.md +0 -156
  40. package/.agents/skills/seed/recipes/navigation-shell.md +0 -786
  41. package/.agents/skills/seed/recipes/onboarding.md +0 -258
  42. package/.agents/skills/seed/recipes/pricing.md +0 -271
  43. package/.agents/skills/seed/recipes/service-detail.md +0 -302
  44. package/.agents/skills/seed/recipes/settings.md +0 -252
  45. package/.agents/skills/seed/references/blocks.md +0 -128
  46. package/.agents/skills/seed/references/components.md +0 -287
  47. package/.agents/skills/seed/references/icons.md +0 -169
  48. package/.agents/skills/seed/references/nextjs.md +0 -49
  49. package/.agents/skills/seed/references/tokens.md +0 -88
@@ -3,8 +3,8 @@ name: Seed Design System
3
3
  description: >
4
4
  Use when building UI with the Seed Design System or composing full pages from
5
5
  Seed components. Covers tokens, components, glass effects, animations,
6
- dual-axis theming, page recipes, and Next.js App Router integration.
7
- tags: [seed, design-system, arctic-glow, react, tailwind, radix, glassmorphism, recipes]
6
+ dual-axis theming, page-kits, and Next.js App Router integration.
7
+ tags: [seed, design-system, arctic-glow, react, tailwind, radix, glassmorphism, page-kits]
8
8
  ---
9
9
 
10
10
  # Seed Design System -- Agent Skill
@@ -20,7 +20,7 @@ Consumer scaffold contract: brand customization stays palette-only unless the ta
20
20
 
21
21
  ## Component Discovery
22
22
 
23
- The catalog (`./catalog` and `./catalog/components` subpath exports) is the single surface for discovering and consuming Seed components.
23
+ The catalog (`./catalog` and `./catalog/components` subpath exports) is the single surface for discovering and consuming Seed blocks and page-kits.
24
24
 
25
25
  **Discovery** (server-safe, read this to learn what's available):
26
26
  ```ts
@@ -36,61 +36,19 @@ import { seedComponents } from "@vadimcomanescu/nadicode-design-system/catalog/c
36
36
 
37
37
  Usage:
38
38
  ```tsx
39
- const { LoginBlock, Button, Card } = seedComponents
39
+ const { LoginBlock, DashboardPageKit } = seedComponents
40
40
  <LoginBlock onSubmit={handleLogin} />
41
41
  ```
42
42
 
43
- Do not import from individual subpath exports. Do not browse package exports. The catalog is the single source of truth.
43
+ **Blocks and page-kits** are imported exclusively from `seedComponents`. Do not import them via individual subpath exports (ADR 0009). The ESLint rule `nadicode/require-catalog-import` enforces this at lint time.
44
44
 
45
- The ESLint rule `nadicode/no-raw-recharts-import` and related rules enforce correct import paths at lint time. See the ESLint Rule Reference in `contract.md`.
46
-
47
- The derived references under `references/components.md` and `references/blocks.md` are generated from the catalog. Any repo `Path` column there is a maintainer source path, not a consumer import path.
45
+ **UI primitives** (Button, Heading, Input, etc.), icons, charts, and effects are imported via individual subpath exports. They are not registered in the catalog.
48
46
 
49
47
  ## Read Order
50
48
 
51
- 1. **This file** -- router, quick references, forbidden patterns
52
- 2. **`contract.md`** -- binary rules, package integration contract
53
- 3. **catalog** (`@vadimcomanescu/nadicode-design-system/catalog`) -- machine-readable component metadata (variants, props, tiers)
54
- 4. **`intent-map.md`** -- intent decision tree + recipe index
55
- 6. **`recipes/<page-type>.md`** -- matching recipe for your page
56
- 7. **`references/`** -- deep dives as needed
57
- 8. **`references/brand-override.md`** -- palette-only brand customization guide for seeded apps
58
-
59
- ---
60
-
61
- ## Intent Decision Tree
62
-
63
- What are you building? Follow the tree to find your recipe.
64
-
65
- ```
66
- Does user have a session?
67
- YES --> app-shell intents:
68
- dashboard .......... recipes/dashboard.md
69
- CRUD list/detail ... recipes/crud-list-detail.md
70
- CRUD form .......... recipes/crud-form.md
71
- settings ........... recipes/settings.md
72
- analytics .......... recipes/analytics.md
73
- agents/chat ........ recipes/agents-chat.md
74
- navigation shell ... recipes/navigation-shell.md
75
- NO --> auth?
76
- YES --> recipes/auth.md (auth-shell)
77
- onboarding?
78
- YES --> recipes/onboarding.md (onboarding-shell)
79
- marketing intents (marketing-shell):
80
- agency home ...... recipes/agency-home.md
81
- landing .......... recipes/marketing-landing.md
82
- digital workers .. recipes/digital-workers.md
83
- service detail ... recipes/service-detail.md
84
- pricing .......... recipes/pricing.md
85
- blog/content ..... recipes/blog-content.md
86
- about/team ....... recipes/company-about.md
87
- contact .......... recipes/company-contact.md
88
- checkout ......... recipes/checkout.md
89
- marketing shell .. recipes/marketing-shell.md
90
- error pages --> recipes/error-pages.md (fallback-shell)
91
- ```
92
-
93
- Full intent-to-recipe mapping with shell selection: see `intent-map.md`.
49
+ 1. **This file** -- router, quick references, forbidden patterns, binary rules
50
+ 2. **catalog** (`@vadimcomanescu/nadicode-design-system/catalog`) -- machine-readable component metadata (variants, props, tiers)
51
+ 3. **`references/`** -- deep dives as needed
94
52
 
95
53
  ---
96
54
 
@@ -113,6 +71,28 @@ Full intent-to-recipe mapping with shell selection: see `intent-map.md`.
113
71
  | CSS hex in vars: `--color-bg: #0F1114` | `--color-background: 15 17 20` | CSS vars use space-separated RGB |
114
72
  | Block without `interface *Props` | `interface MyBlockProps { title?: string }` | Integrity test enforces |
115
73
  | Required content props | Optional with defaults in destructuring | Blocks render standalone |
74
+ | Inline/floating labels | `Label` above control (stacked) | Form convention |
75
+ | `text-[10px]`, `text-[11px]` | `text-xs`, `text-sm`, `Heading`, `Typography` | No arbitrary text sizes |
76
+ | Ad-hoc `chat-*` classes | Compose Seed primitives + motion tokens | No custom chat classes |
77
+ | `import { BarChart } from "recharts"` | `import { BarChart } from "@vadimcomanescu/nadicode-design-system/charts"` | No direct recharts |
78
+ | Ad-hoc Card + value for KPIs | `MetricCard` | Use the DS component |
79
+ | Hex/rgb in chart config | `var(--color-chart-N)` tokens | Chart colors are tokenized |
80
+ | Generic English defaults | Override ALL default copy per brand | No shipping placeholder text |
81
+ | Hardcoded hex in components | Map to semantic tokens | Brand colors via tokens only |
82
+
83
+ ---
84
+
85
+ ## Brand Customization
86
+
87
+ Override all default copy. Map brand colors to semantic tokens. Verify contrast (WCAG AA: 4.5:1 body, 3:1 large). See `references/brand-override.md` for glass intensity presets.
88
+
89
+ ## Dashboard Rules
90
+
91
+ KPI cards: `MetricCard`. Charts: empty-data guard required (`data.length > 0`). Chart colors: `var(--color-chart-N)` tokens. Import from `./charts`, never `recharts` directly. Sidebar navigation must include IA grouping with `SidebarGroupLabel`.
92
+
93
+ ## Admin Chat
94
+
95
+ Chat features must include all three agentic layers: Conversation, Tooling, Traceability. See catalog for available components in each layer. Analytics must use Seed chart primitives.
116
96
 
117
97
  ---
118
98
 
@@ -132,7 +112,7 @@ Full intent-to-recipe mapping with shell selection: see `intent-map.md`.
132
112
 
133
113
  **Sidebar:** `sidebar`, `sidebar-foreground`, `sidebar-primary`, `sidebar-accent`, `sidebar-border`, `sidebar-ring`
134
114
 
135
- Full token tables with CSS variables and Radix scales: `references/tokens.md`
115
+ Token source of truth: `src/lib/tokens.config.js` (authored), `src/index.css` (generated).
136
116
 
137
117
  ---
138
118
 
@@ -223,13 +203,7 @@ import { motionSpring, fadeInUp, blockStagger } from "@/lib/motion"
223
203
 
224
204
  ### Spring Presets
225
205
 
226
- | Name | Stiffness | Damping | Mass | Use For |
227
- |------|-----------|---------|------|---------|
228
- | `snappy` | 400 | 28 | 0.8 | Micro-interactions, tooltips |
229
- | `gentle` | 200 | 20 | 1.0 | Page transitions, drawers |
230
- | `bouncy` | 300 | 14 | 0.8 | Celebration, completion |
231
- | `dramatic` | 500 | 24 | 1.2 | Hero entrances |
232
- | `wobbly` | bloom only | | | Extra bounce |
206
+ `snappy` (micro-interactions), `gentle` (page transitions), `bouncy` (celebration), `dramatic` (hero entrances), `wobbly` (bloom only). Full values: `references/animation.md`.
233
207
 
234
208
  ### Duration Tokens
235
209
 
@@ -267,19 +241,7 @@ import { SettingsIcon, BellIcon } from "@vadimcomanescu/nadicode-design-system/i
267
241
 
268
242
  **Total: 399 icons.** Before adding a new icon, check whether it already exports from `@vadimcomanescu/nadicode-design-system/icons` or a matching `@vadimcomanescu/nadicode-design-system/icons/<name>` subpath.
269
243
 
270
- ### Adding a New Icon
271
-
272
- 1. **Check if it exists** (399 total -- likely yes).
273
- 2. **If missing:** add it to `lucide-wrapped.tsx` using `createAnimatedIcon`:
274
- ```tsx
275
- import { Home } from "lucide-react"
276
- export const HomeIcon = createAnimatedIcon(Home, "HomeIcon")
277
- ```
278
- 3. **If the needed icon is missing**, stop and request an upstream DS export. Do not hand-craft a local scaffold copy just to bypass the package contract.
279
-
280
- `createAnimatedIcon` is also exported for consumers to wrap any Lucide icon ad-hoc without adding it to the catalog.
281
-
282
- Full catalog: `references/icons.md`
244
+ If an icon is missing, add it to `lucide-wrapped.tsx` via `createAnimatedIcon`. Do not hand-craft local copies to bypass the package contract.
283
245
 
284
246
  ---
285
247
 
@@ -328,6 +290,8 @@ Every page = **Shell > Sections > Components**.
328
290
  - 2-8 sections (vertical bands, no nesting)
329
291
  - 1-6 components per section via CSS grid/flex
330
292
 
293
+ Page-kits in the catalog ARE the ready-made compositions. Use `seedComponents.<Name>PageKit` from `@vadimcomanescu/nadicode-design-system/catalog/components` rather than assembling pages by hand.
294
+
331
295
  ### Shell Selection
332
296
 
333
297
  | Intent | Shell | Components |
@@ -340,69 +304,9 @@ Every page = **Shell > Sections > Components**.
340
304
 
341
305
  Content widths, vertical rhythm, responsive contracts: `references/composition.md`
342
306
 
343
- ### Kanban Board (Drag & Drop)
307
+ ### Kanban Board
344
308
 
345
- Compound component for multi-column sortable boards (project boards, runs views, pipelines).
346
-
347
- ```tsx
348
- import {
349
- KanbanBoard, KanbanColumn, KanbanColumnHeader,
350
- KanbanItem, KanbanHandle,
351
- } from '@vadimcomanescu/nadicode-design-system/kanban-board'
352
- import type { KanbanColumnState, KanbanMoveMeta } from '@vadimcomanescu/nadicode-design-system/kanban-board'
353
- ```
354
-
355
- **Architecture:** `@dnd-kit/core` + `@dnd-kit/sortable` internally. Consumer API is Seed-owned (no dnd-kit types leak).
356
-
357
- **Usage:**
358
-
359
- ```tsx
360
- type Task = { id: string; title: string }
361
-
362
- const [columns, setColumns] = useState<KanbanColumnState<Task>[]>([
363
- { id: 'todo', items: [{ id: '1', title: 'Task A' }] },
364
- { id: 'done', items: [] },
365
- ])
366
-
367
- <KanbanBoard
368
- value={columns}
369
- onValueChange={(next, meta) => {
370
- setColumns([...next])
371
- // meta: { item, itemId, fromColumnId, toColumnId, fromIndex, toIndex }
372
- }}
373
- getItemId={(task) => task.id}
374
- getItemLabel={(task) => task.title}
375
- canMove={({ fromColumnId, toColumnId }) => isAllowed(fromColumnId, toColumnId)}
376
- renderOverlay={(task) => <MyCard task={task} />}
377
- >
378
- {columns.map((col) => (
379
- <KanbanColumn key={col.id} id={col.id} items={col.items} aria-label={col.name}>
380
- <KanbanColumnHeader>{col.name} <Badge variant="outline">{col.items.length}</Badge></KanbanColumnHeader>
381
- {col.items.map((task) => (
382
- <KanbanItem key={task.id} value={task}>
383
- <KanbanHandle aria-label={`Move ${task.title}`} />
384
- <MyCard task={task} />
385
- </KanbanItem>
386
- ))}
387
- </KanbanColumn>
388
- ))}
389
- </KanbanBoard>
390
- ```
391
-
392
- **Key props:**
393
-
394
- | Prop | Required | Purpose |
395
- |------|----------|---------|
396
- | `value` | Yes | `KanbanColumnState<T>[]` -- controlled column state |
397
- | `onValueChange` | Yes | `(next, meta) => void` -- fires with new state + move metadata |
398
- | `getItemId` | Yes | Extract stable ID from item |
399
- | `getItemLabel` | No | Human label for screen reader announcements |
400
- | `canMove` | No | Constraint callback to reject moves |
401
- | `renderOverlay` | No | Custom drag ghost (renders inside `glass-floating`) |
402
- | `activationDistance` | No | Px before drag starts (default: 5) |
403
- | `items` on Column | Yes | Pass the column's items array for SortableContext |
404
-
405
- **Card content is consumer-owned.** The DS provides the board structure, drag mechanics, glass styling, and accessibility. Compose card interiors from existing DS primitives: `Badge`, `StatusDot`, `Typography`, `Button`, `Avatar`.
309
+ Compound component via `seedComponents`. Uses `@dnd-kit` internally (no dnd-kit types leak). Card content is consumer-owned. See catalog entry for full props and sub-components. Types: `@vadimcomanescu/nadicode-design-system/kanban-board`.
406
310
 
407
311
  ---
408
312
 
@@ -415,46 +319,14 @@ Patterns: `references/state-machines.md`
415
319
 
416
320
  ---
417
321
 
418
- ## Recipe Index
419
-
420
- | Intent | Recipe | Shell |
421
- |--------|--------|-------|
422
- | Dashboard | `recipes/dashboard.md` | app-shell |
423
- | Marketing Landing | `recipes/marketing-landing.md` | marketing-shell |
424
- | Agency Home | `recipes/agency-home.md` | marketing-shell |
425
- | Digital Workers | `recipes/digital-workers.md` | marketing-shell |
426
- | Service Detail | `recipes/service-detail.md` | marketing-shell |
427
- | CRUD List + Detail | `recipes/crud-list-detail.md` | app-shell |
428
- | CRUD Form | `recipes/crud-form.md` | app-shell |
429
- | Settings | `recipes/settings.md` | app-shell |
430
- | Auth | `recipes/auth.md` | auth-shell |
431
- | Onboarding | `recipes/onboarding.md` | onboarding-shell |
432
- | Pricing | `recipes/pricing.md` | marketing-shell |
433
- | Analytics | `recipes/analytics.md` | app-shell |
434
- | Agent Chat | `recipes/agents-chat.md` | app-shell |
435
- | Error Pages | `recipes/error-pages.md` | fallback-shell |
436
- | Navigation Shell | `recipes/navigation-shell.md` | app-shell |
437
- | Blog / Content | `recipes/blog-content.md` | marketing-shell |
438
- | Company About | `recipes/company-about.md` | marketing-shell |
439
- | Company Contact | `recipes/company-contact.md` | marketing-shell |
440
- | Marketing Shell | `recipes/marketing-shell.md` | marketing-shell |
441
- | Checkout | `recipes/checkout.md` | marketing-shell |
442
-
443
- ---
444
-
445
322
  ## Reference Index
446
323
 
447
324
  | File | Contents |
448
325
  |------|----------|
449
- | `references/tokens.md` | Radix scales, semantic token map, CSS variables, bloom palette |
450
- | `references/components.md` | All UI components with tiers inline, Radix primitives, agentic UI |
451
326
  | `references/patterns.md` | Golden pattern + 4 code examples: Button, Input, Dialog, LoginBlock |
452
327
  | `references/animation.md` | Springs, easings, durations, stagger, choreography, reduced motion |
453
328
  | `references/glass-and-effects.md` | Glass tier CSS, decorative components, text effects, shaders |
454
- | `references/blocks.md` | Blocks by domain with import paths |
455
- | `references/icons.md` | Animated icon usage patterns |
456
329
  | `references/opinions.md` | Decision tables from Opinions Bible |
457
- | `references/nextjs.md` | App Router setup, providers, SSR boundaries, showcase |
458
330
  | `references/composition.md` | Layout algebra, spacing, grid patterns, content widths |
459
331
  | `references/responsive.md` | Breakpoint contracts, mobile-first, touch targets |
460
332
  | `references/state-machines.md` | State machines, loading tiers, streaming, error handling |
@@ -90,7 +90,7 @@ What is the element?
90
90
 
91
91
  ## Storyboard Format
92
92
 
93
- Every recipe includes an animation storyboard:
93
+ Animation storyboard format (use when documenting page-kit entrance sequences):
94
94
 
95
95
  ```
96
96
  ANIMATION STORYBOARD
@@ -254,7 +254,7 @@ When `prefers-reduced-motion` is active:
254
254
  - ScrollFadeIn elements visible immediately
255
255
  - Continuous animations (aurora, shimmer, meteor) paused via CSS
256
256
 
257
- Every recipe storyboard includes a `REDUCED` line specifying fallback behavior.
257
+ Every storyboard includes a `REDUCED` line specifying fallback behavior when `prefers-reduced-motion` is active.
258
258
 
259
259
  ---
260
260
 
@@ -17,7 +17,7 @@ Breakpoint contracts, mobile-first patterns, touch targets, and responsive rules
17
17
 
18
18
  **Design priority**: Mobile-first. Default styles target mobile, add complexity at breakpoints.
19
19
 
20
- **Primary breakpoints** (used in recipes): default, `sm:`, `lg:`, `xl:`. Use `md:` and `2xl:` sparingly.
20
+ **Primary breakpoints**: default, `sm:`, `lg:`, `xl:`. Use `md:` and `2xl:` sparingly.
21
21
 
22
22
  ---
23
23
 
package/README.md CHANGED
@@ -15,12 +15,13 @@ The dev server runs on `http://localhost:5001` and serves the showcase routes un
15
15
 
16
16
  Consumer apps install Seed through an exact released package version. For unpublished local work, stage a tarball under `.nadicode/packages/` and install that committed relative artifact instead. Do not point apps at a live DS repo directory.
17
17
 
18
+ Component discovery and consumption go through the catalog. Blocks and page-kits have no individual subpath exports.
19
+
18
20
  Canonical consumer docs:
19
21
 
20
22
  - [docs/nadicode/SCAFFOLDING_PROCESS.md](docs/nadicode/SCAFFOLDING_PROCESS.md), normative runtime and ownership contract
21
23
  - [docs/nadicode/ADOPTION_PLAYBOOK.md](docs/nadicode/ADOPTION_PLAYBOOK.md), step-by-step install and wiring flow
22
24
  - [.agents/skills/seed/SKILL.md](.agents/skills/seed/SKILL.md), synced agent-facing usage guide
23
- - [.agents/skills/seed/contract.md](.agents/skills/seed/contract.md), synced binary consumer rules
24
25
 
25
26
  ## Canonical Sources
26
27
 
@@ -31,7 +32,6 @@ The repo treats structured truth and prose differently.
31
32
  - Public package surface lives in `package.json` exports, `src/catalog/catalog.ts`, and `bin/shipped-files.json`.
32
33
  - Consumer ownership and package-backed runtime rules live in [docs/nadicode/SCAFFOLDING_PROCESS.md](docs/nadicode/SCAFFOLDING_PROCESS.md).
33
34
  - Release steps live in [docs/releasing-package.md](docs/releasing-package.md).
34
- - Component metadata lives in `dist/catalog/catalog.js`, generated from `src/catalog/catalog.ts`.
35
35
 
36
36
  Use prose docs for guidance and rationale. Use scripts, manifests, and generated artifacts for anything that must stay machine-accurate.
37
37
 
@@ -7,14 +7,14 @@ import { PricingPageKit } from '../chunk-RMGDDOCD.js';
7
7
  import { ProfileSettingsPageKit } from '../chunk-MGSGCARB.js';
8
8
  import { RecoveryPageKit } from '../chunk-BRCBJ3S4.js';
9
9
  import { ResetPageKit } from '../chunk-LP6ZZYOQ.js';
10
- import { ServiceSuitePageKit } from '../chunk-7XLZCXUL.js';
10
+ import { ServiceSuitePageKit } from '../chunk-K4U67BVG.js';
11
11
  import { SettingsPageKit } from '../chunk-RKQPU75I.js';
12
12
  import { SignupPageKit } from '../chunk-BRICSLHJ.js';
13
13
  import { SuccessPageKit } from '../chunk-3U56FXYC.js';
14
14
  import { DashboardPageKit } from '../chunk-C33GUEDY.js';
15
15
  import { ErrorPageKit } from '../chunk-HPTHS7SX.js';
16
16
  import { KanbanBoardPageKit } from '../chunk-25BOZMXA.js';
17
- import { LandingPageKit } from '../chunk-TUJZMJXW.js';
17
+ import { LandingPageKit } from '../chunk-LK2L3C7D.js';
18
18
  import { LoginPageKit } from '../chunk-Z2WION42.js';
19
19
  import { OnboardingPageKit } from '../chunk-BYEHHZZN.js';
20
20
  import { AccountLockedPageKit } from '../chunk-DNJEVMDY.js';
@@ -52,7 +52,7 @@ import { PasswordRecoveryBlock } from '../chunk-5PZ4VR2D.js';
52
52
  import { PricingBlock } from '../chunk-VNNAL4A6.js';
53
53
  import '../chunk-DARC2ACH.js';
54
54
  import { GalleryBlock } from '../chunk-FTGFOK6T.js';
55
- import { HeroBlock } from '../chunk-7A2RXKGH.js';
55
+ import { HeroBlock } from '../chunk-GJ557DGH.js';
56
56
  import { HeroSectionBlock } from '../chunk-ALA6OM7K.js';
57
57
  import '../chunk-QQOWC53X.js';
58
58
  import { HeaderBlock } from '../chunk-WOYBVPXK.js';
@@ -182,7 +182,7 @@ import '../chunk-D4NC7WX5.js';
182
182
  import '../chunk-5UESKK6S.js';
183
183
  import '../chunk-NAAU5IWU.js';
184
184
  import '../chunk-4S326Z3D.js';
185
- import '../chunk-DSMGCFMJ.js';
185
+ import '../chunk-POFFOUQW.js';
186
186
  import '../chunk-GJUR6HT3.js';
187
187
  import '../chunk-7KIDDF3I.js';
188
188
  import '../chunk-4GSFNJAJ.js';
@@ -3,7 +3,7 @@ import { AnimatedGradientText } from './chunk-XZ3A33GP.js';
3
3
  import { Heading } from './chunk-WI547C47.js';
4
4
  import { siteConfig } from './chunk-A7NUWD76.js';
5
5
  import { Card, CardHeader, CardContent } from './chunk-AH6YSYYT.js';
6
- import { MouseGlow } from './chunk-DSMGCFMJ.js';
6
+ import { MouseGlow } from './chunk-POFFOUQW.js';
7
7
  import { Button } from './chunk-7KIDDF3I.js';
8
8
  import { m, heroStagger } from './chunk-PD2YEH3H.js';
9
9
  import { ZapIcon } from './chunk-FLF5AMNO.js';
@@ -2,7 +2,7 @@ import { MarketingShellPageKit } from './chunk-Z233ZQZE.js';
2
2
  import { TeamBlock } from './chunk-VBZQ4DBE.js';
3
3
  import { TestimonialsBlock } from './chunk-FV2G6SAF.js';
4
4
  import { ProcessFlowBlock } from './chunk-HZERHGBT.js';
5
- import { HeroBlock } from './chunk-7A2RXKGH.js';
5
+ import { HeroBlock } from './chunk-GJ557DGH.js';
6
6
  import { FAQBlock } from './chunk-NEHCPO53.js';
7
7
  import { FeatureBlock } from './chunk-HJ3A2YNO.js';
8
8
  import { CallToActionBlock } from './chunk-GJPTPLCQ.js';
@@ -3,7 +3,7 @@ import { SocialProofBlock } from './chunk-C7WHMSF3.js';
3
3
  import { StatsMarketingBlock } from './chunk-QIHA7S3A.js';
4
4
  import { NewsletterBlock } from './chunk-K7NQ6ZAW.js';
5
5
  import { PricingBlock } from './chunk-VNNAL4A6.js';
6
- import { HeroBlock } from './chunk-7A2RXKGH.js';
6
+ import { HeroBlock } from './chunk-GJ557DGH.js';
7
7
  import { FAQBlock } from './chunk-NEHCPO53.js';
8
8
  import { FeatureBlock } from './chunk-HJ3A2YNO.js';
9
9
  import { CallToActionBlock } from './chunk-GJPTPLCQ.js';
@@ -5,10 +5,7 @@ import { createPortal } from 'react-dom';
5
5
  import { useReducedMotion, useMotionValue, useMotionTemplate } from 'motion/react';
6
6
  import { jsxs, jsx } from 'react/jsx-runtime';
7
7
 
8
- function getAccentColor() {
9
- if (typeof window === "undefined") return "10 158 111";
10
- return getComputedStyle(document.documentElement).getPropertyValue("--color-accent").trim() || "10 158 111";
11
- }
8
+ var CSS_ACCENT_095 = "rgb(var(--color-accent) / 0.95)";
12
9
  function MouseGlow({
13
10
  className,
14
11
  dotColor = "rgba(255, 255, 255, 0.5)",
@@ -20,7 +17,7 @@ function MouseGlow({
20
17
  const containerRef = React.useRef(null);
21
18
  const overlayRef = React.useRef(null);
22
19
  const [mounted, setMounted] = React.useState(false);
23
- const resolvedOverlayColor = overlayColor ?? `rgba(${getAccentColor().replace(/ /g, ", ")}, 0.95)`;
20
+ const resolvedOverlayColor = overlayColor ?? CSS_ACCENT_095;
24
21
  React.useEffect(() => {
25
22
  setMounted(true);
26
23
  const handleMouseMove = (e) => {
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- export { HeroBlock } from '../../chunk-7A2RXKGH.js';
2
+ export { HeroBlock } from '../../chunk-GJ557DGH.js';
3
3
  import '../../chunk-G5EO22OR.js';
4
4
  import '../../chunk-OHX2LFAH.js';
5
5
  import '../../chunk-SGI25ZJ6.js';
@@ -14,7 +14,7 @@ import '../../chunk-4O6L5YWT.js';
14
14
  import '../../chunk-WI547C47.js';
15
15
  import '../../chunk-A7NUWD76.js';
16
16
  import '../../chunk-AH6YSYYT.js';
17
- import '../../chunk-DSMGCFMJ.js';
17
+ import '../../chunk-POFFOUQW.js';
18
18
  import '../../chunk-7KIDDF3I.js';
19
19
  import '../../chunk-PD2YEH3H.js';
20
20
  import '../../chunk-CRY67BIF.js';
@@ -1,11 +1,11 @@
1
- export { LandingPageKit } from '../../chunk-TUJZMJXW.js';
1
+ export { LandingPageKit } from '../../chunk-LK2L3C7D.js';
2
2
  import '../../chunk-Z233ZQZE.js';
3
3
  import '../../chunk-C7WHMSF3.js';
4
4
  import '../../chunk-QIHA7S3A.js';
5
5
  import '../../chunk-K7NQ6ZAW.js';
6
6
  import '../../chunk-VNNAL4A6.js';
7
7
  import '../../chunk-DARC2ACH.js';
8
- import '../../chunk-7A2RXKGH.js';
8
+ import '../../chunk-GJ557DGH.js';
9
9
  import '../../chunk-QQOWC53X.js';
10
10
  import '../../chunk-WOYBVPXK.js';
11
11
  import '../../chunk-NEHCPO53.js';
@@ -38,7 +38,7 @@ import '../../chunk-LIBXYD5Q.js';
38
38
  import '../../chunk-I23DDSU7.js';
39
39
  import '../../chunk-AH6YSYYT.js';
40
40
  import '../../chunk-NAAU5IWU.js';
41
- import '../../chunk-DSMGCFMJ.js';
41
+ import '../../chunk-POFFOUQW.js';
42
42
  import '../../chunk-7KIDDF3I.js';
43
43
  import '../../chunk-6FOHUNXR.js';
44
44
  import '../../chunk-PD2YEH3H.js';
@@ -1,9 +1,9 @@
1
- export { ServiceSuitePageKit } from '../../chunk-7XLZCXUL.js';
1
+ export { ServiceSuitePageKit } from '../../chunk-K4U67BVG.js';
2
2
  import '../../chunk-Z233ZQZE.js';
3
3
  import '../../chunk-VBZQ4DBE.js';
4
4
  import '../../chunk-FV2G6SAF.js';
5
5
  import '../../chunk-HZERHGBT.js';
6
- import '../../chunk-7A2RXKGH.js';
6
+ import '../../chunk-GJ557DGH.js';
7
7
  import '../../chunk-QQOWC53X.js';
8
8
  import '../../chunk-WOYBVPXK.js';
9
9
  import '../../chunk-NEHCPO53.js';
@@ -33,7 +33,7 @@ import '../../chunk-LIBXYD5Q.js';
33
33
  import '../../chunk-I23DDSU7.js';
34
34
  import '../../chunk-AH6YSYYT.js';
35
35
  import '../../chunk-NAAU5IWU.js';
36
- import '../../chunk-DSMGCFMJ.js';
36
+ import '../../chunk-POFFOUQW.js';
37
37
  import '../../chunk-7KIDDF3I.js';
38
38
  import '../../chunk-6FOHUNXR.js';
39
39
  import '../../chunk-PD2YEH3H.js';
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { MouseSpotlight } from '../../chunk-DSMGCFMJ.js';
2
+ import { MouseSpotlight } from '../../chunk-POFFOUQW.js';
3
3
  import '../../chunk-PD2YEH3H.js';
4
4
  import '../../chunk-CRY67BIF.js';
5
5
  import '../../chunk-HJC6U46F.js';
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- export { MouseGlow, MouseSpotlight } from '../../chunk-DSMGCFMJ.js';
2
+ export { MouseGlow, MouseSpotlight } from '../../chunk-POFFOUQW.js';
3
3
  import '../../chunk-PD2YEH3H.js';
4
4
  import '../../chunk-CRY67BIF.js';
5
5
  import '../../chunk-HJC6U46F.js';
@@ -83,6 +83,7 @@ export const nadicodeRules = {
83
83
  "nadicode/no-handcoded-empty-state": "error",
84
84
  "nadicode/no-handcoded-field": "error",
85
85
  "nadicode/require-catalog-component": "error",
86
+ "nadicode/require-catalog-import": "error",
86
87
  };
87
88
 
88
89
  function normalizePattern(pattern) {
@@ -70,6 +70,7 @@ import noHandcodedHeading from "./rules/no-handcoded-heading.js";
70
70
  import noHandcodedEmptyState from "./rules/no-handcoded-empty-state.js";
71
71
  import noHandcodedField from "./rules/no-handcoded-field.js";
72
72
  import requireCatalogComponent from "./rules/require-catalog-component.js";
73
+ import requireCatalogImport from "./rules/require-catalog-import.js";
73
74
 
74
75
  export { nadicodeRules, createAllowlistOverrides } from "./config.js";
75
76
 
@@ -147,5 +148,6 @@ export const nadicodePlugin = {
147
148
  "no-handcoded-empty-state": noHandcodedEmptyState,
148
149
  "no-handcoded-field": noHandcodedField,
149
150
  "require-catalog-component": requireCatalogComponent,
151
+ "require-catalog-import": requireCatalogImport,
150
152
  },
151
153
  };
@@ -0,0 +1,111 @@
1
+ import { RuleTester } from "eslint";
2
+ import { describe } from "vitest";
3
+
4
+ import rule from "../require-catalog-import.js";
5
+
6
+ const tester = new RuleTester({
7
+ languageOptions: {
8
+ ecmaVersion: "latest",
9
+ sourceType: "module",
10
+ },
11
+ });
12
+
13
+ describe("require-catalog-import", () => {
14
+ tester.run("require-catalog-import", rule, {
15
+ valid: [
16
+ // Catalog import (correct pattern)
17
+ {
18
+ code: "import { seedComponents } from '@/catalog/components';",
19
+ filename: "/repo/src/app/page.tsx",
20
+ },
21
+ // UI primitive (not a block/page-kit)
22
+ {
23
+ code: "import { Button } from '@/components/ui/Button';",
24
+ filename: "/repo/src/app/page.tsx",
25
+ },
26
+ // Type-only imports are allowed (importKind === "type"), but require TS parser to test.
27
+ // Verified in production via TypeScript ESLint config.
28
+ // Test files are exempt
29
+ {
30
+ code: "import { HeroBlock } from '@/components/blocks/HeroBlock';",
31
+ filename: "/repo/src/components/blocks/__tests__/HeroBlock.test.tsx",
32
+ },
33
+ {
34
+ code: "import { HeroBlock } from '../../blocks/HeroBlock';",
35
+ filename: "/repo/src/components/blocks/HeroBlock.spec.tsx",
36
+ },
37
+ // Catalog barrel itself is exempt
38
+ {
39
+ code: "import { HeroBlock } from '@/components/blocks/HeroBlock';",
40
+ filename: "/repo/src/catalog/components.tsx",
41
+ },
42
+ // Block source files are exempt (internal composition)
43
+ {
44
+ code: "import { AuthLayout } from '../blocks/AuthLayout';",
45
+ filename: "/repo/src/components/blocks/LoginBlock.tsx",
46
+ },
47
+ // Page-kit source files are exempt
48
+ {
49
+ code: "import { HeaderBlock } from '../blocks/HeaderBlock';",
50
+ filename: "/repo/src/components/page-kits/LandingPageKit.tsx",
51
+ },
52
+ ],
53
+ invalid: [
54
+ // Direct block import via absolute alias
55
+ {
56
+ code: "import { HeroBlock } from '@/components/blocks/HeroBlock';",
57
+ filename: "/repo/src/app/page.tsx",
58
+ errors: [
59
+ {
60
+ message:
61
+ "Import 'HeroBlock' from '@/catalog/components' via seedComponents. Direct block/page-kit imports are not allowed (ADR 0009).",
62
+ },
63
+ ],
64
+ },
65
+ // Direct page-kit import via absolute alias
66
+ {
67
+ code: "import { LandingPageKit } from '@/components/page-kits/LandingPageKit';",
68
+ filename: "/repo/src/app/page.tsx",
69
+ errors: [
70
+ {
71
+ message:
72
+ "Import 'LandingPageKit' from '@/catalog/components' via seedComponents. Direct block/page-kit imports are not allowed (ADR 0009).",
73
+ },
74
+ ],
75
+ },
76
+ // Relative block import from pages directory
77
+ {
78
+ code: "import { HeroBlock } from '../../blocks/HeroBlock';",
79
+ filename: "/repo/src/components/pages/showcase/BlocksShowcase.tsx",
80
+ errors: [
81
+ {
82
+ message:
83
+ "Import 'HeroBlock' from '@/catalog/components' via seedComponents. Direct block/page-kit imports are not allowed (ADR 0009).",
84
+ },
85
+ ],
86
+ },
87
+ // Relative block import (one level up)
88
+ {
89
+ code: "import { FooterBlock } from '../blocks/FooterBlock';",
90
+ filename: "/repo/src/components/pages/LandingPage.tsx",
91
+ errors: [
92
+ {
93
+ message:
94
+ "Import 'FooterBlock' from '@/catalog/components' via seedComponents. Direct block/page-kit imports are not allowed (ADR 0009).",
95
+ },
96
+ ],
97
+ },
98
+ // Nested block path (e.g., blocks/user/InviteUserModal)
99
+ {
100
+ code: "import { InviteUserModal } from '../../blocks/user/InviteUserModal';",
101
+ filename: "/repo/src/components/pages/settings/TeamPage.tsx",
102
+ errors: [
103
+ {
104
+ message:
105
+ "Import 'InviteUserModal' from '@/catalog/components' via seedComponents. Direct block/page-kit imports are not allowed (ADR 0009).",
106
+ },
107
+ ],
108
+ },
109
+ ],
110
+ });
111
+ });
@@ -19,7 +19,7 @@ function reportMatches(context, node, tokens) {
19
19
  context.report({
20
20
  node,
21
21
  message:
22
- "Selector '{{sel}}' breaks with animated icon wrappers. Use a data-slot sub-component instead (see golden-pattern.md).",
22
+ "Selector '{{sel}}' breaks with animated icon wrappers. Use a data-slot sub-component instead (see references/patterns.md).",
23
23
  data: { sel: hit },
24
24
  });
25
25
  }