@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/FAQWidget.d.ts +31 -0
- package/dist/FAQWidget.d.ts.map +1 -0
- package/dist/FAQWidget.js +332 -0
- package/dist/cdn.d.ts +38 -0
- package/dist/cdn.d.ts.map +1 -0
- package/dist/cdn.js +36 -0
- package/dist/editor.d.ts +17 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +280 -0
- package/dist/runtime.d.ts +43 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +43 -0
- package/dist/schema.d.ts +653 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +103 -0
- package/dist/types.d.ts +128 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/package.json +49 -0
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"}
|
package/dist/runtime.js
ADDED
|
@@ -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;
|