@fragments-sdk/ui 0.9.6 → 0.10.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 (78) hide show
  1. package/README.md +32 -24
  2. package/dist/codeblock.cjs +25 -29
  3. package/dist/codeblock.cjs.map +1 -1
  4. package/dist/codeblock.js +25 -29
  5. package/dist/codeblock.js.map +1 -1
  6. package/dist/components/Chip/index.cjs +2 -1
  7. package/dist/components/Chip/index.cjs.map +1 -1
  8. package/dist/components/Chip/index.d.ts.map +1 -1
  9. package/dist/components/Chip/index.js +2 -1
  10. package/dist/components/Chip/index.js.map +1 -1
  11. package/dist/components/CodeBlock/index.d.ts.map +1 -1
  12. package/dist/components/Command/index.cjs +6 -0
  13. package/dist/components/Command/index.cjs.map +1 -1
  14. package/dist/components/Command/index.d.ts.map +1 -1
  15. package/dist/components/Command/index.js +6 -0
  16. package/dist/components/Command/index.js.map +1 -1
  17. package/dist/components/DataTable/index.cjs +26 -26
  18. package/dist/components/DataTable/index.cjs.map +1 -1
  19. package/dist/components/DataTable/index.d.ts.map +1 -1
  20. package/dist/components/DataTable/index.js +26 -26
  21. package/dist/components/DataTable/index.js.map +1 -1
  22. package/dist/components/Listbox/index.cjs +6 -0
  23. package/dist/components/Listbox/index.cjs.map +1 -1
  24. package/dist/components/Listbox/index.d.ts.map +1 -1
  25. package/dist/components/Listbox/index.js +6 -0
  26. package/dist/components/Listbox/index.js.map +1 -1
  27. package/dist/components/Loading/index.cjs +2 -12
  28. package/dist/components/Loading/index.cjs.map +1 -1
  29. package/dist/components/Loading/index.d.ts.map +1 -1
  30. package/dist/components/Loading/index.js +2 -12
  31. package/dist/components/Loading/index.js.map +1 -1
  32. package/dist/components/NavigationMenu/index.cjs +12 -1
  33. package/dist/components/NavigationMenu/index.cjs.map +1 -1
  34. package/dist/components/NavigationMenu/index.d.ts.map +1 -1
  35. package/dist/components/NavigationMenu/index.js +12 -1
  36. package/dist/components/NavigationMenu/index.js.map +1 -1
  37. package/dist/components/Skeleton/index.cjs +3 -3
  38. package/dist/components/Skeleton/index.cjs.map +1 -1
  39. package/dist/components/Skeleton/index.js +3 -3
  40. package/dist/components/Skeleton/index.js.map +1 -1
  41. package/dist/components/Stack/index.cjs +4 -3
  42. package/dist/components/Stack/index.cjs.map +1 -1
  43. package/dist/components/Stack/index.d.ts.map +1 -1
  44. package/dist/components/Stack/index.js +4 -3
  45. package/dist/components/Stack/index.js.map +1 -1
  46. package/dist/components/Theme/index.cjs +86 -1
  47. package/dist/components/Theme/index.cjs.map +1 -1
  48. package/dist/components/Theme/index.d.ts +44 -1
  49. package/dist/components/Theme/index.d.ts.map +1 -1
  50. package/dist/components/Theme/index.js +86 -1
  51. package/dist/components/Theme/index.js.map +1 -1
  52. package/dist/index.cjs +2 -0
  53. package/dist/index.cjs.map +1 -1
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +3 -1
  57. package/dist/markdown.cjs +1 -1
  58. package/dist/markdown.cjs.map +1 -1
  59. package/dist/markdown.js +1 -1
  60. package/dist/markdown.js.map +1 -1
  61. package/fragments.json +1 -1
  62. package/package.json +6 -2
  63. package/src/components/Chip/index.tsx +3 -1
  64. package/src/components/CodeBlock/index.tsx +35 -41
  65. package/src/components/ColorPicker/ColorPicker.fragment.tsx +17 -15
  66. package/src/components/Command/index.tsx +1 -0
  67. package/src/components/DataTable/index.tsx +45 -45
  68. package/src/components/Listbox/index.tsx +1 -0
  69. package/src/components/Loading/index.tsx +6 -12
  70. package/src/components/Markdown/index.tsx +2 -2
  71. package/src/components/Menu/Menu.fragment.tsx +17 -15
  72. package/src/components/NavigationMenu/index.tsx +6 -1
  73. package/src/components/Skeleton/index.tsx +3 -3
  74. package/src/components/Slider/Slider.fragment.tsx +19 -17
  75. package/src/components/Stack/index.tsx +4 -3
  76. package/src/components/Theme/index.tsx +168 -1
  77. package/src/index.ts +6 -0
  78. package/src/tokens/_seeds.scss +20 -0
package/README.md CHANGED
@@ -16,12 +16,19 @@ npm install react react-dom
16
16
 
17
17
  ## Setup
18
18
 
19
- Import the global styles in your app entry point:
19
+ **Quick start (no SCSS)** — import the prebuilt CSS in your app entry point. This loads component styles with default tokens:
20
20
 
21
21
  ```tsx
22
22
  import '@fragments-sdk/ui/styles';
23
23
  ```
24
24
 
25
+ **Custom theming (SCSS)** — create a `.scss` file with `@use '@fragments-sdk/ui/styles' with (...)` to set your seed values, then import both:
26
+
27
+ ```tsx
28
+ import '@fragments-sdk/ui/styles'; // component styles (ui.css)
29
+ import './styles/globals.scss'; // your seed overrides
30
+ ```
31
+
25
32
  Then use components:
26
33
 
27
34
  ```tsx
@@ -116,28 +123,27 @@ All fragment and block previews are authored source snippets, not runtime-serial
116
123
 
117
124
  ### Seed-Based Configuration (Recommended)
118
125
 
119
- Configure ~5-10 seeds and everything derives automatically. Set seed variables in your SCSS before importing:
126
+ Configure ~5 seeds and everything derives automatically using the SCSS `@use ... with()` syntax:
120
127
 
121
128
  ```scss
122
129
  // styles/globals.scss
123
130
 
124
- // Minimal setup - just your brand color
125
- $fui-brand: #0066ff;
126
- @use '@fragments-sdk/ui/globals';
131
+ // Minimal setup just your brand color
132
+ @use '@fragments-sdk/ui/styles' with (
133
+ $fui-brand: #0066ff
134
+ );
127
135
  ```
128
136
 
129
137
  ```scss
130
138
  // Full customization
131
- $fui-brand: #0066ff; // Primary brand color
132
- $fui-neutral: "steel"; // Palette: "steel" | "sand" | "smoke" | "ash" | "silver"
133
- $fui-density: "compact"; // Spacing: "compact" | "default" | "relaxed"
134
- $fui-radius-style: "rounded"; // Corners: "sharp" | "subtle" | "default" | "rounded" | "pill"
135
-
136
- // Optional semantic color overrides
137
- $fui-danger: #dc2626;
138
- $fui-success: #16a34a;
139
-
140
- @use '@fragments-sdk/ui/globals';
139
+ @use '@fragments-sdk/ui/styles' with (
140
+ $fui-brand: #0066ff,
141
+ $fui-neutral: "ice",
142
+ $fui-density: "compact",
143
+ $fui-radius-style: "rounded",
144
+ $fui-danger: #dc2626,
145
+ $fui-success: #16a34a
146
+ );
141
147
  ```
142
148
 
143
149
  #### Available Seeds
@@ -145,7 +151,7 @@ $fui-success: #16a34a;
145
151
  | Seed | Type | Default | Description |
146
152
  |------|------|---------|-------------|
147
153
  | `$fui-brand` | Color | `#18181b` | Primary brand color - derives accent, focus rings, etc. |
148
- | `$fui-neutral` | String | `"ash"` | Neutral palette for surfaces, text, borders |
154
+ | `$fui-neutral` | String | `"stone"` | Neutral palette for surfaces, text, borders |
149
155
  | `$fui-density` | String | `"default"` | Spacing density scale |
150
156
  | `$fui-radius-style` | String | `"default"` | Corner radius style |
151
157
  | `$fui-danger` | Color | `#ef4444` | Error/danger semantic color |
@@ -157,11 +163,11 @@ $fui-success: #16a34a;
157
163
 
158
164
  | Name | Description |
159
165
  |------|-------------|
160
- | `steel` | Cool blue-tinted grays (professional, tech) |
161
- | `sand` | Warm brown-tinted grays (organic, approachable) |
162
- | `smoke` | Pure true grays (minimal, neutral) |
163
- | `ash` | Muted cool neutrals (subtle, balanced) - default |
164
- | `silver` | Bright clean grays (light, modern) |
166
+ | `stone` | Cool gray neutrals (balanced, professional) — default |
167
+ | `ice` | Cool blue-tinted grays (crisp, technical) |
168
+ | `earth` | Warm brown-tinted grays (natural, grounded) |
169
+ | `sand` | Warm tan-tinted grays (organic, approachable) |
170
+ | `fire` | Warm red-tinted grays (bold, energetic) |
165
171
 
166
172
  #### Density Presets
167
173
 
@@ -198,7 +204,7 @@ You can still override individual tokens directly:
198
204
  ### Breakpoints
199
205
 
200
206
  ```scss
201
- @use '@fragments-sdk/ui/tokens' as *;
207
+ @use '@fragments-sdk/ui/mixins' as *;
202
208
 
203
209
  .responsive {
204
210
  @include breakpoint-md {
@@ -238,8 +244,10 @@ You can still override individual tokens directly:
238
244
  // ...many more
239
245
 
240
246
  // After: just seeds
241
- $fui-brand: #0066ff;
242
- $fui-neutral: "steel";
247
+ @use '@fragments-sdk/ui/styles' with (
248
+ $fui-brand: #0066ff,
249
+ $fui-neutral: "ice"
250
+ );
243
251
  ```
244
252
 
245
253
  2. Dark mode, hover states, and derived colors are computed automatically
@@ -356,8 +356,7 @@ const CodeBlockBase = React__namespace.forwardRef(function CodeBlock2({
356
356
  ...htmlProps
357
357
  }, ref) {
358
358
  const [copied, setCopied] = React.useState(false);
359
- const [highlightedHtml, setHighlightedHtml] = React.useState("");
360
- const [isLoading, setIsLoading] = React.useState(true);
359
+ const [highlight, setHighlight] = React.useState({ html: "", loading: true });
361
360
  const [isCollapsed, setIsCollapsed] = React.useState(defaultCollapsed);
362
361
  const trimmedCode = React.useMemo(() => normalizeCode(code), [code]);
363
362
  const codeLines = trimmedCode.split("\n");
@@ -374,40 +373,37 @@ const CodeBlockBase = React__namespace.forwardRef(function CodeBlock2({
374
373
  const shouldRenderHeader = Boolean(filename) || shouldShowHeaderCopy;
375
374
  React.useEffect(() => {
376
375
  let cancelled = false;
377
- setIsLoading(true);
378
- loadShikiDeps();
379
- if (_shikiFailed || !_codeToHtml) {
380
- if (_shikiFailed && process.env.NODE_ENV === "development") {
381
- console.warn(
382
- "[@fragments-sdk/ui] CodeBlock: shiki is not installed. Install it with: npm install shiki"
383
- );
376
+ setHighlight((prev) => ({ ...prev, loading: true }));
377
+ const run = async () => {
378
+ loadShikiDeps();
379
+ const fallbackHtml = `<pre class="shiki"><code>${escapeHtml(visibleCode)}</code></pre>`;
380
+ if (_shikiFailed || !_codeToHtml) {
381
+ if (_shikiFailed && process.env.NODE_ENV === "development") {
382
+ console.warn(
383
+ "[@fragments-sdk/ui] CodeBlock: shiki is not installed. Install it with: npm install shiki"
384
+ );
385
+ }
386
+ return fallbackHtml;
384
387
  }
385
- setHighlightedHtml(`<pre class="shiki"><code>${escapeHtml(visibleCode)}</code></pre>`);
386
- setIsLoading(false);
387
- return;
388
- }
389
- _codeToHtml(visibleCode, {
390
- lang: language,
391
- theme
392
- }).then((html) => {
393
- if (!cancelled) {
394
- const processed = processShikiHtml(html, {
388
+ try {
389
+ const html = await _codeToHtml(visibleCode, { lang: language, theme });
390
+ return processShikiHtml(html, {
395
391
  showLineNumbers,
396
392
  startLineNumber,
397
393
  highlightLines: highlightSet,
398
394
  addedLines: addedSet,
399
395
  removedLines: removedSet
400
396
  });
401
- setHighlightedHtml(processed);
402
- setIsLoading(false);
403
- }
404
- }).catch((err) => {
405
- if (process.env.NODE_ENV !== "production") {
406
- console.error("Syntax highlighting failed:", err);
397
+ } catch (err) {
398
+ if (process.env.NODE_ENV !== "production") {
399
+ console.error("Syntax highlighting failed:", err);
400
+ }
401
+ return fallbackHtml;
407
402
  }
403
+ };
404
+ run().then((html) => {
408
405
  if (!cancelled) {
409
- setHighlightedHtml(`<pre class="shiki"><code>${escapeHtml(visibleCode)}</code></pre>`);
410
- setIsLoading(false);
406
+ setHighlight({ html, loading: false });
411
407
  }
412
408
  });
413
409
  return () => {
@@ -478,12 +474,12 @@ const CodeBlockBase = React__namespace.forwardRef(function CodeBlock2({
478
474
  children: copied ? /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: CodeBlock_module.default.icon }) : /* @__PURE__ */ jsxRuntime.jsx(CopyIcon, { className: CodeBlock_module.default.icon })
479
475
  }
480
476
  ),
481
- isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: CodeBlock_module.default.loading, style: codeContainerStyle, children: /* @__PURE__ */ jsxRuntime.jsx("pre", { children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: visibleCode }) }) }) : /* @__PURE__ */ jsxRuntime.jsx(
477
+ highlight.loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: CodeBlock_module.default.loading, style: codeContainerStyle, children: /* @__PURE__ */ jsxRuntime.jsx("pre", { children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: visibleCode }) }) }) : /* @__PURE__ */ jsxRuntime.jsx(
482
478
  "div",
483
479
  {
484
480
  className: CodeBlock_module.default.codeContainer,
485
481
  style: codeContainerStyle,
486
- dangerouslySetInnerHTML: { __html: highlightedHtml }
482
+ dangerouslySetInnerHTML: { __html: highlight.html }
487
483
  }
488
484
  ),
489
485
  persistentCopy && /* @__PURE__ */ jsxRuntime.jsx(
@@ -1 +1 @@
1
- {"version":3,"file":"codeblock.cjs","sources":["../src/components/CodeBlock/index.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useState, useCallback, useEffect, useMemo } from \"react\";\n// ============================================\n// Lazy-loaded dependency (shiki)\n// ============================================\n\nlet _codeToHtml:\n | ((code: string, options: { lang: string; theme: string }) => Promise<string>)\n | null = null;\nlet _shikiLoaded = false;\nlet _shikiFailed = false;\n\nfunction loadShikiDeps() {\n if (_shikiLoaded) return;\n _shikiLoaded = true;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const shiki = require(\"shiki\");\n _codeToHtml = shiki.codeToHtml;\n } catch {\n _shikiFailed = true;\n }\n}\nimport { TabsRoot, TabsList, Tab, TabsPanel } from \"../Tabs\";\nimport { Button } from \"../Button\";\nimport styles from \"./CodeBlock.module.scss\";\nimport \"../../styles/globals.scss\";\n\nexport type CodeBlockLanguage =\n | \"tsx\"\n | \"typescript\"\n | \"javascript\"\n | \"jsx\"\n | \"bash\"\n | \"shell\"\n | \"css\"\n | \"scss\"\n | \"sass\"\n | \"json\"\n | \"html\"\n | \"xml\"\n | \"markdown\"\n | \"md\"\n | \"yaml\"\n | \"yml\"\n | \"python\"\n | \"py\"\n | \"ruby\"\n | \"go\"\n | \"rust\"\n | \"java\"\n | \"kotlin\"\n | \"swift\"\n | \"c\"\n | \"cpp\"\n | \"csharp\"\n | \"php\"\n | \"sql\"\n | \"graphql\"\n | \"diff\"\n | \"plaintext\";\n\n/** Available syntax highlighting themes */\nexport type CodeBlockTheme =\n | \"synthwave-84\"\n | \"github-dark\"\n | \"github-light\"\n | \"one-dark-pro\"\n | \"dracula\"\n | \"nord\"\n | \"monokai\"\n | \"vitesse-dark\"\n | \"vitesse-light\"\n | \"min-dark\"\n | \"min-light\";\n\nexport type CodeBlockCopyPlacement = \"auto\" | \"header\" | \"overlay\";\n\nexport interface CodeBlockProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Code string to display */\n code: string;\n /** Programming language for syntax highlighting */\n language?: CodeBlockLanguage;\n /** Syntax highlighting theme */\n theme?: CodeBlockTheme;\n /** Show copy button */\n showCopy?: boolean;\n /** Optional title above code block (external label) */\n title?: string;\n /** Optional filename shown in header bar inside code block */\n filename?: string;\n /** Optional caption below code block */\n caption?: string;\n /** Show line numbers */\n showLineNumbers?: boolean;\n /** Starting line number (default: 1) */\n startLineNumber?: number;\n /** Highlight specific lines (e.g., [1, 3, '5-7']) */\n highlightLines?: (number | string)[];\n /** Lines marked as added in diff view */\n addedLines?: (number | string)[];\n /** Lines marked as removed in diff view */\n removedLines?: (number | string)[];\n /** Enable word wrapping for long lines */\n wordWrap?: boolean;\n /** Maximum height in pixels (enables scrolling) */\n maxHeight?: number;\n /** Allow collapsing/expanding the code block */\n collapsible?: boolean;\n /** Initial collapsed state (only applies when collapsible is true) */\n defaultCollapsed?: boolean;\n /** Number of lines to show when collapsed */\n collapsedLines?: number;\n /** Compact mode with reduced padding */\n compact?: boolean;\n /** Show a persistent copy button (always visible, uses Button component) */\n persistentCopy?: boolean;\n /** Placement of copy button when not using persistent copy */\n copyPlacement?: CodeBlockCopyPlacement;\n /** Callback fired when the copy button is clicked and copy succeeds */\n onCopy?: () => void;\n}\n\nfunction CopyIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n );\n}\n\nfunction CheckIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n );\n}\n\nfunction ChevronDownIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n );\n}\n\nfunction ChevronUpIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"18 15 12 9 6 15\" />\n </svg>\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, \"&#039;\");\n}\n\n/**\n * Remove common leading whitespace from all lines (dedent).\n * This handles template literals that have extra indentation from code formatting.\n */\nfunction dedent(str: string): string {\n const lines = str.split(\"\\n\");\n\n // Find the minimum indentation (ignoring empty lines)\n let minIndent = Infinity;\n for (const line of lines) {\n if (line.trim() === \"\") continue;\n const match = line.match(/^(\\s*)/);\n if (match) {\n minIndent = Math.min(minIndent, match[1].length);\n }\n }\n\n // If no indentation found, return as-is\n if (minIndent === Infinity || minIndent === 0) {\n return str;\n }\n\n // Remove the common indentation from all lines\n return lines.map((line) => line.slice(minIndent)).join(\"\\n\");\n}\n\n/**\n * Normalize indentation while handling JSX where first line is already at column 0.\n */\nfunction normalizeIndentation(str: string): string {\n const lines = str.split(\"\\n\");\n if (lines.length <= 1) return str;\n\n let minIndent = Infinity;\n const firstLineIndent = lines[0].match(/^(\\s*)/)?.[1].length ?? 0;\n\n for (let i = 1; i < lines.length; i += 1) {\n const line = lines[i];\n if (line.trim().length === 0) continue;\n const indent = line.match(/^(\\s*)/)?.[1].length ?? 0;\n minIndent = Math.min(minIndent, indent);\n }\n\n if (firstLineIndent > 0) {\n minIndent = Math.min(minIndent, firstLineIndent);\n }\n\n if (minIndent === Infinity || minIndent === 0) return str;\n\n return lines\n .map((line) => line.slice(Math.min(minIndent, line.match(/^(\\s*)/)?.[1].length ?? 0)))\n .join(\"\\n\");\n}\n\nfunction trimTrailingWhitespace(str: string): string {\n return str\n .split(\"\\n\")\n .map((line) => line.replace(/[ \\t]+$/g, \"\"))\n .join(\"\\n\");\n}\n\nfunction findTagEnd(line: string): number {\n let quote: '\"' | \"'\" | \"`\" | null = null;\n let escaped = false;\n let braceDepth = 0;\n let bracketDepth = 0;\n let parenDepth = 0;\n\n for (let i = 1; i < line.length; i += 1) {\n const char = line[i];\n\n if (quote) {\n if (char === \"\\\\\" && !escaped) {\n escaped = true;\n continue;\n }\n if (char === quote && !escaped) {\n quote = null;\n }\n escaped = false;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n quote = char;\n continue;\n }\n\n if (char === \"{\") braceDepth += 1;\n else if (char === \"}\") braceDepth = Math.max(0, braceDepth - 1);\n else if (char === \"[\") bracketDepth += 1;\n else if (char === \"]\") bracketDepth = Math.max(0, bracketDepth - 1);\n else if (char === \"(\") parenDepth += 1;\n else if (char === \")\") parenDepth = Math.max(0, parenDepth - 1);\n else if (char === \">\" && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {\n return i;\n }\n }\n\n return -1;\n}\n\nfunction splitJsxAttributes(attrs: string): string[] {\n const parts: string[] = [];\n let current = \"\";\n let quote: '\"' | \"'\" | \"`\" | null = null;\n let escaped = false;\n let braceDepth = 0;\n let bracketDepth = 0;\n let parenDepth = 0;\n\n for (const char of attrs) {\n if (quote) {\n current += char;\n if (char === \"\\\\\" && !escaped) {\n escaped = true;\n continue;\n }\n if (char === quote && !escaped) {\n quote = null;\n }\n escaped = false;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n quote = char;\n current += char;\n continue;\n }\n\n if (char === \"{\") braceDepth += 1;\n else if (char === \"}\") braceDepth = Math.max(0, braceDepth - 1);\n else if (char === \"[\") bracketDepth += 1;\n else if (char === \"]\") bracketDepth = Math.max(0, bracketDepth - 1);\n else if (char === \"(\") parenDepth += 1;\n else if (char === \")\") parenDepth = Math.max(0, parenDepth - 1);\n\n if (/\\s/.test(char) && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {\n if (current.trim().length > 0) {\n parts.push(current.trim());\n current = \"\";\n }\n continue;\n }\n\n current += char;\n }\n\n if (current.trim().length > 0) {\n parts.push(current.trim());\n }\n\n return parts;\n}\n\nfunction formatLongJsxTagLine(line: string): string {\n const maxInlineLength = 110;\n if (line.length <= maxInlineLength) return line;\n\n const indent = line.match(/^(\\s*)/)?.[1] ?? \"\";\n const trimmed = line.trimStart();\n\n if (\n !trimmed.startsWith(\"<\") ||\n trimmed.startsWith(\"</\") ||\n trimmed.startsWith(\"<!\") ||\n trimmed.startsWith(\"<?\")\n ) {\n return line;\n }\n\n const tagEnd = findTagEnd(trimmed);\n if (tagEnd === -1) return line;\n if (trimmed.slice(tagEnd + 1).trim().length > 0) return line;\n\n const rawTagBody = trimmed.slice(1, tagEnd).trim();\n const isSelfClosing = rawTagBody.endsWith(\"/\");\n const tagBody = isSelfClosing ? rawTagBody.slice(0, -1).trimEnd() : rawTagBody;\n const firstSpace = tagBody.search(/\\s/);\n if (firstSpace === -1) return line;\n\n const tagName = tagBody.slice(0, firstSpace);\n if (!/^[A-Za-z][\\w.:-]*$/.test(tagName)) return line;\n\n const attrsSource = tagBody.slice(firstSpace).trim();\n if (!attrsSource.includes(\"=\") && !attrsSource.includes(\"{...\")) return line;\n\n const attrs = splitJsxAttributes(attrsSource);\n if (attrs.length === 0) return line;\n\n const attrIndent = `${indent} `;\n const close = isSelfClosing ? \"/>\" : \">\";\n\n return [\n `${indent}<${tagName}`,\n ...attrs.map((attr) => `${attrIndent}${attr}`),\n `${indent}${close}`,\n ].join(\"\\n\");\n}\n\nfunction formatLongJsxTags(code: string): string {\n return code\n .split(\"\\n\")\n .flatMap((line) => formatLongJsxTagLine(line).split(\"\\n\"))\n .join(\"\\n\");\n}\n\nfunction normalizeCode(code: string): string {\n const trimmed = code.trim();\n if (trimmed.length === 0) return \"\";\n\n const normalized = normalizeIndentation(trimmed);\n const dedented = dedent(normalized);\n const withoutTrailingWhitespace = trimTrailingWhitespace(dedented);\n return formatLongJsxTags(withoutTrailingWhitespace);\n}\n\n/**\n * Parse line specification into a Set of line numbers.\n * Supports: [1, 3, '5-7'] -> Set {1, 3, 5, 6, 7}\n */\nfunction parseLineSpec(spec?: (number | string)[]): Set<number> {\n const lines = new Set<number>();\n if (!spec) return lines;\n\n for (const item of spec) {\n if (typeof item === \"number\") {\n lines.add(item);\n } else if (typeof item === \"string\") {\n const rangeMatch = item.match(/^(\\d+)-(\\d+)$/);\n if (rangeMatch) {\n const start = parseInt(rangeMatch[1], 10);\n const end = parseInt(rangeMatch[2], 10);\n for (let i = start; i <= end; i++) {\n lines.add(i);\n }\n } else {\n const num = parseInt(item, 10);\n if (!isNaN(num)) {\n lines.add(num);\n }\n }\n }\n }\n\n return lines;\n}\n\ninterface ProcessOptions {\n showLineNumbers: boolean;\n startLineNumber: number;\n highlightLines: Set<number>;\n addedLines: Set<number>;\n removedLines: Set<number>;\n}\n\n/**\n * Add line numbers, highlight classes, and diff markers to Shiki HTML output.\n */\nfunction processShikiHtml(html: string, options: ProcessOptions): string {\n const { showLineNumbers, startLineNumber, highlightLines, addedLines, removedLines } = options;\n const hasDiff = addedLines.size > 0 || removedLines.size > 0;\n\n if (!showLineNumbers && highlightLines.size === 0 && !hasDiff) {\n return html;\n }\n\n // Extract the code content from Shiki output\n // Shiki outputs: <pre class=\"shiki ...\"><code>...lines...</code></pre>\n const codeMatch = html.match(/<code[^>]*>([\\s\\S]*?)<\\/code>/);\n if (!codeMatch) return html;\n\n const codeContent = codeMatch[1];\n const lines = codeContent.split(\"\\n\");\n\n // Process each line\n const processedLines = lines.map((line, index) => {\n const lineNum = index + 1;\n const displayLineNum = startLineNumber + index;\n const isHighlighted = highlightLines.has(lineNum);\n const isAdded = addedLines.has(lineNum);\n const isRemoved = removedLines.has(lineNum);\n\n const lineClasses = [\"line\"];\n if (isHighlighted) lineClasses.push(\"highlighted\");\n if (isAdded) lineClasses.push(\"diff-added\");\n if (isRemoved) lineClasses.push(\"diff-removed\");\n\n const lineClass = lineClasses.join(\" \");\n const diffMarker = isAdded ? \"+\" : isRemoved ? \"-\" : \" \";\n\n if (showLineNumbers || hasDiff) {\n const lineNumHtml = showLineNumbers\n ? `<span class=\"line-number\">${displayLineNum}</span>`\n : \"\";\n const diffMarkerHtml = hasDiff ? `<span class=\"diff-marker\">${diffMarker}</span>` : \"\";\n return `<span class=\"${lineClass}\">${lineNumHtml}${diffMarkerHtml}${line}</span>`;\n }\n return `<span class=\"${lineClass}\">${line}</span>`;\n });\n\n // Reconstruct the HTML\n return html.replace(/<code[^>]*>[\\s\\S]*?<\\/code>/, `<code>${processedLines.join(\"\\n\")}</code>`);\n}\n\nconst CodeBlockBase = React.forwardRef<HTMLDivElement, CodeBlockProps>(function CodeBlock(\n {\n code,\n language = \"tsx\",\n theme = \"one-dark-pro\",\n showCopy = true,\n title,\n filename,\n caption,\n showLineNumbers = false,\n startLineNumber = 1,\n highlightLines,\n addedLines,\n removedLines,\n wordWrap = false,\n maxHeight,\n collapsible = false,\n defaultCollapsed = false,\n collapsedLines = 5,\n compact = false,\n persistentCopy = false,\n copyPlacement = \"auto\",\n onCopy,\n className,\n ...htmlProps\n },\n ref\n) {\n const [copied, setCopied] = useState(false);\n const [highlightedHtml, setHighlightedHtml] = useState<string>(\"\");\n const [isLoading, setIsLoading] = useState(true);\n const [isCollapsed, setIsCollapsed] = useState(defaultCollapsed);\n\n const trimmedCode = useMemo(() => normalizeCode(code), [code]);\n const codeLines = trimmedCode.split(\"\\n\");\n const totalLines = codeLines.length;\n const shouldShowCollapse = collapsible && totalLines > collapsedLines;\n\n // Compute visible code when collapsed\n const visibleCode =\n shouldShowCollapse && isCollapsed ? codeLines.slice(0, collapsedLines).join(\"\\n\") : trimmedCode;\n\n const highlightSet = useMemo(() => parseLineSpec(highlightLines), [highlightLines]);\n const addedSet = useMemo(() => parseLineSpec(addedLines), [addedLines]);\n const removedSet = useMemo(() => parseLineSpec(removedLines), [removedLines]);\n const hasDiff = addedSet.size > 0 || removedSet.size > 0;\n const resolvedCopyPlacement =\n copyPlacement === \"auto\" ? (filename ? \"header\" : \"overlay\") : copyPlacement;\n const shouldShowHeaderCopy = showCopy && !persistentCopy && resolvedCopyPlacement === \"header\";\n const shouldShowOverlayCopy = showCopy && !persistentCopy && resolvedCopyPlacement === \"overlay\";\n const shouldRenderHeader = Boolean(filename) || shouldShowHeaderCopy;\n\n // Apply syntax highlighting\n useEffect(() => {\n let cancelled = false;\n setIsLoading(true);\n\n loadShikiDeps();\n\n if (_shikiFailed || !_codeToHtml) {\n if (_shikiFailed && process.env.NODE_ENV === \"development\") {\n console.warn(\n \"[@fragments-sdk/ui] CodeBlock: shiki is not installed. \" +\n \"Install it with: npm install shiki\"\n );\n }\n // Fallback to plain text without syntax highlighting\n setHighlightedHtml(`<pre class=\"shiki\"><code>${escapeHtml(visibleCode)}</code></pre>`);\n setIsLoading(false);\n return;\n }\n\n _codeToHtml(visibleCode, {\n lang: language,\n theme,\n })\n .then((html) => {\n if (!cancelled) {\n const processed = processShikiHtml(html, {\n showLineNumbers,\n startLineNumber,\n highlightLines: highlightSet,\n addedLines: addedSet,\n removedLines: removedSet,\n });\n setHighlightedHtml(processed);\n setIsLoading(false);\n }\n })\n .catch((err) => {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(\"Syntax highlighting failed:\", err);\n }\n if (!cancelled) {\n // Fallback to plain text\n setHighlightedHtml(`<pre class=\"shiki\"><code>${escapeHtml(visibleCode)}</code></pre>`);\n setIsLoading(false);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [\n visibleCode,\n language,\n theme,\n showLineNumbers,\n startLineNumber,\n highlightSet,\n addedSet,\n removedSet,\n ]);\n\n const handleCopy = useCallback(async () => {\n try {\n // Always copy the full code, even when collapsed\n await navigator.clipboard.writeText(trimmedCode);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n onCopy?.();\n } catch (err) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(\"Failed to copy:\", err);\n }\n }\n }, [trimmedCode, onCopy]);\n\n const toggleCollapsed = useCallback(() => {\n setIsCollapsed((prev) => !prev);\n }, []);\n\n const classNames = [\n styles.container,\n showLineNumbers && styles.withLineNumbers,\n hasDiff && styles.withDiff,\n wordWrap && styles.wordWrap,\n compact && styles.compact,\n className,\n ]\n .filter(Boolean)\n .join(\" \");\n\n const wrapperClasses = [\n styles.wrapper,\n persistentCopy && styles.persistentCopyWrapper,\n shouldShowOverlayCopy && styles.withCopyOverlay,\n ]\n .filter(Boolean)\n .join(\" \");\n\n const codeContainerStyle: React.CSSProperties = maxHeight ? { maxHeight, overflow: \"auto\" } : {};\n\n return (\n <div ref={ref} {...htmlProps} className={classNames} data-theme=\"dark\">\n {title && <div className={styles.title}>{title}</div>}\n <div className={wrapperClasses}>\n {shouldRenderHeader && (\n <div className={styles.header}>\n <span className={styles.filename}>{filename ?? \"\"}</span>\n {shouldShowHeaderCopy && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className={`${styles.copyButton} ${copied ? styles.copied : \"\"}`}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n {copied ? (\n <CheckIcon className={styles.icon} />\n ) : (\n <CopyIcon className={styles.icon} />\n )}\n </button>\n )}\n </div>\n )}\n {shouldShowOverlayCopy && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className={`${styles.copyButton} ${styles.copyOverlay} ${copied ? styles.copied : \"\"}`}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n {copied ? <CheckIcon className={styles.icon} /> : <CopyIcon className={styles.icon} />}\n </button>\n )}\n {isLoading ? (\n <div className={styles.loading} style={codeContainerStyle}>\n <pre>\n <code>{visibleCode}</code>\n </pre>\n </div>\n ) : (\n <div\n className={styles.codeContainer}\n style={codeContainerStyle}\n dangerouslySetInnerHTML={{ __html: highlightedHtml }}\n />\n )}\n {persistentCopy && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className={`${styles.persistentCopy} ${styles.copyButton} ${styles.copyOverlay} ${copied ? styles.copied : \"\"}`}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n {copied ? <CheckIcon className={styles.icon} /> : <CopyIcon className={styles.icon} />}\n </button>\n )}\n {shouldShowCollapse && (\n <button\n type=\"button\"\n onClick={toggleCollapsed}\n className={styles.collapseButton}\n aria-expanded={!isCollapsed}\n aria-label={isCollapsed ? \"Expand code\" : \"Collapse code\"}\n >\n {isCollapsed ? (\n <>\n <ChevronDownIcon className={styles.icon} />\n <span>Show {totalLines - collapsedLines} more lines</span>\n </>\n ) : (\n <>\n <ChevronUpIcon className={styles.icon} />\n <span>Show less</span>\n </>\n )}\n </button>\n )}\n </div>\n {caption && <div className={styles.caption}>{caption}</div>}\n </div>\n );\n});\n\n// ============================================\n// Tabbed Code Block\n// ============================================\n\nexport interface CodeBlockTab {\n /** Label shown in the tab */\n label: string;\n /** Code string to display */\n code: string;\n /** Programming language for syntax highlighting */\n language?: CodeBlockLanguage;\n}\n\nexport interface TabbedCodeBlockProps {\n /** Array of code tabs */\n tabs: CodeBlockTab[];\n /** Default selected tab (by label) */\n defaultTab?: string;\n /** Show copy button */\n showCopy?: boolean;\n /** Placement of copy button when not using persistent copy */\n copyPlacement?: CodeBlockCopyPlacement;\n /** Show line numbers */\n showLineNumbers?: boolean;\n /** Syntax highlighting theme (applies to all tabs) */\n theme?: CodeBlockTheme;\n /** Tab list visual style */\n tabsVariant?: \"underline\" | \"pills\";\n /** Enable word wrapping for long lines */\n wordWrap?: boolean;\n /** Maximum height in pixels (enables scrolling) */\n maxHeight?: number;\n /** Additional class name */\n className?: string;\n /** Callback fired when a tab's copy button is clicked. Receives the tab label. */\n onCopy?: (tabLabel: string) => void;\n}\n\nfunction TabbedCodeBlock({\n tabs,\n defaultTab,\n showCopy = true,\n copyPlacement = \"auto\",\n showLineNumbers = false,\n theme,\n tabsVariant = \"pills\",\n wordWrap,\n maxHeight,\n className,\n onCopy,\n}: TabbedCodeBlockProps) {\n const defaultValue = defaultTab || tabs[0]?.label || \"\";\n\n return (\n <div className={className}>\n <TabsRoot defaultValue={defaultValue}>\n <TabsList variant={tabsVariant}>\n {tabs.map((tab) => (\n <Tab key={tab.label} value={tab.label}>\n {tab.label}\n </Tab>\n ))}\n </TabsList>\n {tabs.map((tab) => (\n <TabsPanel key={tab.label} value={tab.label} flush className={styles.tabbedPanel}>\n <CodeBlockBase\n code={tab.code}\n language={tab.language}\n theme={theme}\n showCopy={showCopy}\n copyPlacement={copyPlacement}\n showLineNumbers={showLineNumbers}\n wordWrap={wordWrap}\n maxHeight={maxHeight}\n onCopy={onCopy ? () => onCopy(tab.label) : undefined}\n />\n </TabsPanel>\n ))}\n </TabsRoot>\n </div>\n );\n}\n\n// ============================================\n// Export compound component\n// ============================================\n\nexport const CodeBlock = Object.assign(CodeBlockBase, {\n Tabbed: TabbedCodeBlock,\n});\n\nexport { TabbedCodeBlock };\n"],"names":["jsxs","jsx","_a","index","React","CodeBlock","useState","useMemo","useEffect","useCallback","styles","Fragment","TabsRoot","TabsList","Tab","TabsPanel"],"mappings":"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"}
1
+ {"version":3,"file":"codeblock.cjs","sources":["../src/components/CodeBlock/index.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useState, useCallback, useEffect, useMemo } from \"react\";\n// ============================================\n// Lazy-loaded dependency (shiki)\n// ============================================\n\nlet _codeToHtml:\n | ((code: string, options: { lang: string; theme: string }) => Promise<string>)\n | null = null;\nlet _shikiLoaded = false;\nlet _shikiFailed = false;\n\nfunction loadShikiDeps() {\n if (_shikiLoaded) return;\n _shikiLoaded = true;\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const shiki = require(\"shiki\");\n _codeToHtml = shiki.codeToHtml;\n } catch {\n _shikiFailed = true;\n }\n}\nimport { TabsRoot, TabsList, Tab, TabsPanel } from \"../Tabs\";\nimport { Button } from \"../Button\";\nimport styles from \"./CodeBlock.module.scss\";\nimport \"../../styles/globals.scss\";\n\nexport type CodeBlockLanguage =\n | \"tsx\"\n | \"typescript\"\n | \"javascript\"\n | \"jsx\"\n | \"bash\"\n | \"shell\"\n | \"css\"\n | \"scss\"\n | \"sass\"\n | \"json\"\n | \"html\"\n | \"xml\"\n | \"markdown\"\n | \"md\"\n | \"yaml\"\n | \"yml\"\n | \"python\"\n | \"py\"\n | \"ruby\"\n | \"go\"\n | \"rust\"\n | \"java\"\n | \"kotlin\"\n | \"swift\"\n | \"c\"\n | \"cpp\"\n | \"csharp\"\n | \"php\"\n | \"sql\"\n | \"graphql\"\n | \"diff\"\n | \"plaintext\";\n\n/** Available syntax highlighting themes */\nexport type CodeBlockTheme =\n | \"synthwave-84\"\n | \"github-dark\"\n | \"github-light\"\n | \"one-dark-pro\"\n | \"dracula\"\n | \"nord\"\n | \"monokai\"\n | \"vitesse-dark\"\n | \"vitesse-light\"\n | \"min-dark\"\n | \"min-light\";\n\nexport type CodeBlockCopyPlacement = \"auto\" | \"header\" | \"overlay\";\n\nexport interface CodeBlockProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Code string to display */\n code: string;\n /** Programming language for syntax highlighting */\n language?: CodeBlockLanguage;\n /** Syntax highlighting theme */\n theme?: CodeBlockTheme;\n /** Show copy button */\n showCopy?: boolean;\n /** Optional title above code block (external label) */\n title?: string;\n /** Optional filename shown in header bar inside code block */\n filename?: string;\n /** Optional caption below code block */\n caption?: string;\n /** Show line numbers */\n showLineNumbers?: boolean;\n /** Starting line number (default: 1) */\n startLineNumber?: number;\n /** Highlight specific lines (e.g., [1, 3, '5-7']) */\n highlightLines?: (number | string)[];\n /** Lines marked as added in diff view */\n addedLines?: (number | string)[];\n /** Lines marked as removed in diff view */\n removedLines?: (number | string)[];\n /** Enable word wrapping for long lines */\n wordWrap?: boolean;\n /** Maximum height in pixels (enables scrolling) */\n maxHeight?: number;\n /** Allow collapsing/expanding the code block */\n collapsible?: boolean;\n /** Initial collapsed state (only applies when collapsible is true) */\n defaultCollapsed?: boolean;\n /** Number of lines to show when collapsed */\n collapsedLines?: number;\n /** Compact mode with reduced padding */\n compact?: boolean;\n /** Show a persistent copy button (always visible, uses Button component) */\n persistentCopy?: boolean;\n /** Placement of copy button when not using persistent copy */\n copyPlacement?: CodeBlockCopyPlacement;\n /** Callback fired when the copy button is clicked and copy succeeds */\n onCopy?: () => void;\n}\n\nfunction CopyIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n );\n}\n\nfunction CheckIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n );\n}\n\nfunction ChevronDownIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n );\n}\n\nfunction ChevronUpIcon({ className }: { className?: string }) {\n return (\n <svg\n className={className}\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"18 15 12 9 6 15\" />\n </svg>\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, \"&#039;\");\n}\n\n/**\n * Remove common leading whitespace from all lines (dedent).\n * This handles template literals that have extra indentation from code formatting.\n */\nfunction dedent(str: string): string {\n const lines = str.split(\"\\n\");\n\n // Find the minimum indentation (ignoring empty lines)\n let minIndent = Infinity;\n for (const line of lines) {\n if (line.trim() === \"\") continue;\n const match = line.match(/^(\\s*)/);\n if (match) {\n minIndent = Math.min(minIndent, match[1].length);\n }\n }\n\n // If no indentation found, return as-is\n if (minIndent === Infinity || minIndent === 0) {\n return str;\n }\n\n // Remove the common indentation from all lines\n return lines.map((line) => line.slice(minIndent)).join(\"\\n\");\n}\n\n/**\n * Normalize indentation while handling JSX where first line is already at column 0.\n */\nfunction normalizeIndentation(str: string): string {\n const lines = str.split(\"\\n\");\n if (lines.length <= 1) return str;\n\n let minIndent = Infinity;\n const firstLineIndent = lines[0].match(/^(\\s*)/)?.[1].length ?? 0;\n\n for (let i = 1; i < lines.length; i += 1) {\n const line = lines[i];\n if (line.trim().length === 0) continue;\n const indent = line.match(/^(\\s*)/)?.[1].length ?? 0;\n minIndent = Math.min(minIndent, indent);\n }\n\n if (firstLineIndent > 0) {\n minIndent = Math.min(minIndent, firstLineIndent);\n }\n\n if (minIndent === Infinity || minIndent === 0) return str;\n\n return lines\n .map((line) => line.slice(Math.min(minIndent, line.match(/^(\\s*)/)?.[1].length ?? 0)))\n .join(\"\\n\");\n}\n\nfunction trimTrailingWhitespace(str: string): string {\n return str\n .split(\"\\n\")\n .map((line) => line.replace(/[ \\t]+$/g, \"\"))\n .join(\"\\n\");\n}\n\nfunction findTagEnd(line: string): number {\n let quote: '\"' | \"'\" | \"`\" | null = null;\n let escaped = false;\n let braceDepth = 0;\n let bracketDepth = 0;\n let parenDepth = 0;\n\n for (let i = 1; i < line.length; i += 1) {\n const char = line[i];\n\n if (quote) {\n if (char === \"\\\\\" && !escaped) {\n escaped = true;\n continue;\n }\n if (char === quote && !escaped) {\n quote = null;\n }\n escaped = false;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n quote = char;\n continue;\n }\n\n if (char === \"{\") braceDepth += 1;\n else if (char === \"}\") braceDepth = Math.max(0, braceDepth - 1);\n else if (char === \"[\") bracketDepth += 1;\n else if (char === \"]\") bracketDepth = Math.max(0, bracketDepth - 1);\n else if (char === \"(\") parenDepth += 1;\n else if (char === \")\") parenDepth = Math.max(0, parenDepth - 1);\n else if (char === \">\" && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {\n return i;\n }\n }\n\n return -1;\n}\n\nfunction splitJsxAttributes(attrs: string): string[] {\n const parts: string[] = [];\n let current = \"\";\n let quote: '\"' | \"'\" | \"`\" | null = null;\n let escaped = false;\n let braceDepth = 0;\n let bracketDepth = 0;\n let parenDepth = 0;\n\n for (const char of attrs) {\n if (quote) {\n current += char;\n if (char === \"\\\\\" && !escaped) {\n escaped = true;\n continue;\n }\n if (char === quote && !escaped) {\n quote = null;\n }\n escaped = false;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n quote = char;\n current += char;\n continue;\n }\n\n if (char === \"{\") braceDepth += 1;\n else if (char === \"}\") braceDepth = Math.max(0, braceDepth - 1);\n else if (char === \"[\") bracketDepth += 1;\n else if (char === \"]\") bracketDepth = Math.max(0, bracketDepth - 1);\n else if (char === \"(\") parenDepth += 1;\n else if (char === \")\") parenDepth = Math.max(0, parenDepth - 1);\n\n if (/\\s/.test(char) && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {\n if (current.trim().length > 0) {\n parts.push(current.trim());\n current = \"\";\n }\n continue;\n }\n\n current += char;\n }\n\n if (current.trim().length > 0) {\n parts.push(current.trim());\n }\n\n return parts;\n}\n\nfunction formatLongJsxTagLine(line: string): string {\n const maxInlineLength = 110;\n if (line.length <= maxInlineLength) return line;\n\n const indent = line.match(/^(\\s*)/)?.[1] ?? \"\";\n const trimmed = line.trimStart();\n\n if (\n !trimmed.startsWith(\"<\") ||\n trimmed.startsWith(\"</\") ||\n trimmed.startsWith(\"<!\") ||\n trimmed.startsWith(\"<?\")\n ) {\n return line;\n }\n\n const tagEnd = findTagEnd(trimmed);\n if (tagEnd === -1) return line;\n if (trimmed.slice(tagEnd + 1).trim().length > 0) return line;\n\n const rawTagBody = trimmed.slice(1, tagEnd).trim();\n const isSelfClosing = rawTagBody.endsWith(\"/\");\n const tagBody = isSelfClosing ? rawTagBody.slice(0, -1).trimEnd() : rawTagBody;\n const firstSpace = tagBody.search(/\\s/);\n if (firstSpace === -1) return line;\n\n const tagName = tagBody.slice(0, firstSpace);\n if (!/^[A-Za-z][\\w.:-]*$/.test(tagName)) return line;\n\n const attrsSource = tagBody.slice(firstSpace).trim();\n if (!attrsSource.includes(\"=\") && !attrsSource.includes(\"{...\")) return line;\n\n const attrs = splitJsxAttributes(attrsSource);\n if (attrs.length === 0) return line;\n\n const attrIndent = `${indent} `;\n const close = isSelfClosing ? \"/>\" : \">\";\n\n return [\n `${indent}<${tagName}`,\n ...attrs.map((attr) => `${attrIndent}${attr}`),\n `${indent}${close}`,\n ].join(\"\\n\");\n}\n\nfunction formatLongJsxTags(code: string): string {\n return code\n .split(\"\\n\")\n .flatMap((line) => formatLongJsxTagLine(line).split(\"\\n\"))\n .join(\"\\n\");\n}\n\nfunction normalizeCode(code: string): string {\n const trimmed = code.trim();\n if (trimmed.length === 0) return \"\";\n\n const normalized = normalizeIndentation(trimmed);\n const dedented = dedent(normalized);\n const withoutTrailingWhitespace = trimTrailingWhitespace(dedented);\n return formatLongJsxTags(withoutTrailingWhitespace);\n}\n\n/**\n * Parse line specification into a Set of line numbers.\n * Supports: [1, 3, '5-7'] -> Set {1, 3, 5, 6, 7}\n */\nfunction parseLineSpec(spec?: (number | string)[]): Set<number> {\n const lines = new Set<number>();\n if (!spec) return lines;\n\n for (const item of spec) {\n if (typeof item === \"number\") {\n lines.add(item);\n } else if (typeof item === \"string\") {\n const rangeMatch = item.match(/^(\\d+)-(\\d+)$/);\n if (rangeMatch) {\n const start = parseInt(rangeMatch[1], 10);\n const end = parseInt(rangeMatch[2], 10);\n for (let i = start; i <= end; i++) {\n lines.add(i);\n }\n } else {\n const num = parseInt(item, 10);\n if (!isNaN(num)) {\n lines.add(num);\n }\n }\n }\n }\n\n return lines;\n}\n\ninterface ProcessOptions {\n showLineNumbers: boolean;\n startLineNumber: number;\n highlightLines: Set<number>;\n addedLines: Set<number>;\n removedLines: Set<number>;\n}\n\n/**\n * Add line numbers, highlight classes, and diff markers to Shiki HTML output.\n */\nfunction processShikiHtml(html: string, options: ProcessOptions): string {\n const { showLineNumbers, startLineNumber, highlightLines, addedLines, removedLines } = options;\n const hasDiff = addedLines.size > 0 || removedLines.size > 0;\n\n if (!showLineNumbers && highlightLines.size === 0 && !hasDiff) {\n return html;\n }\n\n // Extract the code content from Shiki output\n // Shiki outputs: <pre class=\"shiki ...\"><code>...lines...</code></pre>\n const codeMatch = html.match(/<code[^>]*>([\\s\\S]*?)<\\/code>/);\n if (!codeMatch) return html;\n\n const codeContent = codeMatch[1];\n const lines = codeContent.split(\"\\n\");\n\n // Process each line\n const processedLines = lines.map((line, index) => {\n const lineNum = index + 1;\n const displayLineNum = startLineNumber + index;\n const isHighlighted = highlightLines.has(lineNum);\n const isAdded = addedLines.has(lineNum);\n const isRemoved = removedLines.has(lineNum);\n\n const lineClasses = [\"line\"];\n if (isHighlighted) lineClasses.push(\"highlighted\");\n if (isAdded) lineClasses.push(\"diff-added\");\n if (isRemoved) lineClasses.push(\"diff-removed\");\n\n const lineClass = lineClasses.join(\" \");\n const diffMarker = isAdded ? \"+\" : isRemoved ? \"-\" : \" \";\n\n if (showLineNumbers || hasDiff) {\n const lineNumHtml = showLineNumbers\n ? `<span class=\"line-number\">${displayLineNum}</span>`\n : \"\";\n const diffMarkerHtml = hasDiff ? `<span class=\"diff-marker\">${diffMarker}</span>` : \"\";\n return `<span class=\"${lineClass}\">${lineNumHtml}${diffMarkerHtml}${line}</span>`;\n }\n return `<span class=\"${lineClass}\">${line}</span>`;\n });\n\n // Reconstruct the HTML\n return html.replace(/<code[^>]*>[\\s\\S]*?<\\/code>/, `<code>${processedLines.join(\"\\n\")}</code>`);\n}\n\nconst CodeBlockBase = React.forwardRef<HTMLDivElement, CodeBlockProps>(function CodeBlock(\n {\n code,\n language = \"tsx\",\n theme = \"one-dark-pro\",\n showCopy = true,\n title,\n filename,\n caption,\n showLineNumbers = false,\n startLineNumber = 1,\n highlightLines,\n addedLines,\n removedLines,\n wordWrap = false,\n maxHeight,\n collapsible = false,\n defaultCollapsed = false,\n collapsedLines = 5,\n compact = false,\n persistentCopy = false,\n copyPlacement = \"auto\",\n onCopy,\n className,\n ...htmlProps\n },\n ref\n) {\n const [copied, setCopied] = useState(false);\n const [highlight, setHighlight] = useState<{ html: string; loading: boolean }>({ html: '', loading: true });\n const [isCollapsed, setIsCollapsed] = useState(defaultCollapsed);\n\n const trimmedCode = useMemo(() => normalizeCode(code), [code]);\n const codeLines = trimmedCode.split(\"\\n\");\n const totalLines = codeLines.length;\n const shouldShowCollapse = collapsible && totalLines > collapsedLines;\n\n // Compute visible code when collapsed\n const visibleCode =\n shouldShowCollapse && isCollapsed ? codeLines.slice(0, collapsedLines).join(\"\\n\") : trimmedCode;\n\n const highlightSet = useMemo(() => parseLineSpec(highlightLines), [highlightLines]);\n const addedSet = useMemo(() => parseLineSpec(addedLines), [addedLines]);\n const removedSet = useMemo(() => parseLineSpec(removedLines), [removedLines]);\n const hasDiff = addedSet.size > 0 || removedSet.size > 0;\n const resolvedCopyPlacement =\n copyPlacement === \"auto\" ? (filename ? \"header\" : \"overlay\") : copyPlacement;\n const shouldShowHeaderCopy = showCopy && !persistentCopy && resolvedCopyPlacement === \"header\";\n const shouldShowOverlayCopy = showCopy && !persistentCopy && resolvedCopyPlacement === \"overlay\";\n const shouldRenderHeader = Boolean(filename) || shouldShowHeaderCopy;\n\n // Apply syntax highlighting\n useEffect(() => {\n let cancelled = false;\n setHighlight((prev) => ({ ...prev, loading: true }));\n\n const run = async () => {\n loadShikiDeps();\n\n const fallbackHtml = `<pre class=\"shiki\"><code>${escapeHtml(visibleCode)}</code></pre>`;\n\n if (_shikiFailed || !_codeToHtml) {\n if (_shikiFailed && process.env.NODE_ENV === \"development\") {\n console.warn(\n \"[@fragments-sdk/ui] CodeBlock: shiki is not installed. \" +\n \"Install it with: npm install shiki\"\n );\n }\n return fallbackHtml;\n }\n\n try {\n const html = await _codeToHtml(visibleCode, { lang: language, theme });\n return processShikiHtml(html, {\n showLineNumbers,\n startLineNumber,\n highlightLines: highlightSet,\n addedLines: addedSet,\n removedLines: removedSet,\n });\n } catch (err) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(\"Syntax highlighting failed:\", err);\n }\n return fallbackHtml;\n }\n };\n\n run().then((html) => {\n if (!cancelled) {\n setHighlight({ html, loading: false });\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [\n visibleCode,\n language,\n theme,\n showLineNumbers,\n startLineNumber,\n highlightSet,\n addedSet,\n removedSet,\n ]);\n\n const handleCopy = useCallback(async () => {\n try {\n // Always copy the full code, even when collapsed\n await navigator.clipboard.writeText(trimmedCode);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n onCopy?.();\n } catch (err) {\n if (process.env.NODE_ENV !== \"production\") {\n console.error(\"Failed to copy:\", err);\n }\n }\n }, [trimmedCode, onCopy]);\n\n const toggleCollapsed = useCallback(() => {\n setIsCollapsed((prev) => !prev);\n }, []);\n\n const classNames = [\n styles.container,\n showLineNumbers && styles.withLineNumbers,\n hasDiff && styles.withDiff,\n wordWrap && styles.wordWrap,\n compact && styles.compact,\n className,\n ]\n .filter(Boolean)\n .join(\" \");\n\n const wrapperClasses = [\n styles.wrapper,\n persistentCopy && styles.persistentCopyWrapper,\n shouldShowOverlayCopy && styles.withCopyOverlay,\n ]\n .filter(Boolean)\n .join(\" \");\n\n const codeContainerStyle: React.CSSProperties = maxHeight ? { maxHeight, overflow: \"auto\" } : {};\n\n return (\n <div ref={ref} {...htmlProps} className={classNames} data-theme=\"dark\">\n {title && <div className={styles.title}>{title}</div>}\n <div className={wrapperClasses}>\n {shouldRenderHeader && (\n <div className={styles.header}>\n <span className={styles.filename}>{filename ?? \"\"}</span>\n {shouldShowHeaderCopy && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className={`${styles.copyButton} ${copied ? styles.copied : \"\"}`}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n {copied ? (\n <CheckIcon className={styles.icon} />\n ) : (\n <CopyIcon className={styles.icon} />\n )}\n </button>\n )}\n </div>\n )}\n {shouldShowOverlayCopy && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className={`${styles.copyButton} ${styles.copyOverlay} ${copied ? styles.copied : \"\"}`}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n {copied ? <CheckIcon className={styles.icon} /> : <CopyIcon className={styles.icon} />}\n </button>\n )}\n {highlight.loading ? (\n <div className={styles.loading} style={codeContainerStyle}>\n <pre>\n <code>{visibleCode}</code>\n </pre>\n </div>\n ) : (\n <div\n className={styles.codeContainer}\n style={codeContainerStyle}\n dangerouslySetInnerHTML={{ __html: highlight.html }}\n />\n )}\n {persistentCopy && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className={`${styles.persistentCopy} ${styles.copyButton} ${styles.copyOverlay} ${copied ? styles.copied : \"\"}`}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n {copied ? <CheckIcon className={styles.icon} /> : <CopyIcon className={styles.icon} />}\n </button>\n )}\n {shouldShowCollapse && (\n <button\n type=\"button\"\n onClick={toggleCollapsed}\n className={styles.collapseButton}\n aria-expanded={!isCollapsed}\n aria-label={isCollapsed ? \"Expand code\" : \"Collapse code\"}\n >\n {isCollapsed ? (\n <>\n <ChevronDownIcon className={styles.icon} />\n <span>Show {totalLines - collapsedLines} more lines</span>\n </>\n ) : (\n <>\n <ChevronUpIcon className={styles.icon} />\n <span>Show less</span>\n </>\n )}\n </button>\n )}\n </div>\n {caption && <div className={styles.caption}>{caption}</div>}\n </div>\n );\n});\n\n// ============================================\n// Tabbed Code Block\n// ============================================\n\nexport interface CodeBlockTab {\n /** Label shown in the tab */\n label: string;\n /** Code string to display */\n code: string;\n /** Programming language for syntax highlighting */\n language?: CodeBlockLanguage;\n}\n\nexport interface TabbedCodeBlockProps {\n /** Array of code tabs */\n tabs: CodeBlockTab[];\n /** Default selected tab (by label) */\n defaultTab?: string;\n /** Show copy button */\n showCopy?: boolean;\n /** Placement of copy button when not using persistent copy */\n copyPlacement?: CodeBlockCopyPlacement;\n /** Show line numbers */\n showLineNumbers?: boolean;\n /** Syntax highlighting theme (applies to all tabs) */\n theme?: CodeBlockTheme;\n /** Tab list visual style */\n tabsVariant?: \"underline\" | \"pills\";\n /** Enable word wrapping for long lines */\n wordWrap?: boolean;\n /** Maximum height in pixels (enables scrolling) */\n maxHeight?: number;\n /** Additional class name */\n className?: string;\n /** Callback fired when a tab's copy button is clicked. Receives the tab label. */\n onCopy?: (tabLabel: string) => void;\n}\n\nfunction TabbedCodeBlock({\n tabs,\n defaultTab,\n showCopy = true,\n copyPlacement = \"auto\",\n showLineNumbers = false,\n theme,\n tabsVariant = \"pills\",\n wordWrap,\n maxHeight,\n className,\n onCopy,\n}: TabbedCodeBlockProps) {\n const defaultValue = defaultTab || tabs[0]?.label || \"\";\n\n return (\n <div className={className}>\n <TabsRoot defaultValue={defaultValue}>\n <TabsList variant={tabsVariant}>\n {tabs.map((tab) => (\n <Tab key={tab.label} value={tab.label}>\n {tab.label}\n </Tab>\n ))}\n </TabsList>\n {tabs.map((tab) => (\n <TabsPanel key={tab.label} value={tab.label} flush className={styles.tabbedPanel}>\n <CodeBlockBase\n code={tab.code}\n language={tab.language}\n theme={theme}\n showCopy={showCopy}\n copyPlacement={copyPlacement}\n showLineNumbers={showLineNumbers}\n wordWrap={wordWrap}\n maxHeight={maxHeight}\n onCopy={onCopy ? () => onCopy(tab.label) : undefined}\n />\n </TabsPanel>\n ))}\n </TabsRoot>\n </div>\n );\n}\n\n// ============================================\n// Export compound component\n// ============================================\n\nexport const CodeBlock = Object.assign(CodeBlockBase, {\n Tabbed: TabbedCodeBlock,\n});\n\nexport { TabbedCodeBlock };\n"],"names":["jsxs","jsx","_a","index","React","CodeBlock","useState","useMemo","useEffect","useCallback","styles","Fragment","TabsRoot","TabsList","Tab","TabsPanel"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAQA,IAAI,cAEO;AACX,IAAI,eAAe;AACnB,IAAI,eAAe;AAEnB,SAAS,gBAAgB;AACvB,MAAI,aAAc;AAClB,iBAAe;AACf,MAAI;AAEF,UAAM,QAAQ,QAAQ,OAAO;AAC7B,kBAAc,MAAM;AAAA,EACtB,QAAQ;AACN,mBAAe;AAAA,EACjB;AACF;AAqGA,SAAS,SAAS,EAAE,aAAqC;AACvD,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ,UAAA;AAAA,QAAAC,2BAAAA,IAAC,QAAA,EAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,QACvDA,2BAAAA,IAAC,QAAA,EAAK,GAAE,0DAAA,CAA0D;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGxE;AAEA,SAAS,UAAU,EAAE,aAAqC;AACxD,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ,UAAAA,2BAAAA,IAAC,YAAA,EAAS,QAAO,iBAAA,CAAiB;AAAA,IAAA;AAAA,EAAA;AAGxC;AAEA,SAAS,gBAAgB,EAAE,aAAqC;AAC9D,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ,UAAAA,2BAAAA,IAAC,YAAA,EAAS,QAAO,iBAAA,CAAiB;AAAA,IAAA;AAAA,EAAA;AAGxC;AAEA,SAAS,cAAc,EAAE,aAAqC;AAC5D,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ,UAAAA,2BAAAA,IAAC,YAAA,EAAS,QAAO,kBAAA,CAAkB;AAAA,IAAA;AAAA,EAAA;AAGzC;AAEA,SAAS,WAAW,KAAqB;AACvC,SAAO,IACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;AAMA,SAAS,OAAO,KAAqB;AACnC,QAAM,QAAQ,IAAI,MAAM,IAAI;AAG5B,MAAI,YAAY;AAChB,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,KAAA,MAAW,GAAI;AACxB,UAAM,QAAQ,KAAK,MAAM,QAAQ;AACjC,QAAI,OAAO;AACT,kBAAY,KAAK,IAAI,WAAW,MAAM,CAAC,EAAE,MAAM;AAAA,IACjD;AAAA,EACF;AAGA,MAAI,cAAc,YAAY,cAAc,GAAG;AAC7C,WAAO;AAAA,EACT;AAGA,SAAO,MAAM,IAAI,CAAC,SAAS,KAAK,MAAM,SAAS,CAAC,EAAE,KAAK,IAAI;AAC7D;AAKA,SAAS,qBAAqB,KAAqB;;AACjD,QAAM,QAAQ,IAAI,MAAM,IAAI;AAC5B,MAAI,MAAM,UAAU,EAAG,QAAO;AAE9B,MAAI,YAAY;AAChB,QAAM,oBAAkB,WAAM,CAAC,EAAE,MAAM,QAAQ,MAAvB,mBAA2B,GAAG,WAAU;AAEhE,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;AACxC,UAAM,OAAO,MAAM,CAAC;AACpB,QAAI,KAAK,OAAO,WAAW,EAAG;AAC9B,UAAM,WAAS,UAAK,MAAM,QAAQ,MAAnB,mBAAuB,GAAG,WAAU;AACnD,gBAAY,KAAK,IAAI,WAAW,MAAM;AAAA,EACxC;AAEA,MAAI,kBAAkB,GAAG;AACvB,gBAAY,KAAK,IAAI,WAAW,eAAe;AAAA,EACjD;AAEA,MAAI,cAAc,YAAY,cAAc,EAAG,QAAO;AAEtD,SAAO,MACJ,IAAI,CAAC,SAAA;;AAAS,gBAAK,MAAM,KAAK,IAAI,aAAWC,MAAA,KAAK,MAAM,QAAQ,MAAnB,gBAAAA,IAAuB,GAAG,WAAU,CAAC,CAAC;AAAA,GAAC,EACpF,KAAK,IAAI;AACd;AAEA,SAAS,uBAAuB,KAAqB;AACnD,SAAO,IACJ,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,QAAQ,YAAY,EAAE,CAAC,EAC1C,KAAK,IAAI;AACd;AAEA,SAAS,WAAW,MAAsB;AACxC,MAAI,QAAgC;AACpC,MAAI,UAAU;AACd,MAAI,aAAa;AACjB,MAAI,eAAe;AACnB,MAAI,aAAa;AAEjB,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,UAAM,OAAO,KAAK,CAAC;AAEnB,QAAI,OAAO;AACT,UAAI,SAAS,QAAQ,CAAC,SAAS;AAC7B,kBAAU;AACV;AAAA,MACF;AACA,UAAI,SAAS,SAAS,CAAC,SAAS;AAC9B,gBAAQ;AAAA,MACV;AACA,gBAAU;AACV;AAAA,IACF;AAEA,QAAI,SAAS,OAAO,SAAS,OAAO,SAAS,KAAK;AAChD,cAAQ;AACR;AAAA,IACF;AAEA,QAAI,SAAS,IAAK,eAAc;AAAA,aACvB,SAAS,IAAK,cAAa,KAAK,IAAI,GAAG,aAAa,CAAC;AAAA,aACrD,SAAS,IAAK,iBAAgB;AAAA,aAC9B,SAAS,IAAK,gBAAe,KAAK,IAAI,GAAG,eAAe,CAAC;AAAA,aACzD,SAAS,IAAK,eAAc;AAAA,aAC5B,SAAS,IAAK,cAAa,KAAK,IAAI,GAAG,aAAa,CAAC;AAAA,aACrD,SAAS,OAAO,eAAe,KAAK,iBAAiB,KAAK,eAAe,GAAG;AACnF,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,mBAAmB,OAAyB;AACnD,QAAM,QAAkB,CAAA;AACxB,MAAI,UAAU;AACd,MAAI,QAAgC;AACpC,MAAI,UAAU;AACd,MAAI,aAAa;AACjB,MAAI,eAAe;AACnB,MAAI,aAAa;AAEjB,aAAW,QAAQ,OAAO;AACxB,QAAI,OAAO;AACT,iBAAW;AACX,UAAI,SAAS,QAAQ,CAAC,SAAS;AAC7B,kBAAU;AACV;AAAA,MACF;AACA,UAAI,SAAS,SAAS,CAAC,SAAS;AAC9B,gBAAQ;AAAA,MACV;AACA,gBAAU;AACV;AAAA,IACF;AAEA,QAAI,SAAS,OAAO,SAAS,OAAO,SAAS,KAAK;AAChD,cAAQ;AACR,iBAAW;AACX;AAAA,IACF;AAEA,QAAI,SAAS,IAAK,eAAc;AAAA,aACvB,SAAS,IAAK,cAAa,KAAK,IAAI,GAAG,aAAa,CAAC;AAAA,aACrD,SAAS,IAAK,iBAAgB;AAAA,aAC9B,SAAS,IAAK,gBAAe,KAAK,IAAI,GAAG,eAAe,CAAC;AAAA,aACzD,SAAS,IAAK,eAAc;AAAA,aAC5B,SAAS,IAAK,cAAa,KAAK,IAAI,GAAG,aAAa,CAAC;AAE9D,QAAI,KAAK,KAAK,IAAI,KAAK,eAAe,KAAK,iBAAiB,KAAK,eAAe,GAAG;AACjF,UAAI,QAAQ,OAAO,SAAS,GAAG;AAC7B,cAAM,KAAK,QAAQ,MAAM;AACzB,kBAAU;AAAA,MACZ;AACA;AAAA,IACF;AAEA,eAAW;AAAA,EACb;AAEA,MAAI,QAAQ,OAAO,SAAS,GAAG;AAC7B,UAAM,KAAK,QAAQ,MAAM;AAAA,EAC3B;AAEA,SAAO;AACT;AAEA,SAAS,qBAAqB,MAAsB;;AAClD,QAAM,kBAAkB;AACxB,MAAI,KAAK,UAAU,gBAAiB,QAAO;AAE3C,QAAM,WAAS,UAAK,MAAM,QAAQ,MAAnB,mBAAuB,OAAM;AAC5C,QAAM,UAAU,KAAK,UAAA;AAErB,MACE,CAAC,QAAQ,WAAW,GAAG,KACvB,QAAQ,WAAW,IAAI,KACvB,QAAQ,WAAW,IAAI,KACvB,QAAQ,WAAW,IAAI,GACvB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,WAAW,OAAO;AACjC,MAAI,WAAW,GAAI,QAAO;AAC1B,MAAI,QAAQ,MAAM,SAAS,CAAC,EAAE,OAAO,SAAS,EAAG,QAAO;AAExD,QAAM,aAAa,QAAQ,MAAM,GAAG,MAAM,EAAE,KAAA;AAC5C,QAAM,gBAAgB,WAAW,SAAS,GAAG;AAC7C,QAAM,UAAU,gBAAgB,WAAW,MAAM,GAAG,EAAE,EAAE,YAAY;AACpE,QAAM,aAAa,QAAQ,OAAO,IAAI;AACtC,MAAI,eAAe,GAAI,QAAO;AAE9B,QAAM,UAAU,QAAQ,MAAM,GAAG,UAAU;AAC3C,MAAI,CAAC,qBAAqB,KAAK,OAAO,EAAG,QAAO;AAEhD,QAAM,cAAc,QAAQ,MAAM,UAAU,EAAE,KAAA;AAC9C,MAAI,CAAC,YAAY,SAAS,GAAG,KAAK,CAAC,YAAY,SAAS,MAAM,EAAG,QAAO;AAExE,QAAM,QAAQ,mBAAmB,WAAW;AAC5C,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAM,aAAa,GAAG,MAAM;AAC5B,QAAM,QAAQ,gBAAgB,OAAO;AAErC,SAAO;AAAA,IACL,GAAG,MAAM,IAAI,OAAO;AAAA,IACpB,GAAG,MAAM,IAAI,CAAC,SAAS,GAAG,UAAU,GAAG,IAAI,EAAE;AAAA,IAC7C,GAAG,MAAM,GAAG,KAAK;AAAA,EAAA,EACjB,KAAK,IAAI;AACb;AAEA,SAAS,kBAAkB,MAAsB;AAC/C,SAAO,KACJ,MAAM,IAAI,EACV,QAAQ,CAAC,SAAS,qBAAqB,IAAI,EAAE,MAAM,IAAI,CAAC,EACxD,KAAK,IAAI;AACd;AAEA,SAAS,cAAc,MAAsB;AAC3C,QAAM,UAAU,KAAK,KAAA;AACrB,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,aAAa,qBAAqB,OAAO;AAC/C,QAAM,WAAW,OAAO,UAAU;AAClC,QAAM,4BAA4B,uBAAuB,QAAQ;AACjE,SAAO,kBAAkB,yBAAyB;AACpD;AAMA,SAAS,cAAc,MAAyC;AAC9D,QAAM,4BAAY,IAAA;AAClB,MAAI,CAAC,KAAM,QAAO;AAElB,aAAW,QAAQ,MAAM;AACvB,QAAI,OAAO,SAAS,UAAU;AAC5B,YAAM,IAAI,IAAI;AAAA,IAChB,WAAW,OAAO,SAAS,UAAU;AACnC,YAAM,aAAa,KAAK,MAAM,eAAe;AAC7C,UAAI,YAAY;AACd,cAAM,QAAQ,SAAS,WAAW,CAAC,GAAG,EAAE;AACxC,cAAM,MAAM,SAAS,WAAW,CAAC,GAAG,EAAE;AACtC,iBAAS,IAAI,OAAO,KAAK,KAAK,KAAK;AACjC,gBAAM,IAAI,CAAC;AAAA,QACb;AAAA,MACF,OAAO;AACL,cAAM,MAAM,SAAS,MAAM,EAAE;AAC7B,YAAI,CAAC,MAAM,GAAG,GAAG;AACf,gBAAM,IAAI,GAAG;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAaA,SAAS,iBAAiB,MAAc,SAAiC;AACvE,QAAM,EAAE,iBAAiB,iBAAiB,gBAAgB,YAAY,iBAAiB;AACvF,QAAM,UAAU,WAAW,OAAO,KAAK,aAAa,OAAO;AAE3D,MAAI,CAAC,mBAAmB,eAAe,SAAS,KAAK,CAAC,SAAS;AAC7D,WAAO;AAAA,EACT;AAIA,QAAM,YAAY,KAAK,MAAM,+BAA+B;AAC5D,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,cAAc,UAAU,CAAC;AAC/B,QAAM,QAAQ,YAAY,MAAM,IAAI;AAGpC,QAAM,iBAAiB,MAAM,IAAI,CAAC,MAAMC,WAAU;AAChD,UAAM,UAAUA,SAAQ;AACxB,UAAM,iBAAiB,kBAAkBA;AACzC,UAAM,gBAAgB,eAAe,IAAI,OAAO;AAChD,UAAM,UAAU,WAAW,IAAI,OAAO;AACtC,UAAM,YAAY,aAAa,IAAI,OAAO;AAE1C,UAAM,cAAc,CAAC,MAAM;AAC3B,QAAI,cAAe,aAAY,KAAK,aAAa;AACjD,QAAI,QAAS,aAAY,KAAK,YAAY;AAC1C,QAAI,UAAW,aAAY,KAAK,cAAc;AAE9C,UAAM,YAAY,YAAY,KAAK,GAAG;AACtC,UAAM,aAAa,UAAU,MAAM,YAAY,MAAM;AAErD,QAAI,mBAAmB,SAAS;AAC9B,YAAM,cAAc,kBAChB,6BAA6B,cAAc,YAC3C;AACJ,YAAM,iBAAiB,UAAU,6BAA6B,UAAU,YAAY;AACpF,aAAO,gBAAgB,SAAS,KAAK,WAAW,GAAG,cAAc,GAAG,IAAI;AAAA,IAC1E;AACA,WAAO,gBAAgB,SAAS,KAAK,IAAI;AAAA,EAC3C,CAAC;AAGD,SAAO,KAAK,QAAQ,+BAA+B,SAAS,eAAe,KAAK,IAAI,CAAC,SAAS;AAChG;AAEA,MAAM,gBAAgBC,iBAAM,WAA2C,SAASC,WAC9E;AAAA,EACE;AAAA,EACA,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA,GAAG;AACL,GACA,KACA;AACA,QAAM,CAAC,QAAQ,SAAS,IAAIC,MAAAA,SAAS,KAAK;AAC1C,QAAM,CAAC,WAAW,YAAY,IAAIA,MAAAA,SAA6C,EAAE,MAAM,IAAI,SAAS,MAAM;AAC1G,QAAM,CAAC,aAAa,cAAc,IAAIA,MAAAA,SAAS,gBAAgB;AAE/D,QAAM,cAAcC,MAAAA,QAAQ,MAAM,cAAc,IAAI,GAAG,CAAC,IAAI,CAAC;AAC7D,QAAM,YAAY,YAAY,MAAM,IAAI;AACxC,QAAM,aAAa,UAAU;AAC7B,QAAM,qBAAqB,eAAe,aAAa;AAGvD,QAAM,cACJ,sBAAsB,cAAc,UAAU,MAAM,GAAG,cAAc,EAAE,KAAK,IAAI,IAAI;AAEtF,QAAM,eAAeA,MAAAA,QAAQ,MAAM,cAAc,cAAc,GAAG,CAAC,cAAc,CAAC;AAClF,QAAM,WAAWA,MAAAA,QAAQ,MAAM,cAAc,UAAU,GAAG,CAAC,UAAU,CAAC;AACtE,QAAM,aAAaA,MAAAA,QAAQ,MAAM,cAAc,YAAY,GAAG,CAAC,YAAY,CAAC;AAC5E,QAAM,UAAU,SAAS,OAAO,KAAK,WAAW,OAAO;AACvD,QAAM,wBACJ,kBAAkB,SAAU,WAAW,WAAW,YAAa;AACjE,QAAM,uBAAuB,YAAY,CAAC,kBAAkB,0BAA0B;AACtF,QAAM,wBAAwB,YAAY,CAAC,kBAAkB,0BAA0B;AACvF,QAAM,qBAAqB,QAAQ,QAAQ,KAAK;AAGhDC,QAAAA,UAAU,MAAM;AACd,QAAI,YAAY;AAChB,iBAAa,CAAC,UAAU,EAAE,GAAG,MAAM,SAAS,OAAO;AAEnD,UAAM,MAAM,YAAY;AACtB,oBAAA;AAEA,YAAM,eAAe,4BAA4B,WAAW,WAAW,CAAC;AAExE,UAAI,gBAAgB,CAAC,aAAa;AAChC,YAAI,gBAAgB,QAAQ,IAAI,aAAa,eAAe;AAC1D,kBAAQ;AAAA,YACN;AAAA,UAAA;AAAA,QAGJ;AACA,eAAO;AAAA,MACT;AAEA,UAAI;AACF,cAAM,OAAO,MAAM,YAAY,aAAa,EAAE,MAAM,UAAU,OAAO;AACrE,eAAO,iBAAiB,MAAM;AAAA,UAC5B;AAAA,UACA;AAAA,UACA,gBAAgB;AAAA,UAChB,YAAY;AAAA,UACZ,cAAc;AAAA,QAAA,CACf;AAAA,MACH,SAAS,KAAK;AACZ,YAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,kBAAQ,MAAM,+BAA+B,GAAG;AAAA,QAClD;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAA,EAAM,KAAK,CAAC,SAAS;AACnB,UAAI,CAAC,WAAW;AACd,qBAAa,EAAE,MAAM,SAAS,MAAA,CAAO;AAAA,MACvC;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AAED,QAAM,aAAaC,MAAAA,YAAY,YAAY;AACzC,QAAI;AAEF,YAAM,UAAU,UAAU,UAAU,WAAW;AAC/C,gBAAU,IAAI;AACd,iBAAW,MAAM,UAAU,KAAK,GAAG,GAAI;AACvC;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,gBAAQ,MAAM,mBAAmB,GAAG;AAAA,MACtC;AAAA,IACF;AAAA,EACF,GAAG,CAAC,aAAa,MAAM,CAAC;AAExB,QAAM,kBAAkBA,MAAAA,YAAY,MAAM;AACxC,mBAAe,CAAC,SAAS,CAAC,IAAI;AAAA,EAChC,GAAG,CAAA,CAAE;AAEL,QAAM,aAAa;AAAA,IACjBC,iBAAAA,QAAO;AAAA,IACP,mBAAmBA,iBAAAA,QAAO;AAAA,IAC1B,WAAWA,iBAAAA,QAAO;AAAA,IAClB,YAAYA,iBAAAA,QAAO;AAAA,IACnB,WAAWA,iBAAAA,QAAO;AAAA,IAClB;AAAA,EAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG;AAEX,QAAM,iBAAiB;AAAA,IACrBA,iBAAAA,QAAO;AAAA,IACP,kBAAkBA,iBAAAA,QAAO;AAAA,IACzB,yBAAyBA,iBAAAA,QAAO;AAAA,EAAA,EAE/B,OAAO,OAAO,EACd,KAAK,GAAG;AAEX,QAAM,qBAA0C,YAAY,EAAE,WAAW,UAAU,OAAA,IAAW,CAAA;AAE9F,SACEV,gCAAC,SAAI,KAAW,GAAG,WAAW,WAAW,YAAY,cAAW,QAC7D,UAAA;AAAA,IAAA,SAASC,2BAAAA,IAAC,OAAA,EAAI,WAAWS,iBAAAA,QAAO,OAAQ,UAAA,OAAM;AAAA,IAC/CV,2BAAAA,KAAC,OAAA,EAAI,WAAW,gBACb,UAAA;AAAA,MAAA,sBACCA,2BAAAA,KAAC,OAAA,EAAI,WAAWU,iBAAAA,QAAO,QACrB,UAAA;AAAA,QAAAT,+BAAC,QAAA,EAAK,WAAWS,iBAAAA,QAAO,UAAW,sBAAY,IAAG;AAAA,QACjD,wBACCT,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS;AAAA,YACT,WAAW,GAAGS,iBAAAA,QAAO,UAAU,IAAI,SAASA,iBAAAA,QAAO,SAAS,EAAE;AAAA,YAC9D,cAAY,SAAS,YAAY;AAAA,YAEhC,UAAA,SACCT,2BAAAA,IAAC,WAAA,EAAU,WAAWS,iBAAAA,QAAO,KAAA,CAAM,IAEnCT,2BAAAA,IAAC,UAAA,EAAS,WAAWS,iBAAAA,QAAO,KAAA,CAAM;AAAA,UAAA;AAAA,QAAA;AAAA,MAEtC,GAEJ;AAAA,MAED,yBACCT,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,WAAW,GAAGS,iBAAAA,QAAO,UAAU,IAAIA,iBAAAA,QAAO,WAAW,IAAI,SAASA,iBAAAA,QAAO,SAAS,EAAE;AAAA,UACpF,cAAY,SAAS,YAAY;AAAA,UAEhC,UAAA,SAAST,2BAAAA,IAAC,WAAA,EAAU,WAAWS,iBAAAA,QAAO,KAAA,CAAM,IAAKT,2BAAAA,IAAC,UAAA,EAAS,WAAWS,iBAAAA,QAAO,KAAA,CAAM;AAAA,QAAA;AAAA,MAAA;AAAA,MAGvF,UAAU,UACTT,2BAAAA,IAAC,OAAA,EAAI,WAAWS,iBAAAA,QAAO,SAAS,OAAO,oBACrC,UAAAT,+BAAC,SACC,UAAAA,2BAAAA,IAAC,QAAA,EAAM,UAAA,aAAY,EAAA,CACrB,GACF,IAEAA,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAWS,iBAAAA,QAAO;AAAA,UAClB,OAAO;AAAA,UACP,yBAAyB,EAAE,QAAQ,UAAU,KAAA;AAAA,QAAK;AAAA,MAAA;AAAA,MAGrD,kBACCT,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,WAAW,GAAGS,iBAAAA,QAAO,cAAc,IAAIA,iBAAAA,QAAO,UAAU,IAAIA,iBAAAA,QAAO,WAAW,IAAI,SAASA,iBAAAA,QAAO,SAAS,EAAE;AAAA,UAC7G,cAAY,SAAS,YAAY;AAAA,UAEhC,UAAA,SAAST,2BAAAA,IAAC,WAAA,EAAU,WAAWS,iBAAAA,QAAO,KAAA,CAAM,IAAKT,2BAAAA,IAAC,UAAA,EAAS,WAAWS,iBAAAA,QAAO,KAAA,CAAM;AAAA,QAAA;AAAA,MAAA;AAAA,MAGvF,sBACCT,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,WAAWS,iBAAAA,QAAO;AAAA,UAClB,iBAAe,CAAC;AAAA,UAChB,cAAY,cAAc,gBAAgB;AAAA,UAEzC,wBACCV,2BAAAA,KAAAW,WAAAA,UAAA,EACE,UAAA;AAAA,YAAAV,2BAAAA,IAAC,iBAAA,EAAgB,WAAWS,iBAAAA,QAAO,KAAA,CAAM;AAAA,4CACxC,QAAA,EAAK,UAAA;AAAA,cAAA;AAAA,cAAM,aAAa;AAAA,cAAe;AAAA,YAAA,EAAA,CAAW;AAAA,UAAA,EAAA,CACrD,IAEAV,2BAAAA,KAAAW,WAAAA,UAAA,EACE,UAAA;AAAA,YAAAV,2BAAAA,IAAC,eAAA,EAAc,WAAWS,iBAAAA,QAAO,KAAA,CAAM;AAAA,YACvCT,2BAAAA,IAAC,UAAK,UAAA,YAAA,CAAS;AAAA,UAAA,EAAA,CACjB;AAAA,QAAA;AAAA,MAAA;AAAA,IAEJ,GAEJ;AAAA,IACC,WAAWA,2BAAAA,IAAC,OAAA,EAAI,WAAWS,iBAAAA,QAAO,SAAU,UAAA,QAAA,CAAQ;AAAA,EAAA,GACvD;AAEJ,CAAC;AAwCD,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;;AACvB,QAAM,eAAe,gBAAc,UAAK,CAAC,MAAN,mBAAS,UAAS;AAErD,SACET,2BAAAA,IAAC,OAAA,EAAI,WACH,UAAAD,2BAAAA,KAACY,MAAAA,YAAS,cACR,UAAA;AAAA,IAAAX,+BAACY,MAAAA,YAAS,SAAS,aAChB,UAAA,KAAK,IAAI,CAAC,QACTZ,+BAACa,MAAAA,KAAA,EAAoB,OAAO,IAAI,OAC7B,UAAA,IAAI,SADG,IAAI,KAEd,CACD,GACH;AAAA,IACC,KAAK,IAAI,CAAC,QACTb,2BAAAA,IAACc,MAAAA,WAAA,EAA0B,OAAO,IAAI,OAAO,OAAK,MAAC,WAAWL,iBAAAA,QAAO,aACnE,UAAAT,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAM,IAAI;AAAA,QACV,UAAU,IAAI;AAAA,QACd;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,SAAS,MAAM,OAAO,IAAI,KAAK,IAAI;AAAA,MAAA;AAAA,IAAA,EAC7C,GAXc,IAAI,KAYpB,CACD;AAAA,EAAA,EAAA,CACH,EAAA,CACF;AAEJ;AAMO,MAAM,YAAY,OAAO,OAAO,eAAe;AAAA,EACpD,QAAQ;AACV,CAAC;;;"}
package/dist/codeblock.js CHANGED
@@ -338,8 +338,7 @@ const CodeBlockBase = React.forwardRef(function CodeBlock2({
338
338
  ...htmlProps
339
339
  }, ref) {
340
340
  const [copied, setCopied] = useState(false);
341
- const [highlightedHtml, setHighlightedHtml] = useState("");
342
- const [isLoading, setIsLoading] = useState(true);
341
+ const [highlight, setHighlight] = useState({ html: "", loading: true });
343
342
  const [isCollapsed, setIsCollapsed] = useState(defaultCollapsed);
344
343
  const trimmedCode = useMemo(() => normalizeCode(code), [code]);
345
344
  const codeLines = trimmedCode.split("\n");
@@ -356,40 +355,37 @@ const CodeBlockBase = React.forwardRef(function CodeBlock2({
356
355
  const shouldRenderHeader = Boolean(filename) || shouldShowHeaderCopy;
357
356
  useEffect(() => {
358
357
  let cancelled = false;
359
- setIsLoading(true);
360
- loadShikiDeps();
361
- if (_shikiFailed || !_codeToHtml) {
362
- if (_shikiFailed && process.env.NODE_ENV === "development") {
363
- console.warn(
364
- "[@fragments-sdk/ui] CodeBlock: shiki is not installed. Install it with: npm install shiki"
365
- );
358
+ setHighlight((prev) => ({ ...prev, loading: true }));
359
+ const run = async () => {
360
+ loadShikiDeps();
361
+ const fallbackHtml = `<pre class="shiki"><code>${escapeHtml(visibleCode)}</code></pre>`;
362
+ if (_shikiFailed || !_codeToHtml) {
363
+ if (_shikiFailed && process.env.NODE_ENV === "development") {
364
+ console.warn(
365
+ "[@fragments-sdk/ui] CodeBlock: shiki is not installed. Install it with: npm install shiki"
366
+ );
367
+ }
368
+ return fallbackHtml;
366
369
  }
367
- setHighlightedHtml(`<pre class="shiki"><code>${escapeHtml(visibleCode)}</code></pre>`);
368
- setIsLoading(false);
369
- return;
370
- }
371
- _codeToHtml(visibleCode, {
372
- lang: language,
373
- theme
374
- }).then((html) => {
375
- if (!cancelled) {
376
- const processed = processShikiHtml(html, {
370
+ try {
371
+ const html = await _codeToHtml(visibleCode, { lang: language, theme });
372
+ return processShikiHtml(html, {
377
373
  showLineNumbers,
378
374
  startLineNumber,
379
375
  highlightLines: highlightSet,
380
376
  addedLines: addedSet,
381
377
  removedLines: removedSet
382
378
  });
383
- setHighlightedHtml(processed);
384
- setIsLoading(false);
385
- }
386
- }).catch((err) => {
387
- if (process.env.NODE_ENV !== "production") {
388
- console.error("Syntax highlighting failed:", err);
379
+ } catch (err) {
380
+ if (process.env.NODE_ENV !== "production") {
381
+ console.error("Syntax highlighting failed:", err);
382
+ }
383
+ return fallbackHtml;
389
384
  }
385
+ };
386
+ run().then((html) => {
390
387
  if (!cancelled) {
391
- setHighlightedHtml(`<pre class="shiki"><code>${escapeHtml(visibleCode)}</code></pre>`);
392
- setIsLoading(false);
388
+ setHighlight({ html, loading: false });
393
389
  }
394
390
  });
395
391
  return () => {
@@ -460,12 +456,12 @@ const CodeBlockBase = React.forwardRef(function CodeBlock2({
460
456
  children: copied ? /* @__PURE__ */ jsx(CheckIcon, { className: styles.icon }) : /* @__PURE__ */ jsx(CopyIcon, { className: styles.icon })
461
457
  }
462
458
  ),
463
- isLoading ? /* @__PURE__ */ jsx("div", { className: styles.loading, style: codeContainerStyle, children: /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: visibleCode }) }) }) : /* @__PURE__ */ jsx(
459
+ highlight.loading ? /* @__PURE__ */ jsx("div", { className: styles.loading, style: codeContainerStyle, children: /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: visibleCode }) }) }) : /* @__PURE__ */ jsx(
464
460
  "div",
465
461
  {
466
462
  className: styles.codeContainer,
467
463
  style: codeContainerStyle,
468
- dangerouslySetInnerHTML: { __html: highlightedHtml }
464
+ dangerouslySetInnerHTML: { __html: highlight.html }
469
465
  }
470
466
  ),
471
467
  persistentCopy && /* @__PURE__ */ jsx(