@vertebr/react 0.4.0 → 0.5.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.
Files changed (82) hide show
  1. package/dist/components/admin/AdminContent.d.ts +36 -0
  2. package/dist/components/admin/AdminContent.d.ts.map +1 -0
  3. package/dist/components/admin/AdminContent.js +107 -0
  4. package/dist/components/admin/AdminHeader.d.ts +13 -0
  5. package/dist/components/admin/AdminHeader.d.ts.map +1 -0
  6. package/dist/components/admin/AdminHeader.js +32 -0
  7. package/dist/components/admin/AdminSidebar.d.ts +25 -0
  8. package/dist/components/admin/AdminSidebar.d.ts.map +1 -0
  9. package/dist/components/admin/AdminSidebar.js +31 -0
  10. package/dist/components/admin/VertebrAdmin.d.ts +3 -18
  11. package/dist/components/admin/VertebrAdmin.d.ts.map +1 -1
  12. package/dist/components/admin/VertebrAdmin.js +130 -120
  13. package/dist/components/admin/sidebar.d.ts +3 -0
  14. package/dist/components/admin/sidebar.d.ts.map +1 -0
  15. package/dist/components/admin/sidebar.js +13 -0
  16. package/dist/components/admin/storage.d.ts +4 -0
  17. package/dist/components/admin/storage.d.ts.map +1 -0
  18. package/dist/components/admin/storage.js +24 -0
  19. package/dist/components/admin/types.d.ts +53 -0
  20. package/dist/components/admin/types.d.ts.map +1 -0
  21. package/dist/components/admin/types.js +1 -0
  22. package/dist/components/config/form/ConfigForm.d.ts +1 -1
  23. package/dist/components/config/form/ConfigForm.d.ts.map +1 -1
  24. package/dist/components/config/form/ConfigForm.js +5 -1
  25. package/dist/components/config/form/RecordConfigForm.d.ts +1 -0
  26. package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -1
  27. package/dist/components/config/form/SettingsConfigForm.d.ts +2 -1
  28. package/dist/components/config/form/SettingsConfigForm.d.ts.map +1 -1
  29. package/dist/components/config/form/SettingsConfigForm.js +2 -2
  30. package/dist/components/config/form/helpers/fields.js +1 -1
  31. package/dist/components/config/form/types.d.ts +4 -0
  32. package/dist/components/config/form/types.d.ts.map +1 -1
  33. package/dist/components/emails/EmailRecipientSelect.d.ts +16 -0
  34. package/dist/components/emails/EmailRecipientSelect.d.ts.map +1 -0
  35. package/dist/components/emails/EmailRecipientSelect.js +10 -0
  36. package/dist/components/emails/EmailsActivityPanel.d.ts +11 -0
  37. package/dist/components/emails/EmailsActivityPanel.d.ts.map +1 -0
  38. package/dist/components/emails/EmailsActivityPanel.js +139 -0
  39. package/dist/components/emails/EmailsBoard.d.ts +47 -0
  40. package/dist/components/emails/EmailsBoard.d.ts.map +1 -0
  41. package/dist/components/emails/EmailsBoard.js +594 -0
  42. package/dist/components/emails/EmailsLibraryPanel.d.ts +25 -0
  43. package/dist/components/emails/EmailsLibraryPanel.d.ts.map +1 -0
  44. package/dist/components/emails/EmailsLibraryPanel.js +379 -0
  45. package/dist/components/emails/EmailsNavSelect.d.ts +18 -0
  46. package/dist/components/emails/EmailsNavSelect.d.ts.map +1 -0
  47. package/dist/components/emails/EmailsNavSelect.js +37 -0
  48. package/dist/components/emails/MultiCheckSelect.d.ts +18 -0
  49. package/dist/components/emails/MultiCheckSelect.d.ts.map +1 -0
  50. package/dist/components/emails/MultiCheckSelect.js +74 -0
  51. package/dist/components/metrics/MetricsBoard.d.ts +8 -2
  52. package/dist/components/metrics/MetricsBoard.d.ts.map +1 -1
  53. package/dist/components/metrics/MetricsBoard.js +55 -2
  54. package/dist/components/metrics/charts.d.ts +14 -0
  55. package/dist/components/metrics/charts.d.ts.map +1 -0
  56. package/dist/components/metrics/charts.js +212 -0
  57. package/dist/components/resources/ResourceActionModal.d.ts +14 -0
  58. package/dist/components/resources/ResourceActionModal.d.ts.map +1 -0
  59. package/dist/components/resources/ResourceActionModal.js +64 -0
  60. package/dist/components/resources/ResourceCell.d.ts.map +1 -1
  61. package/dist/components/resources/ResourceCell.js +25 -9
  62. package/dist/components/resources/ResourceMailModal.d.ts +12 -0
  63. package/dist/components/resources/ResourceMailModal.d.ts.map +1 -0
  64. package/dist/components/resources/ResourceMailModal.js +196 -0
  65. package/dist/components/resources/ResourceTable.d.ts +7 -3
  66. package/dist/components/resources/ResourceTable.d.ts.map +1 -1
  67. package/dist/components/resources/ResourceTable.js +204 -34
  68. package/dist/index.d.ts +7 -1
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +1 -0
  71. package/dist/lib/metricsRanges.d.ts +20 -0
  72. package/dist/lib/metricsRanges.d.ts.map +1 -0
  73. package/dist/lib/metricsRanges.js +14 -0
  74. package/dist/styles/cells.css +42 -0
  75. package/dist/styles/emails.css +632 -0
  76. package/dist/styles/index.css +3 -0
  77. package/dist/styles/mail.css +240 -0
  78. package/dist/styles/metrics.css +633 -0
  79. package/dist/styles/nav.css +103 -1
  80. package/dist/styles/panel.css +2 -68
  81. package/dist/styles/table.css +26 -3
  82. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailRecipientSelect.d.ts","sourceRoot":"","sources":["../../../src/components/emails/EmailRecipientSelect.tsx"],"names":[],"mappings":"AAGA,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACtC,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,EACnC,OAAO,EACP,KAAK,EACL,OAAO,EACP,QAAQ,EACR,QAAQ,GACT,EAAE,yBAAyB,+BAmB3B"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { MultiCheckSelect } from "./MultiCheckSelect";
3
+ export function EmailRecipientSelect({ options, value, loading, disabled, onChange, }) {
4
+ const mapped = options.map((option) => ({
5
+ id: option.email.trim().toLowerCase(),
6
+ label: option.email,
7
+ secondary: option.label,
8
+ }));
9
+ return (_jsx(MultiCheckSelect, { options: mapped, value: value, loading: loading, disabled: disabled, placeholder: "Select emails\u2026", emptyLabel: "No emails on this list", searchPlaceholder: "Search emails\u2026", onChange: onChange }));
10
+ }
@@ -0,0 +1,11 @@
1
+ import type { MailCampaign, MailHistoryEntry } from "@vertebr/client";
2
+ export type EmailsActivityPanelProps = {
3
+ campaigns: MailCampaign[];
4
+ history: MailHistoryEntry[];
5
+ canSchedule?: boolean;
6
+ canHistory?: boolean;
7
+ busy?: boolean;
8
+ onCancel?: (id: string) => Promise<void>;
9
+ };
10
+ export declare function EmailsActivityPanel({ campaigns, history, canSchedule, canHistory, busy, onCancel, }: EmailsActivityPanelProps): import("react").JSX.Element;
11
+ //# sourceMappingURL=EmailsActivityPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailsActivityPanel.d.ts","sourceRoot":"","sources":["../../../src/components/emails/EmailsActivityPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEtE,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C,CAAC;AAqFF,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,OAAO,EACP,WAAW,EACX,UAAU,EACV,IAAI,EACJ,QAAQ,GACT,EAAE,wBAAwB,+BA6L1B"}
@@ -0,0 +1,139 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useState } from "react";
3
+ function formatWhen(iso) {
4
+ const ms = Date.parse(iso);
5
+ if (!Number.isFinite(ms))
6
+ return iso;
7
+ return new Intl.DateTimeFormat(undefined, {
8
+ dateStyle: "medium",
9
+ timeStyle: "short",
10
+ }).format(ms);
11
+ }
12
+ function humanize(value) {
13
+ return value
14
+ .replace(/^library:/i, "")
15
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
16
+ .replace(/[_-]+/g, " ")
17
+ .trim();
18
+ }
19
+ function sourceLabel(source) {
20
+ if (source === "row")
21
+ return "Row";
22
+ if (source === "campaign")
23
+ return "Schedule";
24
+ return "Board";
25
+ }
26
+ function confirmationOf(entry) {
27
+ const stored = entry.reference?.trim();
28
+ if (stored && stored.toUpperCase() !== "MM-PENDING")
29
+ return stored;
30
+ const subject = entry.subject ?? "";
31
+ const match = subject.match(/(?:—|-|–)\s*((?:MM|ORD|ORDER)[-_][A-Z0-9-]+|[A-Z]{2,}[-_][A-Z0-9-]{3,})\s*$/i);
32
+ const value = match?.[1]?.trim();
33
+ if (!value || value.toUpperCase() === "MM-PENDING")
34
+ return "";
35
+ return value;
36
+ }
37
+ function subjectOf(entry) {
38
+ const confirmation = confirmationOf(entry);
39
+ const raw = entry.subject?.trim() ?? "";
40
+ if (!raw)
41
+ return entry.templateLabel ?? "Email";
42
+ let next = raw;
43
+ if (confirmation) {
44
+ next = next
45
+ .replace(new RegExp(`\\s*[—\\-–]\\s*${confirmation}\\s*$`, "i"), "")
46
+ .trim();
47
+ }
48
+ return next.replace(/\s*[—\-–]\s*MM-PENDING\s*$/i, "").trim() || raw;
49
+ }
50
+ function recipientOf(entry) {
51
+ if (entry.recipients?.[0]) {
52
+ const extra = Math.max(0, entry.recipientCount - 1);
53
+ return extra > 0
54
+ ? `${entry.recipients[0]} +${extra}`
55
+ : entry.recipients[0];
56
+ }
57
+ if (entry.recipientCount > 1)
58
+ return `${entry.recipientCount} recipients`;
59
+ return "";
60
+ }
61
+ function deliveryOf(entry) {
62
+ if (entry.failed && entry.failed > 0) {
63
+ return `${entry.sent} / ${entry.failed} failed`;
64
+ }
65
+ return `${entry.sent} / ${entry.recipientCount}`;
66
+ }
67
+ function statusBadge(status) {
68
+ if (status === "sent")
69
+ return { label: "Sent", tone: "ok" };
70
+ if (status === "partial")
71
+ return { label: "Partial" };
72
+ if (status === "failed")
73
+ return { label: "Failed" };
74
+ return { label: "Scheduled", tone: "neutral" };
75
+ }
76
+ function CellEmpty() {
77
+ return _jsx("span", { className: "vertebr-cell-empty", children: "\u2014" });
78
+ }
79
+ export function EmailsActivityPanel({ campaigns, history, canSchedule, canHistory, busy, onCancel, }) {
80
+ const [filter, setFilter] = useState("all");
81
+ const upcoming = useMemo(() => campaigns
82
+ .filter((campaign) => campaign.status === "scheduled")
83
+ .slice()
84
+ .sort((a, b) => Date.parse(a.sendAt) - Date.parse(b.sendAt)), [campaigns]);
85
+ const rows = useMemo(() => {
86
+ const scheduled = upcoming.map((campaign) => ({
87
+ kind: "scheduled",
88
+ id: campaign.id,
89
+ campaign,
90
+ }));
91
+ const sent = history.map((entry) => ({
92
+ kind: "history",
93
+ id: entry.id,
94
+ entry,
95
+ }));
96
+ if (filter === "scheduled")
97
+ return scheduled;
98
+ if (filter === "history")
99
+ return sent;
100
+ return [...scheduled, ...sent];
101
+ }, [filter, upcoming, history]);
102
+ const showActions = Boolean(onCancel) && filter !== "history";
103
+ const cancel = async (campaign) => {
104
+ if (!onCancel)
105
+ return;
106
+ if (!window.confirm(`Cancel scheduled email to ${campaign.resourceLabel ?? campaign.resourceId}?`)) {
107
+ return;
108
+ }
109
+ await onCancel(campaign.id);
110
+ };
111
+ const emptyCopy = (() => {
112
+ if (filter === "scheduled") {
113
+ return canSchedule
114
+ ? "No drops scheduled yet."
115
+ : "Host has not enabled scheduling.";
116
+ }
117
+ if (filter === "history") {
118
+ return canHistory
119
+ ? "No sends recorded yet."
120
+ : "Host has not enabled send history.";
121
+ }
122
+ if (!canSchedule && !canHistory) {
123
+ return "Host has not enabled activity.";
124
+ }
125
+ return "No activity yet.";
126
+ })();
127
+ return (_jsxs("div", { className: "vertebr-emails-activity", children: [_jsxs("div", { className: "vertebr-table-toolbar", children: [_jsx("div", { className: "vertebr-table-toolbar-start", children: _jsxs("div", { className: "vertebr-emails-segment", role: "group", "aria-label": "Activity", children: [_jsx("button", { type: "button", "data-active": filter === "all" ? "true" : undefined, onClick: () => setFilter("all"), children: "All" }), _jsx("button", { type: "button", "data-active": filter === "scheduled" ? "true" : undefined, onClick: () => setFilter("scheduled"), children: "Scheduled" }), _jsx("button", { type: "button", "data-active": filter === "history" ? "true" : undefined, onClick: () => setFilter("history"), children: "History" })] }) }), _jsx("span", { className: "vertebr-count", children: rows.length })] }), rows.length === 0 ? (_jsx("div", { className: "vertebr-empty", children: emptyCopy })) : (_jsx("div", { className: "vertebr-table-wrap", children: _jsxs("table", { className: "vertebr-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "When" }), _jsx("th", { children: "Status" }), _jsx("th", { children: "Subject" }), _jsx("th", { children: "Confirmation" }), _jsx("th", { children: "To" }), _jsx("th", { children: "Audience" }), _jsx("th", { children: "Template" }), _jsx("th", { children: "Via" }), _jsx("th", { children: "Delivery" }), showActions ? _jsx("th", { className: "vertebr-col-actions", children: "Actions" }) : null] }) }), _jsx("tbody", { children: rows.map((row) => {
128
+ if (row.kind === "scheduled") {
129
+ const campaign = row.campaign;
130
+ const badge = statusBadge("scheduled");
131
+ return (_jsxs("tr", { children: [_jsx("td", { children: _jsx("span", { className: "vertebr-cell-datetime", children: formatWhen(campaign.sendAt) }) }), _jsx("td", { children: _jsx("span", { className: "vertebr-badge", "data-tone": badge.tone, children: badge.label }) }), _jsx("td", { children: campaign.subject?.trim() || _jsx(CellEmpty, {}) }), _jsx("td", { children: _jsx(CellEmpty, {}) }), _jsx("td", { children: campaign.recipientCount ?? _jsx(CellEmpty, {}) }), _jsx("td", { children: campaign.resourceLabel ?? campaign.resourceId }), _jsx("td", { children: campaign.templateLabel ?? campaign.templateId }), _jsx("td", { children: "Schedule" }), _jsx("td", { children: _jsx(CellEmpty, {}) }), showActions ? (_jsx("td", { className: "vertebr-col-actions", children: _jsx("button", { type: "button", className: "vertebr-btn vertebr-btn-quiet", disabled: busy, onClick: () => void cancel(campaign), children: "Cancel" }) })) : null] }, `scheduled:${row.id}`));
132
+ }
133
+ const entry = row.entry;
134
+ const badge = statusBadge(entry.status);
135
+ const confirmation = confirmationOf(entry);
136
+ const recipient = recipientOf(entry);
137
+ return (_jsxs("tr", { children: [_jsx("td", { children: _jsx("span", { className: "vertebr-cell-datetime", children: formatWhen(entry.at) }) }), _jsx("td", { children: _jsx("span", { className: "vertebr-badge", "data-tone": badge.tone, children: badge.label }) }), _jsx("td", { children: subjectOf(entry) }), _jsx("td", { children: confirmation || _jsx(CellEmpty, {}) }), _jsx("td", { children: recipient || _jsx(CellEmpty, {}) }), _jsx("td", { children: entry.resourceLabel ?? entry.resourceId }), _jsx("td", { children: entry.templateLabel ?? humanize(entry.templateId) }), _jsx("td", { children: sourceLabel(entry.source) }), _jsx("td", { children: deliveryOf(entry) }), showActions ? (_jsx("td", { className: "vertebr-col-actions" })) : null] }, `history:${row.id}`));
138
+ }) })] }) }))] }));
139
+ }
@@ -0,0 +1,47 @@
1
+ import type { EmailsBoardResponse, MailLibraryTemplate, MailPreviewResponse } from "@vertebr/client";
2
+ import { type EmailRecipientOption } from "./EmailRecipientSelect";
3
+ export type EmailsBoardProps = {
4
+ data: EmailsBoardResponse;
5
+ loading?: boolean;
6
+ /** Controlled section from the admin sidebar (Compose / Templates / Activity). */
7
+ tab?: "compose" | "templates" | "activity";
8
+ onRefresh: () => void | Promise<void>;
9
+ onLoadRecipients: (resourceId: string) => Promise<EmailRecipientOption[]>;
10
+ onPreview: (payload: {
11
+ resourceId: string;
12
+ templateId: string;
13
+ rowId?: string;
14
+ input?: Record<string, unknown>;
15
+ }) => Promise<MailPreviewResponse>;
16
+ onSend: (payload: {
17
+ resourceId: string;
18
+ templateId: string;
19
+ input?: Record<string, unknown>;
20
+ audience: {
21
+ mode: "all";
22
+ } | {
23
+ mode: "emails";
24
+ emails: string[];
25
+ };
26
+ }) => Promise<{
27
+ sent: number;
28
+ failed: number;
29
+ }>;
30
+ onSchedule?: (payload: {
31
+ resourceId: string;
32
+ templateId: string;
33
+ input?: Record<string, unknown>;
34
+ audience: {
35
+ mode: "all";
36
+ } | {
37
+ mode: "emails";
38
+ emails: string[];
39
+ };
40
+ sendAt: string;
41
+ }) => Promise<void>;
42
+ onCancel?: (id: string) => Promise<void>;
43
+ onSaveLibrary?: (template: MailLibraryTemplate) => Promise<void>;
44
+ onDeleteLibrary?: (id: string) => Promise<void>;
45
+ };
46
+ export declare function EmailsBoard({ data, loading, tab: tabProp, onRefresh, onLoadRecipients, onPreview, onSend, onSchedule, onCancel, onSaveLibrary, onDeleteLibrary, }: EmailsBoardProps): import("react").JSX.Element;
47
+ //# sourceMappingURL=EmailsBoard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmailsBoard.d.ts","sourceRoot":"","sources":["../../../src/components/emails/EmailsBoard.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EAEnB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,wBAAwB,CAAC;AAKhC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kFAAkF;IAClF,GAAG,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAC3C,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,gBAAgB,EAAE,CAChB,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACrC,SAAS,EAAE,CAAC,OAAO,EAAE;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACjC,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACnC,MAAM,EAAE,CAAC,OAAO,EAAE;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,QAAQ,EAAE;YAAE,IAAI,EAAE,KAAK,CAAA;SAAE,GAAG;YAAE,IAAI,EAAE,QAAQ,CAAC;YAAC,MAAM,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC;KAClE,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChD,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,QAAQ,EAAE;YAAE,IAAI,EAAE,KAAK,CAAA;SAAE,GAAG;YAAE,IAAI,EAAE,QAAQ,CAAC;YAAC,MAAM,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC;QACjE,MAAM,EAAE,MAAM,CAAC;KAChB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD,CAAC;AA+PF,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,OAAO,EACP,GAAG,EAAE,OAAO,EACZ,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,MAAM,EACN,UAAU,EACV,QAAQ,EACR,aAAa,EACb,eAAe,GAChB,EAAE,gBAAgB,+BAgqBlB"}