@ai-matrx/print 0.1.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/core.d.ts ADDED
@@ -0,0 +1,139 @@
1
+ /**
2
+ * @ai-matrx/print/core — the Block Print contract & print-window composition.
3
+ *
4
+ * Ported VERBATIM from matrx-frontend `lib/block-print/block-print-utils.ts`
5
+ * (2026-08-29 state, including the `number` and `select` PrintSetting types the
6
+ * commerce label lane added). Zero dependencies; touches `window` only at call
7
+ * time, so the module stays import-inert and RSC-safe.
8
+ *
9
+ * BlockPrinter is the only interface a host system needs to know about.
10
+ * Each printable unit exports its own BlockPrinter alongside its render
11
+ * component; host code only ever calls print(data, variantId, settings).
12
+ *
13
+ * `buildFitTextScript` is the ONE auto-shrink script (the flashcards
14
+ * FIT_TEXT pattern, parameterized by selector so the label lane shares it).
15
+ */
16
+ interface PrintVariant {
17
+ id: string;
18
+ label: string;
19
+ description?: string;
20
+ }
21
+ /**
22
+ * A single user-configurable setting shown in the print dialog.
23
+ * Extend the discriminated union for new control types
24
+ * without breaking existing printers.
25
+ */
26
+ type PrintSetting = {
27
+ type: "boolean";
28
+ id: string;
29
+ label: string;
30
+ description?: string;
31
+ /** Default value shown when the dialog first opens */
32
+ defaultValue: boolean;
33
+ /** Which variant IDs this setting applies to. Omit = applies to all. */
34
+ appliesTo?: string[];
35
+ } | {
36
+ /**
37
+ * A numeric "from → to" range control, rendered as two small number inputs.
38
+ * Writes two entries into the resolved PrintSettings map — one under fromId,
39
+ * one under toId. Printers interpret 0 (or missing) as "no bound" by convention.
40
+ */
41
+ type: "range";
42
+ /** Stable id used as React key — not written to the settings map */
43
+ id: string;
44
+ label: string;
45
+ description?: string;
46
+ /** Settings map key for the lower bound value */
47
+ fromId: string;
48
+ /** Settings map key for the upper bound value */
49
+ toId: string;
50
+ defaultFrom: number;
51
+ defaultTo: number;
52
+ /** Minimum accepted value for each input (inclusive). Default 0. */
53
+ min?: number;
54
+ /** Placeholder shown when the input is empty (0). Default "start" / "end". */
55
+ fromPlaceholder?: string;
56
+ toPlaceholder?: string;
57
+ /** Which variant IDs this setting applies to. Omit = applies to all. */
58
+ appliesTo?: string[];
59
+ } | {
60
+ /** A single numeric input (e.g. "start at label #", "copies"). */
61
+ type: "number";
62
+ id: string;
63
+ label: string;
64
+ description?: string;
65
+ defaultValue: number;
66
+ /** Minimum accepted value (inclusive). Default 0. */
67
+ min?: number;
68
+ /** Maximum accepted value (inclusive). Omit = unbounded. */
69
+ max?: number;
70
+ /** Which variant IDs this setting applies to. Omit = applies to all. */
71
+ appliesTo?: string[];
72
+ } | {
73
+ /** A one-of-N choice rendered as a compact segmented row. */
74
+ type: "select";
75
+ id: string;
76
+ label: string;
77
+ description?: string;
78
+ options: {
79
+ value: string;
80
+ label: string;
81
+ }[];
82
+ defaultValue: string;
83
+ /** Which variant IDs this setting applies to. Omit = applies to all. */
84
+ appliesTo?: string[];
85
+ };
86
+ /** A resolved map of setting id → current value, passed to print(). */
87
+ type PrintSettings = Record<string, boolean | string | number>;
88
+ /**
89
+ * The self-contained print capability that each block can export.
90
+ * Host code only ever calls print(data, variantId, settings) — it never inspects internals.
91
+ */
92
+ interface BlockPrinter {
93
+ /** Tooltip / aria-label for the print button in the block header */
94
+ label: string;
95
+ /**
96
+ * Variants offered to the user before printing.
97
+ * Empty array = no options dialog shown; prints immediately with defaults.
98
+ */
99
+ variants: PrintVariant[];
100
+ /**
101
+ * Optional user-configurable settings shown below the variant picker.
102
+ * Omit entirely if the block has no configurable settings.
103
+ */
104
+ settings?: PrintSetting[];
105
+ /**
106
+ * Execute the print.
107
+ * data — the block's structured data (serverData or parsed content)
108
+ * variantId — which variant was chosen (undefined = default / no variants)
109
+ * settings — resolved setting values chosen by the user
110
+ */
111
+ print: (data: unknown, variantId?: string, settings?: PrintSettings) => void | Promise<void>;
112
+ }
113
+ declare function escapeHtml(str: string): string;
114
+ /**
115
+ * Wrap body HTML in a complete, styled print document.
116
+ */
117
+ declare function buildPrintDocument(bodyHtml: string, title?: string, extraStyles?: string): string;
118
+ /**
119
+ * Open a new browser window and write a complete HTML document into it.
120
+ * Falls back to downloading an .html file if the popup is blocked.
121
+ */
122
+ declare function openPrintWindow(htmlDocument: string, filename?: string): void;
123
+ /**
124
+ * Shorthand: build the document and open it in one call.
125
+ */
126
+ declare function printHtmlContent(bodyHtml: string, title?: string, extraStyles?: string): void;
127
+ /**
128
+ * Build the auto-shrink script that runs INSIDE a printed window: for every
129
+ * element matching each selector, its font-size is reduced (0.5pt steps, 6pt
130
+ * floor) until it fits its parent element's box. This is the flashcards
131
+ * FIT_TEXT behavior verbatim, parameterized by selector so every lane
132
+ * (flashcards card text, Avery text, label captions) shares the ONE loop.
133
+ *
134
+ * Pass the same selectors the original used to get byte-identical behavior:
135
+ * flashcards passes `[".card-text .card-text-inner", ".avery-text-wrap .avery-text"]`.
136
+ */
137
+ declare function buildFitTextScript(selectors: readonly string[]): string;
138
+
139
+ export { type BlockPrinter, type PrintSetting, type PrintSettings, type PrintVariant, buildFitTextScript, buildPrintDocument, escapeHtml, openPrintWindow, printHtmlContent };
package/dist/core.js ADDED
@@ -0,0 +1,163 @@
1
+ // src/core.ts
2
+ var PRINT_STYLES = `
3
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
4
+
5
+ body {
6
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
7
+ font-size: 11pt;
8
+ line-height: 1.6;
9
+ color: #1a1a1a;
10
+ background: #fff;
11
+ max-width: 860px;
12
+ margin: 0 auto;
13
+ padding: 28px 36px;
14
+ }
15
+
16
+ .print-actions {
17
+ display: flex;
18
+ gap: 10px;
19
+ margin-bottom: 24px;
20
+ padding-bottom: 18px;
21
+ border-bottom: 2px solid #e5e7eb;
22
+ }
23
+
24
+ .print-btn {
25
+ display: inline-flex;
26
+ align-items: center;
27
+ gap: 6px;
28
+ padding: 8px 20px;
29
+ border-radius: 8px;
30
+ font-size: 13px;
31
+ font-family: inherit;
32
+ cursor: pointer;
33
+ border: none;
34
+ font-weight: 600;
35
+ }
36
+
37
+ .print-btn-primary { background: #2563eb; color: #fff; }
38
+ .print-btn-secondary { background: #f3f4f6; color: #374151; border: 1px solid #d1d5db; }
39
+
40
+ h1 { font-size: 22pt; font-weight: 700; margin-bottom: 0.5em; }
41
+ h2 { font-size: 16pt; font-weight: 700; margin: 1.2em 0 0.4em; border-bottom: 1px solid #e5e7eb; padding-bottom: 0.2em; }
42
+ h3 { font-size: 13pt; font-weight: 600; margin: 1em 0 0.3em; }
43
+ p { margin-bottom: 0.7em; }
44
+
45
+ table {
46
+ width: 100%;
47
+ border-collapse: collapse;
48
+ margin: 1em 0;
49
+ font-size: 10pt;
50
+ }
51
+ th {
52
+ background: #1e293b;
53
+ color: #f8fafc;
54
+ font-weight: 600;
55
+ text-align: left;
56
+ padding: 7px 12px;
57
+ border: 1px solid #334155;
58
+ }
59
+ td {
60
+ padding: 6px 12px;
61
+ border: 1px solid #e2e8f0;
62
+ vertical-align: top;
63
+ }
64
+ tr:nth-child(even) td { background: #f8fafc; }
65
+
66
+ @media print {
67
+ body { max-width: 100%; padding: 0; }
68
+ .print-actions { display: none !important; }
69
+ th { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
70
+ }
71
+ `;
72
+ function escapeHtml(str) {
73
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
74
+ }
75
+ function buildPrintDocument(bodyHtml, title = "AI Response", extraStyles = "") {
76
+ return `<!DOCTYPE html>
77
+ <html lang="en">
78
+ <head>
79
+ <meta charset="UTF-8">
80
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
81
+ <title>${escapeHtml(title)}</title>
82
+ <style>
83
+ ${PRINT_STYLES}
84
+ ${extraStyles}
85
+ </style>
86
+ </head>
87
+ <body>
88
+ <div class="print-actions">
89
+ <button class="print-btn print-btn-primary" onclick="window.print()">Print / Save as PDF</button>
90
+ <button class="print-btn print-btn-secondary" onclick="window.close()">Close</button>
91
+ </div>
92
+ <div class="content">
93
+ ${bodyHtml}
94
+ </div>
95
+ </body>
96
+ </html>`;
97
+ }
98
+ function openPrintWindow(htmlDocument, filename = "print") {
99
+ const win = window.open("", "_blank", "width=920,height=720,scrollbars=yes");
100
+ if (!win) {
101
+ const blob = new Blob([htmlDocument], { type: "text/html;charset=utf-8" });
102
+ const url = URL.createObjectURL(blob);
103
+ const a = document.createElement("a");
104
+ a.href = url;
105
+ a.download = `${filename.replace(/\s+/g, "-").toLowerCase()}.html`;
106
+ document.body.appendChild(a);
107
+ a.click();
108
+ document.body.removeChild(a);
109
+ URL.revokeObjectURL(url);
110
+ return;
111
+ }
112
+ win.document.open();
113
+ win.document.write(htmlDocument);
114
+ win.document.close();
115
+ }
116
+ function printHtmlContent(bodyHtml, title = "AI Response", extraStyles = "") {
117
+ const doc = buildPrintDocument(bodyHtml, title, extraStyles);
118
+ openPrintWindow(doc, title);
119
+ }
120
+ function buildFitTextScript(selectors) {
121
+ const selectorsJson = JSON.stringify([...selectors]);
122
+ return `
123
+ <script>
124
+ (function() {
125
+ function fitText(el, container) {
126
+ // container is the bounding box we must fit inside
127
+ var maxW = container.clientWidth;
128
+ var maxH = container.clientHeight;
129
+ var size = parseFloat(window.getComputedStyle(el).fontSize);
130
+ var minSize = 6;
131
+ // Give the element a chance to reflow at current size before measuring
132
+ el.style.fontSize = size + "pt";
133
+ while (size > minSize && (el.scrollWidth > maxW + 1 || el.scrollHeight > maxH + 1)) {
134
+ size -= 0.5;
135
+ el.style.fontSize = size + "pt";
136
+ }
137
+ }
138
+ function runAll() {
139
+ var selectors = ${selectorsJson};
140
+ for (var s = 0; s < selectors.length; s++) {
141
+ var els = document.querySelectorAll(selectors[s]);
142
+ for (var i = 0; i < els.length; i++) {
143
+ fitText(els[i], els[i].parentElement);
144
+ }
145
+ }
146
+ }
147
+ if (document.readyState === "loading") {
148
+ document.addEventListener("DOMContentLoaded", runAll);
149
+ } else {
150
+ // document.write pages may already be loaded
151
+ setTimeout(runAll, 0);
152
+ }
153
+ })();
154
+ <\/script>`;
155
+ }
156
+ export {
157
+ buildFitTextScript,
158
+ buildPrintDocument,
159
+ escapeHtml,
160
+ openPrintWindow,
161
+ printHtmlContent
162
+ };
163
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core.ts"],"sourcesContent":["/**\n * @ai-matrx/print/core — the Block Print contract & print-window composition.\n *\n * Ported VERBATIM from matrx-frontend `lib/block-print/block-print-utils.ts`\n * (2026-08-29 state, including the `number` and `select` PrintSetting types the\n * commerce label lane added). Zero dependencies; touches `window` only at call\n * time, so the module stays import-inert and RSC-safe.\n *\n * BlockPrinter is the only interface a host system needs to know about.\n * Each printable unit exports its own BlockPrinter alongside its render\n * component; host code only ever calls print(data, variantId, settings).\n *\n * `buildFitTextScript` is the ONE auto-shrink script (the flashcards\n * FIT_TEXT pattern, parameterized by selector so the label lane shares it).\n */\n\n// ─── Contract ────────────────────────────────────────────────────────────────\n\nexport interface PrintVariant {\n id: string;\n label: string;\n description?: string;\n}\n\n/**\n * A single user-configurable setting shown in the print dialog.\n * Extend the discriminated union for new control types\n * without breaking existing printers.\n */\nexport type PrintSetting =\n | {\n type: \"boolean\";\n id: string;\n label: string;\n description?: string;\n /** Default value shown when the dialog first opens */\n defaultValue: boolean;\n /** Which variant IDs this setting applies to. Omit = applies to all. */\n appliesTo?: string[];\n }\n | {\n /**\n * A numeric \"from → to\" range control, rendered as two small number inputs.\n * Writes two entries into the resolved PrintSettings map — one under fromId,\n * one under toId. Printers interpret 0 (or missing) as \"no bound\" by convention.\n */\n type: \"range\";\n /** Stable id used as React key — not written to the settings map */\n id: string;\n label: string;\n description?: string;\n /** Settings map key for the lower bound value */\n fromId: string;\n /** Settings map key for the upper bound value */\n toId: string;\n defaultFrom: number;\n defaultTo: number;\n /** Minimum accepted value for each input (inclusive). Default 0. */\n min?: number;\n /** Placeholder shown when the input is empty (0). Default \"start\" / \"end\". */\n fromPlaceholder?: string;\n toPlaceholder?: string;\n /** Which variant IDs this setting applies to. Omit = applies to all. */\n appliesTo?: string[];\n }\n | {\n /** A single numeric input (e.g. \"start at label #\", \"copies\"). */\n type: \"number\";\n id: string;\n label: string;\n description?: string;\n defaultValue: number;\n /** Minimum accepted value (inclusive). Default 0. */\n min?: number;\n /** Maximum accepted value (inclusive). Omit = unbounded. */\n max?: number;\n /** Which variant IDs this setting applies to. Omit = applies to all. */\n appliesTo?: string[];\n }\n | {\n /** A one-of-N choice rendered as a compact segmented row. */\n type: \"select\";\n id: string;\n label: string;\n description?: string;\n options: { value: string; label: string }[];\n defaultValue: string;\n /** Which variant IDs this setting applies to. Omit = applies to all. */\n appliesTo?: string[];\n };\n\n/** A resolved map of setting id → current value, passed to print(). */\nexport type PrintSettings = Record<string, boolean | string | number>;\n\n/**\n * The self-contained print capability that each block can export.\n * Host code only ever calls print(data, variantId, settings) — it never inspects internals.\n */\nexport interface BlockPrinter {\n /** Tooltip / aria-label for the print button in the block header */\n label: string;\n\n /**\n * Variants offered to the user before printing.\n * Empty array = no options dialog shown; prints immediately with defaults.\n */\n variants: PrintVariant[];\n\n /**\n * Optional user-configurable settings shown below the variant picker.\n * Omit entirely if the block has no configurable settings.\n */\n settings?: PrintSetting[];\n\n /**\n * Execute the print.\n * data — the block's structured data (serverData or parsed content)\n * variantId — which variant was chosen (undefined = default / no variants)\n * settings — resolved setting values chosen by the user\n */\n print: (\n data: unknown,\n variantId?: string,\n settings?: PrintSettings,\n ) => void | Promise<void>;\n}\n\n// ─── Shared Utilities ─────────────────────────────────────────────────────────\n\nconst PRINT_STYLES = `\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;\n font-size: 11pt;\n line-height: 1.6;\n color: #1a1a1a;\n background: #fff;\n max-width: 860px;\n margin: 0 auto;\n padding: 28px 36px;\n }\n\n .print-actions {\n display: flex;\n gap: 10px;\n margin-bottom: 24px;\n padding-bottom: 18px;\n border-bottom: 2px solid #e5e7eb;\n }\n\n .print-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 20px;\n border-radius: 8px;\n font-size: 13px;\n font-family: inherit;\n cursor: pointer;\n border: none;\n font-weight: 600;\n }\n\n .print-btn-primary { background: #2563eb; color: #fff; }\n .print-btn-secondary { background: #f3f4f6; color: #374151; border: 1px solid #d1d5db; }\n\n h1 { font-size: 22pt; font-weight: 700; margin-bottom: 0.5em; }\n h2 { font-size: 16pt; font-weight: 700; margin: 1.2em 0 0.4em; border-bottom: 1px solid #e5e7eb; padding-bottom: 0.2em; }\n h3 { font-size: 13pt; font-weight: 600; margin: 1em 0 0.3em; }\n p { margin-bottom: 0.7em; }\n\n table {\n width: 100%;\n border-collapse: collapse;\n margin: 1em 0;\n font-size: 10pt;\n }\n th {\n background: #1e293b;\n color: #f8fafc;\n font-weight: 600;\n text-align: left;\n padding: 7px 12px;\n border: 1px solid #334155;\n }\n td {\n padding: 6px 12px;\n border: 1px solid #e2e8f0;\n vertical-align: top;\n }\n tr:nth-child(even) td { background: #f8fafc; }\n\n @media print {\n body { max-width: 100%; padding: 0; }\n .print-actions { display: none !important; }\n th { -webkit-print-color-adjust: exact; print-color-adjust: exact; }\n }\n`;\n\nfunction escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\n/**\n * Wrap body HTML in a complete, styled print document.\n */\nexport function buildPrintDocument(\n bodyHtml: string,\n title = \"AI Response\",\n extraStyles = \"\",\n): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(title)}</title>\n <style>\n${PRINT_STYLES}\n${extraStyles}\n </style>\n</head>\n<body>\n <div class=\"print-actions\">\n <button class=\"print-btn print-btn-primary\" onclick=\"window.print()\">Print / Save as PDF</button>\n <button class=\"print-btn print-btn-secondary\" onclick=\"window.close()\">Close</button>\n </div>\n <div class=\"content\">\n${bodyHtml}\n </div>\n</body>\n</html>`;\n}\n\n/**\n * Open a new browser window and write a complete HTML document into it.\n * Falls back to downloading an .html file if the popup is blocked.\n */\nexport function openPrintWindow(\n htmlDocument: string,\n filename = \"print\",\n): void {\n const win = window.open(\"\", \"_blank\", \"width=920,height=720,scrollbars=yes\");\n if (!win) {\n // Popup blocked — fall back to file download\n const blob = new Blob([htmlDocument], { type: \"text/html;charset=utf-8\" });\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = `${filename.replace(/\\s+/g, \"-\").toLowerCase()}.html`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n return;\n }\n win.document.open();\n win.document.write(htmlDocument);\n win.document.close();\n}\n\n/**\n * Shorthand: build the document and open it in one call.\n */\nexport function printHtmlContent(\n bodyHtml: string,\n title = \"AI Response\",\n extraStyles = \"\",\n): void {\n const doc = buildPrintDocument(bodyHtml, title, extraStyles);\n openPrintWindow(doc, title);\n}\n\n/**\n * Build the auto-shrink script that runs INSIDE a printed window: for every\n * element matching each selector, its font-size is reduced (0.5pt steps, 6pt\n * floor) until it fits its parent element's box. This is the flashcards\n * FIT_TEXT behavior verbatim, parameterized by selector so every lane\n * (flashcards card text, Avery text, label captions) shares the ONE loop.\n *\n * Pass the same selectors the original used to get byte-identical behavior:\n * flashcards passes `[\".card-text .card-text-inner\", \".avery-text-wrap .avery-text\"]`.\n */\nexport function buildFitTextScript(selectors: readonly string[]): string {\n const selectorsJson = JSON.stringify([...selectors]);\n return `\n<script>\n(function() {\n function fitText(el, container) {\n // container is the bounding box we must fit inside\n var maxW = container.clientWidth;\n var maxH = container.clientHeight;\n var size = parseFloat(window.getComputedStyle(el).fontSize);\n var minSize = 6;\n // Give the element a chance to reflow at current size before measuring\n el.style.fontSize = size + \"pt\";\n while (size > minSize && (el.scrollWidth > maxW + 1 || el.scrollHeight > maxH + 1)) {\n size -= 0.5;\n el.style.fontSize = size + \"pt\";\n }\n }\n function runAll() {\n var selectors = ${selectorsJson};\n for (var s = 0; s < selectors.length; s++) {\n var els = document.querySelectorAll(selectors[s]);\n for (var i = 0; i < els.length; i++) {\n fitText(els[i], els[i].parentElement);\n }\n }\n }\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", runAll);\n } else {\n // document.write pages may already be loaded\n setTimeout(runAll, 0);\n }\n})();\n</script>`;\n}\n\nexport { escapeHtml };\n"],"mappings":";AAiIA,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuErB,SAAS,WAAW,KAAqB;AACvC,SAAO,IACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,OAAO;AAC1B;AAKO,SAAS,mBACd,UACA,QAAQ,eACR,cAAc,IACN;AACR,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,WAKE,WAAW,KAAK,CAAC;AAAA;AAAA,EAE1B,YAAY;AAAA,EACZ,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASX,QAAQ;AAAA;AAAA;AAAA;AAIV;AAMO,SAAS,gBACd,cACA,WAAW,SACL;AACN,QAAM,MAAM,OAAO,KAAK,IAAI,UAAU,qCAAqC;AAC3E,MAAI,CAAC,KAAK;AAER,UAAM,OAAO,IAAI,KAAK,CAAC,YAAY,GAAG,EAAE,MAAM,0BAA0B,CAAC;AACzE,UAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,UAAM,IAAI,SAAS,cAAc,GAAG;AACpC,MAAE,OAAO;AACT,MAAE,WAAW,GAAG,SAAS,QAAQ,QAAQ,GAAG,EAAE,YAAY,CAAC;AAC3D,aAAS,KAAK,YAAY,CAAC;AAC3B,MAAE,MAAM;AACR,aAAS,KAAK,YAAY,CAAC;AAC3B,QAAI,gBAAgB,GAAG;AACvB;AAAA,EACF;AACA,MAAI,SAAS,KAAK;AAClB,MAAI,SAAS,MAAM,YAAY;AAC/B,MAAI,SAAS,MAAM;AACrB;AAKO,SAAS,iBACd,UACA,QAAQ,eACR,cAAc,IACR;AACN,QAAM,MAAM,mBAAmB,UAAU,OAAO,WAAW;AAC3D,kBAAgB,KAAK,KAAK;AAC5B;AAYO,SAAS,mBAAmB,WAAsC;AACvE,QAAM,gBAAgB,KAAK,UAAU,CAAC,GAAG,SAAS,CAAC;AACnD,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAiBa,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBnC;","names":[]}