@vadimcomanescu/nadicode-design-system 2.0.9 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/.agents/skills/seed/SKILL.md +19 -10
  2. package/.agents/skills/seed/contract.md +9 -2
  3. package/.agents/skills/seed/references/blocks.md +5 -5
  4. package/.agents/skills/seed/references/components.md +2 -2
  5. package/.agents/skills/seed/references/nextjs.md +2 -2
  6. package/README.md +3 -3
  7. package/contracts/consumer-intent-map.json +1 -2
  8. package/contracts/release-governance-baseline.json +3 -37
  9. package/dist/catalog/catalog.d.ts +2220 -0
  10. package/dist/catalog/catalog.js +1913 -0
  11. package/dist/catalog/components.d.ts +201 -0
  12. package/dist/catalog/components.js +407 -0
  13. package/dist/catalog/types.d.ts +4 -0
  14. package/dist/catalog/types.js +1 -0
  15. package/dist/chunk-224KPIOG.js +60 -0
  16. package/dist/chunk-25BOZMXA.js +169 -0
  17. package/dist/chunk-32OLQ7FC.js +130 -0
  18. package/dist/chunk-3JJBJ4VR.js +47 -0
  19. package/dist/chunk-3U56FXYC.js +30 -0
  20. package/dist/chunk-4MWKE6F5.js +86 -0
  21. package/dist/chunk-6HGSU24S.js +94 -0
  22. package/dist/chunk-7IADIXDV.js +168 -0
  23. package/dist/chunk-7NS3VFD7.js +86 -0
  24. package/dist/chunk-7XLZCXUL.js +175 -0
  25. package/dist/chunk-ALA6OM7K.js +134 -0
  26. package/dist/chunk-AN5TW4AL.js +50 -0
  27. package/dist/chunk-AWZFQQGN.js +167 -0
  28. package/dist/chunk-BRCBJ3S4.js +42 -0
  29. package/dist/chunk-BRICSLHJ.js +30 -0
  30. package/dist/chunk-BYEHHZZN.js +115 -0
  31. package/dist/chunk-C33GUEDY.js +149 -0
  32. package/dist/chunk-CUDMDYKE.js +150 -0
  33. package/dist/chunk-CVTMWSNS.js +145 -0
  34. package/dist/chunk-DEZXWNYF.js +165 -0
  35. package/dist/chunk-DNJEVMDY.js +40 -0
  36. package/dist/chunk-DNJOBML6.js +66 -0
  37. package/dist/chunk-FTGFOK6T.js +69 -0
  38. package/dist/chunk-HFBJ6L6O.js +104 -0
  39. package/dist/chunk-HPTHS7SX.js +52 -0
  40. package/dist/chunk-KNR3WB5C.js +147 -0
  41. package/dist/chunk-KQ7ZC6EM.js +66 -0
  42. package/dist/chunk-LGW7FVG5.js +83 -0
  43. package/dist/chunk-LP6ZZYOQ.js +36 -0
  44. package/dist/chunk-LV4P7WVM.js +54 -0
  45. package/dist/chunk-MGSGCARB.js +164 -0
  46. package/dist/chunk-N3YFYMNZ.js +73 -0
  47. package/dist/chunk-Q5IYBNA7.js +56 -0
  48. package/dist/chunk-QJCE7NZF.js +85 -0
  49. package/dist/chunk-QW5II6YK.js +96 -0
  50. package/dist/chunk-RMGDDOCD.js +138 -0
  51. package/dist/chunk-RNCX4JIE.js +70 -0
  52. package/dist/chunk-RWCL5OPX.js +112 -0
  53. package/dist/chunk-S5OY2B63.js +28 -0
  54. package/dist/chunk-SIQNG72C.js +257 -0
  55. package/dist/chunk-SP7NIZFP.js +117 -0
  56. package/dist/chunk-SWRJWMGG.js +30 -0
  57. package/dist/chunk-TCQIJ3DO.js +85 -0
  58. package/dist/chunk-TPJ6JJ2F.js +290 -0
  59. package/dist/chunk-TUJZMJXW.js +72 -0
  60. package/dist/chunk-UR43ANYS.js +159 -0
  61. package/dist/chunk-VRGPG2YN.js +79 -0
  62. package/dist/chunk-WSBLCWY7.js +126 -0
  63. package/dist/chunk-XKKFSFYO.js +93 -0
  64. package/dist/chunk-XO7TBM47.js +32 -0
  65. package/dist/chunk-YDYDGG5K.js +132 -0
  66. package/dist/chunk-YMJOUYMT.js +171 -0
  67. package/dist/chunk-Z2WION42.js +32 -0
  68. package/dist/chunk-ZFKSVEYW.js +35 -0
  69. package/dist/components/blocks/AgentProfileGridBlock.js +8 -86
  70. package/dist/components/blocks/AgentRunOverviewBlock.js +8 -147
  71. package/dist/components/blocks/AgentWorkbenchBlock.js +15 -257
  72. package/dist/components/blocks/AudioVisualizerBlock.js +2 -50
  73. package/dist/components/blocks/AuthLayout.js +9 -73
  74. package/dist/components/blocks/BannerBlock.js +8 -66
  75. package/dist/components/blocks/BarChartBlock.js +5 -47
  76. package/dist/components/blocks/ChartBlock.js +7 -54
  77. package/dist/components/blocks/ChartCollectionBlock.js +11 -171
  78. package/dist/components/blocks/ChatLayout.js +12 -126
  79. package/dist/components/blocks/CreateBlock.js +9 -104
  80. package/dist/components/blocks/DataGridBlock.js +9 -117
  81. package/dist/components/blocks/DirectoryBlock.js +12 -85
  82. package/dist/components/blocks/FeatureGridBlock.js +6 -56
  83. package/dist/components/blocks/GalleryBlock.js +6 -69
  84. package/dist/components/blocks/HeroSectionBlock.js +10 -134
  85. package/dist/components/blocks/IntegrationsBlock.js +13 -94
  86. package/dist/components/blocks/InteractiveAreaChartBlock.js +5 -290
  87. package/dist/components/blocks/KanbanDemoBlock.js +8 -145
  88. package/dist/components/blocks/LogoCloud.js +4 -35
  89. package/dist/components/blocks/NavUser.js +5 -85
  90. package/dist/components/blocks/NotFoundBlock.js +8 -32
  91. package/dist/components/blocks/OnboardingBlock.js +7 -66
  92. package/dist/components/blocks/SettingsLayout.js +13 -86
  93. package/dist/components/blocks/SignUpBlock.js +8 -168
  94. package/dist/components/blocks/SolutionShowcaseBlock.js +11 -112
  95. package/dist/components/blocks/StatsBlock.js +6 -60
  96. package/dist/components/blocks/UsageDonutBlock.js +5 -79
  97. package/dist/components/blocks/WizardBlock.js +12 -93
  98. package/dist/components/blocks/user/InviteUserModal.js +10 -132
  99. package/dist/components/page-kits/AccountLockedPageKit.js +3 -40
  100. package/dist/components/page-kits/AgentsChatPageKit.js +11 -159
  101. package/dist/components/page-kits/AnalyticsPageKit.js +12 -150
  102. package/dist/components/page-kits/BlogContentPageKit.js +12 -167
  103. package/dist/components/page-kits/CheckoutPageKit.js +9 -83
  104. package/dist/components/page-kits/CompanySuitePageKit.js +9 -96
  105. package/dist/components/page-kits/DashboardPageKit.js +11 -149
  106. package/dist/components/page-kits/ErrorPageKit.js +5 -52
  107. package/dist/components/page-kits/KanbanBoardPageKit.js +7 -169
  108. package/dist/components/page-kits/LandingPageKit.js +11 -72
  109. package/dist/components/page-kits/LoginPageKit.js +3 -32
  110. package/dist/components/page-kits/OnboardingPageKit.js +6 -115
  111. package/dist/components/page-kits/PricingPageKit.js +12 -138
  112. package/dist/components/page-kits/ProfileSettingsPageKit.js +10 -164
  113. package/dist/components/page-kits/RecoveryPageKit.js +3 -42
  114. package/dist/components/page-kits/ResetPageKit.js +3 -36
  115. package/dist/components/page-kits/ServiceSuitePageKit.js +10 -175
  116. package/dist/components/page-kits/SignupPageKit.js +3 -30
  117. package/dist/components/page-kits/SuccessPageKit.js +4 -30
  118. package/dist/components/page-kits/TeamSettingsPageKit.js +9 -165
  119. package/dist/components/page-kits/TwoFactorPageKit.js +4 -28
  120. package/dist/components/page-kits/VerifyEmailPageKit.js +4 -30
  121. package/dist/components/page-kits/VoiceAgentsPageKit.js +13 -130
  122. package/dist/components/ui/CheckoutForm.js +5 -70
  123. package/eslint-rules/nadicode/config.js +1 -0
  124. package/eslint-rules/nadicode/data/catalog-names.json +93 -0
  125. package/eslint-rules/nadicode/index.js +2 -0
  126. package/eslint-rules/nadicode/rules/__tests__/require-catalog-component.test.js +77 -0
  127. package/eslint-rules/nadicode/rules/require-catalog-component.js +79 -0
  128. package/package.json +18 -25
  129. package/contracts/block-props-schemas.json +0 -2186
  130. package/contracts/component-props-schemas.json +0 -8322
  131. package/contracts/consumer-contract.json +0 -178
  132. package/contracts/page-kit-props-schemas.json +0 -1894
  133. package/contracts/public-surface-registry.json +0 -5822
  134. package/contracts/public-surface-registry.schema.json +0 -219
  135. package/contracts/spec-manifest.json +0 -46
  136. package/dist/catalog.json +0 -5221
@@ -1,21 +1,22 @@
1
- import { VoiceAgentCard } from '../../chunk-HWHJ6IRQ.js';
2
- import { AgentConversationBlock } from '../../chunk-4IGBBIYW.js';
1
+ export { VoiceAgentsPageKit } from '../../chunk-32OLQ7FC.js';
2
+ import '../../chunk-HWHJ6IRQ.js';
3
+ import '../../chunk-4IGBBIYW.js';
3
4
  import '../../chunk-4WPZ6T7V.js';
4
5
  import '../../chunk-MDAYDDTC.js';
5
- import { Typography } from '../../chunk-N53OMWW2.js';
6
+ import '../../chunk-N53OMWW2.js';
6
7
  import '../../chunk-OSNTB6RY.js';
7
- import { ScrollArea } from '../../chunk-GLU236NN.js';
8
- import { Heading } from '../../chunk-WI547C47.js';
9
- import { Input } from '../../chunk-AP3XXYAY.js';
8
+ import '../../chunk-GLU236NN.js';
9
+ import '../../chunk-WI547C47.js';
10
+ import '../../chunk-AP3XXYAY.js';
10
11
  import '../../chunk-LIBXYD5Q.js';
11
- import { Card, CardContent, CardHeader, CardTitle } from '../../chunk-AH6YSYYT.js';
12
- import { AudioWaveform } from '../../chunk-5UESKK6S.js';
12
+ import '../../chunk-AH6YSYYT.js';
13
+ import '../../chunk-5UESKK6S.js';
13
14
  import '../../chunk-4S326Z3D.js';
14
- import { Button } from '../../chunk-7KIDDF3I.js';
15
+ import '../../chunk-7KIDDF3I.js';
15
16
  import '../../chunk-PD2YEH3H.js';
16
17
  import '../../chunk-CRY67BIF.js';
17
18
  import '../../chunk-HJC6U46F.js';
18
- import { AgentMessageBubble } from '../../chunk-I66XWYSS.js';
19
+ import '../../chunk-I66XWYSS.js';
19
20
  import '../../chunk-GO35FTNJ.js';
20
21
  import '../../chunk-WUO7OONN.js';
21
22
  import '../../chunk-FLF5AMNO.js';
@@ -125,126 +126,8 @@ import '../../chunk-UHXGBV5N.js';
125
126
  import '../../chunk-UIUMTURU.js';
126
127
  import '../../chunk-PRUXIDBD.js';
127
128
  import '../../chunk-NURPUVUV.js';
128
- import { Badge } from '../../chunk-S4JAHKOP.js';
129
+ import '../../chunk-S4JAHKOP.js';
129
130
  import '../../chunk-TV4RSQH4.js';
130
131
  import '../../chunk-HJBXUXTD.js';
131
132
  import '../../chunk-ASKFAYYR.js';
132
- import { cn } from '../../chunk-QYZT24TS.js';
133
- import { useMemo } from 'react';
134
- import { jsxs, jsx } from 'react/jsx-runtime';
135
-
136
- var EMPTY_MESSAGES = [];
137
- function presenceLabel(state) {
138
- switch (state) {
139
- case "listening":
140
- return "Listening";
141
- case "speaking":
142
- return "Speaking";
143
- case "idle":
144
- return "Idle";
145
- }
146
- }
147
- function VoiceAgentsPageKit({
148
- state = "agent-selection",
149
- agents,
150
- selectedAgentId,
151
- presenceState = "idle",
152
- messages = EMPTY_MESSAGES,
153
- streamingReply,
154
- composerValue = "",
155
- composerPlaceholder = "Send a voice prompt...",
156
- onComposerChange,
157
- onSendMessage,
158
- onSelectAgent,
159
- onBackToSelection,
160
- noAgentsMessage = "No voice agents are available right now.",
161
- disconnectedMessage = "The selected agent is unavailable. Choose another agent.",
162
- className
163
- }) {
164
- const selectedAgent = useMemo(
165
- () => selectedAgentId ? agents.find((agent) => agent.id === selectedAgentId) : null,
166
- [agents, selectedAgentId]
167
- );
168
- function handleSendMessage() {
169
- const payload = composerValue.trim();
170
- if (!payload) {
171
- return;
172
- }
173
- onSendMessage?.(payload);
174
- }
175
- if (state === "agent-selection") {
176
- return /* @__PURE__ */ jsxs("section", { className: cn("space-y-6", className), children: [
177
- /* @__PURE__ */ jsxs("header", { className: "space-y-2", children: [
178
- /* @__PURE__ */ jsx(Heading, { level: 3, children: "Voice agents" }),
179
- /* @__PURE__ */ jsx(Typography, { variant: "muted", children: "Choose an agent to start a voice session." })
180
- ] }),
181
- agents.length === 0 ? /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, { className: "py-6", children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-text-secondary", children: noAgentsMessage }) }) }) : /* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", children: agents.map((agent) => /* @__PURE__ */ jsx(
182
- VoiceAgentCard,
183
- {
184
- agent,
185
- state: "idle",
186
- selected: false,
187
- onSelect: () => onSelectAgent?.(agent.id),
188
- ariaLabel: `Select ${agent.name}`
189
- },
190
- agent.id
191
- )) })
192
- ] });
193
- }
194
- return /* @__PURE__ */ jsxs("section", { className: cn("space-y-6", className), children: [
195
- /* @__PURE__ */ jsxs("header", { className: "space-y-2", children: [
196
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
197
- /* @__PURE__ */ jsx(Heading, { level: 3, children: "Voice agents" }),
198
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: onBackToSelection, children: "Back to agent selection" })
199
- ] }),
200
- /* @__PURE__ */ jsx(Typography, { variant: "muted", children: selectedAgent ? `Active voice session with ${selectedAgent.name}.` : disconnectedMessage })
201
- ] }),
202
- selectedAgent ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
203
- /* @__PURE__ */ jsx(Typography, { variant: "small", className: "font-medium text-text-primary", children: selectedAgent.name }),
204
- /* @__PURE__ */ jsx(Badge, { variant: "outline", children: presenceLabel(presenceState) }),
205
- /* @__PURE__ */ jsx(AudioWaveform, { active: presenceState === "speaking", bars: 20, size: "sm", variant: "accent" })
206
- ] }) : /* @__PURE__ */ jsx("div", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive", children: disconnectedMessage }),
207
- /* @__PURE__ */ jsxs(Card, { children: [
208
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: "Conversation" }) }),
209
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-3", children: [
210
- /* @__PURE__ */ jsxs(ScrollArea, { className: "max-h-96", children: [
211
- /* @__PURE__ */ jsx(
212
- AgentConversationBlock,
213
- {
214
- messages: messages.length > 0 ? messages : [{
215
- id: "voice-empty",
216
- role: "system",
217
- content: "No messages yet. Start speaking to begin the session."
218
- }]
219
- }
220
- ),
221
- !!streamingReply && /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-1", children: [
222
- /* @__PURE__ */ jsx(Typography, { variant: "small", className: "font-medium text-text-primary", children: "Streaming response" }),
223
- /* @__PURE__ */ jsx(
224
- AgentMessageBubble,
225
- {
226
- role: "assistant",
227
- content: streamingReply,
228
- isStreaming: true
229
- }
230
- )
231
- ] })
232
- ] }),
233
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [
234
- /* @__PURE__ */ jsx(
235
- Input,
236
- {
237
- "aria-label": "Voice composer",
238
- value: composerValue,
239
- placeholder: composerPlaceholder,
240
- onChange: (event) => onComposerChange?.(event.target.value)
241
- }
242
- ),
243
- /* @__PURE__ */ jsx(Button, { type: "button", onClick: handleSendMessage, children: "Send voice message" })
244
- ] })
245
- ] })
246
- ] })
247
- ] });
248
- }
249
-
250
- export { VoiceAgentsPageKit };
133
+ import '../../chunk-QYZT24TS.js';
@@ -1,7 +1,8 @@
1
1
  'use client';
2
- import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '../../chunk-AH6YSYYT.js';
3
- import { Alert, AlertTitle, AlertDescription } from '../../chunk-GJUR6HT3.js';
4
- import { Button } from '../../chunk-7KIDDF3I.js';
2
+ export { CheckoutForm } from '../../chunk-RNCX4JIE.js';
3
+ import '../../chunk-AH6YSYYT.js';
4
+ import '../../chunk-GJUR6HT3.js';
5
+ import '../../chunk-7KIDDF3I.js';
5
6
  import '../../chunk-PD2YEH3H.js';
6
7
  import '../../chunk-CRY67BIF.js';
7
8
  import '../../chunk-HJC6U46F.js';
@@ -91,7 +92,7 @@ import '../../chunk-FMH55OKV.js';
91
92
  import '../../chunk-WXVNTJIB.js';
92
93
  import '../../chunk-T7H53CK2.js';
93
94
  import '../../chunk-TBKJ34BB.js';
94
- import { LoaderCircleIcon } from '../../chunk-BRP6D56U.js';
95
+ import '../../chunk-BRP6D56U.js';
95
96
  import '../../chunk-6G3RRWJT.js';
96
97
  import '../../chunk-ZU2GYVAP.js';
97
98
  import '../../chunk-CRZ2JE24.js';
@@ -118,69 +119,3 @@ import '../../chunk-TV4RSQH4.js';
118
119
  import '../../chunk-HJBXUXTD.js';
119
120
  import '../../chunk-ASKFAYYR.js';
120
121
  import '../../chunk-QYZT24TS.js';
121
- import { useState } from 'react';
122
- import { useStripe, useElements, PaymentElement } from '@stripe/react-stripe-js';
123
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
124
-
125
- function CheckoutForm({ amount = 2e3, currency = "usd", returnUrl = "/settings/billing" }) {
126
- const stripe = useStripe();
127
- const elements = useElements();
128
- const [message, setMessage] = useState(null);
129
- const [isLoading, setIsLoading] = useState(false);
130
- const handleSubmit = async (e) => {
131
- e.preventDefault();
132
- if (!stripe || !elements) {
133
- return;
134
- }
135
- setIsLoading(true);
136
- setMessage(null);
137
- const { error } = await stripe.confirmPayment({
138
- elements,
139
- confirmParams: {
140
- // Make sure to change this to your payment completion page
141
- return_url: `${window.location.origin}${returnUrl}`
142
- }
143
- });
144
- if (error.type === "card_error" || error.type === "validation_error") {
145
- setMessage(error.message ?? "An unexpected error occurred.");
146
- } else {
147
- setMessage("An unexpected error occurred.");
148
- }
149
- setIsLoading(false);
150
- };
151
- return /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-md", children: [
152
- /* @__PURE__ */ jsxs(CardHeader, { children: [
153
- /* @__PURE__ */ jsx(CardTitle, { children: "Payment Details" }),
154
- /* @__PURE__ */ jsxs(CardDescription, { children: [
155
- "Complete your purchase of $",
156
- amount / 100,
157
- " ",
158
- currency.toUpperCase(),
159
- "."
160
- ] })
161
- ] }),
162
- /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
163
- /* @__PURE__ */ jsxs(CardContent, { className: "grid gap-6", children: [
164
- /* @__PURE__ */ jsx(PaymentElement, { id: "payment-element", options: { layout: "tabs" } }),
165
- !!message && /* @__PURE__ */ jsxs(Alert, { variant: "destructive", children: [
166
- /* @__PURE__ */ jsx(AlertTitle, { children: "Error" }),
167
- /* @__PURE__ */ jsx(AlertDescription, { children: message })
168
- ] })
169
- ] }),
170
- /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(
171
- Button,
172
- {
173
- disabled: isLoading || !stripe || !elements,
174
- className: "w-full",
175
- type: "submit",
176
- children: isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
177
- /* @__PURE__ */ jsx(LoaderCircleIcon, { size: 16, className: "mr-2 animate-spin" }),
178
- "Processing..."
179
- ] }) : "Pay Now"
180
- }
181
- ) })
182
- ] })
183
- ] });
184
- }
185
-
186
- export { CheckoutForm };
@@ -82,6 +82,7 @@ export const nadicodeRules = {
82
82
  "nadicode/no-handcoded-heading": "error",
83
83
  "nadicode/no-handcoded-empty-state": "error",
84
84
  "nadicode/no-handcoded-field": "error",
85
+ "nadicode/require-catalog-component": "error",
85
86
  };
86
87
 
87
88
  function normalizePattern(pattern) {
@@ -0,0 +1,93 @@
1
+ {
2
+ "catalog": [
3
+ "AccountLockedBlock",
4
+ "AccountLockedPageKit",
5
+ "ActivityFeedBlock",
6
+ "AgentConversationBlock",
7
+ "AgentProfileGridBlock",
8
+ "AgentRunOverviewBlock",
9
+ "AgentsChatPageKit",
10
+ "AgentWorkbenchBlock",
11
+ "AnalyticsPageKit",
12
+ "AudioVisualizerBlock",
13
+ "AuthLayout",
14
+ "AuthSuccessBlock",
15
+ "BannerBlock",
16
+ "BarChartBlock",
17
+ "BlogContentPageKit",
18
+ "CallToActionBlock",
19
+ "ChangelogBlock",
20
+ "ChartBlock",
21
+ "ChartCollectionBlock",
22
+ "ChatLayout",
23
+ "CheckoutForm",
24
+ "CheckoutPageKit",
25
+ "CodeBlock",
26
+ "CompanySuitePageKit",
27
+ "ComparisonBlock",
28
+ "ContactBlock",
29
+ "CreateBlock",
30
+ "CrudFormPageKit",
31
+ "CrudListDetailPageKit",
32
+ "DashboardPageKit",
33
+ "DataGridBlock",
34
+ "DirectoryBlock",
35
+ "ErrorPageKit",
36
+ "FAQBlock",
37
+ "FeatureBlock",
38
+ "FeatureGridBlock",
39
+ "FooterBlock",
40
+ "FormWizard",
41
+ "GalleryBlock",
42
+ "HeaderBlock",
43
+ "HeatmapChartBlock",
44
+ "HeroBlock",
45
+ "HeroSectionBlock",
46
+ "IntegrationsBlock",
47
+ "InteractiveAreaChartBlock",
48
+ "InviteUserModal",
49
+ "KanbanBoard",
50
+ "KanbanBoardPageKit",
51
+ "KanbanDemoBlock",
52
+ "LandingPageKit",
53
+ "LoginBlock",
54
+ "LoginPageKit",
55
+ "LogoCloud",
56
+ "MarketingShellPageKit",
57
+ "NavigationShellPageKit",
58
+ "NavUser",
59
+ "NewsletterBlock",
60
+ "NotFoundBlock",
61
+ "OnboardingBlock",
62
+ "OnboardingPageKit",
63
+ "PasswordRecoveryBlock",
64
+ "PricingBlock",
65
+ "PricingPageKit",
66
+ "ProcessFlowBlock",
67
+ "ProfileSettingsPageKit",
68
+ "RecoveryPageKit",
69
+ "ResetPageKit",
70
+ "ResetPasswordBlock",
71
+ "ServiceSuitePageKit",
72
+ "SettingsLayout",
73
+ "SettingsPageKit",
74
+ "SignUpBlock",
75
+ "SignupPageKit",
76
+ "SocialProofBlock",
77
+ "SolutionShowcaseBlock",
78
+ "StatsBlock",
79
+ "StatsMarketingBlock",
80
+ "SuccessPageKit",
81
+ "TeamBlock",
82
+ "TeamSettingsPageKit",
83
+ "TestimonialsBlock",
84
+ "TwoFactorChallengeBlock",
85
+ "TwoFactorPageKit",
86
+ "TwoFactorSetupBlock",
87
+ "UsageDonutBlock",
88
+ "VerifyEmailPageKit",
89
+ "VoiceAgentCard",
90
+ "VoiceAgentsPageKit",
91
+ "WizardBlock"
92
+ ]
93
+ }
@@ -69,6 +69,7 @@ import noHandcodedBadge from "./rules/no-handcoded-badge.js";
69
69
  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
+ import requireCatalogComponent from "./rules/require-catalog-component.js";
72
73
 
73
74
  export { nadicodeRules, createAllowlistOverrides } from "./config.js";
74
75
 
@@ -145,5 +146,6 @@ export const nadicodePlugin = {
145
146
  "no-handcoded-heading": noHandcodedHeading,
146
147
  "no-handcoded-empty-state": noHandcodedEmptyState,
147
148
  "no-handcoded-field": noHandcodedField,
149
+ "require-catalog-component": requireCatalogComponent,
148
150
  },
149
151
  };
@@ -0,0 +1,77 @@
1
+ import { RuleTester } from "eslint";
2
+ import { describe } from "vitest";
3
+
4
+ import rule from "../require-catalog-component.js";
5
+
6
+ const tester = new RuleTester({
7
+ languageOptions: {
8
+ ecmaVersion: "latest",
9
+ sourceType: "module",
10
+ },
11
+ });
12
+
13
+ describe("require-catalog-component", () => {
14
+ tester.run("require-catalog-component", rule, {
15
+ valid: [
16
+ // Component that IS in the catalog (catalog array)
17
+ {
18
+ code: "import HeroBlock from '@/components/blocks/HeroBlock';",
19
+ filename: "/repo/src/app/page.tsx",
20
+ },
21
+ // Page-kit that IS in the catalog
22
+ {
23
+ code: "import { LandingPageKit } from '@/components/page-kits/LandingPageKit';",
24
+ filename: "/repo/src/app/page.tsx",
25
+ },
26
+ // Imports from other paths are not checked
27
+ {
28
+ code: "import { Button } from '@/components/ui/Button';",
29
+ filename: "/repo/src/app/page.tsx",
30
+ },
31
+ // Test files are exempt
32
+ {
33
+ code: "import UnknownBlock from '@/components/blocks/UnknownBlock';",
34
+ filename: "/repo/src/components/blocks/__tests__/UnknownBlock.test.tsx",
35
+ },
36
+ {
37
+ code: "import UnknownBlock from '@/components/blocks/UnknownBlock';",
38
+ filename: "/repo/src/components/blocks/UnknownBlock.spec.tsx",
39
+ },
40
+ ],
41
+ invalid: [
42
+ // Component NOT in catalog (blocks)
43
+ {
44
+ code: "import UnknownBlock from '@/components/blocks/UnknownBlock';",
45
+ filename: "/repo/src/app/page.tsx",
46
+ errors: [
47
+ {
48
+ message:
49
+ "Component 'UnknownBlock' is not in the design system catalog. Add it to src/catalog/catalog.ts before use.",
50
+ },
51
+ ],
52
+ },
53
+ // Component NOT in catalog (page-kits)
54
+ {
55
+ code: "import UnknownPageKit from '@/components/page-kits/UnknownPageKit';",
56
+ filename: "/repo/src/app/page.tsx",
57
+ errors: [
58
+ {
59
+ message:
60
+ "Component 'UnknownPageKit' is not in the design system catalog. Add it to src/catalog/catalog.ts before use.",
61
+ },
62
+ ],
63
+ },
64
+ // Named import from unknown block
65
+ {
66
+ code: "import { GhostBlock } from '@/components/blocks/GhostBlock';",
67
+ filename: "/repo/src/app/marketing/page.tsx",
68
+ errors: [
69
+ {
70
+ message:
71
+ "Component 'GhostBlock' is not in the design system catalog. Add it to src/catalog/catalog.ts before use.",
72
+ },
73
+ ],
74
+ },
75
+ ],
76
+ });
77
+ });
@@ -0,0 +1,79 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ import { getFilename, isTestFile } from "../utils.js";
6
+
7
+ const RULES_DIR = dirname(fileURLToPath(import.meta.url));
8
+ const CATALOG_PATH = resolve(RULES_DIR, "../data/catalog-names.json");
9
+
10
+ const CHECKED_PREFIXES = ["@/components/blocks/", "@/components/page-kits/"];
11
+
12
+ let knownNames = null;
13
+
14
+ function loadKnownNames() {
15
+ if (knownNames) {
16
+ return knownNames;
17
+ }
18
+
19
+ knownNames = new Set();
20
+
21
+ try {
22
+ const data = JSON.parse(readFileSync(CATALOG_PATH, "utf8"));
23
+ for (const name of data.catalog ?? []) {
24
+ knownNames.add(name);
25
+ }
26
+ } catch {
27
+ // Data file missing (first run before generator runs). Rule becomes a no-op.
28
+ }
29
+
30
+ return knownNames;
31
+ }
32
+
33
+ const rule = {
34
+ meta: {
35
+ type: "problem",
36
+ docs: {
37
+ description:
38
+ "Disallow imports of blocks and page-kits that are not registered in the design system catalog.",
39
+ },
40
+ schema: [],
41
+ },
42
+ create(context) {
43
+ const filename = getFilename(context);
44
+ if (isTestFile(filename)) return {};
45
+
46
+ return {
47
+ ImportDeclaration(node) {
48
+ const source = node.source.value;
49
+ if (typeof source !== "string") return;
50
+
51
+ const matched = CHECKED_PREFIXES.find((prefix) =>
52
+ source.startsWith(prefix),
53
+ );
54
+ if (!matched) return;
55
+
56
+ const afterPrefix = source.slice(matched.length);
57
+ // Take only the first path segment so `@/components/blocks/Foo/Bar`
58
+ // resolves to `Foo`, not `Foo/Bar`.
59
+ const name = afterPrefix.split("/")[0];
60
+ if (!name) return;
61
+
62
+ const known = loadKnownNames();
63
+ // Empty set means catalog file is missing; skip silently.
64
+ if (known.size === 0) return;
65
+
66
+ if (!known.has(name)) {
67
+ context.report({
68
+ node,
69
+ message:
70
+ "Component '{{name}}' is not in the design system catalog. Add it to src/catalog/catalog.ts before use.",
71
+ data: { name },
72
+ });
73
+ }
74
+ },
75
+ };
76
+ },
77
+ };
78
+
79
+ export default rule;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vadimcomanescu/nadicode-design-system",
3
- "version": "2.0.9",
3
+ "version": "4.0.0",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"
@@ -29,10 +29,9 @@
29
29
  "start": "next start",
30
30
  "build:types": "tsc -p tsconfig.types.json && node scripts/rewrite-dist-types.mjs",
31
31
  "build:lib": "node scripts/build-tokens-css.mjs && tsup && npm run build:types && npm run contracts:generate && node scripts/check-export-targets.mjs",
32
- "contracts:generate": "npm run catalog:generate:readonly && npm run registry:generate && npm run artifacts:generate && npm run consumer-contract:generate",
33
- "contracts:check": "npm run catalog:check && npm run registry:validate && npm run artifacts:check",
32
+ "contracts:generate": "npm run intent-map:generate && npm run message-contract:generate",
33
+ "contracts:check": "npm run intent-map:validate && npm run message-contract:check",
34
34
  "pack:artifact": "node scripts/pack-package-artifact.mjs",
35
- "exports:generate": "npm run artifacts:generate",
36
35
  "test:distribution": "node scripts/package-smoke-test.mjs",
37
36
  "lint": "eslint src scripts bin eslint-rules --max-warnings 0",
38
37
  "lint:fix": "eslint src scripts bin eslint-rules --fix --max-warnings 0",
@@ -43,26 +42,17 @@
43
42
  "lighthouse": "bin/lighthouse.sh",
44
43
  "ds:validate": "npm run ds:check && npm run lint && tsc --noEmit && node scripts/check-tokens-freshness.mjs && npm run build:lib && npm run test:distribution && npm run build",
45
44
  "ds:check": "node scripts/ds-check.mjs",
46
- "registry:generate": "node scripts/generate-public-surface-registry.mjs && node scripts/generate-consumer-intent-map.mjs && node scripts/generate-message-catalog-contract.mjs && node scripts/generate-spec-manifest.mjs",
47
- "registry:validate": "node scripts/validate-public-surface-registry.mjs && node scripts/validate-consumer-intent-map.mjs && node scripts/validate-spec-manifest.mjs && node scripts/validate-consumer-contract.mjs && node scripts/validate-release-governance.mjs",
48
45
  "intent-map:generate": "node scripts/generate-consumer-intent-map.mjs",
49
46
  "intent-map:validate": "node scripts/validate-consumer-intent-map.mjs",
50
47
  "message-contract:generate": "node scripts/generate-message-catalog-contract.mjs",
51
48
  "message-contract:check": "node scripts/generate-message-catalog-contract.mjs --check",
52
- "consumer-contract:generate": "node scripts/generate-consumer-contract.mjs",
53
- "consumer-contract:check": "node scripts/generate-consumer-contract.mjs --check",
54
- "spec-manifest:generate": "node scripts/generate-spec-manifest.mjs",
55
- "spec-manifest:check": "node scripts/validate-spec-manifest.mjs",
56
49
  "release-governance:baseline": "node scripts/generate-release-governance-baseline.mjs",
57
50
  "release-governance:validate": "node scripts/validate-release-governance.mjs",
58
51
  "ds:task-pack": "node scripts/ds-generate-task-pack.mjs",
59
- "catalog:generate": "node scripts/generate-catalog.mjs",
60
- "catalog:generate:readonly": "SEED_GENERATE_CATALOG_SKIP_DOC_WRITES=1 node scripts/generate-catalog.mjs",
61
- "catalog:check": "SEED_GENERATE_CATALOG_SKIP_DOC_WRITES=1 node scripts/generate-catalog.mjs --check",
62
52
  "docs:api": "node scripts/docs-generate-api.mjs",
63
- "docs:check": "node scripts/docs-check.mjs && npm run catalog:check",
53
+ "docs:check": "node scripts/docs-check.mjs",
64
54
  "docs:inventory": "node scripts/docs-inventory.mjs",
65
- "release:check": "npm run registry:validate && npm run docs:check && npm run test:all",
55
+ "release:check": "npm run contracts:check && npm run docs:check && npm run test:all",
66
56
  "release:verify": "node scripts/verify-package-release.mjs",
67
57
  "publish:package": "node scripts/publish-package.mjs",
68
58
  "release:patch": "npm version patch --no-git-tag-version && npm run publish:package",
@@ -77,9 +67,7 @@
77
67
  "prepack": "npm run build:lib",
78
68
  "prepublishOnly": "npm run ds:check && npm run docs:check",
79
69
  "postpublish": "npm run release:verify",
80
- "ds:update": "node scripts/ds-update.mjs",
81
- "artifacts:generate": "node scripts/generate-public-artifacts.mjs",
82
- "artifacts:check": "node scripts/generate-public-artifacts.mjs --check"
70
+ "ds:update": "node scripts/ds-update.mjs"
83
71
  },
84
72
  "lint-staged": {
85
73
  "{src,scripts,bin,eslint-rules}/**/*.{ts,tsx,js}": [
@@ -390,7 +378,6 @@
390
378
  "import": "./dist/components/ui/BentoGrid.js",
391
379
  "types": "./dist/components/ui/BentoGrid.d.ts"
392
380
  },
393
- "./block-props-schemas": "./contracts/block-props-schemas.json",
394
381
  "./blog-content-page-kit": {
395
382
  "import": "./dist/components/page-kits/BlogContentPageKit.js",
396
383
  "types": "./dist/components/page-kits/BlogContentPageKit.d.ts"
@@ -427,7 +414,6 @@
427
414
  "import": "./dist/components/ui/Carousel.js",
428
415
  "types": "./dist/components/ui/Carousel.d.ts"
429
416
  },
430
- "./catalog": "./dist/catalog.json",
431
417
  "./changelog-block": {
432
418
  "import": "./dist/components/blocks/ChangelogBlock.js",
433
419
  "types": "./dist/components/blocks/ChangelogBlock.d.ts"
@@ -600,12 +586,10 @@
600
586
  "import": "./dist/components/blocks/ComparisonBlock.js",
601
587
  "types": "./dist/components/blocks/ComparisonBlock.d.ts"
602
588
  },
603
- "./component-props-schemas": "./contracts/component-props-schemas.json",
604
589
  "./confetti-burst": {
605
590
  "import": "./dist/components/ui/ConfettiBurst.js",
606
591
  "types": "./dist/components/ui/ConfettiBurst.d.ts"
607
592
  },
608
- "./consumer-contract": "./contracts/consumer-contract.json",
609
593
  "./consumer-intent-map": "./contracts/consumer-intent-map.json",
610
594
  "./contact-block": {
611
595
  "import": "./dist/components/blocks/ContactBlock.js",
@@ -1472,7 +1456,6 @@
1472
1456
  "import": "./dist/components/page-kits/OnboardingPageKit.js",
1473
1457
  "types": "./dist/components/page-kits/OnboardingPageKit.d.ts"
1474
1458
  },
1475
- "./page-kit-props-schemas": "./contracts/page-kit-props-schemas.json",
1476
1459
  "./page-transition": {
1477
1460
  "import": "./dist/components/ui/PageTransition.js",
1478
1461
  "types": "./dist/components/ui/PageTransition.d.ts"
@@ -1529,7 +1512,6 @@
1529
1512
  "import": "./dist/components/ui/PromoCard.js",
1530
1513
  "types": "./dist/components/ui/PromoCard.d.ts"
1531
1514
  },
1532
- "./public-surface-registry": "./contracts/public-surface-registry.json",
1533
1515
  "./radio-group": {
1534
1516
  "import": "./dist/components/ui/RadioGroup.js",
1535
1517
  "types": "./dist/components/ui/RadioGroup.d.ts"
@@ -1542,6 +1524,18 @@
1542
1524
  "import": "./dist/components/page-kits/RecoveryPageKit.js",
1543
1525
  "types": "./dist/components/page-kits/RecoveryPageKit.d.ts"
1544
1526
  },
1527
+ "./catalog": {
1528
+ "import": "./dist/catalog/catalog.js",
1529
+ "types": "./dist/catalog/catalog.d.ts"
1530
+ },
1531
+ "./catalog/components": {
1532
+ "import": "./dist/catalog/components.js",
1533
+ "types": "./dist/catalog/components.d.ts"
1534
+ },
1535
+ "./catalog/types": {
1536
+ "import": "./dist/catalog/types.js",
1537
+ "types": "./dist/catalog/types.d.ts"
1538
+ },
1545
1539
  "./reset-page-kit": {
1546
1540
  "import": "./dist/components/page-kits/ResetPageKit.js",
1547
1541
  "types": "./dist/components/page-kits/ResetPageKit.d.ts"
@@ -1642,7 +1636,6 @@
1642
1636
  "import": "./dist/components/ui/SourceCitation.js",
1643
1637
  "types": "./dist/components/ui/SourceCitation.d.ts"
1644
1638
  },
1645
- "./spec-manifest": "./contracts/spec-manifest.json",
1646
1639
  "./spinner": {
1647
1640
  "import": "./dist/components/ui/Spinner.js",
1648
1641
  "types": "./dist/components/ui/Spinner.d.ts"