@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,386 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import type { ReactNode } from 'react';
5
+ import * as Accordion from '../Accordion';
6
+ import * as Dialog from '../Dialog';
7
+ import * as RadioGroup from '../RadioGroup';
8
+ import { Button } from '../Button';
9
+ import { scenarioSettings } from 'styled-system/recipes';
10
+ import type {
11
+ ScenarioSettingsProps,
12
+ AdjustableSectionId,
13
+ DurationValue,
14
+ QuestionCountValue,
15
+ } from './types';
16
+
17
+ // ── Static section data ────────────────────────────────────────────────────────
18
+
19
+ const INFO_SECTIONS = [
20
+ {
21
+ id: 'conversation-flow' as AdjustableSectionId,
22
+ label: 'Conversation Flow',
23
+ explanation: {
24
+ beginner: 'Topic transitions are explicit and signposted',
25
+ intermediate: 'Conversation flows organically with realistic tangents',
26
+ advanced: 'Topic shifts are sudden and unpredictable',
27
+ },
28
+ },
29
+ {
30
+ id: 'question-complexity' as AdjustableSectionId,
31
+ label: 'Question Complexity',
32
+ explanation: {
33
+ beginner: 'Questions focus on single, clear topics',
34
+ intermediate: 'Questions are layered with multiple components',
35
+ advanced: 'Questions are complex and multi-dimensional',
36
+ },
37
+ },
38
+ {
39
+ id: 'discourse-tone' as AdjustableSectionId,
40
+ label: 'Discourse Tone',
41
+ explanation: {
42
+ beginner: 'AI is warm, encouraging, and supportive',
43
+ intermediate: 'AI is professional, neutral, and balanced',
44
+ advanced: 'AI is direct, skeptical, and challenging',
45
+ },
46
+ },
47
+ {
48
+ id: 'response-pacing' as AdjustableSectionId,
49
+ label: 'Response Pacing',
50
+ explanation: {
51
+ beginner: 'Long pauses welcomed, relaxed timing',
52
+ intermediate: 'Natural conversational rhythm and pacing',
53
+ advanced: 'Quick responses expected, minimal pauses',
54
+ },
55
+ },
56
+ ] as const;
57
+
58
+ const DURATION_OPTIONS = [
59
+ { value: 'quick', label: 'Quick (10 - 15 min)', badgeLabel: '~ (10-15 min)' },
60
+ {
61
+ value: 'standard',
62
+ label: 'Standard (15 - 25 min)',
63
+ badgeLabel: '~ (15-25 min)',
64
+ },
65
+ {
66
+ value: 'extended',
67
+ label: 'Extended (25 - 35 min)',
68
+ badgeLabel: '~ (25-35 min)',
69
+ },
70
+ ] as const;
71
+
72
+ const QUESTION_OPTIONS = [
73
+ { value: 'brief', label: 'Brief (2-4)', badgeLabel: '2-4 questions' },
74
+ { value: 'standard', label: 'Standard (5-8)', badgeLabel: '5-8 questions' },
75
+ { value: 'extended', label: 'Extended (9-12)', badgeLabel: '9-12 questions' },
76
+ ] as const;
77
+
78
+ const ALL_SECTION_IDS = [
79
+ 'conversation-flow',
80
+ 'question-complexity',
81
+ 'discourse-tone',
82
+ 'response-pacing',
83
+ 'duration',
84
+ 'number-of-questions',
85
+ ];
86
+
87
+ // ── Component ─────────────────────────────────────────────────────────────────
88
+
89
+ export function ScenarioSettings({
90
+ defaultValue,
91
+ singleOpen = false,
92
+ adjustmentDialogContent,
93
+ renderAdjustmentDialog,
94
+ defaultDuration = 'quick',
95
+ defaultQuestionCount = 'brief',
96
+ onSelectionChange,
97
+ }: ScenarioSettingsProps) {
98
+ const styles = scenarioSettings();
99
+
100
+ const resolvedDefaultValue =
101
+ defaultValue ?? (singleOpen ? ['conversation-flow'] : ALL_SECTION_IDS);
102
+
103
+ const [duration, setDuration] = useState<DurationValue>(defaultDuration);
104
+ const [questionCount, setQuestionCount] =
105
+ useState<QuestionCountValue>(defaultQuestionCount);
106
+
107
+ const durationBadge =
108
+ DURATION_OPTIONS.find((o) => o.value === duration)?.badgeLabel ??
109
+ '~ (10-15 min)';
110
+ const questionBadge =
111
+ QUESTION_OPTIONS.find((o) => o.value === questionCount)?.badgeLabel ??
112
+ '2-4 questions';
113
+
114
+ function resolveDialogContent(sectionId: AdjustableSectionId): ReactNode {
115
+ if (renderAdjustmentDialog) return renderAdjustmentDialog(sectionId);
116
+ if (adjustmentDialogContent?.[sectionId])
117
+ return adjustmentDialogContent[sectionId];
118
+ return null;
119
+ }
120
+
121
+ return (
122
+ <div className={styles.root}>
123
+ <Accordion.Root
124
+ defaultValue={resolvedDefaultValue}
125
+ collapsible
126
+ variant="plain"
127
+ >
128
+ {/* ── Sections 1-4: Info + Adjustments ───────────────────────────────── */}
129
+ {INFO_SECTIONS.map((section) => {
130
+ const dialogContent = resolveDialogContent(section.id);
131
+ return (
132
+ <Accordion.Item
133
+ key={section.id}
134
+ value={section.id}
135
+ className={styles.section}
136
+ >
137
+ <Accordion.ItemTrigger
138
+ className={styles.sectionTrigger}
139
+ css={{
140
+ fontSize: 'lg',
141
+ fontWeight: 'medium',
142
+ borderRadius: '0',
143
+ py: '4',
144
+ bg: 'surface',
145
+ color: 'onSurface',
146
+ }}
147
+ >
148
+ <span className={styles.triggerLabel}>{section.label}</span>
149
+ <Accordion.ItemIndicator
150
+ className={styles.sectionIndicator}
151
+ css={{ color: 'primary.7' }}
152
+ />
153
+ </Accordion.ItemTrigger>
154
+
155
+ <Accordion.ItemContent className={styles.sectionContent}>
156
+ <div className={styles.infoPanel}>
157
+ <div className={styles.explanationCard}>
158
+ <p className={styles.explanationTitle}>What this means:</p>
159
+ <ul className={styles.explanationList}>
160
+ <li className={styles.explanationItem}>
161
+ <span className={styles.levelLabel}>Beginner:</span>{' '}
162
+ {section.explanation.beginner}
163
+ </li>
164
+ <li className={styles.explanationItem}>
165
+ <span className={styles.levelLabel}>Intermediate:</span>{' '}
166
+ {section.explanation.intermediate}
167
+ </li>
168
+ <li className={styles.explanationItem}>
169
+ <span className={styles.levelLabel}>Advanced:</span>{' '}
170
+ {section.explanation.advanced}
171
+ </li>
172
+ </ul>
173
+ </div>
174
+
175
+ <div className={styles.adjustmentsRow}>
176
+ <Dialog.Root>
177
+ <Dialog.Trigger asChild>
178
+ <Button
179
+ size="sm"
180
+ aria-label={`Open ${section.label} adjustments`}
181
+ css={{
182
+ bg: 'secondary.7',
183
+ color: 'white',
184
+ fontWeight: 'medium',
185
+ fontSize: 'md',
186
+ borderRadius: 'l3',
187
+ px: '4',
188
+ h: '10',
189
+ minW: '36',
190
+ _hover: { bg: 'secondary.8' },
191
+ }}
192
+ >
193
+ Adjustments
194
+ </Button>
195
+ </Dialog.Trigger>
196
+
197
+ <Dialog.Backdrop />
198
+ <Dialog.Positioner>
199
+ <Dialog.Content css={{ maxW: 'lg', w: 'full' }}>
200
+ <Dialog.Header
201
+ css={{
202
+ display: 'flex',
203
+ alignItems: 'center',
204
+ justifyContent: 'space-between',
205
+ pb: '3',
206
+ }}
207
+ >
208
+ <Dialog.Title
209
+ css={{ fontSize: 'xl', fontWeight: 'semibold' }}
210
+ >
211
+ Adjust {section.label}
212
+ </Dialog.Title>
213
+ <Dialog.CloseTrigger
214
+ aria-label="Close dialog"
215
+ css={{
216
+ cursor: 'pointer',
217
+ fontSize: 'lg',
218
+ color: 'fg.muted',
219
+ _hover: { color: 'fg.default' },
220
+ }}
221
+ >
222
+
223
+ </Dialog.CloseTrigger>
224
+ </Dialog.Header>
225
+
226
+ <Dialog.Body>
227
+ {dialogContent ?? (
228
+ <p>
229
+ Adjustment controls for {section.label} will
230
+ appear here.
231
+ </p>
232
+ )}
233
+ </Dialog.Body>
234
+ </Dialog.Content>
235
+ </Dialog.Positioner>
236
+ </Dialog.Root>
237
+ </div>
238
+ </div>
239
+ </Accordion.ItemContent>
240
+ </Accordion.Item>
241
+ );
242
+ })}
243
+
244
+ {/* ── Section 5: Duration ─────────────────────────────────────────────── */}
245
+ <Accordion.Item value="duration" className={styles.section}>
246
+ <Accordion.ItemTrigger
247
+ className={styles.sectionTrigger}
248
+ css={{
249
+ fontSize: 'lg',
250
+ fontWeight: 'medium',
251
+ borderRadius: '0',
252
+ py: '4',
253
+ bg: 'surface',
254
+ color: 'onSurface',
255
+ }}
256
+ >
257
+ <span className={styles.triggerLabel}>Duration</span>
258
+ <Accordion.ItemIndicator
259
+ className={styles.sectionIndicator}
260
+ css={{ color: 'primary.7' }}
261
+ />
262
+ </Accordion.ItemTrigger>
263
+
264
+ <Accordion.ItemContent className={styles.sectionContent}>
265
+ <div className={styles.radioPanel}>
266
+ <div>
267
+ <p className={styles.radioPanelTitle}>
268
+ Expected time to complete
269
+ </p>
270
+ <div className={styles.radioCurrentRow}>
271
+ <span className={styles.radioCurrentLabel}>Currently:</span>
272
+ <span className={styles.currentlyBadge}>{durationBadge}</span>
273
+ </div>
274
+ </div>
275
+
276
+ <RadioGroup.Root
277
+ defaultValue={defaultDuration}
278
+ colorPalette="primary"
279
+ onValueChange={({ value }) => {
280
+ if (!value) return;
281
+ setDuration(value as DurationValue);
282
+ onSelectionChange?.('duration', value);
283
+ }}
284
+ css={{ gap: '3' }}
285
+ >
286
+ {DURATION_OPTIONS.map((option) => (
287
+ <RadioGroup.Item key={option.value} value={option.value}>
288
+ <RadioGroup.ItemControl
289
+ css={{
290
+ boxShadow: 'none',
291
+ borderWidth: '1px',
292
+ borderStyle: 'solid',
293
+ borderColor: 'primary.7',
294
+ _checked: {
295
+ bg: 'm3Primary.container',
296
+ borderColor: 'primary.7',
297
+ _after: { bg: 'primary.7' },
298
+ },
299
+ }}
300
+ />
301
+ <RadioGroup.ItemText
302
+ css={{ fontSize: 'md', fontWeight: 'medium' }}
303
+ >
304
+ {option.label}
305
+ </RadioGroup.ItemText>
306
+ <RadioGroup.ItemHiddenInput />
307
+ </RadioGroup.Item>
308
+ ))}
309
+ </RadioGroup.Root>
310
+ </div>
311
+ </Accordion.ItemContent>
312
+ </Accordion.Item>
313
+
314
+ {/* ── Section 6: Number of Questions ──────────────────────────────────── */}
315
+ <Accordion.Item value="number-of-questions" className={styles.section}>
316
+ <Accordion.ItemTrigger
317
+ className={styles.sectionTrigger}
318
+ css={{
319
+ fontSize: 'lg',
320
+ fontWeight: 'medium',
321
+ borderRadius: '0',
322
+ py: '4',
323
+ bg: 'surface',
324
+ color: 'onSurface',
325
+ }}
326
+ >
327
+ <span className={styles.triggerLabel}>Number of Questions</span>
328
+ <Accordion.ItemIndicator
329
+ className={styles.sectionIndicator}
330
+ css={{ color: 'primary.7' }}
331
+ />
332
+ </Accordion.ItemTrigger>
333
+
334
+ <Accordion.ItemContent className={styles.sectionContent}>
335
+ <div className={styles.radioPanel}>
336
+ <div>
337
+ <p className={styles.radioPanelTitle}>
338
+ Follow up Questions in this session
339
+ </p>
340
+ <div className={styles.radioCurrentRow}>
341
+ <span className={styles.radioCurrentLabel}>Currently:</span>
342
+ <span className={styles.currentlyBadge}>{questionBadge}</span>
343
+ </div>
344
+ </div>
345
+
346
+ <RadioGroup.Root
347
+ defaultValue={defaultQuestionCount}
348
+ colorPalette="primary"
349
+ onValueChange={({ value }) => {
350
+ if (!value) return;
351
+ setQuestionCount(value as QuestionCountValue);
352
+ onSelectionChange?.('number-of-questions', value);
353
+ }}
354
+ css={{ gap: '3' }}
355
+ >
356
+ {QUESTION_OPTIONS.map((option) => (
357
+ <RadioGroup.Item key={option.value} value={option.value}>
358
+ <RadioGroup.ItemControl
359
+ css={{
360
+ boxShadow: 'none',
361
+ borderWidth: '1px',
362
+ borderStyle: 'solid',
363
+ borderColor: 'primary.7',
364
+ _checked: {
365
+ bg: 'm3Primary.container',
366
+ borderColor: 'primary.7',
367
+ _after: { bg: 'primary.7' },
368
+ },
369
+ }}
370
+ />
371
+ <RadioGroup.ItemText
372
+ css={{ fontSize: 'md', fontWeight: 'medium' }}
373
+ >
374
+ {option.label}
375
+ </RadioGroup.ItemText>
376
+ <RadioGroup.ItemHiddenInput />
377
+ </RadioGroup.Item>
378
+ ))}
379
+ </RadioGroup.Root>
380
+ </div>
381
+ </Accordion.ItemContent>
382
+ </Accordion.Item>
383
+ </Accordion.Root>
384
+ </div>
385
+ );
386
+ }
@@ -0,0 +1,11 @@
1
+ export { ScenarioSettings } from './ScenarioSettings';
2
+ export type {
3
+ ScenarioSettingsProps,
4
+ AdjustableSectionId,
5
+ RadioSectionId,
6
+ SectionId,
7
+ DurationValue,
8
+ QuestionCountValue,
9
+ ExplanationContent,
10
+ RadioOption,
11
+ } from './types';
@@ -0,0 +1,70 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export type AdjustableSectionId =
4
+ | 'conversation-flow'
5
+ | 'question-complexity'
6
+ | 'discourse-tone'
7
+ | 'response-pacing';
8
+
9
+ export type RadioSectionId = 'duration' | 'number-of-questions';
10
+
11
+ export type SectionId = AdjustableSectionId | RadioSectionId;
12
+
13
+ export type DurationValue = 'quick' | 'standard' | 'extended';
14
+ export type QuestionCountValue = 'brief' | 'standard' | 'extended';
15
+
16
+ export interface ExplanationContent {
17
+ beginner: string;
18
+ intermediate: string;
19
+ advanced: string;
20
+ }
21
+
22
+ export interface RadioOption {
23
+ value: string;
24
+ label: string;
25
+ }
26
+
27
+ export interface ScenarioSettingsProps {
28
+ /**
29
+ * Section IDs that start expanded.
30
+ * Defaults to all six sections, or ['conversation-flow'] when singleOpen is true.
31
+ */
32
+ defaultValue?: string[];
33
+
34
+ /**
35
+ * When true, only one accordion section can be open at a time.
36
+ * @default false
37
+ */
38
+ singleOpen?: boolean;
39
+
40
+ /**
41
+ * ReactNode content to render inside each adjustable section's dialog.
42
+ * Keyed by section ID. Falls back to a placeholder when not provided.
43
+ */
44
+ adjustmentDialogContent?: Partial<Record<AdjustableSectionId, ReactNode>>;
45
+
46
+ /**
47
+ * Alternative render-function API for dialog content.
48
+ * Takes precedence over adjustmentDialogContent when both are provided.
49
+ */
50
+ renderAdjustmentDialog?: (sectionId: AdjustableSectionId) => ReactNode;
51
+
52
+ /**
53
+ * Default selected value for the Duration radio group.
54
+ * @default 'quick'
55
+ */
56
+ defaultDuration?: DurationValue;
57
+
58
+ /**
59
+ * Default selected value for the Number of Questions radio group.
60
+ * @default 'brief'
61
+ */
62
+ defaultQuestionCount?: QuestionCountValue;
63
+
64
+ /**
65
+ * Called when a radio group selection changes.
66
+ * @param sectionId - 'duration' or 'number-of-questions'
67
+ * @param value - the selected radio value
68
+ */
69
+ onSelectionChange?: (sectionId: RadioSectionId, value: string) => void;
70
+ }
@@ -0,0 +1,94 @@
1
+ /* global describe, it, expect */
2
+ import React from 'react'
3
+ import { render, screen } from '@testing-library/react'
4
+ import * as Breadcrumb from '../Breadcrumb'
5
+
6
+ type BreadcrumbVariant = 'plain' | 'underline' | 'discourser'
7
+
8
+ function renderBreadcrumb(variant?: BreadcrumbVariant) {
9
+ return render(
10
+ <Breadcrumb.Root {...(variant ? { variant } : {})}>
11
+ <Breadcrumb.List>
12
+ <Breadcrumb.Item>
13
+ <Breadcrumb.Link href="/home">Home</Breadcrumb.Link>
14
+ </Breadcrumb.Item>
15
+ <Breadcrumb.Separator />
16
+ <Breadcrumb.Item>
17
+ <Breadcrumb.Link href="/docs">Docs</Breadcrumb.Link>
18
+ </Breadcrumb.Item>
19
+ <Breadcrumb.Separator />
20
+ <Breadcrumb.Item>
21
+ <Breadcrumb.CurrentLink>Components</Breadcrumb.CurrentLink>
22
+ </Breadcrumb.Item>
23
+ </Breadcrumb.List>
24
+ </Breadcrumb.Root>,
25
+ )
26
+ }
27
+
28
+ describe('Breadcrumb', () => {
29
+ describe('Rendering', () => {
30
+ it('renders breadcrumb navigation with correct aria-label', () => {
31
+ renderBreadcrumb()
32
+ expect(screen.getByRole('navigation', { name: 'breadcrumb' })).toBeDefined()
33
+ })
34
+
35
+ it('renders all breadcrumb items', () => {
36
+ renderBreadcrumb()
37
+ expect(screen.getByText('Home')).toBeDefined()
38
+ expect(screen.getByText('Docs')).toBeDefined()
39
+ expect(screen.getByText('Components')).toBeDefined()
40
+ })
41
+
42
+ it('renders separator between items', () => {
43
+ const { container } = renderBreadcrumb()
44
+ // Separators are aria-hidden li elements with svg children
45
+ const separators = container.querySelectorAll('[aria-hidden="true"]')
46
+ expect(separators.length).toBeGreaterThan(0)
47
+ })
48
+
49
+ it('marks the last item as current page with aria-current', () => {
50
+ renderBreadcrumb()
51
+ const current = screen.getByText('Components')
52
+ expect(current.closest('[aria-current="page"]')).toBeDefined()
53
+ })
54
+ })
55
+
56
+ describe('Discourser Variant', () => {
57
+ it('renders with discourser variant class when variant="discourser"', () => {
58
+ const { container } = renderBreadcrumb('discourser')
59
+ // The root nav element should exist with the breadcrumb class
60
+ const nav = container.querySelector('nav')
61
+ expect(nav).toBeDefined()
62
+ })
63
+
64
+ it('CurrentLink renders as span, not anchor', () => {
65
+ renderBreadcrumb()
66
+ const current = screen.getByText('Components')
67
+ expect(current.tagName).toBe('SPAN')
68
+ })
69
+
70
+ it('CurrentLink has aria-current="page" by default', () => {
71
+ renderBreadcrumb()
72
+ const current = screen.getByText('Components')
73
+ expect(current.getAttribute('aria-current')).toBe('page')
74
+ })
75
+ })
76
+
77
+ describe('Accessibility', () => {
78
+ it('has role navigation on root element', () => {
79
+ renderBreadcrumb()
80
+ expect(screen.getByRole('navigation')).toBeDefined()
81
+ })
82
+
83
+ it('renders ordered list for semantic structure', () => {
84
+ const { container } = renderBreadcrumb()
85
+ expect(container.querySelector('ol')).toBeDefined()
86
+ })
87
+
88
+ it('separators are aria-hidden', () => {
89
+ const { container } = renderBreadcrumb()
90
+ const hiddenElements = container.querySelectorAll('[aria-hidden="true"]')
91
+ expect(hiddenElements.length).toBeGreaterThan(0)
92
+ })
93
+ })
94
+ })
@@ -17,7 +17,7 @@ export { InputGroup, type InputGroupProps } from './InputGroup';
17
17
  export { Textarea, type TextareaProps } from './Textarea';
18
18
 
19
19
  // Typography Components (simple)
20
- export { Heading, type HeadingProps } from './Heading';
20
+ export { Header, type HeadingProps } from './Header';
21
21
 
22
22
  // Feedback & Status Components (simple)
23
23
  export { Badge, type BadgeProps } from './Badge';
@@ -44,18 +44,52 @@ export * as Tooltip from './Tooltip';
44
44
  // Utility Components (namespace pattern - may have multiple exports)
45
45
  export * as CloseButton from './CloseButton';
46
46
  export * as Icon from './Icon';
47
+ export * as AbsoluteCenter from './AbsoluteCenter';
48
+ export * as Group from './Group';
47
49
 
48
50
  // Icons (individual icon components)
49
- export { GripDotsVerticalIcon, type GripDotsVerticalIconProps } from './Icons/GripDotsVerticalIcon';
51
+ export {
52
+ GripDotsVerticalIcon,
53
+ type GripDotsVerticalIconProps,
54
+ } from './Icons/GripDotsVerticalIcon';
50
55
  export { ClockIcon, type ClockIconProps } from './Icons/ClockIcon';
51
- export * as AbsoluteCenter from './AbsoluteCenter';
52
- export * as Group from './Group';
56
+ export { DashboardIcon, type DashboardIconProps } from './Icons/DashboardIcon';
57
+ export { NotebookIcon, type NotebookIconProps } from './Icons/NotebookIcon';
58
+ export { ScenarioIcon, type ScenarioIconProps } from './Icons/ScenarioIcon';
59
+ export { HelpIcon, type HelpIconProps } from './Icons/HelpIcon';
60
+ export { AccountIcon, type AccountIconProps } from './Icons/AccountIcon';
61
+ export {
62
+ RightArrowIcon,
63
+ type RightArrowIconProps,
64
+ } from './Icons/RightArrowIcon';
65
+ export { ChevronUpIcon, type ChevronUpIconProps } from './Icons/ChevronUpIcon';
66
+ export { DiscourserLogo, type DiscourserLogoProps } from './Icons/DiscourserLogo';
53
67
 
54
68
  // Navigation & Progress Components
55
69
  export * as Breadcrumb from './Breadcrumb';
70
+ export * as ContentCard from './ContentCard';
56
71
  export { Stepper, type StepperRootProps, type StepItem } from './Stepper';
57
72
 
58
73
  // Composite / Feature Components
74
+ export {
75
+ NavigationMenu,
76
+ type NavigationMenuProps,
77
+ type NavSection,
78
+ type NavItem,
79
+ } from './NavigationMenu';
80
+
81
+ // Settings Components
82
+ export {
83
+ ScenarioSettings,
84
+ type ScenarioSettingsProps,
85
+ type AdjustableSectionId,
86
+ type RadioSectionId,
87
+ type SectionId,
88
+ type DurationValue,
89
+ type QuestionCountValue,
90
+ } from './ScenarioSettings';
91
+
92
+ // Queue Components
59
93
  export {
60
94
  ScenarioQueue,
61
95
  ScenarioCard,