@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
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive FAQ - FAQWidget Component
|
|
3
|
+
*
|
|
4
|
+
* React component that renders a collapsible Q&A accordion with per-item
|
|
5
|
+
* conditional visibility based on showWhen decision strategies.
|
|
6
|
+
*
|
|
7
|
+
* Demonstrates the compositional action pattern where child actions
|
|
8
|
+
* (faq:question) serve as configuration data for the parent widget.
|
|
9
|
+
*/
|
|
10
|
+
import type { FAQWidgetProps, FAQConfig, FAQWidgetRuntime } from './types';
|
|
11
|
+
/**
|
|
12
|
+
* FAQWidget - Renders a collapsible Q&A accordion with per-item activation.
|
|
13
|
+
*
|
|
14
|
+
* This component demonstrates the compositional action pattern:
|
|
15
|
+
* - Parent (FAQWidget) receives `config.actions` array
|
|
16
|
+
* - Each action has optional `showWhen` for per-item visibility
|
|
17
|
+
* - Parent evaluates showWhen and filters visible questions
|
|
18
|
+
* - Parent manages expand state and re-rendering on context changes
|
|
19
|
+
*/
|
|
20
|
+
export declare function FAQWidget({ config, runtime, instanceId }: FAQWidgetProps): import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
/**
|
|
22
|
+
* Mountable widget interface for the runtime's WidgetRegistry.
|
|
23
|
+
*/
|
|
24
|
+
export declare const FAQMountableWidget: {
|
|
25
|
+
mount(container: HTMLElement, config?: FAQConfig & {
|
|
26
|
+
runtime?: FAQWidgetRuntime;
|
|
27
|
+
instanceId?: string;
|
|
28
|
+
}): () => void;
|
|
29
|
+
};
|
|
30
|
+
export default FAQWidget;
|
|
31
|
+
//# sourceMappingURL=FAQWidget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FAQWidget.d.ts","sourceRoot":"","sources":["../src/FAQWidget.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAqB,SAAS,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AA6N9F;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,cAAc,2CAuJxE;AAMD;;GAEG;AACH,eAAO,MAAM,kBAAkB;qBAEhB,WAAW,WACb,SAAS,GAAG;QAAE,OAAO,CAAC,EAAE,gBAAgB,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;CAuC3E,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Adaptive FAQ - FAQWidget Component
|
|
4
|
+
*
|
|
5
|
+
* React component that renders a collapsible Q&A accordion with per-item
|
|
6
|
+
* conditional visibility based on showWhen decision strategies.
|
|
7
|
+
*
|
|
8
|
+
* Demonstrates the compositional action pattern where child actions
|
|
9
|
+
* (faq:question) serve as configuration data for the parent widget.
|
|
10
|
+
*/
|
|
11
|
+
import { useEffect, useReducer, useMemo, useCallback, useState } from 'react';
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Styles
|
|
14
|
+
// ============================================================================
|
|
15
|
+
const baseStyles = {
|
|
16
|
+
container: {
|
|
17
|
+
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
18
|
+
maxWidth: '800px',
|
|
19
|
+
margin: '0 auto',
|
|
20
|
+
},
|
|
21
|
+
searchWrapper: {
|
|
22
|
+
marginBottom: '16px',
|
|
23
|
+
},
|
|
24
|
+
searchInput: {
|
|
25
|
+
width: '100%',
|
|
26
|
+
padding: '12px 16px',
|
|
27
|
+
borderRadius: '8px',
|
|
28
|
+
fontSize: '14px',
|
|
29
|
+
outline: 'none',
|
|
30
|
+
transition: 'border-color 0.15s ease',
|
|
31
|
+
},
|
|
32
|
+
accordion: {
|
|
33
|
+
display: 'flex',
|
|
34
|
+
flexDirection: 'column',
|
|
35
|
+
gap: '8px',
|
|
36
|
+
},
|
|
37
|
+
item: {
|
|
38
|
+
borderRadius: '8px',
|
|
39
|
+
overflow: 'hidden',
|
|
40
|
+
transition: 'box-shadow 0.15s ease',
|
|
41
|
+
},
|
|
42
|
+
question: {
|
|
43
|
+
width: '100%',
|
|
44
|
+
padding: '16px 20px',
|
|
45
|
+
display: 'flex',
|
|
46
|
+
alignItems: 'center',
|
|
47
|
+
justifyContent: 'space-between',
|
|
48
|
+
border: 'none',
|
|
49
|
+
cursor: 'pointer',
|
|
50
|
+
fontSize: '15px',
|
|
51
|
+
fontWeight: 500,
|
|
52
|
+
textAlign: 'left',
|
|
53
|
+
transition: 'background-color 0.15s ease',
|
|
54
|
+
},
|
|
55
|
+
chevron: {
|
|
56
|
+
fontSize: '18px',
|
|
57
|
+
transition: 'transform 0.2s ease',
|
|
58
|
+
},
|
|
59
|
+
answer: {
|
|
60
|
+
padding: '0 20px 16px 20px',
|
|
61
|
+
fontSize: '14px',
|
|
62
|
+
lineHeight: 1.6,
|
|
63
|
+
overflow: 'hidden',
|
|
64
|
+
transition: 'max-height 0.2s ease, padding 0.2s ease',
|
|
65
|
+
},
|
|
66
|
+
category: {
|
|
67
|
+
display: 'inline-block',
|
|
68
|
+
fontSize: '11px',
|
|
69
|
+
fontWeight: 600,
|
|
70
|
+
textTransform: 'uppercase',
|
|
71
|
+
letterSpacing: '0.05em',
|
|
72
|
+
padding: '4px 8px',
|
|
73
|
+
borderRadius: '4px',
|
|
74
|
+
marginBottom: '8px',
|
|
75
|
+
},
|
|
76
|
+
emptyState: {
|
|
77
|
+
textAlign: 'center',
|
|
78
|
+
padding: '48px 24px',
|
|
79
|
+
fontSize: '14px',
|
|
80
|
+
},
|
|
81
|
+
noResults: {
|
|
82
|
+
textAlign: 'center',
|
|
83
|
+
padding: '32px 16px',
|
|
84
|
+
fontSize: '14px',
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
const themeStyles = {
|
|
88
|
+
light: {
|
|
89
|
+
container: {
|
|
90
|
+
backgroundColor: '#ffffff',
|
|
91
|
+
color: '#111827',
|
|
92
|
+
},
|
|
93
|
+
searchInput: {
|
|
94
|
+
backgroundColor: '#f9fafb',
|
|
95
|
+
border: '1px solid #e5e7eb',
|
|
96
|
+
color: '#111827',
|
|
97
|
+
},
|
|
98
|
+
item: {
|
|
99
|
+
backgroundColor: '#f9fafb',
|
|
100
|
+
border: '1px solid #e5e7eb',
|
|
101
|
+
},
|
|
102
|
+
itemExpanded: {
|
|
103
|
+
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)',
|
|
104
|
+
},
|
|
105
|
+
question: {
|
|
106
|
+
backgroundColor: 'transparent',
|
|
107
|
+
color: '#111827',
|
|
108
|
+
},
|
|
109
|
+
questionHover: {
|
|
110
|
+
backgroundColor: '#f3f4f6',
|
|
111
|
+
},
|
|
112
|
+
answer: {
|
|
113
|
+
color: '#4b5563',
|
|
114
|
+
},
|
|
115
|
+
category: {
|
|
116
|
+
backgroundColor: '#e0e7ff',
|
|
117
|
+
color: '#4338ca',
|
|
118
|
+
},
|
|
119
|
+
emptyState: {
|
|
120
|
+
color: '#9ca3af',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
dark: {
|
|
124
|
+
container: {
|
|
125
|
+
backgroundColor: '#111827',
|
|
126
|
+
color: '#f9fafb',
|
|
127
|
+
},
|
|
128
|
+
searchInput: {
|
|
129
|
+
backgroundColor: '#1f2937',
|
|
130
|
+
border: '1px solid #374151',
|
|
131
|
+
color: '#f9fafb',
|
|
132
|
+
},
|
|
133
|
+
item: {
|
|
134
|
+
backgroundColor: '#1f2937',
|
|
135
|
+
border: '1px solid #374151',
|
|
136
|
+
},
|
|
137
|
+
itemExpanded: {
|
|
138
|
+
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
|
|
139
|
+
},
|
|
140
|
+
question: {
|
|
141
|
+
backgroundColor: 'transparent',
|
|
142
|
+
color: '#f9fafb',
|
|
143
|
+
},
|
|
144
|
+
questionHover: {
|
|
145
|
+
backgroundColor: '#374151',
|
|
146
|
+
},
|
|
147
|
+
answer: {
|
|
148
|
+
color: '#9ca3af',
|
|
149
|
+
},
|
|
150
|
+
category: {
|
|
151
|
+
backgroundColor: '#312e81',
|
|
152
|
+
color: '#a5b4fc',
|
|
153
|
+
},
|
|
154
|
+
emptyState: {
|
|
155
|
+
color: '#6b7280',
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
function FAQItem({ item, isExpanded, onToggle, theme }) {
|
|
160
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
161
|
+
const colors = themeStyles[theme];
|
|
162
|
+
const { question, answer, category } = item.config;
|
|
163
|
+
const itemStyle = {
|
|
164
|
+
...baseStyles.item,
|
|
165
|
+
...colors.item,
|
|
166
|
+
...(isExpanded ? colors.itemExpanded : {}),
|
|
167
|
+
};
|
|
168
|
+
const questionStyle = {
|
|
169
|
+
...baseStyles.question,
|
|
170
|
+
...colors.question,
|
|
171
|
+
...(isHovered ? colors.questionHover : {}),
|
|
172
|
+
};
|
|
173
|
+
const chevronStyle = {
|
|
174
|
+
...baseStyles.chevron,
|
|
175
|
+
transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',
|
|
176
|
+
};
|
|
177
|
+
const answerStyle = {
|
|
178
|
+
...baseStyles.answer,
|
|
179
|
+
...colors.answer,
|
|
180
|
+
maxHeight: isExpanded ? '500px' : '0',
|
|
181
|
+
paddingBottom: isExpanded ? '16px' : '0',
|
|
182
|
+
};
|
|
183
|
+
const categoryStyle = {
|
|
184
|
+
...baseStyles.category,
|
|
185
|
+
...colors.category,
|
|
186
|
+
};
|
|
187
|
+
return (_jsxs("div", { style: itemStyle, children: [_jsxs("button", { style: questionStyle, onClick: onToggle, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), "aria-expanded": isExpanded, children: [_jsx("span", { children: question }), _jsx("span", { style: chevronStyle, children: "\u25BC" })] }), _jsxs("div", { style: answerStyle, "aria-hidden": !isExpanded, children: [category && _jsx("span", { style: categoryStyle, children: category }), _jsx("p", { style: { margin: 0 }, children: answer })] })] }));
|
|
188
|
+
}
|
|
189
|
+
// ============================================================================
|
|
190
|
+
// FAQWidget Component
|
|
191
|
+
// ============================================================================
|
|
192
|
+
/**
|
|
193
|
+
* FAQWidget - Renders a collapsible Q&A accordion with per-item activation.
|
|
194
|
+
*
|
|
195
|
+
* This component demonstrates the compositional action pattern:
|
|
196
|
+
* - Parent (FAQWidget) receives `config.actions` array
|
|
197
|
+
* - Each action has optional `showWhen` for per-item visibility
|
|
198
|
+
* - Parent evaluates showWhen and filters visible questions
|
|
199
|
+
* - Parent manages expand state and re-rendering on context changes
|
|
200
|
+
*/
|
|
201
|
+
export function FAQWidget({ config, runtime, instanceId }) {
|
|
202
|
+
// Force re-render when context changes
|
|
203
|
+
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
204
|
+
// Track expanded question IDs
|
|
205
|
+
const [expandedIds, setExpandedIds] = useState(new Set());
|
|
206
|
+
// Search query state
|
|
207
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
208
|
+
// Subscribe to context changes for reactive updates
|
|
209
|
+
useEffect(() => {
|
|
210
|
+
const unsubscribe = runtime.context.subscribe(() => {
|
|
211
|
+
forceUpdate();
|
|
212
|
+
});
|
|
213
|
+
return unsubscribe;
|
|
214
|
+
}, [runtime.context]);
|
|
215
|
+
// Filter visible questions based on per-item showWhen
|
|
216
|
+
const visibleQuestions = useMemo(() => {
|
|
217
|
+
return config.actions.filter((q) => {
|
|
218
|
+
// No showWhen = always visible
|
|
219
|
+
if (!q.showWhen)
|
|
220
|
+
return true;
|
|
221
|
+
// Evaluate the decision strategy
|
|
222
|
+
const result = runtime.evaluateSync(q.showWhen);
|
|
223
|
+
return result.value;
|
|
224
|
+
});
|
|
225
|
+
}, [config.actions, runtime]);
|
|
226
|
+
// Apply search filter
|
|
227
|
+
const filteredQuestions = useMemo(() => {
|
|
228
|
+
if (!config.searchable || !searchQuery.trim()) {
|
|
229
|
+
return visibleQuestions;
|
|
230
|
+
}
|
|
231
|
+
const query = searchQuery.toLowerCase();
|
|
232
|
+
return visibleQuestions.filter((q) => q.config.question.toLowerCase().includes(query) ||
|
|
233
|
+
q.config.answer.toLowerCase().includes(query) ||
|
|
234
|
+
q.config.category?.toLowerCase().includes(query));
|
|
235
|
+
}, [visibleQuestions, searchQuery, config.searchable]);
|
|
236
|
+
// Resolve theme (auto → detect system preference)
|
|
237
|
+
const resolvedTheme = useMemo(() => {
|
|
238
|
+
if (config.theme !== 'auto')
|
|
239
|
+
return config.theme;
|
|
240
|
+
// Check system preference (SSR-safe)
|
|
241
|
+
if (typeof window !== 'undefined') {
|
|
242
|
+
return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
243
|
+
}
|
|
244
|
+
return 'light';
|
|
245
|
+
}, [config.theme]);
|
|
246
|
+
// Handle question toggle
|
|
247
|
+
const handleToggle = useCallback((id) => {
|
|
248
|
+
setExpandedIds((prev) => {
|
|
249
|
+
const next = new Set(prev);
|
|
250
|
+
if (config.expandBehavior === 'single') {
|
|
251
|
+
// Single mode: collapse all others
|
|
252
|
+
if (prev.has(id)) {
|
|
253
|
+
return new Set();
|
|
254
|
+
}
|
|
255
|
+
return new Set([id]);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
// Multiple mode: toggle this one
|
|
259
|
+
if (prev.has(id)) {
|
|
260
|
+
next.delete(id);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
next.add(id);
|
|
264
|
+
}
|
|
265
|
+
return next;
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
// Publish toggle event for analytics
|
|
269
|
+
runtime.events.publish('faq:toggled', {
|
|
270
|
+
instanceId,
|
|
271
|
+
questionId: id,
|
|
272
|
+
expanded: !expandedIds.has(id),
|
|
273
|
+
timestamp: Date.now(),
|
|
274
|
+
});
|
|
275
|
+
}, [config.expandBehavior, runtime.events, instanceId, expandedIds]);
|
|
276
|
+
// Compute styles
|
|
277
|
+
const containerStyle = {
|
|
278
|
+
...baseStyles.container,
|
|
279
|
+
...themeStyles[resolvedTheme].container,
|
|
280
|
+
};
|
|
281
|
+
const searchInputStyle = {
|
|
282
|
+
...baseStyles.searchInput,
|
|
283
|
+
...themeStyles[resolvedTheme].searchInput,
|
|
284
|
+
};
|
|
285
|
+
const emptyStateStyle = {
|
|
286
|
+
...baseStyles.emptyState,
|
|
287
|
+
...themeStyles[resolvedTheme].emptyState,
|
|
288
|
+
};
|
|
289
|
+
// Empty state (no visible questions at all)
|
|
290
|
+
if (visibleQuestions.length === 0) {
|
|
291
|
+
return (_jsx("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-faq", children: _jsx("div", { style: emptyStateStyle, children: "No FAQ questions available." }) }));
|
|
292
|
+
}
|
|
293
|
+
return (_jsxs("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-faq", children: [config.searchable && (_jsx("div", { style: baseStyles.searchWrapper, children: _jsx("input", { type: "text", placeholder: "Search questions...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), style: searchInputStyle }) })), _jsx("div", { style: baseStyles.accordion, children: filteredQuestions.map((q) => (_jsx(FAQItem, { item: q, isExpanded: expandedIds.has(q.config.id), onToggle: () => handleToggle(q.config.id), theme: resolvedTheme }, q.config.id))) }), config.searchable && filteredQuestions.length === 0 && searchQuery && (_jsxs("div", { style: { ...baseStyles.noResults, ...themeStyles[resolvedTheme].emptyState }, children: ["No questions found matching \"", searchQuery, "\""] }))] }));
|
|
294
|
+
}
|
|
295
|
+
// ============================================================================
|
|
296
|
+
// Mountable Widget Interface
|
|
297
|
+
// ============================================================================
|
|
298
|
+
/**
|
|
299
|
+
* Mountable widget interface for the runtime's WidgetRegistry.
|
|
300
|
+
*/
|
|
301
|
+
export const FAQMountableWidget = {
|
|
302
|
+
mount(container, config) {
|
|
303
|
+
// This is a simplified mount for non-React environments
|
|
304
|
+
// In practice, the runtime handles React rendering
|
|
305
|
+
const { runtime, instanceId: _instanceId = 'faq-widget', ...faqConfig } = config || {
|
|
306
|
+
expandBehavior: 'single',
|
|
307
|
+
searchable: false,
|
|
308
|
+
theme: 'auto',
|
|
309
|
+
actions: [],
|
|
310
|
+
};
|
|
311
|
+
// Create simple HTML fallback if no runtime
|
|
312
|
+
if (!runtime) {
|
|
313
|
+
const questions = faqConfig.actions || [];
|
|
314
|
+
container.innerHTML = `
|
|
315
|
+
<div style="font-family: system-ui; max-width: 800px;">
|
|
316
|
+
${questions
|
|
317
|
+
.map((q) => `
|
|
318
|
+
<div style="margin-bottom: 8px; padding: 16px; background: #f9fafb; border-radius: 8px;">
|
|
319
|
+
<strong>${q.config.question}</strong>
|
|
320
|
+
<p style="margin-top: 8px; color: #4b5563;">${q.config.answer}</p>
|
|
321
|
+
</div>
|
|
322
|
+
`)
|
|
323
|
+
.join('')}
|
|
324
|
+
</div>
|
|
325
|
+
`;
|
|
326
|
+
}
|
|
327
|
+
return () => {
|
|
328
|
+
container.innerHTML = '';
|
|
329
|
+
};
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
export default FAQWidget;
|
package/dist/cdn.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDN Entry Point for Adaptive FAQ
|
|
3
|
+
*
|
|
4
|
+
* This module is bundled for CDN delivery and self-registers with the global
|
|
5
|
+
* SynOS app registry when loaded dynamically via the AppLoader.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* App manifest for registry registration.
|
|
9
|
+
* Follows the AppManifest interface expected by AppLoader/AppRegistry.
|
|
10
|
+
*/
|
|
11
|
+
export declare const manifest: {
|
|
12
|
+
id: string;
|
|
13
|
+
version: string;
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
runtime: {
|
|
17
|
+
actions: never[];
|
|
18
|
+
widgets: {
|
|
19
|
+
id: string;
|
|
20
|
+
component: {
|
|
21
|
+
mount(container: HTMLElement, config?: import("./types").FAQConfig & {
|
|
22
|
+
runtime?: import("./types").FAQWidgetRuntime;
|
|
23
|
+
instanceId?: string;
|
|
24
|
+
}): () => void;
|
|
25
|
+
};
|
|
26
|
+
metadata: {
|
|
27
|
+
name: string;
|
|
28
|
+
description: string;
|
|
29
|
+
icon: string;
|
|
30
|
+
};
|
|
31
|
+
}[];
|
|
32
|
+
};
|
|
33
|
+
metadata: {
|
|
34
|
+
isBuiltIn: boolean;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export default manifest;
|
|
38
|
+
//# sourceMappingURL=cdn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdn.d.ts","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;GAGG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;2BA2BixT,CAAC;8BAA8B,CAAC;;;;;;;;;;;;;CAdr0T,CAAC;AAaF,eAAe,QAAQ,CAAC"}
|
package/dist/cdn.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CDN Entry Point for Adaptive FAQ
|
|
3
|
+
*
|
|
4
|
+
* This module is bundled for CDN delivery and self-registers with the global
|
|
5
|
+
* SynOS app registry when loaded dynamically via the AppLoader.
|
|
6
|
+
*/
|
|
7
|
+
import { runtime } from './runtime';
|
|
8
|
+
/**
|
|
9
|
+
* App manifest for registry registration.
|
|
10
|
+
* Follows the AppManifest interface expected by AppLoader/AppRegistry.
|
|
11
|
+
*/
|
|
12
|
+
export const manifest = {
|
|
13
|
+
id: 'faq',
|
|
14
|
+
version: runtime.version,
|
|
15
|
+
name: runtime.name,
|
|
16
|
+
description: runtime.description,
|
|
17
|
+
runtime: {
|
|
18
|
+
// FAQ is widget-based, no action executors
|
|
19
|
+
actions: [],
|
|
20
|
+
widgets: runtime.widgets,
|
|
21
|
+
},
|
|
22
|
+
metadata: {
|
|
23
|
+
isBuiltIn: false,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Self-register with global registry if available.
|
|
28
|
+
* This happens when loaded via script tag (UMD).
|
|
29
|
+
*/
|
|
30
|
+
if (typeof window !== 'undefined') {
|
|
31
|
+
const globalRegistry = window.__SYNOS_APP_REGISTRY__;
|
|
32
|
+
if (globalRegistry && typeof globalRegistry.register === 'function') {
|
|
33
|
+
globalRegistry.register(manifest);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export default manifest;
|
package/dist/editor.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adaptive FAQ - Editor Component
|
|
3
|
+
*
|
|
4
|
+
* Visual editor panel for configuring FAQ questions.
|
|
5
|
+
*/
|
|
6
|
+
import type { EditorPanelProps } from './types';
|
|
7
|
+
export declare function FAQEditor({ config, onChange, editor }: EditorPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
/**
|
|
9
|
+
* Editor panel configuration for the app registry.
|
|
10
|
+
*/
|
|
11
|
+
export declare const editorPanel: {
|
|
12
|
+
title: string;
|
|
13
|
+
icon: string;
|
|
14
|
+
description: string;
|
|
15
|
+
};
|
|
16
|
+
export default FAQEditor;
|
|
17
|
+
//# sourceMappingURL=editor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAqMhD,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,gBAAgB,2CAgNvE;AAED;;GAEG;AACH,eAAO,MAAM,WAAW;;;;CAIvB,CAAC;AAEF,eAAe,SAAS,CAAC"}
|