@syntrologie/adapt-faq 0.0.0-semantically-released

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.
package/dist/editor.js ADDED
@@ -0,0 +1,280 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // Editor Styles
4
+ // ============================================================================
5
+ const styles = {
6
+ container: {
7
+ display: 'flex',
8
+ flexDirection: 'column',
9
+ height: '100%',
10
+ fontFamily: 'system-ui, -apple-system, sans-serif',
11
+ },
12
+ header: {
13
+ padding: '16px',
14
+ borderBottom: '1px solid #334155',
15
+ display: 'flex',
16
+ alignItems: 'center',
17
+ gap: '12px',
18
+ },
19
+ backButton: {
20
+ padding: '6px 12px',
21
+ borderRadius: '6px',
22
+ border: 'none',
23
+ backgroundColor: 'rgba(255,255,255,0.05)',
24
+ color: '#94a3b8',
25
+ fontSize: '13px',
26
+ cursor: 'pointer',
27
+ },
28
+ title: {
29
+ margin: 0,
30
+ fontSize: '15px',
31
+ fontWeight: 600,
32
+ color: '#f8fafc',
33
+ },
34
+ subtitle: {
35
+ margin: '2px 0 0 0',
36
+ fontSize: '11px',
37
+ color: '#64748b',
38
+ },
39
+ content: {
40
+ flex: 1,
41
+ overflow: 'auto',
42
+ padding: '16px',
43
+ },
44
+ section: {
45
+ marginBottom: '24px',
46
+ },
47
+ sectionTitle: {
48
+ fontSize: '12px',
49
+ fontWeight: 600,
50
+ color: '#94a3b8',
51
+ textTransform: 'uppercase',
52
+ letterSpacing: '0.05em',
53
+ marginBottom: '12px',
54
+ },
55
+ select: {
56
+ width: '100%',
57
+ padding: '10px 12px',
58
+ borderRadius: '6px',
59
+ border: '1px solid rgba(255,255,255,0.1)',
60
+ backgroundColor: 'rgba(255,255,255,0.05)',
61
+ color: '#f8fafc',
62
+ fontSize: '13px',
63
+ cursor: 'pointer',
64
+ },
65
+ checkbox: {
66
+ display: 'flex',
67
+ alignItems: 'center',
68
+ gap: '8px',
69
+ fontSize: '13px',
70
+ color: '#d1d5db',
71
+ marginTop: '8px',
72
+ },
73
+ addButton: {
74
+ width: '100%',
75
+ padding: '12px',
76
+ borderRadius: '8px',
77
+ border: '1px dashed rgba(139, 92, 246, 0.3)',
78
+ background: 'rgba(139, 92, 246, 0.05)',
79
+ color: '#8b5cf6',
80
+ fontSize: '13px',
81
+ fontWeight: 600,
82
+ cursor: 'pointer',
83
+ marginBottom: '16px',
84
+ },
85
+ questionCard: {
86
+ padding: '12px',
87
+ borderRadius: '8px',
88
+ border: '1px solid rgba(255,255,255,0.08)',
89
+ background: 'rgba(255,255,255,0.02)',
90
+ marginBottom: '8px',
91
+ },
92
+ questionHeader: {
93
+ display: 'flex',
94
+ alignItems: 'flex-start',
95
+ justifyContent: 'space-between',
96
+ marginBottom: '12px',
97
+ },
98
+ questionPreview: {
99
+ flex: 1,
100
+ },
101
+ questionText: {
102
+ fontSize: '14px',
103
+ fontWeight: 500,
104
+ color: '#f8fafc',
105
+ marginBottom: '4px',
106
+ },
107
+ answerPreview: {
108
+ fontSize: '12px',
109
+ color: '#64748b',
110
+ overflow: 'hidden',
111
+ textOverflow: 'ellipsis',
112
+ whiteSpace: 'nowrap',
113
+ maxWidth: '200px',
114
+ },
115
+ removeButton: {
116
+ padding: '4px 8px',
117
+ borderRadius: '4px',
118
+ border: 'none',
119
+ background: 'rgba(239, 68, 68, 0.1)',
120
+ color: '#ef4444',
121
+ fontSize: '12px',
122
+ cursor: 'pointer',
123
+ flexShrink: 0,
124
+ },
125
+ inputGroup: {
126
+ marginBottom: '8px',
127
+ },
128
+ inputLabel: {
129
+ display: 'block',
130
+ fontSize: '11px',
131
+ color: '#94a3b8',
132
+ marginBottom: '4px',
133
+ },
134
+ input: {
135
+ width: '100%',
136
+ padding: '8px 10px',
137
+ borderRadius: '4px',
138
+ border: '1px solid rgba(255,255,255,0.1)',
139
+ backgroundColor: 'rgba(255,255,255,0.05)',
140
+ color: '#f8fafc',
141
+ fontSize: '13px',
142
+ },
143
+ textarea: {
144
+ width: '100%',
145
+ padding: '8px 10px',
146
+ borderRadius: '4px',
147
+ border: '1px solid rgba(255,255,255,0.1)',
148
+ backgroundColor: 'rgba(255,255,255,0.05)',
149
+ color: '#f8fafc',
150
+ fontSize: '13px',
151
+ minHeight: '80px',
152
+ resize: 'vertical',
153
+ fontFamily: 'inherit',
154
+ },
155
+ emptyState: {
156
+ textAlign: 'center',
157
+ padding: '32px 16px',
158
+ color: '#64748b',
159
+ fontSize: '13px',
160
+ },
161
+ footer: {
162
+ padding: '12px 16px',
163
+ borderTop: '1px solid #334155',
164
+ display: 'flex',
165
+ gap: '8px',
166
+ },
167
+ saveButton: {
168
+ flex: 1,
169
+ padding: '10px',
170
+ borderRadius: '8px',
171
+ border: 'none',
172
+ background: 'rgba(59, 130, 246, 0.15)',
173
+ color: '#3b82f6',
174
+ fontSize: '13px',
175
+ fontWeight: 600,
176
+ cursor: 'pointer',
177
+ },
178
+ publishButton: {
179
+ flex: 1,
180
+ padding: '10px',
181
+ borderRadius: '8px',
182
+ border: 'none',
183
+ background: '#22c55e',
184
+ color: 'white',
185
+ fontSize: '13px',
186
+ fontWeight: 600,
187
+ cursor: 'pointer',
188
+ },
189
+ };
190
+ // ============================================================================
191
+ // FAQEditor Component
192
+ // ============================================================================
193
+ export function FAQEditor({ config, onChange, editor }) {
194
+ const typedConfig = config;
195
+ const questions = typedConfig.actions || [];
196
+ // Generate unique ID
197
+ const generateId = () => `q-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
198
+ // Add a new question
199
+ const handleAddQuestion = () => {
200
+ const newQuestion = {
201
+ kind: 'faq:question',
202
+ config: {
203
+ id: generateId(),
204
+ question: 'New Question',
205
+ answer: 'Enter your answer here...',
206
+ category: undefined,
207
+ },
208
+ showWhen: null,
209
+ };
210
+ onChange({
211
+ ...config,
212
+ actions: [...questions, newQuestion],
213
+ });
214
+ editor.setDirty(true);
215
+ };
216
+ // Remove a question
217
+ const handleRemoveQuestion = (index) => {
218
+ const newQuestions = questions.filter((_, i) => i !== index);
219
+ onChange({
220
+ ...config,
221
+ actions: newQuestions,
222
+ });
223
+ editor.setDirty(true);
224
+ };
225
+ // Update a question
226
+ const handleUpdateQuestion = (index, updates) => {
227
+ const newQuestions = questions.map((q, i) => {
228
+ if (i !== index)
229
+ return q;
230
+ return {
231
+ ...q,
232
+ config: {
233
+ ...q.config,
234
+ ...updates,
235
+ },
236
+ };
237
+ });
238
+ onChange({
239
+ ...config,
240
+ actions: newQuestions,
241
+ });
242
+ editor.setDirty(true);
243
+ };
244
+ // Update expand behavior
245
+ const handleExpandBehaviorChange = (e) => {
246
+ onChange({
247
+ ...config,
248
+ expandBehavior: e.target.value,
249
+ });
250
+ editor.setDirty(true);
251
+ };
252
+ // Update theme
253
+ const handleThemeChange = (e) => {
254
+ onChange({
255
+ ...config,
256
+ theme: e.target.value,
257
+ });
258
+ editor.setDirty(true);
259
+ };
260
+ // Update searchable
261
+ const handleSearchableChange = (e) => {
262
+ onChange({
263
+ ...config,
264
+ searchable: e.target.checked,
265
+ });
266
+ editor.setDirty(true);
267
+ };
268
+ return (_jsxs("div", { style: styles.container, children: [_jsxs("div", { style: styles.header, children: [_jsx("button", { onClick: () => editor.navigateHome(), style: styles.backButton, children: "\u2190 Back" }), _jsxs("div", { children: [_jsx("h2", { style: styles.title, children: "FAQ Accordion" }), _jsx("p", { style: styles.subtitle, children: "Configure questions with per-item visibility" })] })] }), _jsxs("div", { style: styles.content, children: [_jsxs("div", { style: styles.section, children: [_jsx("div", { style: styles.sectionTitle, children: "Expand Behavior" }), _jsxs("select", { value: typedConfig.expandBehavior || 'single', onChange: handleExpandBehaviorChange, style: styles.select, children: [_jsx("option", { value: "single", children: "Single (one at a time)" }), _jsx("option", { value: "multiple", children: "Multiple (any number)" })] })] }), _jsxs("div", { style: styles.section, children: [_jsx("div", { style: styles.sectionTitle, children: "Theme" }), _jsxs("select", { value: typedConfig.theme || 'auto', onChange: handleThemeChange, style: styles.select, children: [_jsx("option", { value: "auto", children: "Auto (System)" }), _jsx("option", { value: "light", children: "Light" }), _jsx("option", { value: "dark", children: "Dark" })] }), _jsxs("label", { style: styles.checkbox, children: [_jsx("input", { type: "checkbox", checked: typedConfig.searchable || false, onChange: handleSearchableChange }), "Enable search/filter"] })] }), _jsxs("div", { style: styles.section, children: [_jsx("div", { style: styles.sectionTitle, children: "Questions" }), _jsx("button", { onClick: handleAddQuestion, style: styles.addButton, children: "+ Add Question" }), questions.map((q, index) => (_jsxs("div", { style: styles.questionCard, children: [_jsxs("div", { style: styles.questionHeader, children: [_jsxs("div", { style: styles.questionPreview, children: [_jsx("div", { style: styles.questionText, children: q.config.question }), _jsx("div", { style: styles.answerPreview, children: q.config.answer })] }), _jsx("button", { onClick: () => handleRemoveQuestion(index), style: styles.removeButton, children: "Remove" })] }), _jsxs("div", { style: styles.inputGroup, children: [_jsx("label", { style: styles.inputLabel, children: "Question" }), _jsx("input", { type: "text", value: q.config.question, onChange: (e) => handleUpdateQuestion(index, { question: e.target.value }), style: styles.input })] }), _jsxs("div", { style: styles.inputGroup, children: [_jsx("label", { style: styles.inputLabel, children: "Answer" }), _jsx("textarea", { value: q.config.answer, onChange: (e) => handleUpdateQuestion(index, { answer: e.target.value }), style: styles.textarea })] }), _jsxs("div", { style: styles.inputGroup, children: [_jsx("label", { style: styles.inputLabel, children: "Category (optional)" }), _jsx("input", { type: "text", value: q.config.category || '', onChange: (e) => handleUpdateQuestion(index, {
269
+ category: e.target.value || undefined,
270
+ }), style: styles.input, placeholder: "e.g., Billing, Account, Features" })] })] }, q.config.id || index))), questions.length === 0 && (_jsx("div", { style: styles.emptyState, children: "No questions configured. Click the button above to add one." }))] })] }), _jsxs("div", { style: styles.footer, children: [_jsx("button", { onClick: () => editor.save(), style: styles.saveButton, children: "Save Draft" }), _jsx("button", { onClick: () => editor.publish(), style: styles.publishButton, children: "Publish" })] })] }));
271
+ }
272
+ /**
273
+ * Editor panel configuration for the app registry.
274
+ */
275
+ export const editorPanel = {
276
+ title: 'FAQ',
277
+ icon: '❓',
278
+ description: 'FAQ accordion with per-item visibility',
279
+ };
280
+ export default FAQEditor;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Adaptive FAQ - Runtime Module
3
+ *
4
+ * Runtime manifest for the FAQ accordion adaptive.
5
+ * This is a widget-based adaptive with no action executors.
6
+ */
7
+ /**
8
+ * Runtime manifest for adaptive-faq.
9
+ *
10
+ * Note: This adaptive is widget-based, not action-based.
11
+ * The `faq:question` actions are compositional - they're rendered by
12
+ * the widget, not executed by the runtime.
13
+ */
14
+ export declare const runtime: {
15
+ id: string;
16
+ version: string;
17
+ name: string;
18
+ description: string;
19
+ /**
20
+ * No action executors - faq:question actions are compositional,
21
+ * meaning they serve as configuration for the FAQWidget.
22
+ */
23
+ executors: never[];
24
+ /**
25
+ * Widget definitions for the runtime's WidgetRegistry.
26
+ */
27
+ widgets: {
28
+ id: string;
29
+ component: {
30
+ mount(container: HTMLElement, config?: import("./types").FAQConfig & {
31
+ runtime?: import("./types").FAQWidgetRuntime;
32
+ instanceId?: string;
33
+ }): () => void;
34
+ };
35
+ metadata: {
36
+ name: string;
37
+ description: string;
38
+ icon: string;
39
+ };
40
+ }[];
41
+ };
42
+ export default runtime;
43
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH;;;;;;GAMG;AACH,eAAO,MAAM,OAAO;;;;;IAMlB;;;OAGG;;IAGH;;OAEG;;;;;uBAey/S,CAAC;0BAA8B,CAAC;;;;;;;;;CAH7hT,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Adaptive FAQ - Runtime Module
3
+ *
4
+ * Runtime manifest for the FAQ accordion adaptive.
5
+ * This is a widget-based adaptive with no action executors.
6
+ */
7
+ import { FAQMountableWidget } from './FAQWidget';
8
+ // ============================================================================
9
+ // App Runtime Manifest
10
+ // ============================================================================
11
+ /**
12
+ * Runtime manifest for adaptive-faq.
13
+ *
14
+ * Note: This adaptive is widget-based, not action-based.
15
+ * The `faq:question` actions are compositional - they're rendered by
16
+ * the widget, not executed by the runtime.
17
+ */
18
+ export const runtime = {
19
+ id: 'adaptive-faq',
20
+ version: '1.0.0',
21
+ name: 'FAQ Accordion',
22
+ description: 'Collapsible Q&A accordion with per-item conditional visibility',
23
+ /**
24
+ * No action executors - faq:question actions are compositional,
25
+ * meaning they serve as configuration for the FAQWidget.
26
+ */
27
+ executors: [],
28
+ /**
29
+ * Widget definitions for the runtime's WidgetRegistry.
30
+ */
31
+ widgets: [
32
+ {
33
+ id: 'adaptive-faq:accordion',
34
+ component: FAQMountableWidget,
35
+ metadata: {
36
+ name: 'FAQ Accordion',
37
+ description: 'Collapsible Q&A accordion with search',
38
+ icon: '❓',
39
+ },
40
+ },
41
+ ],
42
+ };
43
+ export default runtime;