nextworks 0.2.0-alpha.11 → 0.2.0-alpha.13

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 (111) hide show
  1. package/README.md +283 -282
  2. package/dist/cli_manifests/blocks_manifest.json +198 -175
  3. package/dist/kits/blocks/.nextworks/docs/BLOCKS_QUICKSTART.md +101 -100
  4. package/dist/kits/blocks/.nextworks/docs/BLOCKS_README.md +105 -104
  5. package/dist/kits/blocks/.nextworks/docs/THEME_GUIDE.md +1 -1
  6. package/dist/kits/blocks/app/templates/aiworkflow/PresetThemeVars.tsx +58 -0
  7. package/dist/kits/blocks/app/templates/aiworkflow/README.md +46 -0
  8. package/dist/kits/blocks/app/templates/aiworkflow/components/CTA.tsx +44 -0
  9. package/dist/kits/blocks/app/templates/aiworkflow/components/Contact.tsx +105 -0
  10. package/dist/kits/blocks/app/templates/aiworkflow/components/FAQ.tsx +63 -0
  11. package/dist/kits/blocks/app/templates/aiworkflow/components/Features.tsx +65 -0
  12. package/dist/kits/blocks/app/templates/aiworkflow/components/Footer.tsx +109 -0
  13. package/dist/kits/blocks/app/templates/aiworkflow/components/Hero.tsx +636 -0
  14. package/dist/kits/blocks/app/templates/aiworkflow/components/Navbar.tsx +90 -0
  15. package/dist/kits/blocks/app/templates/aiworkflow/components/Pricing.tsx +86 -0
  16. package/dist/kits/blocks/app/templates/aiworkflow/components/ProcessTimeline.tsx +103 -0
  17. package/dist/kits/blocks/app/templates/aiworkflow/components/Testimonials.tsx +56 -0
  18. package/dist/kits/blocks/app/templates/aiworkflow/components/TrustBadges.tsx +59 -0
  19. package/dist/kits/blocks/app/templates/aiworkflow/page.tsx +43 -0
  20. package/dist/kits/blocks/app/templates/digitalagency/PresetThemeVars.tsx +80 -80
  21. package/dist/kits/blocks/app/templates/digitalagency/README.md +42 -42
  22. package/dist/kits/blocks/app/templates/digitalagency/components/Pricing.tsx +114 -114
  23. package/dist/kits/blocks/app/templates/digitalagency/components/Process.tsx +59 -59
  24. package/dist/kits/blocks/app/templates/digitalagency/components/Services.tsx +55 -55
  25. package/dist/kits/blocks/app/templates/digitalagency/components/Team.tsx +28 -28
  26. package/dist/kits/blocks/app/templates/digitalagency/components/Testimonials.tsx +65 -65
  27. package/dist/kits/blocks/app/templates/digitalagency/page.tsx +38 -38
  28. package/dist/kits/blocks/app/templates/gallery/PresetThemeVars.tsx +84 -84
  29. package/dist/kits/blocks/app/templates/productlaunch/PresetThemeVars.tsx +75 -75
  30. package/dist/kits/blocks/app/templates/productlaunch/README.md +62 -62
  31. package/dist/kits/blocks/app/templates/productlaunch/components/About.tsx +84 -84
  32. package/dist/kits/blocks/app/templates/productlaunch/components/CTA.tsx +50 -50
  33. package/dist/kits/blocks/app/templates/productlaunch/components/Contact.tsx +231 -231
  34. package/dist/kits/blocks/app/templates/productlaunch/components/FAQ.tsx +86 -86
  35. package/dist/kits/blocks/app/templates/productlaunch/components/Features.tsx +83 -83
  36. package/dist/kits/blocks/app/templates/productlaunch/components/Footer.tsx +132 -132
  37. package/dist/kits/blocks/app/templates/productlaunch/components/Hero.tsx +88 -88
  38. package/dist/kits/blocks/app/templates/productlaunch/components/Navbar.tsx +116 -116
  39. package/dist/kits/blocks/app/templates/productlaunch/components/Pricing.tsx +106 -106
  40. package/dist/kits/blocks/app/templates/productlaunch/components/ProcessTimeline.tsx +110 -110
  41. package/dist/kits/blocks/app/templates/productlaunch/components/ServicesGrid.tsx +68 -68
  42. package/dist/kits/blocks/app/templates/productlaunch/components/Team.tsx +104 -104
  43. package/dist/kits/blocks/app/templates/productlaunch/components/Testimonials.tsx +90 -90
  44. package/dist/kits/blocks/app/templates/productlaunch/components/TrustBadges.tsx +76 -76
  45. package/dist/kits/blocks/app/templates/productlaunch/page.tsx +43 -43
  46. package/dist/kits/blocks/app/templates/saasdashboard/PresetThemeVars.tsx +80 -80
  47. package/dist/kits/blocks/app/templates/saasdashboard/README.md +44 -44
  48. package/dist/kits/blocks/app/templates/saasdashboard/components/Contact.tsx +129 -129
  49. package/dist/kits/blocks/app/templates/saasdashboard/components/Dashboard.tsx +293 -293
  50. package/dist/kits/blocks/app/templates/saasdashboard/components/FAQ.tsx +55 -55
  51. package/dist/kits/blocks/app/templates/saasdashboard/components/Features.tsx +90 -90
  52. package/dist/kits/blocks/app/templates/saasdashboard/components/Footer.tsx +77 -77
  53. package/dist/kits/blocks/app/templates/saasdashboard/components/Hero.tsx +104 -104
  54. package/dist/kits/blocks/app/templates/saasdashboard/components/Hero_mask.tsx +126 -126
  55. package/dist/kits/blocks/app/templates/saasdashboard/components/Navbar.tsx +117 -117
  56. package/dist/kits/blocks/app/templates/saasdashboard/components/Pricing.tsx +90 -90
  57. package/dist/kits/blocks/app/templates/saasdashboard/components/SmoothScroll.tsx +96 -96
  58. package/dist/kits/blocks/app/templates/saasdashboard/components/Testimonials.tsx +72 -72
  59. package/dist/kits/blocks/app/templates/saasdashboard/components/TrustBadges.tsx +53 -53
  60. package/dist/kits/blocks/app/templates/saasdashboard/page.tsx +39 -39
  61. package/dist/kits/blocks/components/enhanced-theme-provider.tsx +195 -195
  62. package/dist/kits/blocks/components/providers/BlocksAppProviders.tsx +27 -27
  63. package/dist/kits/blocks/components/sections/About.tsx +291 -291
  64. package/dist/kits/blocks/components/sections/CTA.tsx +257 -257
  65. package/dist/kits/blocks/components/sections/Contact.tsx +267 -267
  66. package/dist/kits/blocks/components/sections/FAQ.tsx +214 -214
  67. package/dist/kits/blocks/components/sections/Features.tsx +268 -268
  68. package/dist/kits/blocks/components/sections/Footer.tsx +302 -302
  69. package/dist/kits/blocks/components/sections/HeroMotion.tsx +308 -308
  70. package/dist/kits/blocks/components/sections/HeroOverlay.tsx +358 -358
  71. package/dist/kits/blocks/components/sections/HeroProductDemo.tsx +236 -0
  72. package/dist/kits/blocks/components/sections/HeroSplit.tsx +352 -352
  73. package/dist/kits/blocks/components/sections/Navbar.tsx +350 -350
  74. package/dist/kits/blocks/components/sections/PortfolioSimple.tsx +549 -549
  75. package/dist/kits/blocks/components/sections/Pricing.tsx +264 -264
  76. package/dist/kits/blocks/components/sections/ProcessTimeline.tsx +325 -325
  77. package/dist/kits/blocks/components/sections/ServicesGrid.tsx +210 -210
  78. package/dist/kits/blocks/components/sections/Team.tsx +309 -309
  79. package/dist/kits/blocks/components/sections/Testimonials.tsx +158 -158
  80. package/dist/kits/blocks/components/sections/TrustBadges.tsx +162 -162
  81. package/dist/kits/blocks/components/sections/product-demo/ApprovalInboxPanel.tsx +125 -0
  82. package/dist/kits/blocks/components/sections/product-demo/DemoStage.tsx +397 -0
  83. package/dist/kits/blocks/components/sections/product-demo/DemoWindow.tsx +128 -0
  84. package/dist/kits/blocks/components/sections/product-demo/KnowledgePanel.tsx +127 -0
  85. package/dist/kits/blocks/components/sections/product-demo/RunConsolePanel.tsx +150 -0
  86. package/dist/kits/blocks/components/sections/product-demo/WorkflowStudioPanel.tsx +191 -0
  87. package/dist/kits/blocks/components/sections/product-demo/types.ts +193 -0
  88. package/dist/kits/blocks/components/theme-provider.tsx +1 -1
  89. package/dist/kits/blocks/components/ui/alert-dialog.tsx +134 -134
  90. package/dist/kits/blocks/components/ui/brand-node.tsx +121 -121
  91. package/dist/kits/blocks/components/ui/button.tsx +122 -122
  92. package/dist/kits/blocks/components/ui/card.tsx +95 -95
  93. package/dist/kits/blocks/components/ui/checkbox.tsx +30 -30
  94. package/dist/kits/blocks/components/ui/cta-button.tsx +125 -125
  95. package/dist/kits/blocks/components/ui/dropdown-menu.tsx +201 -201
  96. package/dist/kits/blocks/components/ui/feature-card.tsx +91 -91
  97. package/dist/kits/blocks/components/ui/input.tsx +27 -27
  98. package/dist/kits/blocks/components/ui/label.tsx +29 -29
  99. package/dist/kits/blocks/components/ui/pricing-card.tsx +120 -120
  100. package/dist/kits/blocks/components/ui/select.tsx +25 -25
  101. package/dist/kits/blocks/components/ui/skeleton.tsx +13 -13
  102. package/dist/kits/blocks/components/ui/table.tsx +98 -98
  103. package/dist/kits/blocks/components/ui/testimonial-card.tsx +108 -108
  104. package/dist/kits/blocks/components/ui/textarea.tsx +26 -26
  105. package/dist/kits/blocks/components/ui/theme-selector.tsx +243 -243
  106. package/dist/kits/blocks/components/ui/theme-toggle.tsx +74 -74
  107. package/dist/kits/blocks/components/ui/toaster.tsx +7 -7
  108. package/dist/kits/blocks/lib/themes.ts +400 -400
  109. package/dist/kits/blocks/lib/utils.ts +6 -6
  110. package/dist/kits/blocks/package-deps.json +3 -3
  111. package/package.json +1 -1
@@ -1,214 +1,214 @@
1
- "use client";
2
-
3
- import React, { useMemo, useState } from "react";
4
- import { cn } from "@/lib/utils";
5
- import { ChevronDown, ChevronUp } from "lucide-react";
6
-
7
- /**
8
- * Represents a single FAQ item.
9
- * @public
10
- */
11
- export interface FAQS {
12
- /** The question text */
13
- question?: string;
14
- /** The answer text */
15
- answer?: string;
16
- }
17
-
18
- /**
19
- * Props for the FAQ section component.
20
- *
21
- * @remarks
22
- * - Styling: exposes slot-style className overrides; consumer classes are
23
- * merged after defaults via cn().
24
- * - Behavior: supports single or multiple open items; default open indices
25
- * are respected. Controlled internally with a Set.
26
- * - Motion: when enableMotion is false, collapse/expand transitions are
27
- * removed for a hard-cut.
28
- * - Accessibility: each item uses button+region with aria-controls and
29
- * aria-expanded. Section uses aria-label.
30
- */
31
- export interface FAQProps {
32
- /** Header text displayed at the top of the FAQ section. @defaultValue "Frequently Asked Questions" */
33
- faqSectionHeaderText?: string;
34
- /** Array of question/answer items. @defaultValue defaultFaqData */
35
- faqData?: FAQS[];
36
- /** Optional id for the section root. @defaultValue "faq" */
37
- sectionId?: string;
38
- /** Optional top-level class override */
39
- className?: string;
40
- /** When false, only one item can be open at a time. @defaultValue true */
41
- allowMultipleOpen?: boolean;
42
- /** Indices of items that should be open by default. @defaultValue [] */
43
- defaultOpenIndices?: number[];
44
- /** Optional icons for open/closed states */
45
- openIcon?: React.ReactNode;
46
- closedIcon?: React.ReactNode;
47
- /** ARIA label for the FAQ section. @defaultValue "Frequently asked questions section" */
48
- ariaLabel?: string;
49
- /** Slot-style overrides */
50
- section?: { className?: string };
51
- container?: { className?: string };
52
- heading?: { className?: string };
53
- grid?: { className?: string };
54
- item?: { className?: string };
55
- questionButton?: { className?: string };
56
- questionText?: { className?: string };
57
- chevronIcon?: { className?: string };
58
- answer?: { className?: string };
59
- answerText?: { className?: string };
60
- /** When false, removes transition on collapse/expand for a hard-cut */
61
- enableMotion?: boolean;
62
- }
63
-
64
- const defaultFaqData: FAQS[] = [
65
- {
66
- question: "What does IntelliOpAI do?",
67
- answer: "Automates ops with real-time insights.",
68
- },
69
- {
70
- question: "How secure is my data?",
71
- answer: "We use industry-standard encryption and strict access controls.",
72
- },
73
- {
74
- question: "Can I integrate with other tools?",
75
- answer:
76
- "Yes — supports APIs and popular integrations like Slack, GitHub, and Jira.",
77
- },
78
- {
79
- question: "How do I get support?",
80
- answer:
81
- "Contact our support team via in-app chat or the help center for assistance.",
82
- },
83
- ];
84
-
85
- /**
86
- * Expandable FAQ section with accessible toggles and optional icons.
87
- *
88
- * @remarks
89
- * - Supports multiple or single open item behavior via allowMultipleOpen.
90
- * - Uses button with aria-expanded and a region with aria-labelledby.
91
- * - Motion can be disabled via enableMotion for reduced animation.
92
- *
93
- * @example
94
- * <FAQ faqData={[{ question: 'What is X?', answer: 'Y' }]} />
95
- */
96
- export function FAQ({
97
- faqSectionHeaderText = "Frequently Asked Questions",
98
- faqData = defaultFaqData,
99
- sectionId = "faq",
100
- className,
101
- allowMultipleOpen = true,
102
- defaultOpenIndices = [],
103
- openIcon,
104
- closedIcon,
105
- ariaLabel = "Frequently asked questions section",
106
- section = { className: "py-10 px-5 bg-muted text-foreground" },
107
- container = { className: "mx-auto max-w-7xl" },
108
- heading = {
109
- className: "mb-6 text-center text-2xl font-bold text-foreground",
110
- },
111
- grid = { className: "grid grid-cols-1 gap-4 md:grid-cols-2 md:gap-6" },
112
- item = { className: "mb-4" },
113
- questionButton = {
114
- className:
115
- "shadow-md hover:shadow-lg border-[var(--btn-border)] focus-visible:ring-[var(--btn-ring)] bg-[var(--faq-btn-bg,var(--btn-bg))] text-[var(--faq-btn-fg,var(--btn-fg))] hover:bg-[var(--faq-btn-hover-bg,var(--btn-hover-bg))] hover:text-[var(--faq-btn-hover-fg,var(--btn-hover-fg))]",
116
- },
117
- questionText = { className: "" },
118
- chevronIcon = { className: "transition-transform duration-200" },
119
- answer = {
120
- className:
121
- "bg-[var(--faq-answer-bg,var(--card-bg))] text-[var(--faq-answer-fg,var(--card-fg))] border-[var(--card-border)]",
122
- },
123
- answerText = { className: "leading-relaxed" },
124
- enableMotion = true,
125
- }: FAQProps) {
126
- const [openSet, setOpenSet] = useState<Set<number>>(
127
- () => new Set(defaultOpenIndices),
128
- );
129
- const idPrefix = useMemo(() => sectionId || "faq", [sectionId]);
130
-
131
- const onToggle = (idx: number) => {
132
- setOpenSet((prev) => {
133
- const next = new Set(prev);
134
- if (next.has(idx)) next.delete(idx);
135
- else {
136
- if (!allowMultipleOpen) next.clear();
137
- next.add(idx);
138
- }
139
- return next;
140
- });
141
- };
142
-
143
- return (
144
- <section
145
- id={sectionId}
146
- className={cn(section.className, className)}
147
- aria-label={ariaLabel}
148
- >
149
- <div className={cn(container.className)}>
150
- {faqSectionHeaderText && (
151
- <h2 className={cn(heading.className)}>{faqSectionHeaderText}</h2>
152
- )}
153
- <div className={cn(grid.className)}>
154
- {faqData.map((faq, index) => {
155
- const transitionCls = enableMotion
156
- ? "transition-all duration-300 ease-in-out"
157
- : "transition-none";
158
- const isOpen = openSet.has(index);
159
- return (
160
- <div
161
- key={`${idPrefix}-item-${index}`}
162
- className={cn("w-full", item.className)}
163
- >
164
- <button
165
- id={`${idPrefix}-trigger-${index}`}
166
- aria-controls={`${idPrefix}-panel-${index}`}
167
- aria-expanded={isOpen}
168
- onClick={() => onToggle(index)}
169
- className={cn(
170
- "flex w-full items-center justify-between rounded-md p-4 text-left focus:outline-none",
171
- // preset-first ring/border
172
- "border-[var(--btn-border)] focus-visible:ring-2 focus-visible:ring-[var(--btn-ring)] focus-visible:ring-offset-2",
173
- questionButton.className,
174
- )}
175
- >
176
- <span
177
- className={cn(
178
- "flex-1 font-medium select-none",
179
- questionText.className,
180
- )}
181
- >
182
- {faq.question}
183
- </span>
184
- <span
185
- className={cn("ml-3 flex-shrink-0", chevronIcon.className)}
186
- >
187
- {isOpen
188
- ? (openIcon ?? <ChevronUp className="h-5 w-5" />)
189
- : (closedIcon ?? <ChevronDown className="h-5 w-5" />)}
190
- </span>
191
- </button>
192
- <div
193
- id={`${idPrefix}-panel-${index}`}
194
- role="region"
195
- aria-labelledby={`${idPrefix}-trigger-${index}`}
196
- className={cn(
197
- "border-border overflow-hidden rounded-md border",
198
- isOpen ? "max-h-96 opacity-100" : "max-h-0 opacity-0",
199
- transitionCls,
200
- answer.className,
201
- )}
202
- >
203
- <div className={cn("p-4", answerText.className)}>
204
- {faq.answer}
205
- </div>
206
- </div>
207
- </div>
208
- );
209
- })}
210
- </div>
211
- </div>
212
- </section>
213
- );
214
- }
1
+ "use client";
2
+
3
+ import React, { useMemo, useState } from "react";
4
+ import { cn } from "@/lib/utils";
5
+ import { ChevronDown, ChevronUp } from "lucide-react";
6
+
7
+ /**
8
+ * Represents a single FAQ item.
9
+ * @public
10
+ */
11
+ export interface FAQS {
12
+ /** The question text */
13
+ question?: string;
14
+ /** The answer text */
15
+ answer?: string;
16
+ }
17
+
18
+ /**
19
+ * Props for the FAQ section component.
20
+ *
21
+ * @remarks
22
+ * - Styling: exposes slot-style className overrides; consumer classes are
23
+ * merged after defaults via cn().
24
+ * - Behavior: supports single or multiple open items; default open indices
25
+ * are respected. Controlled internally with a Set.
26
+ * - Motion: when enableMotion is false, collapse/expand transitions are
27
+ * removed for a hard-cut.
28
+ * - Accessibility: each item uses button+region with aria-controls and
29
+ * aria-expanded. Section uses aria-label.
30
+ */
31
+ export interface FAQProps {
32
+ /** Header text displayed at the top of the FAQ section. @defaultValue "Frequently Asked Questions" */
33
+ faqSectionHeaderText?: string;
34
+ /** Array of question/answer items. @defaultValue defaultFaqData */
35
+ faqData?: FAQS[];
36
+ /** Optional id for the section root. @defaultValue "faq" */
37
+ sectionId?: string;
38
+ /** Optional top-level class override */
39
+ className?: string;
40
+ /** When false, only one item can be open at a time. @defaultValue true */
41
+ allowMultipleOpen?: boolean;
42
+ /** Indices of items that should be open by default. @defaultValue [] */
43
+ defaultOpenIndices?: number[];
44
+ /** Optional icons for open/closed states */
45
+ openIcon?: React.ReactNode;
46
+ closedIcon?: React.ReactNode;
47
+ /** ARIA label for the FAQ section. @defaultValue "Frequently asked questions section" */
48
+ ariaLabel?: string;
49
+ /** Slot-style overrides */
50
+ section?: { className?: string };
51
+ container?: { className?: string };
52
+ heading?: { className?: string };
53
+ grid?: { className?: string };
54
+ item?: { className?: string };
55
+ questionButton?: { className?: string };
56
+ questionText?: { className?: string };
57
+ chevronIcon?: { className?: string };
58
+ answer?: { className?: string };
59
+ answerText?: { className?: string };
60
+ /** When false, removes transition on collapse/expand for a hard-cut */
61
+ enableMotion?: boolean;
62
+ }
63
+
64
+ const defaultFaqData: FAQS[] = [
65
+ {
66
+ question: "What does IntelliOpAI do?",
67
+ answer: "Automates ops with real-time insights.",
68
+ },
69
+ {
70
+ question: "How secure is my data?",
71
+ answer: "We use industry-standard encryption and strict access controls.",
72
+ },
73
+ {
74
+ question: "Can I integrate with other tools?",
75
+ answer:
76
+ "Yes — supports APIs and popular integrations like Slack, GitHub, and Jira.",
77
+ },
78
+ {
79
+ question: "How do I get support?",
80
+ answer:
81
+ "Contact our support team via in-app chat or the help center for assistance.",
82
+ },
83
+ ];
84
+
85
+ /**
86
+ * Expandable FAQ section with accessible toggles and optional icons.
87
+ *
88
+ * @remarks
89
+ * - Supports multiple or single open item behavior via allowMultipleOpen.
90
+ * - Uses button with aria-expanded and a region with aria-labelledby.
91
+ * - Motion can be disabled via enableMotion for reduced animation.
92
+ *
93
+ * @example
94
+ * <FAQ faqData={[{ question: 'What is X?', answer: 'Y' }]} />
95
+ */
96
+ export function FAQ({
97
+ faqSectionHeaderText = "Frequently Asked Questions",
98
+ faqData = defaultFaqData,
99
+ sectionId = "faq",
100
+ className,
101
+ allowMultipleOpen = true,
102
+ defaultOpenIndices = [],
103
+ openIcon,
104
+ closedIcon,
105
+ ariaLabel = "Frequently asked questions section",
106
+ section = { className: "py-10 px-5 bg-muted text-foreground" },
107
+ container = { className: "mx-auto max-w-7xl" },
108
+ heading = {
109
+ className: "mb-6 text-center text-2xl font-bold text-foreground",
110
+ },
111
+ grid = { className: "grid grid-cols-1 gap-4 md:grid-cols-2 md:gap-6" },
112
+ item = { className: "mb-4" },
113
+ questionButton = {
114
+ className:
115
+ "shadow-md hover:shadow-lg border-[var(--btn-border)] focus-visible:ring-[var(--btn-ring)] bg-[var(--faq-btn-bg,var(--btn-bg))] text-[var(--faq-btn-fg,var(--btn-fg))] hover:bg-[var(--faq-btn-hover-bg,var(--btn-hover-bg))] hover:text-[var(--faq-btn-hover-fg,var(--btn-hover-fg))]",
116
+ },
117
+ questionText = { className: "" },
118
+ chevronIcon = { className: "transition-transform duration-200" },
119
+ answer = {
120
+ className:
121
+ "bg-[var(--faq-answer-bg,var(--card-bg))] text-[var(--faq-answer-fg,var(--card-fg))] border-[var(--card-border)]",
122
+ },
123
+ answerText = { className: "leading-relaxed" },
124
+ enableMotion = true,
125
+ }: FAQProps) {
126
+ const [openSet, setOpenSet] = useState<Set<number>>(
127
+ () => new Set(defaultOpenIndices),
128
+ );
129
+ const idPrefix = useMemo(() => sectionId || "faq", [sectionId]);
130
+
131
+ const onToggle = (idx: number) => {
132
+ setOpenSet((prev) => {
133
+ const next = new Set(prev);
134
+ if (next.has(idx)) next.delete(idx);
135
+ else {
136
+ if (!allowMultipleOpen) next.clear();
137
+ next.add(idx);
138
+ }
139
+ return next;
140
+ });
141
+ };
142
+
143
+ return (
144
+ <section
145
+ id={sectionId}
146
+ className={cn(section.className, className)}
147
+ aria-label={ariaLabel}
148
+ >
149
+ <div className={cn(container.className)}>
150
+ {faqSectionHeaderText && (
151
+ <h2 className={cn(heading.className)}>{faqSectionHeaderText}</h2>
152
+ )}
153
+ <div className={cn(grid.className)}>
154
+ {faqData.map((faq, index) => {
155
+ const transitionCls = enableMotion
156
+ ? "transition-all duration-300 ease-in-out"
157
+ : "transition-none";
158
+ const isOpen = openSet.has(index);
159
+ return (
160
+ <div
161
+ key={`${idPrefix}-item-${index}`}
162
+ className={cn("w-full", item.className)}
163
+ >
164
+ <button
165
+ id={`${idPrefix}-trigger-${index}`}
166
+ aria-controls={`${idPrefix}-panel-${index}`}
167
+ aria-expanded={isOpen}
168
+ onClick={() => onToggle(index)}
169
+ className={cn(
170
+ "flex w-full items-center justify-between rounded-md p-4 text-left focus:outline-none",
171
+ // preset-first ring/border
172
+ "border-[var(--btn-border)] focus-visible:ring-2 focus-visible:ring-[var(--btn-ring)] focus-visible:ring-offset-2",
173
+ questionButton.className,
174
+ )}
175
+ >
176
+ <span
177
+ className={cn(
178
+ "flex-1 font-medium select-none",
179
+ questionText.className,
180
+ )}
181
+ >
182
+ {faq.question}
183
+ </span>
184
+ <span
185
+ className={cn("ml-3 flex-shrink-0", chevronIcon.className)}
186
+ >
187
+ {isOpen
188
+ ? (openIcon ?? <ChevronUp className="h-5 w-5" />)
189
+ : (closedIcon ?? <ChevronDown className="h-5 w-5" />)}
190
+ </span>
191
+ </button>
192
+ <div
193
+ id={`${idPrefix}-panel-${index}`}
194
+ role="region"
195
+ aria-labelledby={`${idPrefix}-trigger-${index}`}
196
+ className={cn(
197
+ "border-border overflow-hidden rounded-md border",
198
+ isOpen ? "max-h-96 opacity-100" : "max-h-0 opacity-0",
199
+ transitionCls,
200
+ answer.className,
201
+ )}
202
+ >
203
+ <div className={cn("p-4", answerText.className)}>
204
+ {faq.answer}
205
+ </div>
206
+ </div>
207
+ </div>
208
+ );
209
+ })}
210
+ </div>
211
+ </div>
212
+ </section>
213
+ );
214
+ }