@discourser/design-system 0.15.1 → 0.18.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 (281) hide show
  1. package/dist/{chunk-UNWXE6UB.cjs → chunk-2P7Z5PVP.cjs} +817 -16
  2. package/dist/chunk-2P7Z5PVP.cjs.map +1 -0
  3. package/dist/{chunk-ABC7N32K.cjs → chunk-PFWU7QSM.cjs} +464 -8
  4. package/dist/chunk-PFWU7QSM.cjs.map +1 -0
  5. package/dist/{chunk-GD6Q2FUE.js → chunk-QC7LGFM3.js} +808 -18
  6. package/dist/chunk-QC7LGFM3.js.map +1 -0
  7. package/dist/{chunk-SBKRSXSZ.js → chunk-SNUJBT5R.js} +464 -8
  8. package/dist/chunk-SNUJBT5R.js.map +1 -0
  9. package/dist/components/Accordion.figma.d.ts +2 -0
  10. package/dist/components/Accordion.figma.d.ts.map +1 -0
  11. package/dist/components/Breadcrumb.d.ts +2 -0
  12. package/dist/components/Breadcrumb.d.ts.map +1 -1
  13. package/dist/components/Breadcrumb.figma.d.ts +2 -0
  14. package/dist/components/Breadcrumb.figma.d.ts.map +1 -0
  15. package/dist/components/ContentCard/ContentCard.d.ts +13 -0
  16. package/dist/components/ContentCard/ContentCard.d.ts.map +1 -0
  17. package/dist/components/ContentCard/ContentCard.figma.d.ts +2 -0
  18. package/dist/components/ContentCard/ContentCard.figma.d.ts.map +1 -0
  19. package/dist/components/ContentCard/index.d.ts +2 -0
  20. package/dist/components/ContentCard/index.d.ts.map +1 -0
  21. package/dist/components/{Heading.d.ts → Header.d.ts} +3 -3
  22. package/dist/components/Header.d.ts.map +1 -0
  23. package/dist/components/Header.figma.d.ts +2 -0
  24. package/dist/components/Header.figma.d.ts.map +1 -0
  25. package/dist/components/Icons/AccountIcon.d.ts +6 -0
  26. package/dist/components/Icons/AccountIcon.d.ts.map +1 -0
  27. package/dist/components/Icons/AudienceIcon.d.ts +6 -0
  28. package/dist/components/Icons/AudienceIcon.d.ts.map +1 -0
  29. package/dist/components/Icons/AudienceIcon.figma.d.ts +2 -0
  30. package/dist/components/Icons/AudienceIcon.figma.d.ts.map +1 -0
  31. package/dist/components/Icons/AudioSpeakerIcon.d.ts +6 -0
  32. package/dist/components/Icons/AudioSpeakerIcon.d.ts.map +1 -0
  33. package/dist/components/Icons/AudioSpeakerIcon.figma.d.ts +2 -0
  34. package/dist/components/Icons/AudioSpeakerIcon.figma.d.ts.map +1 -0
  35. package/dist/components/Icons/BookmarkPlusIcon.d.ts +6 -0
  36. package/dist/components/Icons/BookmarkPlusIcon.d.ts.map +1 -0
  37. package/dist/components/Icons/BookmarkPlusIcon.figma.d.ts +2 -0
  38. package/dist/components/Icons/BookmarkPlusIcon.figma.d.ts.map +1 -0
  39. package/dist/components/Icons/ChevronUpIcon.d.ts +6 -0
  40. package/dist/components/Icons/ChevronUpIcon.d.ts.map +1 -0
  41. package/dist/components/Icons/ClipBoardIcon.d.ts +6 -0
  42. package/dist/components/Icons/ClipBoardIcon.d.ts.map +1 -0
  43. package/dist/components/Icons/ClipBoardIcon.figma.d.ts +2 -0
  44. package/dist/components/Icons/ClipBoardIcon.figma.d.ts.map +1 -0
  45. package/dist/components/Icons/ClockIcon.d.ts.map +1 -1
  46. package/dist/components/Icons/DashboardIcon.d.ts +6 -0
  47. package/dist/components/Icons/DashboardIcon.d.ts.map +1 -0
  48. package/dist/components/Icons/DiscourserLogo.d.ts +6 -0
  49. package/dist/components/Icons/DiscourserLogo.d.ts.map +1 -0
  50. package/dist/components/Icons/DiscourserLogo.figma.d.ts +2 -0
  51. package/dist/components/Icons/DiscourserLogo.figma.d.ts.map +1 -0
  52. package/dist/components/Icons/ExitStudioIcon.d.ts +6 -0
  53. package/dist/components/Icons/ExitStudioIcon.d.ts.map +1 -0
  54. package/dist/components/Icons/ExitStudioIcon.figma.d.ts +2 -0
  55. package/dist/components/Icons/ExitStudioIcon.figma.d.ts.map +1 -0
  56. package/dist/components/Icons/GripDotsVerticalIcon.d.ts.map +1 -1
  57. package/dist/components/Icons/HelpIcon.d.ts +6 -0
  58. package/dist/components/Icons/HelpIcon.d.ts.map +1 -0
  59. package/dist/components/Icons/MicrophoneIcon.d.ts +6 -0
  60. package/dist/components/Icons/MicrophoneIcon.d.ts.map +1 -0
  61. package/dist/components/Icons/MicrophoneIcon.figma.d.ts +2 -0
  62. package/dist/components/Icons/MicrophoneIcon.figma.d.ts.map +1 -0
  63. package/dist/components/Icons/NotebookIcon.d.ts +6 -0
  64. package/dist/components/Icons/NotebookIcon.d.ts.map +1 -0
  65. package/dist/components/Icons/NotebookPenIcon.d.ts +6 -0
  66. package/dist/components/Icons/NotebookPenIcon.d.ts.map +1 -0
  67. package/dist/components/Icons/NotebookPenIcon.figma.d.ts +2 -0
  68. package/dist/components/Icons/NotebookPenIcon.figma.d.ts.map +1 -0
  69. package/dist/components/Icons/PausePlayIcon.d.ts +6 -0
  70. package/dist/components/Icons/PausePlayIcon.d.ts.map +1 -0
  71. package/dist/components/Icons/PausePlayIcon.figma.d.ts +2 -0
  72. package/dist/components/Icons/PausePlayIcon.figma.d.ts.map +1 -0
  73. package/dist/components/Icons/PlayIcon.d.ts +6 -0
  74. package/dist/components/Icons/PlayIcon.d.ts.map +1 -0
  75. package/dist/components/Icons/PlayIcon.figma.d.ts +2 -0
  76. package/dist/components/Icons/PlayIcon.figma.d.ts.map +1 -0
  77. package/dist/components/Icons/RecordIcon.d.ts +6 -0
  78. package/dist/components/Icons/RecordIcon.d.ts.map +1 -0
  79. package/dist/components/Icons/RecordIcon.figma.d.ts +2 -0
  80. package/dist/components/Icons/RecordIcon.figma.d.ts.map +1 -0
  81. package/dist/components/Icons/RepeatQuestionIcon.d.ts +6 -0
  82. package/dist/components/Icons/RepeatQuestionIcon.d.ts.map +1 -0
  83. package/dist/components/Icons/RepeatQuestionIcon.figma.d.ts +2 -0
  84. package/dist/components/Icons/RepeatQuestionIcon.figma.d.ts.map +1 -0
  85. package/dist/components/Icons/RightArrowIcon.d.ts +6 -0
  86. package/dist/components/Icons/RightArrowIcon.d.ts.map +1 -0
  87. package/dist/components/Icons/ScenarioIcon.d.ts +6 -0
  88. package/dist/components/Icons/ScenarioIcon.d.ts.map +1 -0
  89. package/dist/components/Icons/ScrollTextIcon.d.ts +6 -0
  90. package/dist/components/Icons/ScrollTextIcon.d.ts.map +1 -0
  91. package/dist/components/Icons/ScrollTextIcon.figma.d.ts +2 -0
  92. package/dist/components/Icons/ScrollTextIcon.figma.d.ts.map +1 -0
  93. package/dist/components/Icons/SparklesIcon.d.ts +6 -0
  94. package/dist/components/Icons/SparklesIcon.d.ts.map +1 -0
  95. package/dist/components/Icons/SparklesIcon.figma.d.ts +2 -0
  96. package/dist/components/Icons/SparklesIcon.figma.d.ts.map +1 -0
  97. package/dist/components/Icons/SpeechIcon.d.ts +6 -0
  98. package/dist/components/Icons/SpeechIcon.d.ts.map +1 -0
  99. package/dist/components/Icons/SpeechIcon.figma.d.ts +2 -0
  100. package/dist/components/Icons/SpeechIcon.figma.d.ts.map +1 -0
  101. package/dist/components/Icons/StopPlayIcon.d.ts +6 -0
  102. package/dist/components/Icons/StopPlayIcon.d.ts.map +1 -0
  103. package/dist/components/Icons/StopPlayIcon.figma.d.ts +2 -0
  104. package/dist/components/Icons/StopPlayIcon.figma.d.ts.map +1 -0
  105. package/dist/components/Icons/TimerIcon.d.ts +6 -0
  106. package/dist/components/Icons/TimerIcon.d.ts.map +1 -0
  107. package/dist/components/Icons/TimerIcon.figma.d.ts +2 -0
  108. package/dist/components/Icons/TimerIcon.figma.d.ts.map +1 -0
  109. package/dist/components/Icons/UserProfileIcon.d.ts +6 -0
  110. package/dist/components/Icons/UserProfileIcon.d.ts.map +1 -0
  111. package/dist/components/Icons/UserProfileIcon.figma.d.ts +2 -0
  112. package/dist/components/Icons/UserProfileIcon.figma.d.ts.map +1 -0
  113. package/dist/components/Icons/index.d.ts +26 -1
  114. package/dist/components/Icons/index.d.ts.map +1 -1
  115. package/dist/components/NavigationMenu/NavigationMenu.d.ts +3 -0
  116. package/dist/components/NavigationMenu/NavigationMenu.d.ts.map +1 -0
  117. package/dist/components/NavigationMenu/NavigationMenu.figma.d.ts +2 -0
  118. package/dist/components/NavigationMenu/NavigationMenu.figma.d.ts.map +1 -0
  119. package/dist/components/NavigationMenu/index.d.ts +3 -0
  120. package/dist/components/NavigationMenu/index.d.ts.map +1 -0
  121. package/dist/components/NavigationMenu/types.d.ts +25 -0
  122. package/dist/components/NavigationMenu/types.d.ts.map +1 -0
  123. package/dist/components/QuickStartPage/QuickStartPage.d.ts +21 -0
  124. package/dist/components/QuickStartPage/QuickStartPage.d.ts.map +1 -0
  125. package/dist/components/QuickStartPage/index.d.ts +3 -0
  126. package/dist/components/QuickStartPage/index.d.ts.map +1 -0
  127. package/dist/components/ScenarioQueue/ScenarioQueue.figma.d.ts +2 -0
  128. package/dist/components/ScenarioQueue/ScenarioQueue.figma.d.ts.map +1 -0
  129. package/dist/components/ScenarioSettings/ScenarioSettings.d.ts +3 -0
  130. package/dist/components/ScenarioSettings/ScenarioSettings.d.ts.map +1 -0
  131. package/dist/components/ScenarioSettings/ScenarioSettings.figma.d.ts +2 -0
  132. package/dist/components/ScenarioSettings/ScenarioSettings.figma.d.ts.map +1 -0
  133. package/dist/components/ScenarioSettings/index.d.ts +3 -0
  134. package/dist/components/ScenarioSettings/index.d.ts.map +1 -0
  135. package/dist/components/ScenarioSettings/types.d.ts +54 -0
  136. package/dist/components/ScenarioSettings/types.d.ts.map +1 -0
  137. package/dist/components/index.cjs +86 -42
  138. package/dist/components/index.d.ts +14 -3
  139. package/dist/components/index.d.ts.map +1 -1
  140. package/dist/components/index.js +1 -1
  141. package/dist/figma-codex/config.d.ts +8 -0
  142. package/dist/figma-codex/config.d.ts.map +1 -0
  143. package/dist/figma-codex/fixtures/CompoundComponent/CompoundComponent.d.ts +6 -0
  144. package/dist/figma-codex/fixtures/CompoundComponent/CompoundComponent.d.ts.map +1 -0
  145. package/dist/figma-codex/fixtures/CompoundComponent/index.d.ts +2 -0
  146. package/dist/figma-codex/fixtures/CompoundComponent/index.d.ts.map +1 -0
  147. package/dist/figma-codex/fixtures/CompoundComponent.figma.d.ts +2 -0
  148. package/dist/figma-codex/fixtures/CompoundComponent.figma.d.ts.map +1 -0
  149. package/dist/figma-codex/fixtures/SimpleComponent.d.ts +8 -0
  150. package/dist/figma-codex/fixtures/SimpleComponent.d.ts.map +1 -0
  151. package/dist/figma-codex/fixtures/SimpleComponent.figma.d.ts +2 -0
  152. package/dist/figma-codex/fixtures/SimpleComponent.figma.d.ts.map +1 -0
  153. package/dist/figma-codex/generate.d.ts +6 -0
  154. package/dist/figma-codex/generate.d.ts.map +1 -0
  155. package/dist/figma-codex/parser.d.ts +18 -0
  156. package/dist/figma-codex/parser.d.ts.map +1 -0
  157. package/dist/figma-codex/resolver.d.ts +5 -0
  158. package/dist/figma-codex/resolver.d.ts.map +1 -0
  159. package/dist/figma-codex/schema.d.ts +60 -0
  160. package/dist/figma-codex/schema.d.ts.map +1 -0
  161. package/dist/figma-codex/writer.d.ts +8 -0
  162. package/dist/figma-codex/writer.d.ts.map +1 -0
  163. package/dist/figma-codex.json +679 -0
  164. package/dist/index.cjs +90 -46
  165. package/dist/index.js +2 -2
  166. package/dist/preset/index.cjs +2 -2
  167. package/dist/preset/index.d.ts.map +1 -1
  168. package/dist/preset/index.js +1 -1
  169. package/dist/preset/recipes/accordion.d.ts.map +1 -1
  170. package/dist/preset/recipes/breadcrumb.d.ts.map +1 -1
  171. package/dist/preset/recipes/content-card.d.ts +2 -0
  172. package/dist/preset/recipes/content-card.d.ts.map +1 -0
  173. package/dist/preset/recipes/index.d.ts +4 -0
  174. package/dist/preset/recipes/index.d.ts.map +1 -1
  175. package/dist/preset/recipes/navigation-menu.d.ts +2 -0
  176. package/dist/preset/recipes/navigation-menu.d.ts.map +1 -0
  177. package/dist/preset/recipes/scenario-settings.d.ts +2 -0
  178. package/dist/preset/recipes/scenario-settings.d.ts.map +1 -0
  179. package/package.json +26 -2
  180. package/src/components/Accordion.figma.tsx +20 -0
  181. package/src/components/Breadcrumb.figma.tsx +18 -0
  182. package/src/components/Breadcrumb.tsx +33 -15
  183. package/src/components/ContentCard/ContentCard.figma.tsx +21 -0
  184. package/src/components/ContentCard/ContentCard.test.tsx +197 -0
  185. package/src/components/ContentCard/ContentCard.tsx +19 -0
  186. package/src/components/ContentCard/index.ts +13 -0
  187. package/src/components/Header.figma.tsx +25 -0
  188. package/src/components/{Heading.tsx → Header.tsx} +2 -2
  189. package/src/components/Icons/AccountIcon.tsx +26 -0
  190. package/src/components/Icons/AudienceIcon.figma.tsx +10 -0
  191. package/src/components/Icons/AudienceIcon.tsx +20 -0
  192. package/src/components/Icons/AudioSpeakerIcon.figma.tsx +10 -0
  193. package/src/components/Icons/AudioSpeakerIcon.tsx +26 -0
  194. package/src/components/Icons/BookmarkPlusIcon.figma.tsx +10 -0
  195. package/src/components/Icons/BookmarkPlusIcon.tsx +26 -0
  196. package/src/components/Icons/ChevronUpIcon.tsx +24 -0
  197. package/src/components/Icons/ClipBoardIcon.figma.tsx +10 -0
  198. package/src/components/Icons/ClipBoardIcon.tsx +61 -0
  199. package/src/components/Icons/ClockIcon.tsx +6 -6
  200. package/src/components/Icons/DashboardIcon.tsx +47 -0
  201. package/src/components/Icons/Discourser-Logo.svg +14 -0
  202. package/src/components/Icons/DiscourserLogo.figma.tsx +10 -0
  203. package/src/components/Icons/DiscourserLogo.tsx +72 -0
  204. package/src/components/Icons/ExitStudioIcon.figma.tsx +10 -0
  205. package/src/components/Icons/ExitStudioIcon.tsx +34 -0
  206. package/src/components/Icons/GripDotsVerticalIcon.tsx +6 -6
  207. package/src/components/Icons/HelpIcon.tsx +26 -0
  208. package/src/components/Icons/MicrophoneIcon.figma.tsx +10 -0
  209. package/src/components/Icons/MicrophoneIcon.tsx +40 -0
  210. package/src/components/Icons/NotebookIcon.tsx +26 -0
  211. package/src/components/Icons/NotebookPenIcon.figma.tsx +10 -0
  212. package/src/components/Icons/NotebookPenIcon.tsx +26 -0
  213. package/src/components/Icons/PausePlayIcon.figma.tsx +10 -0
  214. package/src/components/Icons/PausePlayIcon.tsx +41 -0
  215. package/src/components/Icons/PlayIcon.figma.tsx +10 -0
  216. package/src/components/Icons/PlayIcon.tsx +33 -0
  217. package/src/components/Icons/RecordIcon.figma.tsx +10 -0
  218. package/src/components/Icons/RecordIcon.tsx +41 -0
  219. package/src/components/Icons/RepeatQuestionIcon.figma.tsx +10 -0
  220. package/src/components/Icons/RepeatQuestionIcon.tsx +26 -0
  221. package/src/components/Icons/RightArrowIcon.tsx +23 -0
  222. package/src/components/Icons/ScenarioIcon.tsx +26 -0
  223. package/src/components/Icons/ScrollTextIcon.figma.tsx +10 -0
  224. package/src/components/Icons/ScrollTextIcon.tsx +26 -0
  225. package/src/components/Icons/SparklesIcon.figma.tsx +10 -0
  226. package/src/components/Icons/SparklesIcon.tsx +26 -0
  227. package/src/components/Icons/SpeechIcon.figma.tsx +10 -0
  228. package/src/components/Icons/SpeechIcon.tsx +26 -0
  229. package/src/components/Icons/StopPlayIcon.figma.tsx +10 -0
  230. package/src/components/Icons/StopPlayIcon.tsx +35 -0
  231. package/src/components/Icons/TimerIcon.figma.tsx +10 -0
  232. package/src/components/Icons/TimerIcon.tsx +26 -0
  233. package/src/components/Icons/UserProfileIcon.figma.tsx +10 -0
  234. package/src/components/Icons/UserProfileIcon.tsx +26 -0
  235. package/src/components/Icons/index.ts +39 -2
  236. package/src/components/NavigationMenu/NavigationMenu.figma.tsx +26 -0
  237. package/src/components/NavigationMenu/NavigationMenu.test.tsx +524 -0
  238. package/src/components/NavigationMenu/NavigationMenu.tsx +102 -0
  239. package/src/components/NavigationMenu/index.ts +2 -0
  240. package/src/components/NavigationMenu/types.ts +27 -0
  241. package/src/components/QuickStartPage/QuickStartPage.tsx +627 -0
  242. package/src/components/QuickStartPage/index.ts +2 -0
  243. package/src/components/ScenarioQueue/ScenarioQueue.figma.tsx +37 -0
  244. package/src/components/ScenarioSettings/ScenarioSettings.figma.tsx +12 -0
  245. package/src/components/ScenarioSettings/ScenarioSettings.test.tsx +406 -0
  246. package/src/components/ScenarioSettings/ScenarioSettings.tsx +386 -0
  247. package/src/components/ScenarioSettings/index.ts +11 -0
  248. package/src/components/ScenarioSettings/types.ts +70 -0
  249. package/src/components/__tests__/Breadcrumb.test.tsx +94 -0
  250. package/src/components/index.ts +38 -4
  251. package/src/figma-codex/README.md +186 -0
  252. package/src/figma-codex/__tests__/config.test.ts +63 -0
  253. package/src/figma-codex/__tests__/generate.test.ts +78 -0
  254. package/src/figma-codex/__tests__/parser.test.ts +138 -0
  255. package/src/figma-codex/__tests__/resolver.test.ts +196 -0
  256. package/src/figma-codex/__tests__/writer.test.ts +111 -0
  257. package/src/figma-codex/config.ts +42 -0
  258. package/src/figma-codex/fixtures/CompoundComponent/CompoundComponent.tsx +17 -0
  259. package/src/figma-codex/fixtures/CompoundComponent/index.ts +1 -0
  260. package/src/figma-codex/fixtures/CompoundComponent.figma.tsx +14 -0
  261. package/src/figma-codex/fixtures/SimpleComponent.figma.tsx +10 -0
  262. package/src/figma-codex/fixtures/SimpleComponent.tsx +10 -0
  263. package/src/figma-codex/fixtures/expected-output.json +78 -0
  264. package/src/figma-codex/generate.ts +106 -0
  265. package/src/figma-codex/parser.ts +138 -0
  266. package/src/figma-codex/resolver.ts +280 -0
  267. package/src/figma-codex/schema.ts +79 -0
  268. package/src/figma-codex/writer.ts +54 -0
  269. package/src/preset/index.ts +6 -0
  270. package/src/preset/recipes/accordion.ts +8 -5
  271. package/src/preset/recipes/breadcrumb.ts +34 -2
  272. package/src/preset/recipes/content-card.ts +124 -0
  273. package/src/preset/recipes/index.ts +4 -0
  274. package/src/preset/recipes/navigation-menu.ts +97 -0
  275. package/src/preset/recipes/scenario-settings.ts +182 -0
  276. package/src/test/setup.ts +12 -9
  277. package/dist/chunk-ABC7N32K.cjs.map +0 -1
  278. package/dist/chunk-GD6Q2FUE.js.map +0 -1
  279. package/dist/chunk-SBKRSXSZ.js.map +0 -1
  280. package/dist/chunk-UNWXE6UB.cjs.map +0 -1
  281. package/dist/components/Heading.d.ts.map +0 -1
@@ -0,0 +1,280 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import type { ParsedFigmaFile } from './parser';
4
+ import type { FigmaCodexConfig } from './config';
5
+ import type {
6
+ ComponentEntry,
7
+ PropDefinition,
8
+ SubComponentEntry,
9
+ } from './schema';
10
+
11
+ function resolveSourceFile(
12
+ importSource: string,
13
+ figmaFilePath: string,
14
+ ): string | null {
15
+ const baseDir = dirname(figmaFilePath);
16
+ const candidates = [
17
+ join(baseDir, importSource + '.tsx'),
18
+ join(baseDir, importSource + '.ts'),
19
+ join(baseDir, importSource, 'index.ts'),
20
+ join(baseDir, importSource, 'index.tsx'),
21
+ join(baseDir, importSource),
22
+ ];
23
+ for (const c of candidates) {
24
+ if (existsSync(c)) return c;
25
+ }
26
+ return null;
27
+ }
28
+
29
+ function resolveImplementationFile(sourceFile: string): string {
30
+ const content = readFileSync(sourceFile, 'utf-8');
31
+ // If this is an index that re-exports from a single file, resolve to that file
32
+ // Use a simple match without end-of-string anchor to handle trailing newlines
33
+ const reExportMatch = content.match(/from\s+['"]\.\/(\w+)['"]/);
34
+ if (reExportMatch) {
35
+ const implFile = join(dirname(sourceFile), reExportMatch[1] + '.tsx');
36
+ if (existsSync(implFile)) return implFile;
37
+ }
38
+ return sourceFile;
39
+ }
40
+
41
+ function extractProps(sourceContent: string): PropDefinition[] {
42
+ const props: PropDefinition[] = [];
43
+
44
+ // Step 1: Find the Props interface and extract its full body using balanced-brace tracking
45
+ const ifaceRe = /interface\s+\w+Props\s*\{/g;
46
+ const startMatch = ifaceRe.exec(sourceContent);
47
+ if (!startMatch) return props;
48
+
49
+ // Find the opening { of the interface body
50
+ const openBrace = sourceContent.indexOf(
51
+ '{',
52
+ startMatch.index + startMatch[0].length - 1,
53
+ );
54
+ let depth = 0;
55
+ let closeBrace = openBrace;
56
+ for (let i = openBrace; i < sourceContent.length; i++) {
57
+ if (sourceContent[i] === '{') depth++;
58
+ else if (sourceContent[i] === '}') {
59
+ depth--;
60
+ if (depth === 0) {
61
+ closeBrace = i;
62
+ break;
63
+ }
64
+ }
65
+ }
66
+
67
+ const body = sourceContent.slice(openBrace + 1, closeBrace);
68
+
69
+ // Step 2: Parse each prop using a position-based scanner
70
+ let pos = 0;
71
+
72
+ while (pos < body.length) {
73
+ // Skip whitespace
74
+ while (pos < body.length && /\s/.test(body[pos])) pos++;
75
+ if (pos >= body.length) break;
76
+
77
+ // Try to match JSDoc comment /** ... */
78
+ let jsdoc: string | undefined;
79
+ if (body.startsWith('/**', pos)) {
80
+ const endDoc = body.indexOf('*/', pos);
81
+ if (endDoc !== -1) {
82
+ jsdoc = body
83
+ .slice(pos + 3, endDoc)
84
+ .trim()
85
+ .replace(/\n\s*\*\s*/g, ' ');
86
+ pos = endDoc + 2;
87
+ while (pos < body.length && /\s/.test(body[pos])) pos++;
88
+ }
89
+ }
90
+
91
+ // Match prop name followed by optional `?` and `:`
92
+ const nameMatch = /^(\w+)(\?)?:/.exec(body.slice(pos));
93
+ if (!nameMatch) {
94
+ // Not a prop — skip to next semicolon or newline
95
+ const next = body.indexOf('\n', pos);
96
+ pos = next === -1 ? body.length : next + 1;
97
+ continue;
98
+ }
99
+
100
+ const [fullMatch, name, optional] = nameMatch;
101
+ pos += fullMatch.length;
102
+
103
+ if (name === 'children') {
104
+ // Skip children — find the next semicolon at depth 0
105
+ let bracketDepth = 0;
106
+ while (pos < body.length) {
107
+ const ch = body[pos];
108
+ if (ch === '(' || ch === '{') bracketDepth++;
109
+ else if ((ch === ')' || ch === '}') && bracketDepth > 0) bracketDepth--;
110
+ else if (ch === ';' && bracketDepth === 0) {
111
+ pos++;
112
+ break;
113
+ }
114
+ pos++;
115
+ }
116
+ continue;
117
+ }
118
+
119
+ // Skip whitespace after the colon
120
+ while (pos < body.length && body[pos] === ' ') pos++;
121
+
122
+ // Read the type: track () and {} depth, stop at ; when depth === 0
123
+ const typeStart = pos;
124
+ let bracketDepth = 0;
125
+ while (pos < body.length) {
126
+ const ch = body[pos];
127
+ if (ch === '(' || ch === '{') {
128
+ bracketDepth++;
129
+ } else if ((ch === ')' || ch === '}') && bracketDepth > 0) {
130
+ bracketDepth--;
131
+ } else if (ch === ';' && bracketDepth === 0) {
132
+ break;
133
+ } else if (ch === '\n' && bracketDepth === 0) {
134
+ break;
135
+ }
136
+ pos++;
137
+ }
138
+
139
+ const typeRaw = body.slice(typeStart, pos).trim();
140
+ // Normalize multi-line types: collapse internal whitespace sequences
141
+ const typeNormalized = typeRaw.replace(/\s+/g, ' ');
142
+
143
+ // Skip the terminating ; or newline
144
+ if (pos < body.length && (body[pos] === ';' || body[pos] === '\n')) pos++;
145
+
146
+ if (!name || !typeNormalized) continue;
147
+
148
+ props.push({
149
+ name,
150
+ type: typeNormalized,
151
+ required: !optional,
152
+ description: jsdoc?.trim(),
153
+ });
154
+ }
155
+
156
+ return props;
157
+ }
158
+
159
+ function extractSubComponents(sourceContent: string): SubComponentEntry[] {
160
+ const subs: SubComponentEntry[] = [];
161
+ const re =
162
+ /export\s+const\s+(\w+)\s+=\s+with(?:Provider|Context)\(ark\.(\w+)/g;
163
+ let m: RegExpExecArray | null;
164
+ while ((m = re.exec(sourceContent)) !== null) {
165
+ const [, name, element] = m;
166
+ subs.push({ name, element });
167
+ }
168
+ return subs;
169
+ }
170
+
171
+ function classifyComponent(
172
+ parsed: ParsedFigmaFile,
173
+ sourceContent: string,
174
+ ): 'simple' | 'compound' | 'composite' {
175
+ if (parsed.importStyle === 'namespace') return 'compound';
176
+ // Composite: imports from sibling DDS components (e.g., '../Accordion')
177
+ if (/from\s+['"]\.\.\//g.test(sourceContent)) return 'composite';
178
+ return 'simple';
179
+ }
180
+
181
+ function resolveSubpath(
182
+ parsed: ParsedFigmaFile,
183
+ config: FigmaCodexConfig,
184
+ projectRoot: string,
185
+ ): string | undefined {
186
+ try {
187
+ const pkgPath = join(projectRoot, 'package.json');
188
+ if (!existsSync(pkgPath)) return undefined;
189
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
190
+ const exports = pkg.exports as Record<string, unknown>;
191
+ if (!exports) return undefined;
192
+
193
+ const name = parsed.componentName;
194
+ for (const key of Object.keys(exports)) {
195
+ if (key === `./${name}` || key.endsWith(`/${name}`)) {
196
+ return `${config.packageName}${key.slice(1)}`;
197
+ }
198
+ }
199
+ } catch {
200
+ // ignore
201
+ }
202
+ return undefined;
203
+ }
204
+
205
+ export function resolveComponent(
206
+ parsed: ParsedFigmaFile,
207
+ config: FigmaCodexConfig,
208
+ ): ComponentEntry {
209
+ // Determine project root: walk up from figma file until we find package.json
210
+ let projectRoot = dirname(parsed.filePath);
211
+ for (let i = 0; i < 8; i++) {
212
+ if (existsSync(join(projectRoot, 'package.json'))) break;
213
+ projectRoot = dirname(projectRoot);
214
+ }
215
+
216
+ const sourceFile = resolveSourceFile(parsed.importSource, parsed.filePath);
217
+
218
+ let sourceContent = '';
219
+ if (sourceFile && existsSync(sourceFile)) {
220
+ sourceContent = readFileSync(sourceFile, 'utf-8');
221
+ // For index files, look for the actual implementation
222
+ if (sourceFile.endsWith('index.ts') || sourceFile.endsWith('index.tsx')) {
223
+ const implFile = resolveImplementationFile(sourceFile);
224
+ if (implFile !== sourceFile && existsSync(implFile)) {
225
+ sourceContent = readFileSync(implFile, 'utf-8');
226
+ }
227
+ }
228
+ }
229
+
230
+ // For composite components, types may be in a separate types.ts file
231
+ let typesContent = sourceContent;
232
+ if (sourceFile) {
233
+ const typesFile = join(dirname(sourceFile), 'types.ts');
234
+ if (existsSync(typesFile)) {
235
+ typesContent = readFileSync(typesFile, 'utf-8');
236
+ }
237
+ }
238
+
239
+ const componentType = classifyComponent(parsed, sourceContent);
240
+ const props = extractProps(typesContent);
241
+ const subComponents =
242
+ componentType === 'compound'
243
+ ? extractSubComponents(sourceContent)
244
+ : undefined;
245
+
246
+ const subpath = resolveSubpath(parsed, config, projectRoot);
247
+ const isNamespace = parsed.importStyle === 'namespace';
248
+ const importName = isNamespace
249
+ ? `* as ${parsed.componentName}`
250
+ : `{ ${parsed.componentName} }`;
251
+ const importFrom = subpath ?? `${config.packageName}/${parsed.componentName}`;
252
+ const primaryImport = `import ${importName} from '${importFrom}'`;
253
+
254
+ const namedExports = isNamespace
255
+ ? (subComponents?.map((s) => `${parsed.componentName}.${s.name}`) ?? [])
256
+ : [parsed.componentName];
257
+
258
+ const sourcePath = sourceFile
259
+ ? sourceFile.replace(projectRoot + '/', '')
260
+ : parsed.importSource;
261
+
262
+ return {
263
+ name: parsed.componentName,
264
+ type: componentType,
265
+ figma: {
266
+ fileKey: parsed.figmaFileKey,
267
+ nodeId: parsed.figmaNodeId,
268
+ url: parsed.figmaUrl,
269
+ },
270
+ imports: {
271
+ primary: primaryImport,
272
+ namedExports,
273
+ subpath,
274
+ },
275
+ props,
276
+ subComponents,
277
+ example: parsed.example,
278
+ sourcePath,
279
+ };
280
+ }
@@ -0,0 +1,79 @@
1
+ // src/figma-codex/schema.ts
2
+
3
+ export interface FigmaCodex {
4
+ /** Schema version for forward compatibility */
5
+ version: '1.0.0';
6
+
7
+ /** Package name of the design system */
8
+ packageName: string;
9
+
10
+ /** ISO timestamp of generation */
11
+ generatedAt: string;
12
+
13
+ /** Git commit hash (if available) */
14
+ gitHash?: string;
15
+
16
+ /** Source Figma file(s) referenced */
17
+ figmaFiles: Record<
18
+ string,
19
+ {
20
+ fileKey: string;
21
+ fileName?: string;
22
+ }
23
+ >;
24
+
25
+ /** The component registry */
26
+ components: Record<string, ComponentEntry>;
27
+ }
28
+
29
+ export interface ComponentEntry {
30
+ /** Human-readable component name */
31
+ name: string;
32
+
33
+ /** Component type classification */
34
+ type: 'simple' | 'compound' | 'composite';
35
+
36
+ /** Figma reference */
37
+ figma: {
38
+ fileKey: string;
39
+ nodeId: string;
40
+ nodeName?: string;
41
+ url: string;
42
+ };
43
+
44
+ /** Import information */
45
+ imports: {
46
+ /** Primary import statement */
47
+ primary: string;
48
+ /** Named exports available */
49
+ namedExports: string[];
50
+ /** Package subpath, e.g. '@discourser/design-system/Breadcrumb' */
51
+ subpath?: string;
52
+ };
53
+
54
+ /** Prop interface (extracted from TypeScript source) */
55
+ props: PropDefinition[];
56
+
57
+ /** Sub-components for compound components */
58
+ subComponents?: SubComponentEntry[];
59
+
60
+ /** Example JSX from .figma.tsx */
61
+ example: string;
62
+
63
+ /** Source file path relative to project root */
64
+ sourcePath: string;
65
+ }
66
+
67
+ export interface PropDefinition {
68
+ name: string;
69
+ type: string; // TypeScript type as string
70
+ required: boolean;
71
+ description?: string; // JSDoc comment if available
72
+ defaultValue?: string;
73
+ }
74
+
75
+ export interface SubComponentEntry {
76
+ name: string; // e.g. 'Root', 'Header', 'Title'
77
+ element: string; // underlying HTML element, e.g. 'div', 'h2', 'nav'
78
+ description?: string;
79
+ }
@@ -0,0 +1,54 @@
1
+ import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
2
+ import { dirname, join, isAbsolute } from 'node:path';
3
+ import { execSync } from 'node:child_process';
4
+ import type { ComponentEntry, FigmaCodex } from './schema';
5
+
6
+ interface WriteOptions {
7
+ packageName: string;
8
+ outputPath: string;
9
+ }
10
+
11
+ function getGitHash(cwd: string): string | undefined {
12
+ try {
13
+ return execSync('git rev-parse --short HEAD', {
14
+ cwd,
15
+ stdio: ['pipe', 'pipe', 'pipe'],
16
+ })
17
+ .toString()
18
+ .trim();
19
+ } catch {
20
+ return undefined;
21
+ }
22
+ }
23
+
24
+ export function writeManifest(
25
+ components: Record<string, ComponentEntry>,
26
+ options: WriteOptions,
27
+ projectRoot: string,
28
+ ): void {
29
+ const figmaFiles: FigmaCodex['figmaFiles'] = {};
30
+ for (const entry of Object.values(components)) {
31
+ const { fileKey } = entry.figma;
32
+ if (fileKey && !figmaFiles[fileKey]) {
33
+ figmaFiles[fileKey] = { fileKey };
34
+ }
35
+ }
36
+
37
+ const manifest: FigmaCodex = {
38
+ version: '1.0.0',
39
+ packageName: options.packageName,
40
+ generatedAt: new Date().toISOString(),
41
+ gitHash: getGitHash(projectRoot),
42
+ figmaFiles,
43
+ components,
44
+ };
45
+
46
+ const outPath = isAbsolute(options.outputPath)
47
+ ? options.outputPath
48
+ : join(projectRoot, options.outputPath);
49
+
50
+ const outDir = dirname(outPath);
51
+ if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });
52
+
53
+ writeFileSync(outPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
54
+ }
@@ -21,6 +21,7 @@ import { tabs } from './recipes/tabs';
21
21
 
22
22
  // Park UI recipes - Navigation
23
23
  import { breadcrumb } from './recipes/breadcrumb';
24
+ import { navigationMenu } from './recipes/navigation-menu';
24
25
 
25
26
  // Park UI recipes - Form Elements
26
27
  import { switchRecipe } from './recipes/switch';
@@ -47,8 +48,10 @@ import { heading } from './recipes/heading';
47
48
 
48
49
  // Custom Components
49
50
  import { stepper } from './recipes/stepper';
51
+ import { contentCard } from './recipes/content-card';
50
52
  import { scenarioCard } from './recipes/scenario-card';
51
53
  import { scenarioQueue } from './recipes/scenario-queue';
54
+ import { scenarioSettings } from './recipes/scenario-settings';
52
55
 
53
56
  // Park UI theme extensions
54
57
  import { layerStyles } from './layer-styles';
@@ -162,6 +165,7 @@ export const discourserPandaPreset = definePreset({
162
165
  tabs,
163
166
  // Navigation
164
167
  breadcrumb,
168
+ navigationMenu,
165
169
  // Form Elements
166
170
  switchComponent: switchRecipe,
167
171
  checkbox,
@@ -178,8 +182,10 @@ export const discourserPandaPreset = definePreset({
178
182
  tooltip,
179
183
  // Custom Components
180
184
  stepper,
185
+ contentCard,
181
186
  scenarioCard,
182
187
  scenarioQueue,
188
+ scenarioSettings,
183
189
  },
184
190
  },
185
191
  },
@@ -53,13 +53,16 @@ export const accordion = defineSlotRecipe({
53
53
  overflow: 'hidden',
54
54
  borderRadius: 'var(--accordion-radius)',
55
55
  _open: {
56
- animationName: 'expand-height, fade-in',
57
- animationDuration: 'normal',
56
+ animationName: 'slide-down',
57
+ animationDuration: '250ms',
58
+ animationTimingFunction: 'ease-out',
59
+ animationFillMode: 'forwards',
58
60
  },
59
61
  _closed: {
60
- animationName: 'collapse-height, fade-out',
61
- animationDuration: 'normal',
62
- display: 'none',
62
+ animationName: 'slide-up',
63
+ animationDuration: '200ms',
64
+ animationTimingFunction: 'ease-out',
65
+ animationFillMode: 'forwards',
63
66
  },
64
67
  },
65
68
  },
@@ -1,4 +1,4 @@
1
- import { defineSlotRecipe } from '@pandacss/dev'
1
+ import { defineSlotRecipe } from '@pandacss/dev';
2
2
 
3
3
  export const breadcrumb = defineSlotRecipe({
4
4
  className: 'breadcrumb',
@@ -61,6 +61,38 @@ export const breadcrumb = defineSlotRecipe({
61
61
  _currentPage: { color: 'fg.default' },
62
62
  },
63
63
  },
64
+ discourser: {
65
+ list: {
66
+ gap: '2.5',
67
+ alignItems: 'center',
68
+ },
69
+ item: {
70
+ bg: 'transparent',
71
+ px: '1.5',
72
+ py: '1.5',
73
+ borderRadius: 'l2',
74
+ h: '9',
75
+ display: 'inline-flex',
76
+ alignItems: 'center',
77
+ _last: {
78
+ color: 'fg.default',
79
+ fontWeight: 'medium',
80
+ fontSize: 'md',
81
+ fontFeatureSettings: "'liga' 0, 'calt' 0",
82
+ },
83
+ },
84
+ link: {
85
+ color: 'fg.subtle',
86
+ fontWeight: 'medium',
87
+ fontSize: 'lg',
88
+ _hover: { color: 'fg.default' },
89
+ _currentPage: { color: 'fg.default', fontWeight: 'semibold' },
90
+ },
91
+ separator: {
92
+ color: 'primary.7',
93
+ _icon: { width: '27px', height: '27px' },
94
+ },
95
+ },
64
96
  },
65
97
  size: {
66
98
  xs: { list: { gap: '1', textStyle: 'xs' } },
@@ -74,4 +106,4 @@ export const breadcrumb = defineSlotRecipe({
74
106
  variant: 'plain',
75
107
  size: 'md',
76
108
  },
77
- })
109
+ });
@@ -0,0 +1,124 @@
1
+ import { defineSlotRecipe } from '@pandacss/dev';
2
+
3
+ export const contentCard = defineSlotRecipe({
4
+ className: 'content-card',
5
+ slots: [
6
+ 'root',
7
+ 'header',
8
+ 'title',
9
+ 'badgeBar',
10
+ 'body',
11
+ 'section',
12
+ 'sectionTitle',
13
+ 'separator',
14
+ 'list',
15
+ 'listItem',
16
+ ],
17
+ base: {
18
+ root: {
19
+ bg: 'neutral.1',
20
+ borderRadius: 'xl',
21
+ borderWidth: '2px',
22
+ borderColor: 'border.default',
23
+ display: 'flex',
24
+ flexDirection: 'column',
25
+ w: 'full',
26
+ },
27
+ header: {
28
+ display: 'flex',
29
+ flexDirection: 'column',
30
+ gap: '4',
31
+ },
32
+ title: {
33
+ fontFamily: 'heading',
34
+ fontWeight: 'semibold',
35
+ fontSize: '2xl',
36
+ color: 'fg.default',
37
+ fontVariationSettings: "'SOFT' 0, 'WONK' 1",
38
+ },
39
+ badgeBar: {
40
+ display: 'flex',
41
+ flexWrap: 'wrap',
42
+ gap: '2.5',
43
+ px: '2.5',
44
+ py: '1',
45
+ },
46
+ body: {
47
+ display: 'flex',
48
+ flexDirection: 'column',
49
+ gap: '9',
50
+ fontSize: 'xl',
51
+ lineHeight: '1.4',
52
+ color: 'fg.default',
53
+ },
54
+ section: {
55
+ display: 'flex',
56
+ flexDirection: 'column',
57
+ gap: '5',
58
+ },
59
+ sectionTitle: {
60
+ fontFamily: 'heading',
61
+ fontWeight: 'semibold',
62
+ fontSize: '2xl',
63
+ color: 'fg.default',
64
+ fontVariationSettings: "'SOFT' 0, 'WONK' 1",
65
+ px: '2.5',
66
+ py: '2.5',
67
+ },
68
+ separator: {
69
+ borderTopWidth: '1px',
70
+ borderColor: 'border.default',
71
+ w: 'full',
72
+ my: '4',
73
+ },
74
+ list: {
75
+ display: 'flex',
76
+ flexDirection: 'column',
77
+ gap: '5',
78
+ listStyleType: 'disc',
79
+ ps: '8',
80
+ },
81
+ listItem: {
82
+ fontSize: 'xl',
83
+ lineHeight: '1.4',
84
+ color: 'fg.default',
85
+ },
86
+ },
87
+ variants: {
88
+ size: {
89
+ sm: {
90
+ root: { maxW: 'xl', pt: '6', px: '6', pb: '6' },
91
+ title: { fontSize: 'xl' },
92
+ body: { fontSize: 'lg' },
93
+ listItem: { fontSize: 'lg' },
94
+ },
95
+ md: {
96
+ root: { maxW: '2xl', pt: '10', px: '10', pb: '10', gap: '6' },
97
+ title: { fontSize: '2xl' },
98
+ body: { fontSize: 'xl' },
99
+ listItem: { fontSize: 'xl' },
100
+ },
101
+ lg: {
102
+ root: { maxW: '4xl', pt: '12', px: '12', pb: '12', gap: '8' },
103
+ title: { fontSize: '3xl' },
104
+ body: { fontSize: 'xl' },
105
+ listItem: { fontSize: 'xl' },
106
+ },
107
+ },
108
+ variant: {
109
+ elevated: {
110
+ root: { boxShadow: 'lg', borderWidth: '0' },
111
+ },
112
+ outline: {
113
+ root: { borderWidth: '2px', borderColor: 'border.default' },
114
+ },
115
+ flat: {
116
+ root: { borderWidth: '0', bg: 'transparent' },
117
+ },
118
+ },
119
+ },
120
+ defaultVariants: {
121
+ size: 'md',
122
+ variant: 'outline',
123
+ },
124
+ });
@@ -13,6 +13,7 @@ export * from './tabs';
13
13
 
14
14
  // Navigation
15
15
  export * from './breadcrumb';
16
+ export * from './navigation-menu';
16
17
 
17
18
  // Form elements
18
19
  export * from './switch';
@@ -43,5 +44,8 @@ export * from './absolute-center';
43
44
  export * from './group';
44
45
 
45
46
  // Custom Components
47
+ export * from './stepper';
48
+ export * from './content-card';
46
49
  export * from './scenario-card';
47
50
  export * from './scenario-queue';
51
+ export * from './scenario-settings';