@syntrologie/adapt-faq 2.16.0 → 2.17.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.
package/dist/runtime.js CHANGED
@@ -1,94 +1,1249 @@
1
- /**
2
- * Adaptive FAQ - Runtime Module
3
- *
4
- * Runtime manifest for the FAQ accordion adaptive.
5
- * Provides action executors and widget registration.
6
- */
7
- import { executorDefinitions } from './executors';
8
- import { FAQMountableWidget } from './FAQWidget';
9
- import './FAQWidgetLit'; // registers <syntro-faq-accordion> custom element
10
- // ============================================================================
11
- // Lit Mountable Widget
12
- // ============================================================================
13
- /**
14
- * Mountable widget interface for <syntro-faq-accordion> (Lit web component).
15
- *
16
- * Mirrors FAQMountableWidget but mounts the Lit element instead of a React
17
- * root — no React dependency required at mount time.
18
- */
19
- export const FAQWidgetLitMountable = {
20
- mount(container, config) {
21
- const { runtime, instanceId = 'faq-widget', ...faqConfig } = config ?? {
22
- expandBehavior: 'single',
23
- searchable: false,
24
- theme: 'auto',
25
- actions: [],
26
- };
27
- const el = document.createElement('syntro-faq-accordion');
28
- Object.assign(el, {
29
- faqConfig: faqConfig,
30
- runtime: runtime ?? null,
31
- instanceId,
1
+ // src/executors.ts
2
+ function resolveItem(store, itemId, itemQuestion) {
3
+ if (itemId) {
4
+ const found = store.getState().items.find((i) => i.config.id === itemId);
5
+ if (found) return found;
6
+ }
7
+ if (itemQuestion) {
8
+ const found = store.findByQuestion(itemQuestion);
9
+ if (found) return found;
10
+ }
11
+ throw new Error("FAQ item not found");
12
+ }
13
+ async function executeScrollToFaq(action, context, store) {
14
+ const item = resolveItem(store, action.itemId, action.itemQuestion);
15
+ const { id } = item.config;
16
+ if (action.expand !== false) {
17
+ store.expand(id);
18
+ }
19
+ const el = document.querySelector(`[data-faq-item-id="${id}"]`);
20
+ if (el) {
21
+ el.scrollIntoView({
22
+ behavior: action.behavior ?? "smooth"
23
+ });
24
+ }
25
+ context.publishEvent("faq:scroll_to", { itemId: id });
26
+ return {
27
+ cleanup: () => {
28
+ }
29
+ };
30
+ }
31
+ async function executeToggleFaqItem(action, context, store) {
32
+ const item = resolveItem(store, action.itemId, action.itemQuestion);
33
+ const { id } = item.config;
34
+ const desiredState = action.state ?? "toggle";
35
+ let newState;
36
+ switch (desiredState) {
37
+ case "open":
38
+ store.expand(id);
39
+ newState = "open";
40
+ break;
41
+ case "closed":
42
+ store.collapse(id);
43
+ newState = "closed";
44
+ break;
45
+ default: {
46
+ const wasExpanded = store.getState().expandedItems.has(id);
47
+ store.toggle(id);
48
+ newState = wasExpanded ? "closed" : "open";
49
+ break;
50
+ }
51
+ }
52
+ context.publishEvent("faq:toggle", { itemId: id, newState });
53
+ return {
54
+ cleanup: () => {
55
+ }
56
+ };
57
+ }
58
+ async function executeUpdateFaq(action, context, store) {
59
+ switch (action.operation) {
60
+ case "add": {
61
+ const items = action.items ?? [];
62
+ const position = action.position === "prepend" ? "prepend" : "append";
63
+ store.addItems(items, position);
64
+ break;
65
+ }
66
+ case "remove": {
67
+ if (!action.itemId) {
68
+ throw new Error("FAQ item not found");
69
+ }
70
+ const exists = store.getState().items.some((i) => i.config.id === action.itemId);
71
+ if (!exists) {
72
+ throw new Error("FAQ item not found");
73
+ }
74
+ store.removeItem(action.itemId);
75
+ break;
76
+ }
77
+ case "reorder": {
78
+ const order = action.order ?? [];
79
+ store.reorderItems(order);
80
+ break;
81
+ }
82
+ case "replace": {
83
+ const items = action.items ?? [];
84
+ store.replaceItems(items);
85
+ break;
86
+ }
87
+ }
88
+ context.publishEvent("faq:update", { operation: action.operation });
89
+ return {
90
+ cleanup: () => {
91
+ }
92
+ };
93
+ }
94
+ var executorDefinitions = [
95
+ { kind: "faq:scroll_to", executor: executeScrollToFaq },
96
+ { kind: "faq:toggle_item", executor: executeToggleFaqItem },
97
+ { kind: "faq:update", executor: executeUpdateFaq }
98
+ ];
99
+
100
+ // ../../design-system/dist/tokens/colors.js
101
+ var base = {
102
+ white: "#ffffff",
103
+ black: "#000000"
104
+ };
105
+ var brand = {
106
+ 0: "#2c0b0a",
107
+ 1: "#5b1715",
108
+ 2: "#89221f",
109
+ 3: "#b72e2a",
110
+ 4: "#d44844",
111
+ 5: "#dd6d69",
112
+ 6: "#e5918f",
113
+ 7: "#eeb6b4",
114
+ 8: "#f6dada",
115
+ 9: "#faebea"
116
+ };
117
+ var slateGrey = {
118
+ 0: "#07080a",
119
+ 1: "#0f1318",
120
+ 2: "#0e1114",
121
+ 3: "#1c222a",
122
+ 4: "#2b333f",
123
+ 5: "#394454",
124
+ 6: "#475569",
125
+ 7: "#677384",
126
+ 8: "#87919f",
127
+ 9: "#a8afba",
128
+ 10: "#cbd0d7",
129
+ 11: "#e8eaee",
130
+ 12: "#f6f7f9"
131
+ };
132
+ var green = {
133
+ 0: "#07230a",
134
+ 1: "#0e4514",
135
+ 2: "#16681e",
136
+ 3: "#1d8a28",
137
+ 4: "#24ad32",
138
+ 5: "#4fbd5a",
139
+ 6: "#7acd82",
140
+ 7: "#a5deab",
141
+ 8: "#d0eed3",
142
+ 9: "#e5f6e7"
143
+ };
144
+ var yellow = {
145
+ 0: "#301f09",
146
+ 1: "#5f3e12",
147
+ 2: "#8f5e1b",
148
+ 3: "#be7d24",
149
+ 4: "#ee9c2d",
150
+ 5: "#f1b057",
151
+ 6: "#f5c481",
152
+ 7: "#f8d7ab",
153
+ 8: "#fcebd5",
154
+ 9: "#fdf5ea"
155
+ };
156
+ var red = {
157
+ 0: "#330707",
158
+ 1: "#660f0e",
159
+ 2: "#991616",
160
+ 3: "#cc1e1d",
161
+ 4: "#ff2524",
162
+ 5: "#ff5150",
163
+ 6: "#ff7c7c",
164
+ 7: "#ffa8a7",
165
+ 8: "#ffd3d3",
166
+ 9: "#ffe9e9"
167
+ };
168
+ var blue = {
169
+ 0: "#051533",
170
+ 1: "#0a2a66",
171
+ 2: "#0f3f98",
172
+ 3: "#1454cb",
173
+ 4: "#1969fe",
174
+ 5: "#4787fe",
175
+ 6: "#75a5fe",
176
+ 7: "#a3c3ff",
177
+ 8: "#d1e1ff",
178
+ 9: "#e8f0ff"
179
+ };
180
+ var orange = {
181
+ 0: "#662500",
182
+ 1: "#993d00",
183
+ 2: "#cc5800",
184
+ 3: "#ff7700",
185
+ 4: "#fea85d",
186
+ 5: "#fec58f",
187
+ 6: "#ffd6ae",
188
+ 7: "#fee6cd",
189
+ 8: "#fff1e1",
190
+ 9: "#fff8f0"
191
+ };
192
+ var purple = {
193
+ 0: "#151229",
194
+ 1: "#2a2452",
195
+ 2: "#40357c",
196
+ 3: "#5547a5",
197
+ 4: "#6a59ce",
198
+ 5: "#887ad8",
199
+ 6: "#a69be2",
200
+ 7: "#c3bdeb",
201
+ 8: "#e1def5",
202
+ 9: "#f0eefa"
203
+ };
204
+ var pink = {
205
+ 0: "#37091f",
206
+ 1: "#69123c",
207
+ 2: "#9b1c58",
208
+ 3: "#cd2575",
209
+ 4: "#ff2e92",
210
+ 5: "#ff58a8",
211
+ 6: "#ff82be",
212
+ 7: "#ffabd3",
213
+ 8: "#ffd5e9",
214
+ 9: "#ffeaf4"
215
+ };
216
+ var text = {
217
+ primary: slateGrey[10],
218
+ secondary: slateGrey[9],
219
+ tertiary: slateGrey[8]
220
+ };
221
+ var background = {
222
+ primary: slateGrey[2],
223
+ secondary: slateGrey[0]
224
+ };
225
+ var border = {
226
+ primary: slateGrey[4],
227
+ secondary: slateGrey[3]
228
+ };
229
+ var button = {
230
+ primary: {
231
+ text: base.white,
232
+ icon: base.white,
233
+ border: brand[3],
234
+ backgroundDefault: brand[3],
235
+ backgroundHover: brand[2]
236
+ },
237
+ neutral: {
238
+ text: slateGrey[10],
239
+ textHover: base.white,
240
+ icon: slateGrey[10],
241
+ iconHover: base.white,
242
+ border: slateGrey[4],
243
+ background: slateGrey[2]
244
+ },
245
+ link: {
246
+ text: base.white,
247
+ icon: base.white,
248
+ hover: brand[5]
249
+ },
250
+ error: {
251
+ text: red[5],
252
+ hover: red[6]
253
+ },
254
+ success: {
255
+ text: green[5],
256
+ hover: green[6]
257
+ }
258
+ };
259
+ var badge = {
260
+ slateGrey: {
261
+ content: slateGrey[10],
262
+ pillOutline: slateGrey[10],
263
+ borderPrimary: slateGrey[5],
264
+ borderSecondary: slateGrey[5],
265
+ background: slateGrey[3]
266
+ },
267
+ brand: {
268
+ content: brand[9],
269
+ pillOutline: brand[9],
270
+ borderPrimary: brand[6],
271
+ borderSecondary: brand[6],
272
+ background: brand[0]
273
+ },
274
+ red: {
275
+ content: red[8],
276
+ pillOutline: red[4],
277
+ borderPrimary: red[2],
278
+ borderSecondary: red[2],
279
+ background: red[0]
280
+ },
281
+ yellow: {
282
+ content: yellow[8],
283
+ pillOutline: yellow[4],
284
+ borderPrimary: yellow[2],
285
+ borderSecondary: yellow[2],
286
+ background: yellow[0]
287
+ },
288
+ green: {
289
+ content: green[8],
290
+ pillOutline: green[4],
291
+ borderPrimary: green[2],
292
+ borderSecondary: green[2],
293
+ background: green[0]
294
+ },
295
+ purple: {
296
+ content: purple[8],
297
+ pillOutline: purple[4],
298
+ borderPrimary: purple[2],
299
+ borderSecondary: purple[2],
300
+ background: purple[0]
301
+ },
302
+ blue: {
303
+ content: blue[8],
304
+ pillOutline: blue[4],
305
+ borderPrimary: blue[2],
306
+ borderSecondary: blue[2],
307
+ background: blue[0]
308
+ },
309
+ orange: {
310
+ content: orange[8],
311
+ pillOutline: orange[4],
312
+ borderPrimary: orange[2],
313
+ borderSecondary: orange[2],
314
+ background: orange[0]
315
+ },
316
+ pink: {
317
+ content: pink[8],
318
+ pillOutline: pink[4],
319
+ borderPrimary: pink[2],
320
+ borderSecondary: pink[2],
321
+ background: pink[0]
322
+ }
323
+ };
324
+ var badgeBanner = {
325
+ green: {
326
+ content: green[8],
327
+ border: green[2],
328
+ background: green[0]
329
+ },
330
+ yellow: {
331
+ content: yellow[8],
332
+ border: yellow[2],
333
+ background: yellow[0]
334
+ },
335
+ red: {
336
+ content: red[8],
337
+ border: red[2],
338
+ background: red[0]
339
+ }
340
+ };
341
+ var alert = {
342
+ green: {
343
+ content: green[1],
344
+ background: green[9]
345
+ },
346
+ yellow: {
347
+ content: yellow[1],
348
+ background: yellow[9]
349
+ },
350
+ red: {
351
+ content: red[1],
352
+ background: red[9]
353
+ }
354
+ };
355
+ var tag = {
356
+ content: slateGrey[10],
357
+ border: slateGrey[4],
358
+ background: slateGrey[3]
359
+ };
360
+ var menu = {
361
+ backgroundDefault: slateGrey[2],
362
+ backgroundHover: slateGrey[1],
363
+ selected: slateGrey[3]
364
+ };
365
+ var inputDropdown = {
366
+ background: slateGrey[2],
367
+ icon: slateGrey[10],
368
+ borderDefault: slateGrey[4],
369
+ borderSelected: brand[3],
370
+ textLabel: slateGrey[9],
371
+ textPlaceholder: slateGrey[8],
372
+ textHint: slateGrey[8]
373
+ };
374
+ var inputField = {
375
+ backgroundDefault: slateGrey[2],
376
+ backgroundDisabled: slateGrey[0],
377
+ textLabel: slateGrey[9],
378
+ textPlaceholder: slateGrey[8],
379
+ textHint: slateGrey[8],
380
+ textError: red[5],
381
+ iconDefault: slateGrey[9],
382
+ iconPlaceholder: slateGrey[10],
383
+ iconError: red[5],
384
+ borderDefault: slateGrey[4],
385
+ borderSelected: brand[3],
386
+ borderError: red[5]
387
+ };
388
+ var toggle = {
389
+ handleDefault: base.white,
390
+ handleDisabled: slateGrey[10],
391
+ off: {
392
+ backgroundDefault: slateGrey[4],
393
+ backgroundHover: slateGrey[5],
394
+ backgroundDisabled: slateGrey[4]
395
+ },
396
+ on: {
397
+ backgroundDefault: green[3],
398
+ backgroundHover: green[2],
399
+ backgroundDisabled: slateGrey[4]
400
+ }
401
+ };
402
+ var checkbox = {
403
+ off: {
404
+ backgroundDefault: "#00000000",
405
+ backgroundHover: slateGrey[5],
406
+ backgroundDisabled: slateGrey[2],
407
+ border: slateGrey[6]
408
+ },
409
+ on: {
410
+ backgroundDefault: green[0],
411
+ backgroundHover: green[1],
412
+ backgroundDisabled: slateGrey[2],
413
+ border: green[3]
414
+ }
415
+ };
416
+ var avatar = {
417
+ content: slateGrey[10],
418
+ background: slateGrey[4]
419
+ };
420
+ var progressBarSlider = {
421
+ background: slateGrey[4],
422
+ active: green[3]
423
+ };
424
+ var card = {
425
+ background: slateGrey[1],
426
+ content: slateGrey[9],
427
+ border: slateGrey[4]
428
+ };
429
+ var sidebar = {
430
+ backgroundDefault: slateGrey[1],
431
+ backgroundHover: slateGrey[3],
432
+ backgroundActive: slateGrey[4],
433
+ border: slateGrey[4],
434
+ contentPrimary: slateGrey[10],
435
+ contentSecondary: slateGrey[9],
436
+ contentTertiary: slateGrey[8]
437
+ };
438
+ var modal = {
439
+ background: slateGrey[1],
440
+ content: slateGrey[9],
441
+ border: slateGrey[4]
442
+ };
443
+ var tab = {
444
+ activeBackground: slateGrey[3],
445
+ activeContent: brand[5],
446
+ inactiveContent: slateGrey[9],
447
+ border: slateGrey[4]
448
+ };
449
+ var table = {
450
+ header: {
451
+ textDefault: slateGrey[9],
452
+ textHover: slateGrey[8],
453
+ backgroundDefault: slateGrey[1]
454
+ },
455
+ border: slateGrey[4],
456
+ cell: {
457
+ textPrimary: slateGrey[10],
458
+ textSecondary: slateGrey[9],
459
+ backgroundDefault: slateGrey[2],
460
+ backgroundHover: slateGrey[1]
461
+ }
462
+ };
463
+ var breadcrumbs = {
464
+ textPrimaryDefault: slateGrey[10],
465
+ textPrimaryHover: slateGrey[10],
466
+ textSecondaryDefault: slateGrey[8],
467
+ textSecondaryHover: slateGrey[9],
468
+ iconPrimary: slateGrey[10],
469
+ iconSecondary: slateGrey[8]
470
+ };
471
+ var loadingIndicator = {
472
+ background: green[1],
473
+ active: green[5]
474
+ };
475
+ var datePicker = {
476
+ textDefault: slateGrey[10],
477
+ textSelected: base.white,
478
+ textDisabled: slateGrey[7],
479
+ backgroundDefault: slateGrey[2],
480
+ backgroundMiddle: slateGrey[3],
481
+ backgroundSelected: brand[3],
482
+ border: slateGrey[4]
483
+ };
484
+ var scroll = slateGrey[9];
485
+
486
+ // ../../design-system/dist/tokens/panel-shell.js
487
+ var fab = {
488
+ /** Diameter in pixels. */
489
+ size: 56,
490
+ /** Inset from the panel's top-left corner in pixels. */
491
+ inset: 12,
492
+ /** Background color (always the brand black). */
493
+ background: base.black,
494
+ /** Icon / logo color. */
495
+ color: base.white,
496
+ /** Border — 2px brand red ring. */
497
+ border: `2px solid ${brand[3]}`,
498
+ /** Shadow when the panel is open (inner ring for "active" state). */
499
+ shadowOpen: "0 4px 24px rgba(0,0,0,0.6), 0 0 0 2px rgba(255,255,255,0.08)",
500
+ /** Shadow when the panel is closed. */
501
+ shadowClosed: "0 4px 24px rgba(0,0,0,0.6)"
502
+ };
503
+
504
+ // src/FAQWidgetLit.ts
505
+ import { html, LitElement, nothing } from "lit";
506
+ import { styleMap } from "lit/directives/style-map.js";
507
+ import { unsafeHTML } from "lit/directives/unsafe-html.js";
508
+ import { Marked } from "marked";
509
+
510
+ // src/faq-styles.ts
511
+ var baseStyles = {
512
+ container: {
513
+ fontFamily: "var(--sc-font-family, system-ui, -apple-system, sans-serif)",
514
+ maxWidth: "800px",
515
+ margin: "0 auto"
516
+ },
517
+ searchWrapper: {
518
+ marginBottom: "8px"
519
+ },
520
+ searchInput: {
521
+ width: "100%",
522
+ padding: "12px 16px",
523
+ borderRadius: "8px",
524
+ fontSize: "14px",
525
+ outline: "none",
526
+ transition: "border-color 0.15s ease",
527
+ backgroundColor: "var(--sc-content-search-background)",
528
+ color: "var(--sc-content-search-color)"
529
+ },
530
+ accordion: {
531
+ display: "flex",
532
+ flexDirection: "column",
533
+ gap: "var(--sc-content-item-gap, 6px)"
534
+ },
535
+ item: {
536
+ borderRadius: "var(--sc-content-border-radius, 8px)",
537
+ overflow: "hidden",
538
+ transition: "box-shadow 0.15s ease"
539
+ },
540
+ question: {
541
+ width: "100%",
542
+ padding: "var(--sc-content-item-padding, 12px 16px)",
543
+ display: "flex",
544
+ alignItems: "center",
545
+ justifyContent: "space-between",
546
+ border: "none",
547
+ cursor: "pointer",
548
+ fontSize: "var(--sc-content-item-font-size, 15px)",
549
+ fontWeight: 500,
550
+ textAlign: "left",
551
+ transition: "background-color 0.15s ease"
552
+ },
553
+ chevron: {
554
+ fontSize: "20px",
555
+ transition: "transform 0.2s ease",
556
+ color: "var(--sc-content-chevron-color, currentColor)"
557
+ },
558
+ answer: {
559
+ padding: "var(--sc-content-body-padding, 0 16px 12px 16px)",
560
+ fontSize: "var(--sc-content-body-font-size, 14px)",
561
+ lineHeight: 1.6,
562
+ overflow: "hidden",
563
+ transition: "max-height 0.2s ease, padding 0.2s ease"
564
+ },
565
+ category: {
566
+ display: "inline-block",
567
+ fontSize: "11px",
568
+ fontWeight: 600,
569
+ textTransform: "uppercase",
570
+ letterSpacing: "0.05em",
571
+ padding: "4px 8px",
572
+ borderRadius: "4px",
573
+ marginBottom: "8px"
574
+ },
575
+ categoryHeader: {
576
+ fontSize: "var(--sc-content-category-font-size, 12px)",
577
+ fontWeight: 700,
578
+ textTransform: "uppercase",
579
+ letterSpacing: "0.05em",
580
+ padding: "var(--sc-content-category-padding, 8px 4px 4px 4px)",
581
+ marginTop: "var(--sc-content-category-gap, 4px)"
582
+ },
583
+ feedback: {
584
+ display: "flex",
585
+ alignItems: "center",
586
+ gap: "8px",
587
+ marginTop: "12px",
588
+ paddingTop: "10px",
589
+ borderTop: "1px solid rgba(0, 0, 0, 0.08)",
590
+ fontSize: "13px"
591
+ },
592
+ feedbackButton: {
593
+ background: "none",
594
+ border: "1px solid transparent",
595
+ cursor: "pointer",
596
+ fontSize: "16px",
597
+ padding: "4px 8px",
598
+ borderRadius: "4px",
599
+ transition: "background-color 0.15s ease, border-color 0.15s ease"
600
+ },
601
+ feedbackButtonSelected: {
602
+ borderColor: "rgba(0, 0, 0, 0.2)",
603
+ backgroundColor: "rgba(0, 0, 0, 0.04)"
604
+ },
605
+ emptyState: {
606
+ textAlign: "center",
607
+ padding: "48px 24px",
608
+ fontSize: "14px"
609
+ },
610
+ noResults: {
611
+ textAlign: "center",
612
+ padding: "32px 16px",
613
+ fontSize: "14px"
614
+ }
615
+ };
616
+ var themeStyles = {
617
+ light: {
618
+ container: {
619
+ backgroundColor: "transparent",
620
+ color: "inherit"
621
+ },
622
+ searchInput: {
623
+ border: `1px solid ${slateGrey[11]}`
624
+ },
625
+ item: {
626
+ backgroundColor: "var(--sc-content-background)",
627
+ borderTop: "var(--sc-content-border)",
628
+ borderRight: "var(--sc-content-border)",
629
+ borderBottom: "var(--sc-content-border)",
630
+ borderLeft: "var(--sc-content-border)"
631
+ },
632
+ itemExpanded: {
633
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.08)"
634
+ },
635
+ question: {
636
+ backgroundColor: "transparent",
637
+ color: "var(--sc-content-text-color)"
638
+ },
639
+ questionHover: {
640
+ backgroundColor: "var(--sc-content-background-hover)"
641
+ },
642
+ answer: {
643
+ color: "var(--sc-content-text-secondary-color)"
644
+ },
645
+ category: {
646
+ backgroundColor: purple[8],
647
+ color: purple[2]
648
+ },
649
+ categoryHeader: {
650
+ color: slateGrey[7]
651
+ },
652
+ emptyState: {
653
+ color: slateGrey[8]
654
+ },
655
+ feedbackPrompt: {
656
+ color: slateGrey[7]
657
+ }
658
+ },
659
+ dark: {
660
+ container: {
661
+ backgroundColor: "transparent",
662
+ color: "inherit"
663
+ },
664
+ searchInput: {
665
+ border: `1px solid ${slateGrey[5]}`
666
+ },
667
+ item: {
668
+ backgroundColor: "var(--sc-content-background)",
669
+ borderTop: "var(--sc-content-border)",
670
+ borderRight: "var(--sc-content-border)",
671
+ borderBottom: "var(--sc-content-border)",
672
+ borderLeft: "var(--sc-content-border)"
673
+ },
674
+ itemExpanded: {
675
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)"
676
+ },
677
+ question: {
678
+ backgroundColor: "transparent",
679
+ color: "var(--sc-content-text-color)"
680
+ },
681
+ questionHover: {
682
+ backgroundColor: "var(--sc-content-background-hover)"
683
+ },
684
+ answer: {
685
+ color: "var(--sc-content-text-secondary-color)"
686
+ },
687
+ category: {
688
+ backgroundColor: purple[0],
689
+ color: purple[6]
690
+ },
691
+ categoryHeader: {
692
+ color: slateGrey[8]
693
+ },
694
+ emptyState: {
695
+ color: slateGrey[7]
696
+ },
697
+ feedbackPrompt: {
698
+ color: slateGrey[8]
699
+ }
700
+ }
701
+ };
702
+
703
+ // src/FAQWidgetLit.ts
704
+ function sm(styles) {
705
+ return styles;
706
+ }
707
+ var marked = new Marked({ async: false, gfm: true, breaks: true });
708
+ function getAnswerText(answer) {
709
+ if (typeof answer === "string") return answer;
710
+ if (answer.type === "rich") return answer.html;
711
+ return answer.content;
712
+ }
713
+ function renderAnswerHtml(answer) {
714
+ if (typeof answer === "string") {
715
+ return marked.parse(answer);
716
+ }
717
+ if (answer.type === "rich") {
718
+ return answer.html;
719
+ }
720
+ return marked.parse(answer.content);
721
+ }
722
+ function resolveFeedbackConfig(feedback) {
723
+ if (!feedback) return null;
724
+ if (feedback === true) return { style: "thumbs" };
725
+ return feedback;
726
+ }
727
+ function getFeedbackPrompt(feedbackConfig) {
728
+ return feedbackConfig.prompt ?? "Was this helpful?";
729
+ }
730
+ function resolveTheme(theme) {
731
+ if (theme && theme !== "auto") return theme;
732
+ if (typeof window !== "undefined") {
733
+ return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
734
+ }
735
+ return "light";
736
+ }
737
+ var FAQAccordionElement = class extends LitElement {
738
+ constructor() {
739
+ super(...arguments);
740
+ // -----------------------------------------------------------------------
741
+ // Property declarations
742
+ // -----------------------------------------------------------------------
743
+ this.faqConfig = {
744
+ expandBehavior: "single",
745
+ searchable: false,
746
+ theme: "auto",
747
+ actions: []
748
+ };
749
+ this.runtime = null;
750
+ this.instanceId = "faq-widget";
751
+ // Internal state
752
+ this._expandedIds = /* @__PURE__ */ new Set();
753
+ this._highlightId = null;
754
+ this._searchQuery = "";
755
+ this._feedbackState = /* @__PURE__ */ new Map();
756
+ this._hoveredId = null;
757
+ // Subscription cleanup handles
758
+ this._unsubContext = null;
759
+ this._unsubAccumulator = null;
760
+ this._unsubCta = null;
761
+ this._unsubDeepLink = null;
762
+ this._unsubSessionMetrics = null;
763
+ this._highlightTimer = null;
764
+ }
765
+ // -----------------------------------------------------------------------
766
+ // Light DOM — no Shadow DOM so CSS variables from the host page apply
767
+ // -----------------------------------------------------------------------
768
+ createRenderRoot() {
769
+ return this;
770
+ }
771
+ // -----------------------------------------------------------------------
772
+ // Lifecycle
773
+ // -----------------------------------------------------------------------
774
+ connectedCallback() {
775
+ super.connectedCallback();
776
+ this._subscribeAll();
777
+ }
778
+ disconnectedCallback() {
779
+ super.disconnectedCallback();
780
+ this._unsubscribeAll();
781
+ if (this._highlightTimer !== null) {
782
+ clearTimeout(this._highlightTimer);
783
+ this._highlightTimer = null;
784
+ }
785
+ }
786
+ // Re-subscribe when runtime changes (property may be set after connectedCallback)
787
+ updated(changedProps) {
788
+ if (changedProps.has("runtime")) {
789
+ this._unsubscribeAll();
790
+ this._subscribeAll();
791
+ }
792
+ }
793
+ // -----------------------------------------------------------------------
794
+ // Subscription management
795
+ // -----------------------------------------------------------------------
796
+ _subscribeAll() {
797
+ if (!this.runtime) return;
798
+ this._unsubContext = this.runtime.context.subscribe(() => {
799
+ this.requestUpdate();
800
+ });
801
+ if (this.runtime.accumulator?.subscribe) {
802
+ this._unsubAccumulator = this.runtime.accumulator.subscribe(() => {
803
+ this.requestUpdate();
804
+ });
805
+ }
806
+ if (this.runtime.sessionMetrics?.subscribe) {
807
+ this._unsubSessionMetrics = this.runtime.sessionMetrics.subscribe(() => {
808
+ this.requestUpdate();
809
+ });
810
+ }
811
+ if (this.runtime.events.subscribe) {
812
+ if (this.runtime.events.getRecent) {
813
+ const recentEvents = this.runtime.events.getRecent(
814
+ { patterns: ["^action\\.tooltip_cta_clicked$", "^action\\.modal_cta_clicked$"] },
815
+ 10
816
+ );
817
+ const pendingEvent = recentEvents.filter((e) => {
818
+ const actionId = e.props?.actionId;
819
+ return typeof actionId === "string" && actionId.startsWith("faq:open:");
820
+ }).pop();
821
+ if (pendingEvent && Date.now() - pendingEvent.ts < 1e4) {
822
+ const questionId = pendingEvent.props.actionId.replace("faq:open:", "");
823
+ this._expandedIds = /* @__PURE__ */ new Set([questionId]);
824
+ requestAnimationFrame(() => {
825
+ const el = document.querySelector(`[data-faq-item-id="${questionId}"]`);
826
+ if (el) el.scrollIntoView({ behavior: "smooth", block: "center" });
827
+ });
828
+ }
829
+ }
830
+ this._unsubCta = this.runtime.events.subscribe(
831
+ { patterns: ["^action\\.tooltip_cta_clicked$", "^action\\.modal_cta_clicked$"] },
832
+ (event) => {
833
+ const actionId = event.props?.actionId;
834
+ if (typeof actionId !== "string" || !actionId.startsWith("faq:open:")) return;
835
+ const questionId = actionId.replace("faq:open:", "");
836
+ this._expandedIds = /* @__PURE__ */ new Set([questionId]);
837
+ requestAnimationFrame(() => {
838
+ const el = document.querySelector(`[data-faq-item-id="${questionId}"]`);
839
+ if (el) el.scrollIntoView({ behavior: "smooth", block: "center" });
840
+ });
841
+ this.runtime?.events.publish("canvas.requestOpen");
842
+ }
843
+ );
844
+ }
845
+ if (this.runtime.events.subscribe) {
846
+ const handleDeepLink = (event) => {
847
+ const tileId = event.props?.tileId;
848
+ const itemId = event.props?.itemId;
849
+ if (tileId !== this.instanceId) return;
850
+ if (!itemId) return;
851
+ this._expandedIds = /* @__PURE__ */ new Set([itemId]);
852
+ this._highlightId = itemId;
853
+ if (this._highlightTimer !== null) clearTimeout(this._highlightTimer);
854
+ this._highlightTimer = setTimeout(() => {
855
+ this._highlightId = null;
856
+ this._highlightTimer = null;
857
+ }, 1500);
858
+ requestAnimationFrame(() => {
859
+ const el = document.querySelector(`[data-faq-item-id="${itemId}"]`);
860
+ if (el) el.scrollIntoView({ behavior: "smooth", block: "center" });
32
861
  });
33
- container.appendChild(el);
34
- return () => el.remove();
35
- },
36
- };
37
- // ============================================================================
38
- // App Runtime Manifest
39
- // ============================================================================
40
- /**
41
- * Runtime manifest for adaptive-faq.
42
- *
43
- * Provides:
44
- * - FAQ action executors (scroll_to, toggle_item, update)
45
- * - Widget-based accordion (compositional faq:question actions)
46
- */
47
- export const runtime = {
48
- id: 'adaptive-faq',
49
- version: '2.0.0',
50
- name: 'FAQ Accordion',
51
- description: 'Collapsible Q&A accordion with actions, rich content, feedback, and personalization',
52
- /**
53
- * Action executors for programmatic FAQ interaction.
54
- */
55
- executors: executorDefinitions,
56
- /**
57
- * Widget definitions for the runtime's WidgetRegistry.
58
- */
59
- widgets: [
60
- {
61
- id: 'adaptive-faq:accordion',
62
- component: FAQMountableWidget,
63
- metadata: {
64
- name: 'FAQ Accordion',
65
- description: 'Collapsible Q&A accordion with search, categories, and feedback',
66
- icon: '❓',
67
- subtitle: 'Curated just for you.',
68
- },
69
- },
70
- ],
71
- /**
72
- * Extract notify watcher entries from tile config props.
73
- * The runtime evaluates these continuously (even with drawer closed)
74
- * and publishes faq:question_revealed when triggerWhen transitions false → true.
75
- */
76
- notifyWatchers(props) {
77
- const actions = (props.actions ?? []);
78
- return actions
79
- .filter((a) => a.notify && a.triggerWhen)
80
- .map((a) => ({
81
- id: `faq:${a.config.id}`,
82
- strategy: a.triggerWhen,
83
- eventName: 'faq:question_revealed',
84
- eventProps: {
85
- questionId: a.config.id,
86
- question: a.config.question,
87
- title: a.notify.title,
88
- body: a.notify.body,
89
- icon: a.notify.icon,
90
- },
91
- }));
92
- },
93
- };
94
- export default runtime;
862
+ };
863
+ if (this.runtime.events.getRecent) {
864
+ const recent = this.runtime.events.getRecent({ names: ["notification.deep_link"] }, 5);
865
+ const pending = recent.filter((e) => e.props?.tileId === this.instanceId && e.props?.itemId).pop();
866
+ if (pending && Date.now() - pending.ts < 1e4) {
867
+ handleDeepLink(pending);
868
+ }
869
+ }
870
+ this._unsubDeepLink = this.runtime.events.subscribe(
871
+ { names: ["notification.deep_link"] },
872
+ handleDeepLink
873
+ );
874
+ }
875
+ }
876
+ _unsubscribeAll() {
877
+ this._unsubContext?.();
878
+ this._unsubAccumulator?.();
879
+ this._unsubSessionMetrics?.();
880
+ this._unsubCta?.();
881
+ this._unsubDeepLink?.();
882
+ this._unsubContext = null;
883
+ this._unsubAccumulator = null;
884
+ this._unsubSessionMetrics = null;
885
+ this._unsubCta = null;
886
+ this._unsubDeepLink = null;
887
+ }
888
+ // -----------------------------------------------------------------------
889
+ // Handlers
890
+ // -----------------------------------------------------------------------
891
+ _handleToggle(id) {
892
+ const prev = this._expandedIds;
893
+ let next;
894
+ if (this.faqConfig.expandBehavior === "single") {
895
+ next = prev.has(id) ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([id]);
896
+ } else {
897
+ next = new Set(prev);
898
+ if (prev.has(id)) {
899
+ next.delete(id);
900
+ } else {
901
+ next.add(id);
902
+ }
903
+ }
904
+ const willBeExpanded = !prev.has(id);
905
+ this._expandedIds = next;
906
+ this.runtime?.events.publish("faq:toggled", {
907
+ instanceId: this.instanceId,
908
+ questionId: id,
909
+ expanded: willBeExpanded,
910
+ timestamp: Date.now()
911
+ });
912
+ }
913
+ _handleFeedback(itemId, question, value) {
914
+ const next = new Map(this._feedbackState);
915
+ next.set(itemId, value);
916
+ this._feedbackState = next;
917
+ this.runtime?.events.publish("faq:feedback", { itemId, question, value });
918
+ }
919
+ // -----------------------------------------------------------------------
920
+ // Computed helpers
921
+ // -----------------------------------------------------------------------
922
+ _visibleQuestions() {
923
+ return (this.faqConfig.actions ?? []).filter((q) => {
924
+ if (!q.triggerWhen) return true;
925
+ if (!this.runtime) return true;
926
+ const result = this.runtime.evaluateSync(q.triggerWhen);
927
+ return result.value;
928
+ });
929
+ }
930
+ _orderedQuestions(visible) {
931
+ if (this.faqConfig.ordering === "priority") {
932
+ return [...visible].sort((a, b) => (b.config.priority ?? 0) - (a.config.priority ?? 0));
933
+ }
934
+ return visible;
935
+ }
936
+ _filteredQuestions(ordered) {
937
+ const q = this._searchQuery.trim().toLowerCase();
938
+ if (!this.faqConfig.searchable || !q) return ordered;
939
+ return ordered.filter(
940
+ (item) => item.config.question.toLowerCase().includes(q) || getAnswerText(item.config.answer).toLowerCase().includes(q) || item.config.category?.toLowerCase().includes(q)
941
+ );
942
+ }
943
+ _categoryGroups(filtered) {
944
+ const groups = /* @__PURE__ */ new Map();
945
+ for (const item of filtered) {
946
+ const cat = item.config.category;
947
+ if (!groups.has(cat)) groups.set(cat, []);
948
+ groups.get(cat).push(item);
949
+ }
950
+ return groups;
951
+ }
952
+ // -----------------------------------------------------------------------
953
+ // Render helpers
954
+ // -----------------------------------------------------------------------
955
+ _renderAnswer(answer) {
956
+ const html_str = renderAnswerHtml(answer);
957
+ return html`<div style="margin:0" data-faq-markdown="">${unsafeHTML(html_str)}</div>`;
958
+ }
959
+ _renderFeedback(item, feedbackConfig, feedbackValue, theme) {
960
+ const colors = themeStyles[theme];
961
+ const feedbackStyle = { ...baseStyles.feedback, ...colors.feedbackPrompt };
962
+ return html`
963
+ <div style=${styleMap(sm(feedbackStyle))}>
964
+ <span>${getFeedbackPrompt(feedbackConfig)}</span>
965
+ <button
966
+ type="button"
967
+ style=${styleMap(
968
+ sm({
969
+ ...baseStyles.feedbackButton,
970
+ ...feedbackValue === "up" ? baseStyles.feedbackButtonSelected : {}
971
+ })
972
+ )}
973
+ aria-label="Thumbs up"
974
+ @click=${() => this._handleFeedback(item.config.id, item.config.question, "up")}
975
+ >\uD83D\uDC4D</button>
976
+ <button
977
+ type="button"
978
+ style=${styleMap(
979
+ sm({
980
+ ...baseStyles.feedbackButton,
981
+ ...feedbackValue === "down" ? baseStyles.feedbackButtonSelected : {}
982
+ })
983
+ )}
984
+ aria-label="Thumbs down"
985
+ @click=${() => this._handleFeedback(item.config.id, item.config.question, "down")}
986
+ >\uD83D\uDC4E</button>
987
+ </div>
988
+ `;
989
+ }
990
+ _renderItem(item, isLast, theme, feedbackConfig) {
991
+ const colors = themeStyles[theme];
992
+ const isExpanded = this._expandedIds.has(item.config.id);
993
+ const isHighlighted = this._highlightId === item.config.id;
994
+ const isHovered = this._hoveredId === item.config.id;
995
+ const itemStyle = {
996
+ ...baseStyles.item,
997
+ ...colors.item,
998
+ ...isExpanded ? colors.itemExpanded : {},
999
+ ...isHighlighted ? {
1000
+ boxShadow: `0 0 0 2px ${purple[4]}, 0 0 12px rgba(106, 89, 206, 0.4)`,
1001
+ transition: "box-shadow 0.3s ease"
1002
+ } : {},
1003
+ ...!isLast ? { borderBottom: "var(--sc-content-item-divider, none)" } : {}
1004
+ };
1005
+ const questionStyle = {
1006
+ ...baseStyles.question,
1007
+ ...colors.question,
1008
+ ...isHovered ? colors.questionHover : {}
1009
+ };
1010
+ const chevronStyle = {
1011
+ ...baseStyles.chevron,
1012
+ transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)"
1013
+ };
1014
+ const answerStyle = {
1015
+ ...baseStyles.answer,
1016
+ ...colors.answer,
1017
+ maxHeight: isExpanded ? "500px" : "0",
1018
+ paddingBottom: isExpanded ? "16px" : "0"
1019
+ };
1020
+ return html`
1021
+ <div
1022
+ style=${styleMap(sm(itemStyle))}
1023
+ data-faq-item-id=${item.config.id}
1024
+ >
1025
+ <button
1026
+ type="button"
1027
+ style=${styleMap(sm(questionStyle))}
1028
+ aria-expanded=${isExpanded}
1029
+ @click=${() => this._handleToggle(item.config.id)}
1030
+ @mouseenter=${() => {
1031
+ this._hoveredId = item.config.id;
1032
+ }}
1033
+ @mouseleave=${() => {
1034
+ this._hoveredId = null;
1035
+ }}
1036
+ >
1037
+ <span>${item.config.question}</span>
1038
+ <span style=${styleMap(sm(chevronStyle))}>\u203A</span>
1039
+ </button>
1040
+
1041
+ <div
1042
+ style=${styleMap(sm(answerStyle))}
1043
+ aria-hidden=${!isExpanded}
1044
+ >
1045
+ ${this._renderAnswer(item.config.answer)}
1046
+ ${isExpanded && feedbackConfig ? this._renderFeedback(
1047
+ item,
1048
+ feedbackConfig,
1049
+ this._feedbackState.get(item.config.id),
1050
+ theme
1051
+ ) : nothing}
1052
+ </div>
1053
+ </div>
1054
+ `;
1055
+ }
1056
+ _renderItems(items, theme, feedbackConfig) {
1057
+ return items.map(
1058
+ (item, index) => this._renderItem(item, index === items.length - 1, theme, feedbackConfig)
1059
+ );
1060
+ }
1061
+ // -----------------------------------------------------------------------
1062
+ // Render
1063
+ // -----------------------------------------------------------------------
1064
+ render() {
1065
+ const theme = resolveTheme(this.faqConfig.theme);
1066
+ const colors = themeStyles[theme];
1067
+ const feedbackConfig = resolveFeedbackConfig(this.faqConfig.feedback);
1068
+ const visible = this._visibleQuestions();
1069
+ const ordered = this._orderedQuestions(visible);
1070
+ const filtered = this._filteredQuestions(ordered);
1071
+ const hasCategories = filtered.some((q) => q.config.category);
1072
+ const groups = hasCategories ? this._categoryGroups(filtered) : null;
1073
+ const containerStyle = {
1074
+ ...baseStyles.container,
1075
+ ...colors.container
1076
+ };
1077
+ const emptyStateStyle = {
1078
+ ...baseStyles.emptyState,
1079
+ ...colors.emptyState
1080
+ };
1081
+ const categoryHeaderStyle = {
1082
+ ...baseStyles.categoryHeader,
1083
+ ...colors.categoryHeader
1084
+ };
1085
+ const searchInputStyle = {
1086
+ ...baseStyles.searchInput,
1087
+ ...colors.searchInput
1088
+ };
1089
+ if (visible.length === 0) {
1090
+ return html`
1091
+ <div
1092
+ style=${styleMap(sm(containerStyle))}
1093
+ data-adaptive-id=${this.instanceId}
1094
+ data-adaptive-type="adaptive-faq"
1095
+ >
1096
+ <div style=${styleMap(sm(emptyStateStyle))}>
1097
+ You're all set for now! We'll surface answers here when they're relevant to what
1098
+ you're doing.
1099
+ </div>
1100
+ </div>
1101
+ `;
1102
+ }
1103
+ return html`
1104
+ <div
1105
+ style=${styleMap(sm(containerStyle))}
1106
+ data-adaptive-id=${this.instanceId}
1107
+ data-adaptive-type="adaptive-faq"
1108
+ >
1109
+ ${this.faqConfig.searchable ? html`
1110
+ <div style=${styleMap(sm(baseStyles.searchWrapper))}>
1111
+ <style>
1112
+ [data-adaptive-id="${this.instanceId}"] input::placeholder {
1113
+ color: var(--sc-content-search-color, inherit);
1114
+ opacity: 0.7;
1115
+ }
1116
+ </style>
1117
+ <input
1118
+ type="text"
1119
+ placeholder="Search questions..."
1120
+ .value=${this._searchQuery}
1121
+ style=${styleMap(sm(searchInputStyle))}
1122
+ @input=${(e) => {
1123
+ this._searchQuery = e.target.value;
1124
+ }}
1125
+ />
1126
+ </div>
1127
+ ` : nothing}
1128
+
1129
+ <div style=${styleMap(sm(baseStyles.accordion))}>
1130
+ ${groups ? Array.from(groups.entries()).map(
1131
+ ([category, items]) => html`
1132
+ ${category ? html`
1133
+ <div
1134
+ style=${styleMap(sm(categoryHeaderStyle))}
1135
+ data-category-header=${category}
1136
+ >
1137
+ ${category}
1138
+ </div>
1139
+ ` : nothing}
1140
+ ${this._renderItems(items, theme, feedbackConfig)}
1141
+ `
1142
+ ) : this._renderItems(filtered, theme, feedbackConfig)}
1143
+ </div>
1144
+
1145
+ ${this.faqConfig.searchable && filtered.length === 0 && this._searchQuery ? html`
1146
+ <div
1147
+ style=${styleMap(sm({ ...baseStyles.noResults, ...colors.emptyState }))}
1148
+ >
1149
+ No questions found matching &quot;${this._searchQuery}&quot;
1150
+ </div>
1151
+ ` : nothing}
1152
+ </div>
1153
+ `;
1154
+ }
1155
+ };
1156
+ // -----------------------------------------------------------------------
1157
+ // Reactive properties (no decorators — tsconfig forbids experimentalDecorators)
1158
+ // -----------------------------------------------------------------------
1159
+ FAQAccordionElement.properties = {
1160
+ // Public API — set from the outside
1161
+ faqConfig: { attribute: false },
1162
+ runtime: { attribute: false },
1163
+ instanceId: { type: String },
1164
+ // Internal reactive state (prefixed with _ to signal "private")
1165
+ _expandedIds: { state: true },
1166
+ _highlightId: { state: true },
1167
+ _searchQuery: { state: true },
1168
+ _feedbackState: { state: true },
1169
+ _hoveredId: { state: true }
1170
+ };
1171
+ if (!customElements.get("syntro-faq-accordion")) {
1172
+ customElements.define("syntro-faq-accordion", FAQAccordionElement);
1173
+ }
1174
+
1175
+ // src/runtime.ts
1176
+ var FAQWidgetLitMountable = {
1177
+ mount(container, config) {
1178
+ const {
1179
+ runtime: runtime2,
1180
+ instanceId = "faq-widget",
1181
+ ...faqConfig
1182
+ } = config ?? {
1183
+ expandBehavior: "single",
1184
+ searchable: false,
1185
+ theme: "auto",
1186
+ actions: []
1187
+ };
1188
+ const el = document.createElement("syntro-faq-accordion");
1189
+ Object.assign(el, {
1190
+ faqConfig,
1191
+ runtime: runtime2 ?? null,
1192
+ instanceId
1193
+ });
1194
+ container.appendChild(el);
1195
+ return () => el.remove();
1196
+ }
1197
+ };
1198
+ var runtime = {
1199
+ id: "adaptive-faq",
1200
+ version: "2.0.0",
1201
+ name: "FAQ Accordion",
1202
+ description: "Collapsible Q&A accordion with actions, rich content, feedback, and personalization",
1203
+ /**
1204
+ * Action executors for programmatic FAQ interaction.
1205
+ */
1206
+ executors: executorDefinitions,
1207
+ /**
1208
+ * Widget definitions for the runtime's WidgetRegistry.
1209
+ */
1210
+ widgets: [
1211
+ {
1212
+ id: "adaptive-faq:accordion",
1213
+ component: FAQWidgetLitMountable,
1214
+ metadata: {
1215
+ name: "FAQ Accordion",
1216
+ description: "Collapsible Q&A accordion with search, categories, and feedback",
1217
+ icon: "\u2753",
1218
+ subtitle: "Curated just for you."
1219
+ }
1220
+ }
1221
+ ],
1222
+ /**
1223
+ * Extract notify watcher entries from tile config props.
1224
+ * The runtime evaluates these continuously (even with drawer closed)
1225
+ * and publishes faq:question_revealed when triggerWhen transitions false → true.
1226
+ */
1227
+ notifyWatchers(props) {
1228
+ const actions = props.actions ?? [];
1229
+ return actions.filter((a) => a.notify && a.triggerWhen).map((a) => ({
1230
+ id: `faq:${a.config.id}`,
1231
+ strategy: a.triggerWhen,
1232
+ eventName: "faq:question_revealed",
1233
+ eventProps: {
1234
+ questionId: a.config.id,
1235
+ question: a.config.question,
1236
+ title: a.notify.title,
1237
+ body: a.notify.body,
1238
+ icon: a.notify.icon
1239
+ }
1240
+ }));
1241
+ }
1242
+ };
1243
+ var runtime_default = runtime;
1244
+ export {
1245
+ FAQWidgetLitMountable,
1246
+ runtime_default as default,
1247
+ runtime
1248
+ };
1249
+ //# sourceMappingURL=runtime.js.map