@intlayer/design-system 9.4.1 → 9.4.3

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 (215) hide show
  1. package/README.md +1 -1
  2. package/dist/esm/api/index.mjs +2 -2
  3. package/dist/esm/api/useUser/index.mjs +1 -1
  4. package/dist/esm/components/Avatar/index.mjs +1 -1
  5. package/dist/esm/components/Avatar/index.mjs.map +1 -1
  6. package/dist/esm/components/Badge/index.mjs +3 -3
  7. package/dist/esm/components/Badge/index.mjs.map +1 -1
  8. package/dist/esm/components/Breadcrumb/index.mjs +5 -5
  9. package/dist/esm/components/Breadcrumb/index.mjs.map +1 -1
  10. package/dist/esm/components/Browser/Browser.mjs +4 -4
  11. package/dist/esm/components/Browser/Browser.mjs.map +1 -1
  12. package/dist/esm/components/Button/Button.mjs +1 -0
  13. package/dist/esm/components/Button/Button.mjs.map +1 -1
  14. package/dist/esm/components/Carousel/index.mjs +5 -5
  15. package/dist/esm/components/Carousel/index.mjs.map +1 -1
  16. package/dist/esm/components/CollapsibleTable/CollapsibleTable.mjs +5 -5
  17. package/dist/esm/components/CollapsibleTable/CollapsibleTable.mjs.map +1 -1
  18. package/dist/esm/components/Container/index.mjs +2 -2
  19. package/dist/esm/components/Container/index.mjs.map +1 -1
  20. package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +1 -1
  21. package/dist/esm/components/DictionaryEditor/ItemLayout.mjs +1 -1
  22. package/dist/esm/components/DictionaryEditor/ItemLayout.mjs.map +1 -1
  23. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +7 -7
  24. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs.map +1 -1
  25. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +1 -1
  26. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +9 -9
  27. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs.map +1 -1
  28. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +4 -4
  29. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs.map +1 -1
  30. package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +1 -1
  31. package/dist/esm/components/DictionaryFieldEditor/{ContentEditor.mjs → NodeEditor.mjs} +9 -9
  32. package/dist/esm/components/DictionaryFieldEditor/NodeEditor.mjs.map +1 -0
  33. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +3 -3
  34. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs.map +1 -1
  35. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +2 -2
  36. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs.map +1 -1
  37. package/dist/esm/components/DictionaryFieldEditor/VersionSwitcherDropDown/VersionSwitcher.mjs +2 -2
  38. package/dist/esm/components/DictionaryFieldEditor/VersionSwitcherDropDown/VersionSwitcher.mjs.map +1 -1
  39. package/dist/esm/components/DictionaryFieldEditor/index.mjs +3 -3
  40. package/dist/esm/components/Footer/index.mjs +5 -3
  41. package/dist/esm/components/Footer/index.mjs.map +1 -1
  42. package/dist/esm/components/HeightResizer/index.mjs +1 -1
  43. package/dist/esm/components/HeightResizer/index.mjs.map +1 -1
  44. package/dist/esm/components/IDE/Code.mjs +1 -1
  45. package/dist/esm/components/IDE/Code.mjs.map +1 -1
  46. package/dist/esm/components/IDE/CodeBlockHighlight.mjs +1 -1
  47. package/dist/esm/components/IDE/CodeBlockHighlight.mjs.map +1 -1
  48. package/dist/esm/components/IDE/CodeBlockServer.mjs +1 -1
  49. package/dist/esm/components/IDE/CodeBlockServer.mjs.map +1 -1
  50. package/dist/esm/components/IDE/CodeBlockShiki.mjs +6 -48
  51. package/dist/esm/components/IDE/CodeBlockShiki.mjs.map +1 -1
  52. package/dist/esm/components/IDE/FileList.mjs +1 -1
  53. package/dist/esm/components/IDE/FileList.mjs.map +1 -1
  54. package/dist/esm/components/IDE/FileTree.mjs +1 -1
  55. package/dist/esm/components/IDE/FileTree.mjs.map +1 -1
  56. package/dist/esm/components/IDE/IDE.mjs +10 -7
  57. package/dist/esm/components/IDE/IDE.mjs.map +1 -1
  58. package/dist/esm/components/IDE/MarkDownRender.mjs +4 -3
  59. package/dist/esm/components/IDE/MarkDownRender.mjs.map +1 -1
  60. package/dist/esm/components/IDE/shikiBundle.mjs +61 -0
  61. package/dist/esm/components/IDE/shikiBundle.mjs.map +1 -0
  62. package/dist/esm/components/IDE/shikiLanguages.mjs +2 -39
  63. package/dist/esm/components/IDE/shikiLanguages.mjs.map +1 -1
  64. package/dist/esm/components/IDE/shikiThemes.mjs.map +1 -1
  65. package/dist/esm/components/Input/Checkbox.mjs +4 -4
  66. package/dist/esm/components/Input/Checkbox.mjs.map +1 -1
  67. package/dist/esm/components/Input/Input.mjs +2 -2
  68. package/dist/esm/components/Input/Input.mjs.map +1 -1
  69. package/dist/esm/components/Input/OTPInput.mjs +1 -1
  70. package/dist/esm/components/Input/OTPInput.mjs.map +1 -1
  71. package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs +2 -2
  72. package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs.map +1 -1
  73. package/dist/esm/components/LanguageBackground/LanguageSection.mjs +6 -8
  74. package/dist/esm/components/LanguageBackground/LanguageSection.mjs.map +1 -1
  75. package/dist/esm/components/LanguageBackground/index.mjs +2 -2
  76. package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +2 -2
  77. package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs.map +1 -1
  78. package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs +8 -3
  79. package/dist/esm/components/MarkDownRender/MarkDownIframe.mjs.map +1 -1
  80. package/dist/esm/components/MarkDownRender/MarkDownRender.mjs +9 -8
  81. package/dist/esm/components/MarkDownRender/MarkDownRender.mjs.map +1 -1
  82. package/dist/esm/components/MarkdownEditor/MarkdownEditor.mjs +2 -2
  83. package/dist/esm/components/MarkdownEditor/MarkdownEditor.mjs.map +1 -1
  84. package/dist/esm/components/MarkdownEditor/extensions.mjs +1 -1
  85. package/dist/esm/components/MarkdownEditor/extensions.mjs.map +1 -1
  86. package/dist/esm/components/MarkdownEditor/generative/AISelector.mjs +3 -3
  87. package/dist/esm/components/MarkdownEditor/generative/AISelector.mjs.map +1 -1
  88. package/dist/esm/components/MarkdownEditor/generative/AISelectorCommands.mjs +2 -2
  89. package/dist/esm/components/MarkdownEditor/generative/AISelectorCommands.mjs.map +1 -1
  90. package/dist/esm/components/MarkdownEditor/generative/GenerativeMenuSwitch.mjs +2 -2
  91. package/dist/esm/components/MarkdownEditor/generative/GenerativeMenuSwitch.mjs.map +1 -1
  92. package/dist/esm/components/MarkdownEditor/novel/extensions/code-block-shiki.mjs +197 -0
  93. package/dist/esm/components/MarkdownEditor/novel/extensions/code-block-shiki.mjs.map +1 -0
  94. package/dist/esm/components/MarkdownEditor/novel/extensions/index.mjs +2 -1
  95. package/dist/esm/components/MarkdownEditor/novel/extensions/index.mjs.map +1 -1
  96. package/dist/esm/components/MarkdownEditor/novel/index.mjs +2 -1
  97. package/dist/esm/components/Modal/Modal.mjs +0 -1
  98. package/dist/esm/components/Modal/Modal.mjs.map +1 -1
  99. package/dist/esm/components/Navbar/DesktopNavbar.mjs +3 -3
  100. package/dist/esm/components/Navbar/DesktopNavbar.mjs.map +1 -1
  101. package/dist/esm/components/Navbar/MobileNavbar.mjs +1 -1
  102. package/dist/esm/components/Navbar/MobileNavbar.mjs.map +1 -1
  103. package/dist/esm/components/Pattern/GridDistortionPattern.mjs +2 -2
  104. package/dist/esm/components/Pattern/GridDistortionPattern.mjs.map +1 -1
  105. package/dist/esm/components/Pattern/GridPattern.mjs +1 -1
  106. package/dist/esm/components/Pattern/GridPattern.mjs.map +1 -1
  107. package/dist/esm/components/RightDrawer/RightDrawer.mjs +2 -2
  108. package/dist/esm/components/RightDrawer/RightDrawer.mjs.map +1 -1
  109. package/dist/esm/components/Select/Multiselect.mjs +2 -2
  110. package/dist/esm/components/Select/Multiselect.mjs.map +1 -1
  111. package/dist/esm/components/Select/Select.mjs +2 -2
  112. package/dist/esm/components/Select/Select.mjs.map +1 -1
  113. package/dist/esm/components/Status/index.mjs +28 -0
  114. package/dist/esm/components/Status/index.mjs.map +1 -0
  115. package/dist/esm/components/Steps/index.mjs +3 -3
  116. package/dist/esm/components/Steps/index.mjs.map +1 -1
  117. package/dist/esm/components/SwitchSelector/SwitchSelector.mjs +12 -11
  118. package/dist/esm/components/SwitchSelector/SwitchSelector.mjs.map +1 -1
  119. package/dist/esm/components/SwitchSelector/VerticalSwitchSelector.mjs +6 -6
  120. package/dist/esm/components/SwitchSelector/VerticalSwitchSelector.mjs.map +1 -1
  121. package/dist/esm/components/Tab/Tab.mjs +1 -1
  122. package/dist/esm/components/Tab/Tab.mjs.map +1 -1
  123. package/dist/esm/components/TabSelector/TabSelector.mjs +5 -5
  124. package/dist/esm/components/TabSelector/TabSelector.mjs.map +1 -1
  125. package/dist/esm/components/Table/SmartTable.mjs +2 -2
  126. package/dist/esm/components/Table/SmartTable.mjs.map +1 -1
  127. package/dist/esm/components/Table/Table.mjs +1 -1
  128. package/dist/esm/components/Table/Table.mjs.map +1 -1
  129. package/dist/esm/components/Table/TableElements.mjs +2 -2
  130. package/dist/esm/components/Table/TableElements.mjs.map +1 -1
  131. package/dist/esm/components/Tag/index.mjs +1 -1
  132. package/dist/esm/components/Tag/index.mjs.map +1 -1
  133. package/dist/esm/components/TechLogo/TechLogo.mjs +2 -0
  134. package/dist/esm/components/TechLogo/TechLogo.mjs.map +1 -1
  135. package/dist/esm/components/TechLogo/logos/HTMX.mjs +31 -0
  136. package/dist/esm/components/TechLogo/logos/HTMX.mjs.map +1 -0
  137. package/dist/esm/components/TechLogo/logos/Remix.mjs +22 -0
  138. package/dist/esm/components/TechLogo/logos/Remix.mjs.map +1 -0
  139. package/dist/esm/components/TechLogo/techLogos.mjs +5 -1
  140. package/dist/esm/components/TechLogo/techLogos.mjs.map +1 -1
  141. package/dist/esm/components/Terminal/Terminal.mjs +4 -4
  142. package/dist/esm/components/Terminal/Terminal.mjs.map +1 -1
  143. package/dist/esm/components/TextArea/TextArea.mjs.map +1 -1
  144. package/dist/esm/components/Toaster/Toast.mjs +4 -4
  145. package/dist/esm/components/Toaster/Toast.mjs.map +1 -1
  146. package/dist/esm/components/index.mjs +8 -7
  147. package/dist/esm/hooks/usePersistedStore.mjs +6 -18
  148. package/dist/esm/hooks/usePersistedStore.mjs.map +1 -1
  149. package/dist/esm/providers/ReactQueryProvider.mjs +10 -2
  150. package/dist/esm/providers/ReactQueryProvider.mjs.map +1 -1
  151. package/dist/esm/providers/ThemeProvider.mjs +27 -15
  152. package/dist/esm/providers/ThemeProvider.mjs.map +1 -1
  153. package/dist/esm/routes.mjs +24 -6
  154. package/dist/esm/routes.mjs.map +1 -1
  155. package/dist/esm/structured-data/buildItemListJsonLd.mjs +27 -0
  156. package/dist/esm/structured-data/buildItemListJsonLd.mjs.map +1 -0
  157. package/dist/esm/structured-data/index.mjs +2 -1
  158. package/dist/types/components/Badge/index.d.ts.map +1 -1
  159. package/dist/types/components/Button/Button.d.ts +2 -2
  160. package/dist/types/components/Button/Button.d.ts.map +1 -1
  161. package/dist/types/components/Container/index.d.ts.map +1 -1
  162. package/dist/types/components/DictionaryFieldEditor/ContentEditorView/TextEditor.d.ts.map +1 -1
  163. package/dist/types/components/DictionaryFieldEditor/NodeEditor.d.ts +10 -0
  164. package/dist/types/components/DictionaryFieldEditor/NodeEditor.d.ts.map +1 -0
  165. package/dist/types/components/DictionaryFieldEditor/index.d.ts +2 -2
  166. package/dist/types/components/Footer/index.d.ts.map +1 -1
  167. package/dist/types/components/Form/FormBase.d.ts +1 -1
  168. package/dist/types/components/IDE/CodeBlockServer.d.ts +1 -1
  169. package/dist/types/components/IDE/CodeBlockServer.d.ts.map +1 -1
  170. package/dist/types/components/IDE/CodeBlockShiki.d.ts.map +1 -1
  171. package/dist/types/components/IDE/MarkDownRender.d.ts +1 -0
  172. package/dist/types/components/IDE/MarkDownRender.d.ts.map +1 -1
  173. package/dist/types/components/IDE/shikiBundle.d.ts +74 -0
  174. package/dist/types/components/IDE/shikiBundle.d.ts.map +1 -0
  175. package/dist/types/components/IDE/shikiLanguages.d.ts +2 -39
  176. package/dist/types/components/IDE/shikiLanguages.d.ts.map +1 -1
  177. package/dist/types/components/IDE/shikiThemes.d.ts +3 -1
  178. package/dist/types/components/IDE/shikiThemes.d.ts.map +1 -1
  179. package/dist/types/components/LanguageBackground/LanguageSection.d.ts +5 -1
  180. package/dist/types/components/LanguageBackground/LanguageSection.d.ts.map +1 -1
  181. package/dist/types/components/LanguageBackground/index.d.ts +2 -2
  182. package/dist/types/components/MarkDownRender/MarkDownIframe.d.ts.map +1 -1
  183. package/dist/types/components/MarkDownRender/MarkDownRender.d.ts.map +1 -1
  184. package/dist/types/components/MarkdownEditor/novel/extensions/code-block-shiki.d.ts +15 -0
  185. package/dist/types/components/MarkdownEditor/novel/extensions/code-block-shiki.d.ts.map +1 -0
  186. package/dist/types/components/MarkdownEditor/novel/extensions/index.d.ts +2 -1
  187. package/dist/types/components/MarkdownEditor/novel/extensions/index.d.ts.map +1 -1
  188. package/dist/types/components/MarkdownEditor/novel/index.d.ts +2 -1
  189. package/dist/types/components/Status/index.d.ts +8 -0
  190. package/dist/types/components/Status/index.d.ts.map +1 -0
  191. package/dist/types/components/SwitchSelector/SwitchSelector.d.ts +3 -3
  192. package/dist/types/components/SwitchSelector/SwitchSelector.d.ts.map +1 -1
  193. package/dist/types/components/Table/TableElements.d.ts.map +1 -1
  194. package/dist/types/components/TechLogo/TechLogo.d.ts.map +1 -1
  195. package/dist/types/components/TechLogo/logos/HTMX.d.ts +6 -0
  196. package/dist/types/components/TechLogo/logos/HTMX.d.ts.map +1 -0
  197. package/dist/types/components/TechLogo/logos/Remix.d.ts +6 -0
  198. package/dist/types/components/TechLogo/logos/Remix.d.ts.map +1 -0
  199. package/dist/types/components/TechLogo/techLogos.d.ts +4 -2
  200. package/dist/types/components/TechLogo/types.d.ts +1 -1
  201. package/dist/types/components/TextArea/TextArea.d.ts +1 -1
  202. package/dist/types/components/index.d.ts +3 -2
  203. package/dist/types/providers/ThemeProvider.d.ts.map +1 -1
  204. package/dist/types/routes.d.ts +21 -3
  205. package/dist/types/routes.d.ts.map +1 -1
  206. package/dist/types/structured-data/buildItemListJsonLd.d.ts +36 -0
  207. package/dist/types/structured-data/buildItemListJsonLd.d.ts.map +1 -0
  208. package/dist/types/structured-data/index.d.ts +2 -1
  209. package/package.json +68 -54
  210. package/src/components/MarkdownEditor/markdown-editor.css +17 -17
  211. package/styles/globals.css +71 -0
  212. package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs.map +0 -1
  213. package/dist/types/components/DictionaryFieldEditor/ContentEditor.d.ts +0 -10
  214. package/dist/types/components/DictionaryFieldEditor/ContentEditor.d.ts.map +0 -1
  215. package/tailwind.css +0 -269
@@ -35,7 +35,7 @@ const CodeBlockHighlight = ({ children, originalLang, targetFormat, initialHtml
35
35
  code = transformCode(String(children), targetFormat);
36
36
  shikiLang = resolveCodeLanguage(deriveLanguage(originalLang, targetFormat)).id;
37
37
  }
38
- const { codeToHtml } = await import("shiki/bundle/web");
38
+ const { codeToHtml } = await import("./shikiBundle.mjs");
39
39
  if (cancelled) return;
40
40
  const out = await codeToHtml(String(code), {
41
41
  lang: shikiLang,
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlockHighlight.mjs","names":[],"sources":["../../../../src/components/IDE/CodeBlockHighlight.tsx"],"sourcesContent":["'use client';\n\n/**\n * Client-side Shiki highlighter that also handles TypeScript→ESM/CJS transformation.\n *\n * Everything runs inside a single useEffect so that:\n * - Nothing is imported at all while the canonical TypeScript source is shown\n * and its markup was already highlighted ahead of time.\n * - The transformer is only dynamically imported when a non-TypeScript format is selected.\n * - The previous highlighted HTML stays visible while the new one loads (no white-text flash).\n */\n\nimport { type ReactNode, useEffect, useRef, useState } from 'react';\nimport type { CodeFormat } from './CodeContext';\nimport { type CodeLanguage, resolveCodeLanguage } from './shikiLanguages';\nimport { SHIKI_THEMES } from './shikiThemes';\n\ntype Props = {\n /** Raw TypeScript source code (the canonical \"source of truth\"). */\n children: ReactNode;\n /** Language of the source (e.g. 'tsx', 'typescript'). */\n originalLang: CodeLanguage;\n /** Currently selected format: 'typescript' | 'esm' | 'commonjs'. */\n targetFormat: Exclude<CodeFormat, 'json'>;\n /** Markup for the TypeScript source, highlighted ahead of time. */\n initialHtml?: string;\n};\n\nexport const CodeBlockHighlight = ({\n children,\n originalLang,\n targetFormat,\n initialHtml,\n}: Props) => {\n const [html, setHtml] = useState<string | null>(initialHtml ?? null);\n const prevHtml = useRef<string | null>(initialHtml ?? null);\n\n useEffect(() => {\n // The pre-highlighted markup already is the TypeScript rendering — no need\n // to pull Shiki into the browser until another format is picked.\n if (initialHtml && targetFormat === 'typescript') {\n prevHtml.current = initialHtml;\n setHtml(initialHtml);\n return;\n }\n\n let cancelled = false;\n\n (async () => {\n try {\n let code = children;\n let shikiLang = resolveCodeLanguage(originalLang).id;\n\n // Only import the transformer when we actually need it.\n if (targetFormat !== 'typescript') {\n const { transformCode, deriveLanguage } = await import(\n './codeTransformer'\n );\n if (cancelled) return;\n code = transformCode(String(children), targetFormat);\n shikiLang = resolveCodeLanguage(\n deriveLanguage(originalLang, targetFormat)\n ).id;\n }\n\n const { codeToHtml } = await import('shiki/bundle/web');\n if (cancelled) return;\n\n const out = await codeToHtml(String(code), {\n lang: shikiLang,\n themes: SHIKI_THEMES,\n defaultColor: false,\n });\n\n if (!cancelled) {\n prevHtml.current = out;\n setHtml(out);\n }\n } catch {\n // Shiki failed (unknown language, etc.) — fall through to plain-text.\n if (!cancelled) setHtml('');\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [children, originalLang, targetFormat, initialHtml]);\n\n // Keep the previous highlighted output visible while the new one is loading.\n // This prevents the white-text flash on format switches.\n const display = html ?? prevHtml.current;\n\n if (!display) {\n return (\n <pre className=\"min-w-0 max-w-full overflow-x-auto\">\n <code>{children}</code>\n </pre>\n );\n }\n\n return (\n <div\n // biome-ignore lint/security/noDangerouslySetInnerHtml: Shiki generates safe HTML for code highlighting\n dangerouslySetInnerHTML={{ __html: display }}\n style={{ backgroundColor: 'transparent' }}\n />\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AA4BA,MAAa,sBAAsB,EACjC,UACA,cACA,cACA,kBACW;CACX,MAAM,CAAC,MAAM,WAAW,SAAwB,eAAe,IAAI;CACnE,MAAM,WAAW,OAAsB,eAAe,IAAI;CAE1D,gBAAgB;EAGd,IAAI,eAAe,iBAAiB,cAAc;GAChD,SAAS,UAAU;GACnB,QAAQ,WAAW;GACnB;EACF;EAEA,IAAI,YAAY;EAEhB,CAAC,YAAY;GACX,IAAI;IACF,IAAI,OAAO;IACX,IAAI,YAAY,oBAAoB,YAAY,CAAC,CAAC;IAGlD,IAAI,iBAAiB,cAAc;KACjC,MAAM,EAAE,eAAe,mBAAmB,MAAM,OAC9C;KAEF,IAAI,WAAW;KACf,OAAO,cAAc,OAAO,QAAQ,GAAG,YAAY;KACnD,YAAY,oBACV,eAAe,cAAc,YAAY,CAC3C,CAAC,CAAC;IACJ;IAEA,MAAM,EAAE,eAAe,MAAM,OAAO;IACpC,IAAI,WAAW;IAEf,MAAM,MAAM,MAAM,WAAW,OAAO,IAAI,GAAG;KACzC,MAAM;KACN,QAAQ;KACR,cAAc;IAChB,CAAC;IAED,IAAI,CAAC,WAAW;KACd,SAAS,UAAU;KACnB,QAAQ,GAAG;IACb;GACF,QAAQ;IAEN,IAAI,CAAC,WAAW,QAAQ,EAAE;GAC5B;EACF,EAAC,CAAE;EAEH,aAAa;GACX,YAAY;EACd;CACF,GAAG;EAAC;EAAU;EAAc;EAAc;CAAW,CAAC;CAItD,MAAM,UAAU,QAAQ,SAAS;CAEjC,IAAI,CAAC,SACH,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,QAAD,EAAO,SAAe;CACnB;CAIT,OACE,oBAAC,OAAD;EAEE,yBAAyB,EAAE,QAAQ,QAAQ;EAC3C,OAAO,EAAE,iBAAiB,cAAc;CACzC;AAEL"}
1
+ {"version":3,"file":"CodeBlockHighlight.mjs","names":[],"sources":["../../../../src/components/IDE/CodeBlockHighlight.tsx"],"sourcesContent":["'use client';\n\n/**\n * Client-side Shiki highlighter that also handles TypeScript→ESM/CJS transformation.\n *\n * Everything runs inside a single useEffect so that:\n * - Nothing is imported at all while the canonical TypeScript source is shown\n * and its markup was already highlighted ahead of time.\n * - The transformer is only dynamically imported when a non-TypeScript format is selected.\n * - The previous highlighted HTML stays visible while the new one loads (no white-text flash).\n */\n\nimport { type ReactNode, useEffect, useRef, useState } from 'react';\nimport type { CodeFormat } from './CodeContext';\nimport { type CodeLanguage, resolveCodeLanguage } from './shikiLanguages';\nimport { SHIKI_THEMES } from './shikiThemes';\n\ntype Props = {\n /** Raw TypeScript source code (the canonical \"source of truth\"). */\n children: ReactNode;\n /** Language of the source (e.g. 'tsx', 'typescript'). */\n originalLang: CodeLanguage;\n /** Currently selected format: 'typescript' | 'esm' | 'commonjs'. */\n targetFormat: Exclude<CodeFormat, 'json'>;\n /** Markup for the TypeScript source, highlighted ahead of time. */\n initialHtml?: string;\n};\n\nexport const CodeBlockHighlight = ({\n children,\n originalLang,\n targetFormat,\n initialHtml,\n}: Props) => {\n const [html, setHtml] = useState<string | null>(initialHtml ?? null);\n const prevHtml = useRef<string | null>(initialHtml ?? null);\n\n useEffect(() => {\n // The pre-highlighted markup already is the TypeScript rendering — no need\n // to pull Shiki into the browser until another format is picked.\n if (initialHtml && targetFormat === 'typescript') {\n prevHtml.current = initialHtml;\n setHtml(initialHtml);\n return;\n }\n\n let cancelled = false;\n\n (async () => {\n try {\n let code = children;\n let shikiLang = resolveCodeLanguage(originalLang).id;\n\n // Only import the transformer when we actually need it.\n if (targetFormat !== 'typescript') {\n const { transformCode, deriveLanguage } = await import(\n './codeTransformer'\n );\n if (cancelled) return;\n code = transformCode(String(children), targetFormat);\n shikiLang = resolveCodeLanguage(\n deriveLanguage(originalLang, targetFormat)\n ).id;\n }\n\n const { codeToHtml } = await import('./shikiBundle');\n if (cancelled) return;\n\n const out = await codeToHtml(String(code), {\n lang: shikiLang,\n themes: SHIKI_THEMES,\n defaultColor: false,\n });\n\n if (!cancelled) {\n prevHtml.current = out;\n setHtml(out);\n }\n } catch {\n // Shiki failed (unknown language, etc.) — fall through to plain-text.\n if (!cancelled) setHtml('');\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [children, originalLang, targetFormat, initialHtml]);\n\n // Keep the previous highlighted output visible while the new one is loading.\n // This prevents the white-text flash on format switches.\n const display = html ?? prevHtml.current;\n\n if (!display) {\n return (\n <pre className=\"min-w-0 max-w-full overflow-x-auto\">\n <code>{children}</code>\n </pre>\n );\n }\n\n return (\n <div\n // biome-ignore lint/security/noDangerouslySetInnerHtml: Shiki generates safe HTML for code highlighting\n dangerouslySetInnerHTML={{ __html: display }}\n style={{ backgroundColor: 'transparent' }}\n />\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AA4BA,MAAa,sBAAsB,EACjC,UACA,cACA,cACA,kBACW;CACX,MAAM,CAAC,MAAM,WAAW,SAAwB,eAAe,IAAI;CACnE,MAAM,WAAW,OAAsB,eAAe,IAAI;CAE1D,gBAAgB;EAGd,IAAI,eAAe,iBAAiB,cAAc;GAChD,SAAS,UAAU;GACnB,QAAQ,WAAW;GACnB;EACF;EAEA,IAAI,YAAY;EAEhB,CAAC,YAAY;GACX,IAAI;IACF,IAAI,OAAO;IACX,IAAI,YAAY,oBAAoB,YAAY,CAAC,CAAC;IAGlD,IAAI,iBAAiB,cAAc;KACjC,MAAM,EAAE,eAAe,mBAAmB,MAAM,OAC9C;KAEF,IAAI,WAAW;KACf,OAAO,cAAc,OAAO,QAAQ,GAAG,YAAY;KACnD,YAAY,oBACV,eAAe,cAAc,YAAY,CAC3C,CAAC,CAAC;IACJ;IAEA,MAAM,EAAE,eAAe,MAAM,OAAO;IACpC,IAAI,WAAW;IAEf,MAAM,MAAM,MAAM,WAAW,OAAO,IAAI,GAAG;KACzC,MAAM;KACN,QAAQ;KACR,cAAc;IAChB,CAAC;IAED,IAAI,CAAC,WAAW;KACd,SAAS,UAAU;KACnB,QAAQ,GAAG;IACb;GACF,QAAQ;IAEN,IAAI,CAAC,WAAW,QAAQ,EAAE;GAC5B;EACF,EAAC,CAAE;EAEH,aAAa;GACX,YAAY;EACd;CACF,GAAG;EAAC;EAAU;EAAc;EAAc;CAAW,CAAC;CAItD,MAAM,UAAU,QAAQ,SAAS;CAEjC,IAAI,CAAC,SACH,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,QAAD,EAAO,SAAe;CACnB;CAIT,OACE,oBAAC,OAAD;EAEE,yBAAyB,EAAE,QAAQ,QAAQ;EAC3C,OAAO,EAAE,iBAAiB,cAAc;CACzC;AAEL"}
@@ -1,9 +1,9 @@
1
1
  import { cn } from "../../utils/cn.mjs";
2
2
  import { SHIKI_THEMES } from "./shikiThemes.mjs";
3
+ import { codeToHtml } from "./shikiBundle.mjs";
3
4
  import { Suspense } from "react";
4
5
  import { jsx } from "react/jsx-runtime";
5
6
  import { transformerMetaHighlight, transformerMetaWordHighlight, transformerNotationDiff, transformerNotationErrorLevel, transformerNotationHighlight, transformerNotationWordHighlight } from "@shikijs/transformers";
6
- import { codeToHtml } from "shiki/bundle/web";
7
7
 
8
8
  //#region src/components/IDE/CodeBlockServer.tsx
9
9
  const CodeBlockShiki = (async ({ children, lang, onChange, ...props }) => {
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlockServer.mjs","names":[],"sources":["../../../../src/components/IDE/CodeBlockServer.tsx"],"sourcesContent":["import {\n transformerMetaHighlight,\n transformerMetaWordHighlight,\n transformerNotationDiff,\n transformerNotationErrorLevel,\n transformerNotationHighlight,\n transformerNotationWordHighlight,\n} from '@shikijs/transformers';\nimport { cn } from '@utils/cn';\nimport { type FC, type HTMLAttributes, Suspense } from 'react';\nimport {\n type BundledLanguage,\n type BundledTheme,\n type CodeToHastOptions,\n codeToHtml,\n} from 'shiki/bundle/web';\nimport { SHIKI_THEMES } from './shikiThemes';\n\nexport const CodeBlockShiki = (async ({\n children,\n lang,\n onChange,\n ...props\n}: CodeBlockProps) => {\n const shikiOptions: CodeToHastOptions<BundledLanguage, BundledTheme> = {\n lang,\n themes: SHIKI_THEMES,\n // Both palettes ship as CSS variables, so one markup serves both themes.\n defaultColor: false,\n transformers: [\n transformerNotationDiff(),\n transformerNotationHighlight(),\n transformerNotationWordHighlight(),\n transformerNotationErrorLevel(),\n transformerMetaHighlight(),\n transformerMetaWordHighlight(),\n ],\n };\n\n const out = await codeToHtml(children, shikiOptions);\n\n return (\n <div\n dangerouslySetInnerHTML={{ __html: out }}\n {...props}\n style={{ backgroundColor: 'transparent' }}\n />\n );\n}) as unknown as FC<CodeBlockProps>;\n\nconst CodeDefault: FC<CodeBlockProps> = ({\n children,\n isEditable,\n onChange,\n ...props\n}) => (\n <div contentEditable={isEditable} {...props}>\n <pre>\n <code>\n {typeof children === 'string'\n ? children.split('\\n').map((line, index) => (\n <span className=\"line block w-full\" key={index}>\n {line}\n </span>\n ))\n : children}\n </code>\n </pre>\n </div>\n);\n\nexport type CodeBlockProps = {\n children: string;\n lang: BundledLanguage;\n isEditable?: boolean;\n onChange?: (content: string) => void;\n} & Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>;\n\nexport const CodeBlock: FC<CodeBlockProps> = ({\n className,\n onChange,\n isEditable,\n ...props\n}) => (\n <Suspense fallback={<CodeDefault {...props} />}>\n <CodeBlockShiki\n className={cn('flex w-full', className)}\n contentEditable={isEditable}\n onInput={(e) => onChange?.(e.currentTarget.textContent ?? '')}\n {...props}\n />\n </Suspense>\n);\n"],"mappings":";;;;;;;;AAkBA,MAAa,kBAAkB,OAAO,EACpC,UACA,MACA,UACA,GAAG,YACiB;CACpB,MAAM,eAAiE;EACrE;EACA,QAAQ;EAER,cAAc;EACd,cAAc;GACZ,wBAAwB;GACxB,6BAA6B;GAC7B,iCAAiC;GACjC,8BAA8B;GAC9B,yBAAyB;GACzB,6BAA6B;EAC/B;CACF;CAEA,MAAM,MAAM,MAAM,WAAW,UAAU,YAAY;CAEnD,OACE,oBAAC,OAAD;EACE,yBAAyB,EAAE,QAAQ,IAAI;EACvC,GAAI;EACJ,OAAO,EAAE,iBAAiB,cAAc;CACzC;AAEL;AAEA,MAAM,eAAmC,EACvC,UACA,YACA,UACA,GAAG,YAEH,oBAAC,OAAD;CAAK,iBAAiB;CAAY,GAAI;WACpC,oBAAC,OAAD,YACE,oBAAC,QAAD,YACG,OAAO,aAAa,WACjB,SAAS,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,UAC9B,oBAAC,QAAD;EAAM,WAAU;YACb;CACG,GAFmC,KAEnC,CACP,IACD,SACA,GACH;AACF;AAUP,MAAa,aAAiC,EAC5C,WACA,UACA,YACA,GAAG,YAEH,oBAAC,UAAD;CAAU,UAAU,oBAAC,aAAD,EAAa,GAAI,MAAQ;WAC3C,oBAAC,gBAAD;EACE,WAAW,GAAG,eAAe,SAAS;EACtC,iBAAiB;EACjB,UAAU,MAAM,WAAW,EAAE,cAAc,eAAe,EAAE;EAC5D,GAAI;CACL;AACO"}
1
+ {"version":3,"file":"CodeBlockServer.mjs","names":[],"sources":["../../../../src/components/IDE/CodeBlockServer.tsx"],"sourcesContent":["import {\n transformerMetaHighlight,\n transformerMetaWordHighlight,\n transformerNotationDiff,\n transformerNotationErrorLevel,\n transformerNotationHighlight,\n transformerNotationWordHighlight,\n} from '@shikijs/transformers';\nimport { cn } from '@utils/cn';\nimport { type FC, type HTMLAttributes, Suspense } from 'react';\nimport { type BundledLanguage, codeToHtml } from './shikiBundle';\nimport { SHIKI_THEMES } from './shikiThemes';\n\nexport const CodeBlockShiki = (async ({\n children,\n lang,\n onChange,\n ...props\n}: CodeBlockProps) => {\n const shikiOptions: Parameters<typeof codeToHtml>[1] = {\n lang,\n themes: SHIKI_THEMES,\n // Both palettes ship as CSS variables, so one markup serves both themes.\n defaultColor: false,\n transformers: [\n transformerNotationDiff(),\n transformerNotationHighlight(),\n transformerNotationWordHighlight(),\n transformerNotationErrorLevel(),\n transformerMetaHighlight(),\n transformerMetaWordHighlight(),\n ],\n };\n\n const out = await codeToHtml(children, shikiOptions);\n\n return (\n <div\n dangerouslySetInnerHTML={{ __html: out }}\n {...props}\n style={{ backgroundColor: 'transparent' }}\n />\n );\n}) as unknown as FC<CodeBlockProps>;\n\nconst CodeDefault: FC<CodeBlockProps> = ({\n children,\n isEditable,\n onChange,\n ...props\n}) => (\n <div contentEditable={isEditable} {...props}>\n <pre>\n <code>\n {typeof children === 'string'\n ? children.split('\\n').map((line, index) => (\n <span className=\"line block w-full\" key={index}>\n {line}\n </span>\n ))\n : children}\n </code>\n </pre>\n </div>\n);\n\nexport type CodeBlockProps = {\n children: string;\n lang: BundledLanguage;\n isEditable?: boolean;\n onChange?: (content: string) => void;\n} & Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>;\n\nexport const CodeBlock: FC<CodeBlockProps> = ({\n className,\n onChange,\n isEditable,\n ...props\n}) => (\n <Suspense fallback={<CodeDefault {...props} />}>\n <CodeBlockShiki\n className={cn('flex w-full', className)}\n contentEditable={isEditable}\n onInput={(e) => onChange?.(e.currentTarget.textContent ?? '')}\n {...props}\n />\n </Suspense>\n);\n"],"mappings":";;;;;;;;AAaA,MAAa,kBAAkB,OAAO,EACpC,UACA,MACA,UACA,GAAG,YACiB;CACpB,MAAM,eAAiD;EACrD;EACA,QAAQ;EAER,cAAc;EACd,cAAc;GACZ,wBAAwB;GACxB,6BAA6B;GAC7B,iCAAiC;GACjC,8BAA8B;GAC9B,yBAAyB;GACzB,6BAA6B;EAC/B;CACF;CAEA,MAAM,MAAM,MAAM,WAAW,UAAU,YAAY;CAEnD,OACE,oBAAC,OAAD;EACE,yBAAyB,EAAE,QAAQ,IAAI;EACvC,GAAI;EACJ,OAAO,EAAE,iBAAiB,cAAc;CACzC;AAEL;AAEA,MAAM,eAAmC,EACvC,UACA,YACA,UACA,GAAG,YAEH,oBAAC,OAAD;CAAK,iBAAiB;CAAY,GAAI;WACpC,oBAAC,OAAD,YACE,oBAAC,QAAD,YACG,OAAO,aAAa,WACjB,SAAS,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,UAC9B,oBAAC,QAAD;EAAM,WAAU;YACb;CACG,GAFmC,KAEnC,CACP,IACD,SACA,GACH;AACF;AAUP,MAAa,aAAiC,EAC5C,WACA,UACA,YACA,GAAG,YAEH,oBAAC,UAAD;CAAU,UAAU,oBAAC,aAAD,EAAa,GAAI,MAAQ;WAC3C,oBAAC,gBAAD;EACE,WAAW,GAAG,eAAe,SAAS;EACtC,iBAAiB;EACjB,UAAU,MAAM,WAAW,EAAE,cAAc,eAAe,EAAE;EAC5D,GAAI;CACL;AACO"}
@@ -7,60 +7,18 @@ import { useEffect, useState } from "react";
7
7
  import { jsx } from "react/jsx-runtime";
8
8
 
9
9
  //#region src/components/IDE/CodeBlockShiki.tsx
10
- const languageCache = /* @__PURE__ */ new Map();
11
- const themeCache = /* @__PURE__ */ new Map();
12
- /**
13
- * Lazy load the grammar of an already resolved language.
14
- *
15
- * @returns The grammar registrations, or `null` for languages Shiki renders
16
- * without a grammar (plain text).
17
- */
18
- const loadLanguage = async ({ id, loadGrammar }) => {
19
- if (!loadGrammar) return null;
20
- const cachedLanguage = languageCache.get(id);
21
- if (cachedLanguage) return cachedLanguage;
22
- const languagePromise = loadGrammar().then((module) => module.default);
23
- languageCache.set(id, languagePromise);
24
- return languagePromise;
25
- };
26
- /**
27
- * Lazy load a theme module.
28
- */
29
- const loadTheme = async (themeName) => {
30
- const cachedTheme = themeCache.get(themeName);
31
- if (cachedTheme) return cachedTheme;
32
- const themePromise = (themeName === SHIKI_THEMES.dark ? import("shiki/themes/github-dark.mjs") : import("shiki/themes/github-light.mjs")).then((module) => module.default);
33
- themeCache.set(themeName, themePromise);
34
- return themePromise;
35
- };
36
- let highlighterPromise = null;
37
- const getHighlighterInstance = async () => {
38
- if (!highlighterPromise) highlighterPromise = import("shiki/bundle/web").then(({ createHighlighter }) => createHighlighter({
39
- langs: [],
40
- themes: []
41
- }));
42
- return highlighterPromise;
43
- };
44
10
  /**
45
11
  * Highlight a snippet, lazily loading only the grammar and themes it needs.
46
12
  *
47
13
  * The language is resolved to a canonical Shiki id first, so that the id passed
48
- * to `codeToHtml` always matches the grammar that was loaded.
14
+ * to `codeToHtml` always matches a grammar the bundle can load. Shiki itself is
15
+ * imported from `./shikiBundle` — the fine-grained bundle — and only once a
16
+ * snippet actually has to be highlighted in the browser.
49
17
  */
50
18
  const highlightCode = async (code, lang) => {
51
- const resolvedLanguage = resolveCodeLanguage(lang);
52
- const [highlighter, languageModule, lightTheme, darkTheme] = await Promise.all([
53
- getHighlighterInstance(),
54
- loadLanguage(resolvedLanguage),
55
- loadTheme(SHIKI_THEMES.light),
56
- loadTheme(SHIKI_THEMES.dark)
57
- ]);
58
- if (languageModule && !highlighter.getLoadedLanguages().includes(resolvedLanguage.id)) await highlighter.loadLanguage(languageModule);
59
- const loadedThemes = highlighter.getLoadedThemes();
60
- if (!loadedThemes.includes(SHIKI_THEMES.light)) await highlighter.loadTheme(lightTheme);
61
- if (!loadedThemes.includes(SHIKI_THEMES.dark)) await highlighter.loadTheme(darkTheme);
62
- return highlighter.codeToHtml(String(code), {
63
- lang: resolvedLanguage.id,
19
+ const { codeToHtml } = await import("./shikiBundle.mjs");
20
+ return codeToHtml(String(code), {
21
+ lang: resolveCodeLanguage(lang).id,
64
22
  themes: SHIKI_THEMES,
65
23
  defaultColor: false
66
24
  });
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlockShiki.mjs","names":[],"sources":["../../../../src/components/IDE/CodeBlockShiki.tsx"],"sourcesContent":["'use client';\n\nimport { type FC, type ReactNode, useEffect, useState } from 'react';\nimport { CodeDefault, shikiWrapperClassName } from './CodeBlockClient';\nimport {\n type CodeLanguage,\n type LanguageGrammar,\n type ResolvedCodeLanguage,\n resolveCodeLanguage,\n} from './shikiLanguages';\nimport { SHIKI_THEMES } from './shikiThemes';\n\n/** Theme registration, as default-exported by the `shiki/themes/*` modules. */\ntype ThemeRegistration =\n typeof import('shiki/themes/github-dark.mjs')['default'];\n\n/** Minimal Shiki highlighter surface used here, with unrestricted language ids. */\ntype CodeHighlighter = {\n getLoadedLanguages(): string[];\n getLoadedThemes(): string[];\n loadLanguage(grammar: LanguageGrammar): Promise<void>;\n loadTheme(theme: ThemeRegistration): Promise<void>;\n codeToHtml(\n code: string,\n options: {\n lang: string;\n themes: { light: string; dark: string };\n defaultColor: false;\n }\n ): string;\n};\n\n// Map of in-flight/loaded modules to avoid re-importing\nconst languageCache = new Map<string, Promise<LanguageGrammar>>();\nconst themeCache = new Map<string, Promise<ThemeRegistration>>();\n\n/**\n * Lazy load the grammar of an already resolved language.\n *\n * @returns The grammar registrations, or `null` for languages Shiki renders\n * without a grammar (plain text).\n */\nconst loadLanguage = async ({\n id,\n loadGrammar,\n}: ResolvedCodeLanguage): Promise<LanguageGrammar | null> => {\n if (!loadGrammar) return null;\n\n const cachedLanguage = languageCache.get(id);\n if (cachedLanguage) return cachedLanguage;\n\n const languagePromise = loadGrammar().then((module) => module.default);\n languageCache.set(id, languagePromise);\n\n return languagePromise;\n};\n\n/**\n * Lazy load a theme module.\n */\nconst loadTheme = async (themeName: string): Promise<ThemeRegistration> => {\n const cachedTheme = themeCache.get(themeName);\n if (cachedTheme) return cachedTheme;\n\n const themePromise = (\n themeName === SHIKI_THEMES.dark\n ? import('shiki/themes/github-dark.mjs')\n : import('shiki/themes/github-light.mjs')\n ).then((module) => module.default);\n\n themeCache.set(themeName, themePromise);\n\n return themePromise;\n};\n\n// Singleton Highlighter Instance\nlet highlighterPromise: Promise<CodeHighlighter> | null = null;\n\nconst getHighlighterInstance = async () => {\n if (!highlighterPromise) {\n highlighterPromise = import('shiki/bundle/web').then(\n ({ createHighlighter }) =>\n createHighlighter({\n langs: [],\n themes: [],\n })\n );\n }\n return highlighterPromise;\n};\n\n/**\n * Highlight a snippet, lazily loading only the grammar and themes it needs.\n *\n * The language is resolved to a canonical Shiki id first, so that the id passed\n * to `codeToHtml` always matches the grammar that was loaded.\n */\nconst highlightCode = async (\n code: ReactNode,\n lang: CodeLanguage\n): Promise<string> => {\n const resolvedLanguage = resolveCodeLanguage(lang);\n\n // Load highlighter, language, and themes in parallel\n const [highlighter, languageModule, lightTheme, darkTheme] =\n await Promise.all([\n getHighlighterInstance(),\n loadLanguage(resolvedLanguage),\n loadTheme(SHIKI_THEMES.light),\n loadTheme(SHIKI_THEMES.dark),\n ]);\n\n // Load into the singleton instance if not already loaded\n if (\n languageModule &&\n !highlighter.getLoadedLanguages().includes(resolvedLanguage.id)\n ) {\n await highlighter.loadLanguage(languageModule);\n }\n\n const loadedThemes = highlighter.getLoadedThemes();\n if (!loadedThemes.includes(SHIKI_THEMES.light)) {\n await highlighter.loadTheme(lightTheme);\n }\n if (!loadedThemes.includes(SHIKI_THEMES.dark)) {\n await highlighter.loadTheme(darkTheme);\n }\n\n return highlighter.codeToHtml(String(code), {\n lang: resolvedLanguage.id,\n themes: SHIKI_THEMES,\n defaultColor: false,\n });\n};\n\nexport type CodeBlockShikiProps = {\n children: ReactNode;\n lang: CodeLanguage;\n};\n\nexport const CodeBlockShiki: FC<CodeBlockShikiProps> = ({ children, lang }) => {\n const [html, setHtml] = useState<string | null>(null);\n\n useEffect(() => {\n let isCancelled = false;\n\n highlightCode(children, lang)\n .then((result) => {\n if (!isCancelled) setHtml(result);\n })\n .catch((error) => {\n console.error('Failed to highlight code:', error);\n if (!isCancelled) setHtml('');\n });\n\n return () => {\n isCancelled = true;\n };\n }, [children, lang]);\n\n return (\n <div className={shikiWrapperClassName}>\n {html ? (\n // biome-ignore lint/security/noDangerouslySetInnerHtml: Shiki generates safe HTML for code highlighting\n <div dangerouslySetInnerHTML={{ __html: html }} />\n ) : (\n <CodeDefault>{children}</CodeDefault>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;AAiCA,MAAM,gCAAgB,IAAI,IAAsC;AAChE,MAAM,6BAAa,IAAI,IAAwC;;;;;;;AAQ/D,MAAM,eAAe,OAAO,EAC1B,IACA,kBAC2D;CAC3D,IAAI,CAAC,aAAa,OAAO;CAEzB,MAAM,iBAAiB,cAAc,IAAI,EAAE;CAC3C,IAAI,gBAAgB,OAAO;CAE3B,MAAM,kBAAkB,YAAY,CAAC,CAAC,MAAM,WAAW,OAAO,OAAO;CACrE,cAAc,IAAI,IAAI,eAAe;CAErC,OAAO;AACT;;;;AAKA,MAAM,YAAY,OAAO,cAAkD;CACzE,MAAM,cAAc,WAAW,IAAI,SAAS;CAC5C,IAAI,aAAa,OAAO;CAExB,MAAM,gBACJ,cAAc,aAAa,OACvB,OAAO,kCACP,OAAO,iCAAgC,CAC3C,MAAM,WAAW,OAAO,OAAO;CAEjC,WAAW,IAAI,WAAW,YAAY;CAEtC,OAAO;AACT;AAGA,IAAI,qBAAsD;AAE1D,MAAM,yBAAyB,YAAY;CACzC,IAAI,CAAC,oBACH,qBAAqB,OAAO,mBAAmB,CAAC,MAC7C,EAAE,wBACD,kBAAkB;EAChB,OAAO,CAAC;EACR,QAAQ,CAAC;CACX,CAAC,CACL;CAEF,OAAO;AACT;;;;;;;AAQA,MAAM,gBAAgB,OACpB,MACA,SACoB;CACpB,MAAM,mBAAmB,oBAAoB,IAAI;CAGjD,MAAM,CAAC,aAAa,gBAAgB,YAAY,aAC9C,MAAM,QAAQ,IAAI;EAChB,uBAAuB;EACvB,aAAa,gBAAgB;EAC7B,UAAU,aAAa,KAAK;EAC5B,UAAU,aAAa,IAAI;CAC7B,CAAC;CAGH,IACE,kBACA,CAAC,YAAY,mBAAmB,CAAC,CAAC,SAAS,iBAAiB,EAAE,GAE9D,MAAM,YAAY,aAAa,cAAc;CAG/C,MAAM,eAAe,YAAY,gBAAgB;CACjD,IAAI,CAAC,aAAa,SAAS,aAAa,KAAK,GAC3C,MAAM,YAAY,UAAU,UAAU;CAExC,IAAI,CAAC,aAAa,SAAS,aAAa,IAAI,GAC1C,MAAM,YAAY,UAAU,SAAS;CAGvC,OAAO,YAAY,WAAW,OAAO,IAAI,GAAG;EAC1C,MAAM,iBAAiB;EACvB,QAAQ;EACR,cAAc;CAChB,CAAC;AACH;AAOA,MAAa,kBAA2C,EAAE,UAAU,WAAW;CAC7E,MAAM,CAAC,MAAM,WAAW,SAAwB,IAAI;CAEpD,gBAAgB;EACd,IAAI,cAAc;EAElB,cAAc,UAAU,IAAI,CAAC,CAC1B,MAAM,WAAW;GAChB,IAAI,CAAC,aAAa,QAAQ,MAAM;EAClC,CAAC,CAAC,CACD,OAAO,UAAU;GAChB,QAAQ,MAAM,6BAA6B,KAAK;GAChD,IAAI,CAAC,aAAa,QAAQ,EAAE;EAC9B,CAAC;EAEH,aAAa;GACX,cAAc;EAChB;CACF,GAAG,CAAC,UAAU,IAAI,CAAC;CAEnB,OACE,oBAAC,OAAD;EAAK,WAAW;YACb,OAEC,oBAAC,OAAD,EAAK,yBAAyB,EAAE,QAAQ,KAAK,EAAI,KAEjD,oBAAC,aAAD,EAAc,SAAsB;CAEnC;AAET"}
1
+ {"version":3,"file":"CodeBlockShiki.mjs","names":[],"sources":["../../../../src/components/IDE/CodeBlockShiki.tsx"],"sourcesContent":["'use client';\n\nimport { type FC, type ReactNode, useEffect, useState } from 'react';\nimport { CodeDefault, shikiWrapperClassName } from './CodeBlockClient';\nimport { type CodeLanguage, resolveCodeLanguage } from './shikiLanguages';\nimport { SHIKI_THEMES } from './shikiThemes';\n\n/**\n * Highlight a snippet, lazily loading only the grammar and themes it needs.\n *\n * The language is resolved to a canonical Shiki id first, so that the id passed\n * to `codeToHtml` always matches a grammar the bundle can load. Shiki itself is\n * imported from `./shikiBundle` — the fine-grained bundle — and only once a\n * snippet actually has to be highlighted in the browser.\n */\nconst highlightCode = async (\n code: ReactNode,\n lang: CodeLanguage\n): Promise<string> => {\n const { codeToHtml } = await import('./shikiBundle');\n\n return codeToHtml(String(code), {\n lang: resolveCodeLanguage(lang).id,\n themes: SHIKI_THEMES,\n defaultColor: false,\n });\n};\n\nexport type CodeBlockShikiProps = {\n children: ReactNode;\n lang: CodeLanguage;\n};\n\nexport const CodeBlockShiki: FC<CodeBlockShikiProps> = ({ children, lang }) => {\n const [html, setHtml] = useState<string | null>(null);\n\n useEffect(() => {\n let isCancelled = false;\n\n highlightCode(children, lang)\n .then((result) => {\n if (!isCancelled) setHtml(result);\n })\n .catch((error) => {\n console.error('Failed to highlight code:', error);\n if (!isCancelled) setHtml('');\n });\n\n return () => {\n isCancelled = true;\n };\n }, [children, lang]);\n\n return (\n <div className={shikiWrapperClassName}>\n {html ? (\n // biome-ignore lint/security/noDangerouslySetInnerHtml: Shiki generates safe HTML for code highlighting\n <div dangerouslySetInnerHTML={{ __html: html }} />\n ) : (\n <CodeDefault>{children}</CodeDefault>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AAeA,MAAM,gBAAgB,OACpB,MACA,SACoB;CACpB,MAAM,EAAE,eAAe,MAAM,OAAO;CAEpC,OAAO,WAAW,OAAO,IAAI,GAAG;EAC9B,MAAM,oBAAoB,IAAI,CAAC,CAAC;EAChC,QAAQ;EACR,cAAc;CAChB,CAAC;AACH;AAOA,MAAa,kBAA2C,EAAE,UAAU,WAAW;CAC7E,MAAM,CAAC,MAAM,WAAW,SAAwB,IAAI;CAEpD,gBAAgB;EACd,IAAI,cAAc;EAElB,cAAc,UAAU,IAAI,CAAC,CAC1B,MAAM,WAAW;GAChB,IAAI,CAAC,aAAa,QAAQ,MAAM;EAClC,CAAC,CAAC,CACD,OAAO,UAAU;GAChB,QAAQ,MAAM,6BAA6B,KAAK;GAChD,IAAI,CAAC,aAAa,QAAQ,EAAE;EAC9B,CAAC;EAEH,aAAa;GACX,cAAc;EAChB;CACF,GAAG,CAAC,UAAU,IAAI,CAAC;CAEnB,OACE,oBAAC,OAAD;EAAK,WAAW;YACb,OAEC,oBAAC,OAAD,EAAK,yBAAyB,EAAE,QAAQ,KAAK,EAAI,KAEjD,oBAAC,aAAD,EAAc,SAAsB;CAEnC;AAET"}
@@ -9,7 +9,7 @@ const FileList = ({ filePaths, ...props }) => /* @__PURE__ */ jsxs(Container, {
9
9
  transparency: "none",
10
10
  ...props,
11
11
  children: [/* @__PURE__ */ jsx("div", {
12
- className: "flex w-auto flex-row items-center justify-start gap-1 rounded-t-3xl bg-neutral-200 text-neutral text-xs dark:bg-neutral-950",
12
+ className: "flex w-auto flex-row items-center justify-start gap-1 rounded-t-3xl bg-neutral-200 text-muted-foreground text-xs dark:bg-neutral-950",
13
13
  children: /* @__PURE__ */ jsxs("div", {
14
14
  className: "mx-2 flex items-center justify-start gap-2 p-1",
15
15
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"FileList.mjs","names":[],"sources":["../../../../src/components/IDE/FileList.tsx"],"sourcesContent":["import type { FC, HTMLAttributes } from 'react';\nimport { Container } from '../Container';\nimport { FileTree } from './FileTree';\n\nexport type FileListProps = {\n filePaths: string[];\n} & HTMLAttributes<HTMLDivElement>;\n\nexport const FileList: FC<FileListProps> = ({ filePaths, ...props }) => (\n <Container\n className=\"flex size-full flex-col justify-start overflow-auto shadow-lg\"\n roundedSize=\"3xl\"\n transparency=\"none\"\n {...props}\n >\n <div className=\"flex w-auto flex-row items-center justify-start gap-1 rounded-t-3xl bg-neutral-200 text-neutral text-xs dark:bg-neutral-950\">\n <div className=\"mx-2 flex items-center justify-start gap-2 p-1\">\n <div className=\"size-3 rounded-full bg-error\" />\n <div className=\"size-3 rounded-full bg-yellow-500\" />\n <div className=\"size-3 rounded-full bg-green-500\" />\n </div>\n </div>\n <div className=\"relative flex size-full flex-1 flex-row justify-start shadow-lg\">\n <div className=\"absolute top-0 left-0 size-full\">\n <div className=\"flex size-full\">\n <FileTree filesPaths={filePaths} />\n </div>\n </div>\n </div>\n </Container>\n);\n"],"mappings":";;;;;AAQA,MAAa,YAA+B,EAAE,WAAW,GAAG,YAC1D,qBAAC,WAAD;CACE,WAAU;CACV,aAAY;CACZ,cAAa;CACb,GAAI;WAJN,CAME,oBAAC,OAAD;EAAK,WAAU;YACb,qBAAC,OAAD;GAAK,WAAU;aAAf;IACE,oBAAC,OAAD,EAAK,WAAU,+BAAgC;IAC/C,oBAAC,OAAD,EAAK,WAAU,oCAAqC;IACpD,oBAAC,OAAD,EAAK,WAAU,mCAAoC;GAChD;;CACF,IACL,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,UAAD,EAAU,YAAY,UAAY;GAC/B;EACF;CACF,EACI"}
1
+ {"version":3,"file":"FileList.mjs","names":[],"sources":["../../../../src/components/IDE/FileList.tsx"],"sourcesContent":["import type { FC, HTMLAttributes } from 'react';\nimport { Container } from '../Container';\nimport { FileTree } from './FileTree';\n\nexport type FileListProps = {\n filePaths: string[];\n} & HTMLAttributes<HTMLDivElement>;\n\nexport const FileList: FC<FileListProps> = ({ filePaths, ...props }) => (\n <Container\n className=\"flex size-full flex-col justify-start overflow-auto shadow-lg\"\n roundedSize=\"3xl\"\n transparency=\"none\"\n {...props}\n >\n <div className=\"flex w-auto flex-row items-center justify-start gap-1 rounded-t-3xl bg-neutral-200 text-muted-foreground text-xs dark:bg-neutral-950\">\n <div className=\"mx-2 flex items-center justify-start gap-2 p-1\">\n <div className=\"size-3 rounded-full bg-error\" />\n <div className=\"size-3 rounded-full bg-yellow-500\" />\n <div className=\"size-3 rounded-full bg-green-500\" />\n </div>\n </div>\n <div className=\"relative flex size-full flex-1 flex-row justify-start shadow-lg\">\n <div className=\"absolute top-0 left-0 size-full\">\n <div className=\"flex size-full\">\n <FileTree filesPaths={filePaths} />\n </div>\n </div>\n </div>\n </Container>\n);\n"],"mappings":";;;;;AAQA,MAAa,YAA+B,EAAE,WAAW,GAAG,YAC1D,qBAAC,WAAD;CACE,WAAU;CACV,aAAY;CACZ,cAAa;CACb,GAAI;WAJN,CAME,oBAAC,OAAD;EAAK,WAAU;YACb,qBAAC,OAAD;GAAK,WAAU;aAAf;IACE,oBAAC,OAAD,EAAK,WAAU,+BAAgC;IAC/C,oBAAC,OAAD,EAAK,WAAU,oCAAqC;IACpD,oBAAC,OAAD,EAAK,WAAU,mCAAoC;GAChD;;CACF,IACL,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,UAAD,EAAU,YAAY,UAAY;GAC/B;EACF;CACF,EACI"}
@@ -48,7 +48,7 @@ const FileItem = ({ filesPaths, path, subPath, onClickFile, activeFile, prePaths
48
48
  const FileTree = ({ filesPaths, activeFile, onClickFile, prePaths = [] }) => {
49
49
  const fileTree = createFileTree(filesPaths);
50
50
  return /* @__PURE__ */ jsx("div", {
51
- className: "flex size-full flex-col items-start justify-start py-1 text-neutral",
51
+ className: "flex size-full flex-col items-start justify-start py-1 text-muted-foreground",
52
52
  children: fileTree.map(({ path, subPath, isFile }) => /* @__PURE__ */ jsx(FileItem, {
53
53
  isFile,
54
54
  subPath,
@@ -1 +1 @@
1
- {"version":3,"file":"FileTree.mjs","names":[],"sources":["../../../../src/components/IDE/FileTree.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport { ChevronRight } from 'lucide-react';\nimport { type FC, useState } from 'react';\nimport { MaxHeightSmoother } from '../MaxHeightSmoother';\nimport { createFileTree, type FilePath } from './createFileTree';\n\ntype FileTreeProps = {\n filesPaths: string[];\n activeFile?: string;\n onClickFile?: (filePath: string) => void;\n prePaths?: string[];\n};\n\nconst concatFilePath = (paths: string[]) => paths.join('/');\n\ntype FileItemProps = {\n filesPaths: string[];\n subPath?: FilePath[];\n path: string;\n onClickFile?: (title: string) => void;\n activeFile?: string;\n prePaths: string[];\n isFile: boolean;\n};\n\nconst FileItem: FC<FileItemProps> = ({\n filesPaths,\n path,\n subPath,\n onClickFile,\n activeFile,\n prePaths,\n isFile,\n}) => {\n const [subPathOpen, setSubPathOpen] = useState(true);\n\n const level = prePaths.length + 1;\n const currentPath = concatFilePath([\n ...prePaths.slice(level - 1, level),\n path,\n ]);\n const totalPath = concatFilePath([...prePaths, path]);\n\n const filteredFilePaths = filesPaths\n .map(\n (path) => path.replace(/^\\/?/, '') // This regex matches the first slash, if it exists, at the start of the string)\n )\n .filter((filePath) => filePath.startsWith(currentPath));\n\n const newPath = filteredFilePaths.map((path) =>\n path.replace(currentPath, '').replace(/^\\/?/, '')\n );\n\n const isActive = totalPath === activeFile;\n\n const indentation = new Array(level).fill(' ').join('');\n\n return (\n <>\n <button\n className={cn(\n 'flex w-full items-start justify-start whitespace-pre text-nowrap px-2 py-1 text-xs transition',\n isActive\n ? 'bg-neutral-200 dark:bg-neutral-800'\n : 'cursor-pointer hover:bg-neutral-300 dark:hover:bg-neutral-900'\n )}\n key={path}\n onClick={() => {\n if (isFile) {\n onClickFile?.(totalPath);\n } else {\n setSubPathOpen(!subPathOpen);\n }\n }}\n >\n <span className={cn('whitespace-pre', isFile && 'ml-2')}>\n {indentation}\n </span>\n\n {!isFile && (\n <ChevronRight\n className={cn(`transition`, subPathOpen && `rotate-90 transform`)}\n size={16}\n />\n )}\n {path}\n </button>\n {subPath && (\n <MaxHeightSmoother\n isHidden={!subPathOpen}\n className=\"overflow-x-hidden\"\n >\n <FileTree\n filesPaths={newPath}\n activeFile={activeFile}\n onClickFile={onClickFile}\n prePaths={[...prePaths, path]}\n />\n </MaxHeightSmoother>\n )}\n </>\n );\n};\n\nexport const FileTree: FC<FileTreeProps> = ({\n filesPaths,\n activeFile,\n onClickFile,\n prePaths = [],\n}) => {\n const fileTree = createFileTree(filesPaths);\n\n return (\n <div className=\"flex size-full flex-col items-start justify-start py-1 text-neutral\">\n {fileTree.map(({ path, subPath, isFile }) => (\n <FileItem\n key={path}\n isFile={isFile}\n subPath={subPath}\n path={path}\n onClickFile={onClickFile}\n activeFile={activeFile}\n prePaths={prePaths}\n filesPaths={filesPaths}\n />\n ))}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;AAeA,MAAM,kBAAkB,UAAoB,MAAM,KAAK,GAAG;AAY1D,MAAM,YAA+B,EACnC,YACA,MACA,SACA,aACA,YACA,UACA,aACI;CACJ,MAAM,CAAC,aAAa,kBAAkB,SAAS,IAAI;CAEnD,MAAM,QAAQ,SAAS,SAAS;CAChC,MAAM,cAAc,eAAe,CACjC,GAAG,SAAS,MAAM,QAAQ,GAAG,KAAK,GAClC,IACF,CAAC;CACD,MAAM,YAAY,eAAe,CAAC,GAAG,UAAU,IAAI,CAAC;CAQpD,MAAM,UANoB,WACvB,KACE,SAAS,KAAK,QAAQ,QAAQ,EAAE,CACnC,CAAC,CACA,QAAQ,aAAa,SAAS,WAAW,WAAW,CAEvB,CAAC,CAAC,KAAK,SACrC,KAAK,QAAQ,aAAa,EAAE,CAAC,CAAC,QAAQ,QAAQ,EAAE,CAClD;CAEA,MAAM,WAAW,cAAc;CAE/B,MAAM,cAAc,IAAI,MAAM,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,EAAE;CAEvD,OACE,8CACE,qBAAC,UAAD;EACE,WAAW,GACT,iGACA,WACI,uCACA,+DACN;EAEA,eAAe;GACb,IAAI,QACF,cAAc,SAAS;QAEvB,eAAe,CAAC,WAAW;EAE/B;YAdF;GAgBE,oBAAC,QAAD;IAAM,WAAW,GAAG,kBAAkB,UAAU,MAAM;cACnD;GACG;GAEL,CAAC,UACA,oBAAC,cAAD;IACE,WAAW,GAAG,cAAc,eAAe,qBAAqB;IAChE,MAAM;GACP;GAEF;EACK;IApBD,IAoBC,GACP,WACC,oBAAC,mBAAD;EACE,UAAU,CAAC;EACX,WAAU;YAEV,oBAAC,UAAD;GACE,YAAY;GACA;GACC;GACb,UAAU,CAAC,GAAG,UAAU,IAAI;EAC7B;CACgB,EAErB;AAEN;AAEA,MAAa,YAA+B,EAC1C,YACA,YACA,aACA,WAAW,CAAC,QACR;CACJ,MAAM,WAAW,eAAe,UAAU;CAE1C,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,SAAS,KAAK,EAAE,MAAM,SAAS,aAC9B,oBAAC,UAAD;GAEU;GACC;GACH;GACO;GACD;GACF;GACE;EACb,GARM,IAQN,CACF;CACE;AAET"}
1
+ {"version":3,"file":"FileTree.mjs","names":[],"sources":["../../../../src/components/IDE/FileTree.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport { ChevronRight } from 'lucide-react';\nimport { type FC, useState } from 'react';\nimport { MaxHeightSmoother } from '../MaxHeightSmoother';\nimport { createFileTree, type FilePath } from './createFileTree';\n\ntype FileTreeProps = {\n filesPaths: string[];\n activeFile?: string;\n onClickFile?: (filePath: string) => void;\n prePaths?: string[];\n};\n\nconst concatFilePath = (paths: string[]) => paths.join('/');\n\ntype FileItemProps = {\n filesPaths: string[];\n subPath?: FilePath[];\n path: string;\n onClickFile?: (title: string) => void;\n activeFile?: string;\n prePaths: string[];\n isFile: boolean;\n};\n\nconst FileItem: FC<FileItemProps> = ({\n filesPaths,\n path,\n subPath,\n onClickFile,\n activeFile,\n prePaths,\n isFile,\n}) => {\n const [subPathOpen, setSubPathOpen] = useState(true);\n\n const level = prePaths.length + 1;\n const currentPath = concatFilePath([\n ...prePaths.slice(level - 1, level),\n path,\n ]);\n const totalPath = concatFilePath([...prePaths, path]);\n\n const filteredFilePaths = filesPaths\n .map(\n (path) => path.replace(/^\\/?/, '') // This regex matches the first slash, if it exists, at the start of the string)\n )\n .filter((filePath) => filePath.startsWith(currentPath));\n\n const newPath = filteredFilePaths.map((path) =>\n path.replace(currentPath, '').replace(/^\\/?/, '')\n );\n\n const isActive = totalPath === activeFile;\n\n const indentation = new Array(level).fill(' ').join('');\n\n return (\n <>\n <button\n className={cn(\n 'flex w-full items-start justify-start whitespace-pre text-nowrap px-2 py-1 text-xs transition',\n isActive\n ? 'bg-neutral-200 dark:bg-neutral-800'\n : 'cursor-pointer hover:bg-neutral-300 dark:hover:bg-neutral-900'\n )}\n key={path}\n onClick={() => {\n if (isFile) {\n onClickFile?.(totalPath);\n } else {\n setSubPathOpen(!subPathOpen);\n }\n }}\n >\n <span className={cn('whitespace-pre', isFile && 'ml-2')}>\n {indentation}\n </span>\n\n {!isFile && (\n <ChevronRight\n className={cn(`transition`, subPathOpen && `rotate-90 transform`)}\n size={16}\n />\n )}\n {path}\n </button>\n {subPath && (\n <MaxHeightSmoother\n isHidden={!subPathOpen}\n className=\"overflow-x-hidden\"\n >\n <FileTree\n filesPaths={newPath}\n activeFile={activeFile}\n onClickFile={onClickFile}\n prePaths={[...prePaths, path]}\n />\n </MaxHeightSmoother>\n )}\n </>\n );\n};\n\nexport const FileTree: FC<FileTreeProps> = ({\n filesPaths,\n activeFile,\n onClickFile,\n prePaths = [],\n}) => {\n const fileTree = createFileTree(filesPaths);\n\n return (\n <div className=\"flex size-full flex-col items-start justify-start py-1 text-muted-foreground\">\n {fileTree.map(({ path, subPath, isFile }) => (\n <FileItem\n key={path}\n isFile={isFile}\n subPath={subPath}\n path={path}\n onClickFile={onClickFile}\n activeFile={activeFile}\n prePaths={prePaths}\n filesPaths={filesPaths}\n />\n ))}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;AAeA,MAAM,kBAAkB,UAAoB,MAAM,KAAK,GAAG;AAY1D,MAAM,YAA+B,EACnC,YACA,MACA,SACA,aACA,YACA,UACA,aACI;CACJ,MAAM,CAAC,aAAa,kBAAkB,SAAS,IAAI;CAEnD,MAAM,QAAQ,SAAS,SAAS;CAChC,MAAM,cAAc,eAAe,CACjC,GAAG,SAAS,MAAM,QAAQ,GAAG,KAAK,GAClC,IACF,CAAC;CACD,MAAM,YAAY,eAAe,CAAC,GAAG,UAAU,IAAI,CAAC;CAQpD,MAAM,UANoB,WACvB,KACE,SAAS,KAAK,QAAQ,QAAQ,EAAE,CACnC,CAAC,CACA,QAAQ,aAAa,SAAS,WAAW,WAAW,CAEvB,CAAC,CAAC,KAAK,SACrC,KAAK,QAAQ,aAAa,EAAE,CAAC,CAAC,QAAQ,QAAQ,EAAE,CAClD;CAEA,MAAM,WAAW,cAAc;CAE/B,MAAM,cAAc,IAAI,MAAM,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,EAAE;CAEvD,OACE,8CACE,qBAAC,UAAD;EACE,WAAW,GACT,iGACA,WACI,uCACA,+DACN;EAEA,eAAe;GACb,IAAI,QACF,cAAc,SAAS;QAEvB,eAAe,CAAC,WAAW;EAE/B;YAdF;GAgBE,oBAAC,QAAD;IAAM,WAAW,GAAG,kBAAkB,UAAU,MAAM;cACnD;GACG;GAEL,CAAC,UACA,oBAAC,cAAD;IACE,WAAW,GAAG,cAAc,eAAe,qBAAqB;IAChE,MAAM;GACP;GAEF;EACK;IApBD,IAoBC,GACP,WACC,oBAAC,mBAAD;EACE,UAAU,CAAC;EACX,WAAU;YAEV,oBAAC,UAAD;GACE,YAAY;GACA;GACC;GACb,UAAU,CAAC,GAAG,UAAU,IAAI;EAC7B;CACgB,EAErB;AAEN;AAEA,MAAa,YAA+B,EAC1C,YACA,YACA,aACA,WAAW,CAAC,QACR;CACJ,MAAM,WAAW,eAAe,UAAU;CAE1C,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,SAAS,KAAK,EAAE,MAAM,SAAS,aAC9B,oBAAC,UAAD;GAEU;GACC;GACH;GACO;GACD;GACF;GACE;EACb,GARM,IAQN,CACF;CACE;AAET"}
@@ -33,12 +33,12 @@ const IDE = ({ pages: initialPages, className, activeTab: defaultActiveTab, ...p
33
33
  setActiveTab(newPageIndex);
34
34
  };
35
35
  return /* @__PURE__ */ jsxs(Container, {
36
- className: cn("flex size-full flex-col justify-start overflow-hidden shadow-lg", className),
37
- roundedSize: "3xl",
36
+ className: cn("flex size-full flex-col justify-start overflow-hidden border", className),
37
+ roundedSize: "lg",
38
38
  transparency: "none",
39
39
  ...props,
40
40
  children: [/* @__PURE__ */ jsxs("div", {
41
- className: "flex w-auto flex-row items-center justify-start gap-1 bg-neutral-200 text-neutral text-xs dark:bg-neutral-950",
41
+ className: "flex w-auto flex-row items-center justify-start gap-1 border-b bg-card text-muted-foreground text-xs",
42
42
  children: [/* @__PURE__ */ jsxs("div", {
43
43
  className: "mx-2 flex items-center justify-start gap-2 p-1",
44
44
  children: [
@@ -47,12 +47,12 @@ const IDE = ({ pages: initialPages, className, activeTab: defaultActiveTab, ...p
47
47
  /* @__PURE__ */ jsx("div", { className: "size-3 rounded-full bg-green-500" })
48
48
  ]
49
49
  }), /* @__PURE__ */ jsx("div", {
50
- className: "flex size-full overflow-y-auto",
50
+ className: "flex h-full divide-x overflow-y-auto border-x",
51
51
  children: tabs.map(({ path }, index) => {
52
52
  const fullPath = path.split("/");
53
53
  const title = fullPath[fullPath.length - 1];
54
54
  return /* @__PURE__ */ jsx("button", {
55
- className: cn("flex h-8 min-w-20 max-w-30 items-center justify-start truncate text-nowrap px-3 py-1 transition", index === activeTab ? "bg-card" : "cursor-pointer bg-neutral-200 hover:bg-neutral-300 dark:bg-neutral-950"),
55
+ className: cn("flex h-8 min-w-20 max-w-100 items-center justify-start truncate text-nowrap px-3 py-1 transition", index === activeTab ? "bg-background font-medium text-foreground" : "cursor-pointer opacity-80 hover:text-foreground hover:opacity-100"),
56
56
  onClick: () => setActiveTab(index),
57
57
  children: title
58
58
  }, title);
@@ -75,8 +75,11 @@ const IDE = ({ pages: initialPages, className, activeTab: defaultActiveTab, ...p
75
75
  })
76
76
  })
77
77
  }), /* @__PURE__ */ jsx("div", {
78
- className: "size-full flex-1 overflow-auto pt-2 text-xs",
79
- children: /* @__PURE__ */ jsx(MarkdownRenderer, { children: content })
78
+ className: "size-full flex-1 overflow-auto bg-background text-xs",
79
+ children: content && /* @__PURE__ */ jsx(MarkdownRenderer, {
80
+ codeClassName: "bg-background rounded-none",
81
+ children: content
82
+ })
80
83
  })]
81
84
  })
82
85
  })
@@ -1 +1 @@
1
- {"version":3,"file":"IDE.mjs","names":[],"sources":["../../../../src/components/IDE/IDE.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport { type FC, type HTMLAttributes, useEffect, useState } from 'react';\nimport { Container } from '../Container';\nimport { WithResizer } from '../WithResizer';\nimport { FileTree } from './FileTree';\nimport { MarkdownRenderer } from './MarkDownRender';\n\nexport type IDEProps = {\n pages: {\n path: string;\n content: string;\n isOpen?: boolean;\n }[];\n activeTab?: number;\n} & HTMLAttributes<HTMLDivElement>;\n\nexport const IDE: FC<IDEProps> = ({\n pages: initialPages,\n className,\n activeTab: defaultActiveTab,\n ...props\n}) => {\n const [pages, setPages] = useState(initialPages);\n const tabs = pages.filter(({ isOpen }) => isOpen);\n\n const firstTabIndex = tabs.findIndex(({ isOpen }) => isOpen);\n const [activeTab, setActiveTab] = useState(defaultActiveTab ?? firstTabIndex);\n\n useEffect(() => {\n setActiveTab(defaultActiveTab ?? firstTabIndex);\n }, [initialPages, defaultActiveTab]);\n\n const { content, path } = pages[activeTab] ?? {};\n const filePaths = initialPages.map(({ path: title }) => title);\n\n const handleClickFile = (title: string) => {\n const page = pages.find(({ path: tabTitle }) => tabTitle === title);\n if (!page) return;\n\n const newPages = pages.map((page) => {\n if (page.path === title) {\n return { ...page, isOpen: true };\n }\n return page;\n });\n\n setPages(newPages);\n\n const newPageIndex = newPages.findIndex(\n ({ path: tabTitle }) => tabTitle === title\n );\n\n setActiveTab(newPageIndex);\n };\n\n return (\n <Container\n className={cn(\n 'flex size-full flex-col justify-start overflow-hidden shadow-lg',\n className\n )}\n roundedSize=\"3xl\"\n transparency=\"none\"\n {...props}\n >\n <div className=\"flex w-auto flex-row items-center justify-start gap-1 bg-neutral-200 text-neutral text-xs dark:bg-neutral-950\">\n <div className=\"mx-2 flex items-center justify-start gap-2 p-1\">\n <div className=\"size-3 rounded-full bg-error\" />\n <div className=\"size-3 rounded-full bg-yellow-500\" />\n <div className=\"size-3 rounded-full bg-green-500\" />\n </div>\n <div className=\"flex size-full overflow-y-auto\">\n {tabs.map(({ path }, index) => {\n const fullPath = path.split('/');\n const title = fullPath[fullPath.length - 1];\n const isActive = index === activeTab;\n\n return (\n <button\n className={cn(\n 'flex h-8 min-w-20 max-w-30 items-center justify-start truncate text-nowrap px-3 py-1 transition',\n isActive\n ? 'bg-card'\n : 'cursor-pointer bg-neutral-200 hover:bg-neutral-300 dark:bg-neutral-950'\n )}\n key={title}\n onClick={() => setActiveTab(index)}\n >\n {title}\n </button>\n );\n })}\n </div>\n </div>\n <div className=\"relative flex size-full flex-1 flex-row justify-start\">\n <div className=\"absolute top-0 left-0 size-full\">\n <div className=\"flex size-full\">\n <WithResizer initialWidth={150}>\n <div className=\"max-h-full flex-1 overflow-y-auto\">\n <FileTree\n filesPaths={filePaths}\n activeFile={path}\n onClickFile={handleClickFile}\n />\n </div>\n </WithResizer>\n\n <div className=\"size-full flex-1 overflow-auto pt-2 text-xs\">\n <MarkdownRenderer>{content}</MarkdownRenderer>\n </div>\n </div>\n </div>\n </div>\n </Container>\n );\n};\n"],"mappings":";;;;;;;;;;;AAkBA,MAAa,OAAqB,EAChC,OAAO,cACP,WACA,WAAW,kBACX,GAAG,YACC;CACJ,MAAM,CAAC,OAAO,YAAY,SAAS,YAAY;CAC/C,MAAM,OAAO,MAAM,QAAQ,EAAE,aAAa,MAAM;CAEhD,MAAM,gBAAgB,KAAK,WAAW,EAAE,aAAa,MAAM;CAC3D,MAAM,CAAC,WAAW,gBAAgB,SAAS,oBAAoB,aAAa;CAE5E,gBAAgB;EACd,aAAa,oBAAoB,aAAa;CAChD,GAAG,CAAC,cAAc,gBAAgB,CAAC;CAEnC,MAAM,EAAE,SAAS,SAAS,MAAM,cAAc,CAAC;CAC/C,MAAM,YAAY,aAAa,KAAK,EAAE,MAAM,YAAY,KAAK;CAE7D,MAAM,mBAAmB,UAAkB;EAEzC,IAAI,CADS,MAAM,MAAM,EAAE,MAAM,eAAe,aAAa,KACrD,GAAG;EAEX,MAAM,WAAW,MAAM,KAAK,SAAS;GACnC,IAAI,KAAK,SAAS,OAChB,OAAO;IAAE,GAAG;IAAM,QAAQ;GAAK;GAEjC,OAAO;EACT,CAAC;EAED,SAAS,QAAQ;EAEjB,MAAM,eAAe,SAAS,WAC3B,EAAE,MAAM,eAAe,aAAa,KACvC;EAEA,aAAa,YAAY;CAC3B;CAEA,OACE,qBAAC,WAAD;EACE,WAAW,GACT,mEACA,SACF;EACA,aAAY;EACZ,cAAa;EACb,GAAI;YAPN,CASE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,OAAD,EAAK,WAAU,+BAAgC;KAC/C,oBAAC,OAAD,EAAK,WAAU,oCAAqC;KACpD,oBAAC,OAAD,EAAK,WAAU,mCAAoC;IAChD;OACL,oBAAC,OAAD;IAAK,WAAU;cACZ,KAAK,KAAK,EAAE,QAAQ,UAAU;KAC7B,MAAM,WAAW,KAAK,MAAM,GAAG;KAC/B,MAAM,QAAQ,SAAS,SAAS,SAAS;KAGzC,OACE,oBAAC,UAAD;MACE,WAAW,GACT,mGALW,UAAU,YAOjB,YACA,wEACN;MAEA,eAAe,aAAa,KAAK;gBAEhC;KACK,GAJD,KAIC;IAEZ,CAAC;GACE,EACF;MACL,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD;IAAK,WAAU;cACb,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,oBAAC,aAAD;MAAa,cAAc;gBACzB,oBAAC,OAAD;OAAK,WAAU;iBACb,oBAAC,UAAD;QACE,YAAY;QACZ,YAAY;QACZ,aAAa;OACd;MACE;KACM,IAEb,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,kBAAD,YAAmB,QAA0B;KAC1C,EACF;;GACF;EACF,EACI;;AAEf"}
1
+ {"version":3,"file":"IDE.mjs","names":[],"sources":["../../../../src/components/IDE/IDE.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport { type FC, type HTMLAttributes, useEffect, useState } from 'react';\nimport { Container } from '../Container';\nimport { WithResizer } from '../WithResizer';\nimport { FileTree } from './FileTree';\nimport { MarkdownRenderer } from './MarkDownRender';\n\nexport type IDEProps = {\n pages: {\n path: string;\n content: string;\n isOpen?: boolean;\n }[];\n activeTab?: number;\n} & HTMLAttributes<HTMLDivElement>;\n\nexport const IDE: FC<IDEProps> = ({\n pages: initialPages,\n className,\n activeTab: defaultActiveTab,\n ...props\n}) => {\n const [pages, setPages] = useState(initialPages);\n const tabs = pages.filter(({ isOpen }) => isOpen);\n\n const firstTabIndex = tabs.findIndex(({ isOpen }) => isOpen);\n const [activeTab, setActiveTab] = useState(defaultActiveTab ?? firstTabIndex);\n\n useEffect(() => {\n setActiveTab(defaultActiveTab ?? firstTabIndex);\n }, [initialPages, defaultActiveTab]);\n\n const { content, path } = pages[activeTab] ?? {};\n const filePaths = initialPages.map(({ path: title }) => title);\n\n const handleClickFile = (title: string) => {\n const page = pages.find(({ path: tabTitle }) => tabTitle === title);\n if (!page) return;\n\n const newPages = pages.map((page) => {\n if (page.path === title) {\n return { ...page, isOpen: true };\n }\n return page;\n });\n\n setPages(newPages);\n\n const newPageIndex = newPages.findIndex(\n ({ path: tabTitle }) => tabTitle === title\n );\n\n setActiveTab(newPageIndex);\n };\n\n return (\n <Container\n className={cn(\n 'flex size-full flex-col justify-start overflow-hidden border',\n className\n )}\n roundedSize=\"lg\"\n transparency=\"none\"\n {...props}\n >\n <div className=\"flex w-auto flex-row items-center justify-start gap-1 border-b bg-card text-muted-foreground text-xs\">\n <div className=\"mx-2 flex items-center justify-start gap-2 p-1\">\n <div className=\"size-3 rounded-full bg-error\" />\n <div className=\"size-3 rounded-full bg-yellow-500\" />\n <div className=\"size-3 rounded-full bg-green-500\" />\n </div>\n <div className=\"flex h-full divide-x overflow-y-auto border-x\">\n {tabs.map(({ path }, index) => {\n const fullPath = path.split('/');\n const title = fullPath[fullPath.length - 1];\n const isActive = index === activeTab;\n\n return (\n <button\n className={cn(\n 'flex h-8 min-w-20 max-w-100 items-center justify-start truncate text-nowrap px-3 py-1 transition',\n isActive\n ? 'bg-background font-medium text-foreground'\n : 'cursor-pointer opacity-80 hover:text-foreground hover:opacity-100'\n )}\n key={title}\n onClick={() => setActiveTab(index)}\n >\n {title}\n </button>\n );\n })}\n </div>\n </div>\n <div className=\"relative flex size-full flex-1 flex-row justify-start\">\n <div className=\"absolute top-0 left-0 size-full\">\n <div className=\"flex size-full\">\n <WithResizer initialWidth={150}>\n <div className=\"max-h-full flex-1 overflow-y-auto\">\n <FileTree\n filesPaths={filePaths}\n activeFile={path}\n onClickFile={handleClickFile}\n />\n </div>\n </WithResizer>\n\n <div className=\"size-full flex-1 overflow-auto bg-background text-xs\">\n {content && (\n <MarkdownRenderer codeClassName=\"bg-background rounded-none\">\n {content}\n </MarkdownRenderer>\n )}\n </div>\n </div>\n </div>\n </div>\n </Container>\n );\n};\n"],"mappings":";;;;;;;;;;;AAkBA,MAAa,OAAqB,EAChC,OAAO,cACP,WACA,WAAW,kBACX,GAAG,YACC;CACJ,MAAM,CAAC,OAAO,YAAY,SAAS,YAAY;CAC/C,MAAM,OAAO,MAAM,QAAQ,EAAE,aAAa,MAAM;CAEhD,MAAM,gBAAgB,KAAK,WAAW,EAAE,aAAa,MAAM;CAC3D,MAAM,CAAC,WAAW,gBAAgB,SAAS,oBAAoB,aAAa;CAE5E,gBAAgB;EACd,aAAa,oBAAoB,aAAa;CAChD,GAAG,CAAC,cAAc,gBAAgB,CAAC;CAEnC,MAAM,EAAE,SAAS,SAAS,MAAM,cAAc,CAAC;CAC/C,MAAM,YAAY,aAAa,KAAK,EAAE,MAAM,YAAY,KAAK;CAE7D,MAAM,mBAAmB,UAAkB;EAEzC,IAAI,CADS,MAAM,MAAM,EAAE,MAAM,eAAe,aAAa,KACrD,GAAG;EAEX,MAAM,WAAW,MAAM,KAAK,SAAS;GACnC,IAAI,KAAK,SAAS,OAChB,OAAO;IAAE,GAAG;IAAM,QAAQ;GAAK;GAEjC,OAAO;EACT,CAAC;EAED,SAAS,QAAQ;EAEjB,MAAM,eAAe,SAAS,WAC3B,EAAE,MAAM,eAAe,aAAa,KACvC;EAEA,aAAa,YAAY;CAC3B;CAEA,OACE,qBAAC,WAAD;EACE,WAAW,GACT,gEACA,SACF;EACA,aAAY;EACZ,cAAa;EACb,GAAI;YAPN,CASE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,OAAD,EAAK,WAAU,+BAAgC;KAC/C,oBAAC,OAAD,EAAK,WAAU,oCAAqC;KACpD,oBAAC,OAAD,EAAK,WAAU,mCAAoC;IAChD;OACL,oBAAC,OAAD;IAAK,WAAU;cACZ,KAAK,KAAK,EAAE,QAAQ,UAAU;KAC7B,MAAM,WAAW,KAAK,MAAM,GAAG;KAC/B,MAAM,QAAQ,SAAS,SAAS,SAAS;KAGzC,OACE,oBAAC,UAAD;MACE,WAAW,GACT,oGALW,UAAU,YAOjB,8CACA,mEACN;MAEA,eAAe,aAAa,KAAK;gBAEhC;KACK,GAJD,KAIC;IAEZ,CAAC;GACE,EACF;MACL,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD;IAAK,WAAU;cACb,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,oBAAC,aAAD;MAAa,cAAc;gBACzB,oBAAC,OAAD;OAAK,WAAU;iBACb,oBAAC,UAAD;QACE,YAAY;QACZ,YAAY;QACZ,aAAa;OACd;MACE;KACM,IAEb,oBAAC,OAAD;MAAK,WAAU;gBACZ,WACC,oBAAC,kBAAD;OAAkB,eAAc;iBAC7B;MACe;KAEjB,EACF;;GACF;EACF,EACI;;AAEf"}
@@ -1,15 +1,16 @@
1
1
  import { Code } from "./Code.mjs";
2
2
  import { jsx } from "react/jsx-runtime";
3
- import { MarkdownRenderer as MarkdownRenderer$1 } from "react-intlayer";
3
+ import cn from "cnfast";
4
+ import { MarkdownRenderer as MarkdownRenderer$1 } from "react-intlayer/markdown";
4
5
 
5
6
  //#region src/components/IDE/MarkDownRender.tsx
6
- const MarkdownRenderer = ({ children }) => /* @__PURE__ */ jsx(MarkdownRenderer$1, {
7
+ const MarkdownRenderer = ({ children, codeClassName }) => /* @__PURE__ */ jsx(MarkdownRenderer$1, {
7
8
  components: {
8
9
  code: (props) => /* @__PURE__ */ jsx(Code, {
9
10
  ...props,
10
11
  language: props.className?.replace("lang-", ""),
11
12
  showHeader: false,
12
- className: "text-xs leading-5",
13
+ className: cn("text-xs leading-5", codeClassName),
13
14
  children: props.children
14
15
  }),
15
16
  pre: (props) => props.children
@@ -1 +1 @@
1
- {"version":3,"file":"MarkDownRender.mjs","names":["MarkdownRendererIntlayer"],"sources":["../../../../src/components/IDE/MarkDownRender.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { MarkdownRenderer as MarkdownRendererIntlayer } from 'react-intlayer';\nimport { Code } from './Code';\nimport type { CodeLanguage } from './shikiLanguages';\n\ntype MarkdownRendererProps = {\n children: string;\n};\n\nexport const MarkdownRenderer: FC<MarkdownRendererProps> = ({ children }) => (\n <MarkdownRendererIntlayer\n components={{\n code: (props) => (\n <Code\n {...props}\n language={props.className?.replace('lang-', '') as CodeLanguage}\n showHeader={false}\n className=\"text-xs leading-5\"\n >\n {props.children as string}\n </Code>\n ),\n pre: (props) => props.children,\n }}\n >\n {children ?? ''}\n </MarkdownRendererIntlayer>\n);\n"],"mappings":";;;;;AASA,MAAa,oBAA+C,EAAE,eAC5D,oBAACA,oBAAD;CACE,YAAY;EACV,OAAO,UACL,oBAAC,MAAD;GACE,GAAI;GACJ,UAAU,MAAM,WAAW,QAAQ,SAAS,EAAE;GAC9C,YAAY;GACZ,WAAU;aAET,MAAM;EACH;EAER,MAAM,UAAU,MAAM;CACxB;WAEC,YAAY;AACW"}
1
+ {"version":3,"file":"MarkDownRender.mjs","names":["MarkdownRendererIntlayer"],"sources":["../../../../src/components/IDE/MarkDownRender.tsx"],"sourcesContent":["import cn from 'cnfast';\nimport type { FC } from 'react';\nimport { MarkdownRenderer as MarkdownRendererIntlayer } from 'react-intlayer/markdown';\nimport { Code } from './Code';\nimport type { CodeLanguage } from './shikiLanguages';\n\ntype MarkdownRendererProps = {\n codeClassName?: string;\n children: string;\n};\n\nexport const MarkdownRenderer: FC<MarkdownRendererProps> = ({\n children,\n codeClassName,\n}) => (\n <MarkdownRendererIntlayer\n components={{\n code: (props) => (\n <Code\n {...props}\n language={props.className?.replace('lang-', '') as CodeLanguage}\n showHeader={false}\n className={cn('text-xs leading-5', codeClassName)}\n >\n {props.children as string}\n </Code>\n ),\n pre: (props) => props.children,\n }}\n >\n {children ?? ''}\n </MarkdownRendererIntlayer>\n);\n"],"mappings":";;;;;;AAWA,MAAa,oBAA+C,EAC1D,UACA,oBAEA,oBAACA,oBAAD;CACE,YAAY;EACV,OAAO,UACL,oBAAC,MAAD;GACE,GAAI;GACJ,UAAU,MAAM,WAAW,QAAQ,SAAS,EAAE;GAC9C,YAAY;GACZ,WAAW,GAAG,qBAAqB,aAAa;aAE/C,MAAM;EACH;EAER,MAAM,UAAU,MAAM;CACxB;WAEC,YAAY;AACW"}
@@ -0,0 +1,61 @@
1
+ import { grammarAliases, grammarLoaders } from "./shikiLanguages.mjs";
2
+ import { createBundledHighlighter, createSingletonShorthands, guessEmbeddedLanguages } from "@shikijs/core";
3
+ import { createOnigurumaEngine } from "@shikijs/engine-oniguruma";
4
+
5
+ //#region src/components/IDE/shikiBundle.ts
6
+ /**
7
+ * Fine-grained Shiki bundle — a drop-in replacement for `shiki` and
8
+ * `shiki/bundle/web`.
9
+ *
10
+ * Both of those entry points statically pull `@shikijs/themes` (~70 themes) in
11
+ * full, and reference every grammar of their bundle (~220 and ~100
12
+ * respectively). Bundlers that group a package into a single chunk — Nitro does
13
+ * exactly that for `node_modules` — therefore emit ~10 MB of grammars and
14
+ * themes even though only two themes and the languages of
15
+ * {@link grammarLoaders} are ever asked for.
16
+ *
17
+ * This module rebuilds the same public surface on top of `@shikijs/core`, so
18
+ * the module graph only ever contains what is actually reachable. Everything is
19
+ * loaded on demand, exactly like the upstream bundles.
20
+ *
21
+ * @see https://shiki.style/guide/bundles#fine-grained-bundle
22
+ */
23
+ /**
24
+ * Alias ids pointed at the loader of the grammar that owns them, so that an
25
+ * alias is enough to pull its grammar in — the way it is with the upstream
26
+ * bundles, whose maps carry the same alias entries.
27
+ */
28
+ const aliasLoaders = Object.fromEntries(Object.entries(grammarAliases).map(([alias, canonicalId]) => [alias, grammarLoaders[canonicalId]]));
29
+ /** Every language id this bundle can highlight, aliases included. */
30
+ const bundledLanguages = {
31
+ ...grammarLoaders,
32
+ ...aliasLoaders
33
+ };
34
+ /** The two themes every code block is highlighted with. */
35
+ const bundledThemes = {
36
+ "github-light": () => import("shiki/themes/github-light.mjs"),
37
+ "github-dark": () => import("shiki/themes/github-dark.mjs")
38
+ };
39
+ /**
40
+ * Creates a highlighter that resolves language and theme ids against this
41
+ * bundle, loading each one the first time it is asked for.
42
+ *
43
+ * Ids still have to be the ones a grammar answers to — pass every fence name
44
+ * through {@link resolveCodeLanguage} first, exactly as with `shiki`'s own
45
+ * bundles.
46
+ */
47
+ const createHighlighter = createBundledHighlighter({
48
+ langs: bundledLanguages,
49
+ themes: bundledThemes,
50
+ engine: () => createOnigurumaEngine(import("shiki/wasm"))
51
+ });
52
+ /**
53
+ * Shorthands backed by a lazily created singleton highlighter — the same
54
+ * `codeToHtml` / `codeToHast` / … functions `shiki` exports, restricted to this
55
+ * bundle.
56
+ */
57
+ const { codeToHast, codeToHtml, codeToTokens, codeToTokensBase, codeToTokensWithThemes, getLastGrammarState, getSingletonHighlighter } = createSingletonShorthands(createHighlighter, { guessEmbeddedLanguages });
58
+
59
+ //#endregion
60
+ export { bundledLanguages, bundledThemes, codeToHast, codeToHtml, codeToTokens, codeToTokensBase, codeToTokensWithThemes, createHighlighter, getLastGrammarState, getSingletonHighlighter };
61
+ //# sourceMappingURL=shikiBundle.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shikiBundle.mjs","names":[],"sources":["../../../../src/components/IDE/shikiBundle.ts"],"sourcesContent":["/**\n * Fine-grained Shiki bundle — a drop-in replacement for `shiki` and\n * `shiki/bundle/web`.\n *\n * Both of those entry points statically pull `@shikijs/themes` (~70 themes) in\n * full, and reference every grammar of their bundle (~220 and ~100\n * respectively). Bundlers that group a package into a single chunk — Nitro does\n * exactly that for `node_modules` — therefore emit ~10 MB of grammars and\n * themes even though only two themes and the languages of\n * {@link grammarLoaders} are ever asked for.\n *\n * This module rebuilds the same public surface on top of `@shikijs/core`, so\n * the module graph only ever contains what is actually reachable. Everything is\n * loaded on demand, exactly like the upstream bundles.\n *\n * @see https://shiki.style/guide/bundles#fine-grained-bundle\n */\n\nimport {\n createBundledHighlighter,\n createSingletonShorthands,\n guessEmbeddedLanguages,\n} from '@shikijs/core';\nimport { createOnigurumaEngine } from '@shikijs/engine-oniguruma';\nimport {\n type GrammarLoader,\n grammarAliases,\n grammarLoaders,\n type ShikiLanguageAlias,\n type ShikiLanguageId,\n} from './shikiLanguages';\nimport type { ShikiThemeId } from './shikiThemes';\n\n/** Theme registrations, as default-exported by the `shiki/themes/*` modules. */\nexport type ThemeRegistration =\n typeof import('shiki/themes/github-dark.mjs')['default'];\n\n/** Loads a single Shiki theme. */\nexport type ThemeLoader = () => Promise<{ default: ThemeRegistration }>;\n\n/**\n * Alias ids pointed at the loader of the grammar that owns them, so that an\n * alias is enough to pull its grammar in — the way it is with the upstream\n * bundles, whose maps carry the same alias entries.\n */\nconst aliasLoaders = Object.fromEntries(\n Object.entries(grammarAliases).map(([alias, canonicalId]) => [\n alias,\n grammarLoaders[canonicalId as ShikiLanguageId],\n ])\n) as Record<ShikiLanguageAlias, GrammarLoader>;\n\n/** Every language id this bundle can highlight, aliases included. */\nexport const bundledLanguages = {\n ...grammarLoaders,\n ...aliasLoaders,\n};\n\n/** The two themes every code block is highlighted with. */\nexport const bundledThemes = {\n 'github-light': () => import('shiki/themes/github-light.mjs'),\n 'github-dark': () => import('shiki/themes/github-dark.mjs'),\n} satisfies Record<ShikiThemeId, ThemeLoader>;\n\n/** Language ids accepted by this bundle's highlighter. */\nexport type BundledLanguage = keyof typeof bundledLanguages;\n\n/** Theme ids accepted by this bundle's highlighter. */\nexport type BundledTheme = keyof typeof bundledThemes;\n\n/**\n * Creates a highlighter that resolves language and theme ids against this\n * bundle, loading each one the first time it is asked for.\n *\n * Ids still have to be the ones a grammar answers to — pass every fence name\n * through {@link resolveCodeLanguage} first, exactly as with `shiki`'s own\n * bundles.\n */\nexport const createHighlighter = createBundledHighlighter<\n BundledLanguage,\n BundledTheme\n>({\n langs: bundledLanguages,\n themes: bundledThemes,\n engine: () => createOnigurumaEngine(import('shiki/wasm')),\n});\n\n/** Highlighter instance produced by {@link createHighlighter}. */\nexport type Highlighter = Awaited<ReturnType<typeof createHighlighter>>;\n\n/**\n * Shorthands backed by a lazily created singleton highlighter — the same\n * `codeToHtml` / `codeToHast` / … functions `shiki` exports, restricted to this\n * bundle.\n */\nexport const {\n codeToHast,\n codeToHtml,\n codeToTokens,\n codeToTokensBase,\n codeToTokensWithThemes,\n getLastGrammarState,\n getSingletonHighlighter,\n} = createSingletonShorthands<BundledLanguage, BundledTheme>(\n createHighlighter,\n {\n guessEmbeddedLanguages,\n }\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,MAAM,eAAe,OAAO,YAC1B,OAAO,QAAQ,cAAc,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAC3D,OACA,eAAe,YACjB,CAAC,CACH;;AAGA,MAAa,mBAAmB;CAC9B,GAAG;CACH,GAAG;AACL;;AAGA,MAAa,gBAAgB;CAC3B,sBAAsB,OAAO;CAC7B,qBAAqB,OAAO;AAC9B;;;;;;;;;AAgBA,MAAa,oBAAoB,yBAG/B;CACA,OAAO;CACP,QAAQ;CACR,cAAc,sBAAsB,OAAO,aAAa;AAC1D,CAAC;;;;;;AAUD,MAAa,EACX,YACA,YACA,cACA,kBACA,wBACA,qBACA,4BACE,0BACF,mBACA,EACE,uBACF,CACF"}
@@ -7,43 +7,16 @@
7
7
  * grammar instead of bundling every language up front.
8
8
  */
9
9
  const grammarLoaders = {
10
- "angular-html": () => import("shiki/langs/angular-html.mjs"),
11
- "angular-ts": () => import("shiki/langs/angular-ts.mjs"),
12
10
  astro: () => import("shiki/langs/astro.mjs"),
13
11
  bash: () => import("shiki/langs/bash.mjs"),
14
- c: () => import("shiki/langs/c.mjs"),
15
- cpp: () => import("shiki/langs/cpp.mjs"),
16
- csharp: () => import("shiki/langs/csharp.mjs"),
17
12
  css: () => import("shiki/langs/css.mjs"),
18
- csv: () => import("shiki/langs/csv.mjs"),
19
- dart: () => import("shiki/langs/dart.mjs"),
20
- diff: () => import("shiki/langs/diff.mjs"),
21
- docker: () => import("shiki/langs/docker.mjs"),
22
- go: () => import("shiki/langs/go.mjs"),
23
- graphql: () => import("shiki/langs/graphql.mjs"),
24
13
  html: () => import("shiki/langs/html.mjs"),
25
- http: () => import("shiki/langs/http.mjs"),
26
- ini: () => import("shiki/langs/ini.mjs"),
27
- java: () => import("shiki/langs/java.mjs"),
28
14
  javascript: () => import("shiki/langs/javascript.mjs"),
29
15
  json: () => import("shiki/langs/json.mjs"),
30
16
  json5: () => import("shiki/langs/json5.mjs"),
31
- kotlin: () => import("shiki/langs/kotlin.mjs"),
32
- less: () => import("shiki/langs/less.mjs"),
33
- lua: () => import("shiki/langs/lua.mjs"),
17
+ jsonc: () => import("shiki/langs/jsonc.mjs"),
34
18
  markdown: () => import("shiki/langs/markdown.mjs"),
35
- nginx: () => import("shiki/langs/nginx.mjs"),
36
- php: () => import("shiki/langs/php.mjs"),
37
- powershell: () => import("shiki/langs/powershell.mjs"),
38
- prisma: () => import("shiki/langs/prisma.mjs"),
39
- python: () => import("shiki/langs/python.mjs"),
40
- ruby: () => import("shiki/langs/ruby.mjs"),
41
- rust: () => import("shiki/langs/rust.mjs"),
42
- scss: () => import("shiki/langs/scss.mjs"),
43
- sql: () => import("shiki/langs/sql.mjs"),
44
19
  svelte: () => import("shiki/langs/svelte.mjs"),
45
- swift: () => import("shiki/langs/swift.mjs"),
46
- toml: () => import("shiki/langs/toml.mjs"),
47
20
  tsx: () => import("shiki/langs/tsx.mjs"),
48
21
  typescript: () => import("shiki/langs/typescript.mjs"),
49
22
  vue: () => import("shiki/langs/vue.mjs"),
@@ -57,30 +30,20 @@ const shikiLanguageIds = Object.keys(grammarLoaders);
57
30
  * canonical id that actually owns the grammar.
58
31
  */
59
32
  const grammarAliases = {
60
- "c#": "csharp",
61
- "c++": "cpp",
62
33
  cjs: "javascript",
63
34
  console: "bash",
64
- cs: "csharp",
65
35
  cts: "typescript",
66
36
  dockerfile: "docker",
67
- golang: "go",
68
37
  gql: "graphql",
69
38
  htm: "html",
70
39
  js: "javascript",
71
40
  jsonc: "json5",
72
41
  jsx: "tsx",
73
- kt: "kotlin",
74
42
  md: "markdown",
75
43
  mdx: "markdown",
76
44
  mjs: "javascript",
77
45
  mts: "typescript",
78
46
  postcss: "css",
79
- ps1: "powershell",
80
- pwsh: "powershell",
81
- py: "python",
82
- rb: "ruby",
83
- rs: "rust",
84
47
  sh: "bash",
85
48
  shell: "bash",
86
49
  shellscript: "bash",
@@ -118,5 +81,5 @@ const resolveCodeLanguage = (language) => {
118
81
  };
119
82
 
120
83
  //#endregion
121
- export { resolveCodeLanguage, shikiLanguageIds };
84
+ export { grammarAliases, grammarLoaders, resolveCodeLanguage, shikiLanguageIds };
122
85
  //# sourceMappingURL=shikiLanguages.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"shikiLanguages.mjs","names":[],"sources":["../../../../src/components/IDE/shikiLanguages.ts"],"sourcesContent":["/**\n * Grammar registrations, as default-exported by the `shiki/langs/*` modules.\n */\nexport type LanguageGrammar =\n typeof import('shiki/langs/typescript.mjs')['default'];\n\n/**\n * Loads a single Shiki grammar (and its embedded dependencies).\n */\nexport type GrammarLoader = () => Promise<{ default: LanguageGrammar }>;\n\n/**\n * Shiki grammar loaders, keyed by the canonical Shiki language id.\n *\n * Import specifiers are written as literals (never template strings) so that\n * bundlers can statically analyse them and emit one lazily fetched chunk per\n * grammar instead of bundling every language up front.\n */\nconst grammarLoaders = {\n 'angular-html': () => import('shiki/langs/angular-html.mjs'),\n 'angular-ts': () => import('shiki/langs/angular-ts.mjs'),\n astro: () => import('shiki/langs/astro.mjs'),\n bash: () => import('shiki/langs/bash.mjs'),\n c: () => import('shiki/langs/c.mjs'),\n cpp: () => import('shiki/langs/cpp.mjs'),\n csharp: () => import('shiki/langs/csharp.mjs'),\n css: () => import('shiki/langs/css.mjs'),\n csv: () => import('shiki/langs/csv.mjs'),\n dart: () => import('shiki/langs/dart.mjs'),\n diff: () => import('shiki/langs/diff.mjs'),\n docker: () => import('shiki/langs/docker.mjs'),\n go: () => import('shiki/langs/go.mjs'),\n graphql: () => import('shiki/langs/graphql.mjs'),\n html: () => import('shiki/langs/html.mjs'),\n http: () => import('shiki/langs/http.mjs'),\n ini: () => import('shiki/langs/ini.mjs'),\n java: () => import('shiki/langs/java.mjs'),\n javascript: () => import('shiki/langs/javascript.mjs'),\n json: () => import('shiki/langs/json.mjs'),\n json5: () => import('shiki/langs/json5.mjs'),\n kotlin: () => import('shiki/langs/kotlin.mjs'),\n less: () => import('shiki/langs/less.mjs'),\n lua: () => import('shiki/langs/lua.mjs'),\n markdown: () => import('shiki/langs/markdown.mjs'),\n nginx: () => import('shiki/langs/nginx.mjs'),\n php: () => import('shiki/langs/php.mjs'),\n powershell: () => import('shiki/langs/powershell.mjs'),\n prisma: () => import('shiki/langs/prisma.mjs'),\n python: () => import('shiki/langs/python.mjs'),\n ruby: () => import('shiki/langs/ruby.mjs'),\n rust: () => import('shiki/langs/rust.mjs'),\n scss: () => import('shiki/langs/scss.mjs'),\n sql: () => import('shiki/langs/sql.mjs'),\n svelte: () => import('shiki/langs/svelte.mjs'),\n swift: () => import('shiki/langs/swift.mjs'),\n toml: () => import('shiki/langs/toml.mjs'),\n tsx: () => import('shiki/langs/tsx.mjs'),\n typescript: () => import('shiki/langs/typescript.mjs'),\n vue: () => import('shiki/langs/vue.mjs'),\n xml: () => import('shiki/langs/xml.mjs'),\n yaml: () => import('shiki/langs/yaml.mjs'),\n} satisfies Record<string, GrammarLoader>;\n\n/** Canonical Shiki language ids this package can highlight. */\nexport type ShikiLanguageId = keyof typeof grammarLoaders;\n\n/** Every canonical language id that ships with a grammar loader. */\nexport const shikiLanguageIds = Object.keys(\n grammarLoaders\n) as ShikiLanguageId[];\n\n/**\n * Code fence names that are rendered by another grammar, mapped to the\n * canonical id that actually owns the grammar.\n */\nconst grammarAliases = {\n 'c#': 'csharp',\n 'c++': 'cpp',\n cjs: 'javascript',\n console: 'bash',\n cs: 'csharp',\n cts: 'typescript',\n dockerfile: 'docker',\n golang: 'go',\n gql: 'graphql',\n htm: 'html',\n js: 'javascript',\n jsonc: 'json5',\n jsx: 'tsx',\n kt: 'kotlin',\n md: 'markdown',\n mdx: 'markdown',\n mjs: 'javascript',\n mts: 'typescript',\n postcss: 'css',\n ps1: 'powershell',\n pwsh: 'powershell',\n py: 'python',\n rb: 'ruby',\n rs: 'rust',\n sh: 'bash',\n shell: 'bash',\n shellscript: 'bash',\n ts: 'typescript',\n yml: 'yaml',\n zsh: 'bash',\n} satisfies Record<string, ShikiLanguageId>;\n\n/** Code fence names accepted as aliases of a canonical language id. */\nexport type ShikiLanguageAlias = keyof typeof grammarAliases;\n\n/**\n * Languages Shiki renders without any grammar. They are also used as the\n * fallback for languages this package does not ship a grammar for.\n */\nexport type PlainTextLanguage = 'plaintext' | 'text' | 'txt';\n\nconst PLAIN_TEXT_LANGUAGE = 'plaintext' satisfies PlainTextLanguage;\n\n/** Every language name accepted by the code block components. */\nexport type CodeLanguage =\n | ShikiLanguageId\n | ShikiLanguageAlias\n | PlainTextLanguage;\n\n/**\n * A language name resolved to what Shiki actually needs to highlight it.\n */\nexport type ResolvedCodeLanguage = {\n /** Canonical language id to pass to `codeToHtml` / `codeToHast`. */\n id: ShikiLanguageId | PlainTextLanguage;\n /** Grammar loader, or `null` when the language needs no grammar. */\n loadGrammar: GrammarLoader | null;\n};\n\n/**\n * Resolve a code fence language name to a canonical Shiki id and its grammar\n * loader.\n *\n * Unknown names resolve to plain text rather than to an arbitrary grammar, so\n * that `codeToHtml` never receives a language it has not loaded.\n *\n * @param language - Language name coming from a code fence or a `lang` prop.\n *\n * @example\n * resolveCodeLanguage('ts'); // { id: 'typescript', loadGrammar: fn }\n * resolveCodeLanguage('toml'); // { id: 'toml', loadGrammar: fn }\n * resolveCodeLanguage('brainfuck'); // { id: 'plaintext', loadGrammar: null }\n */\nexport const resolveCodeLanguage = (\n language: CodeLanguage | string | undefined | null\n): ResolvedCodeLanguage => {\n const normalizedLanguage = (language ?? '').trim().toLowerCase();\n\n const canonicalId =\n grammarAliases[normalizedLanguage as ShikiLanguageAlias] ??\n (normalizedLanguage as ShikiLanguageId);\n\n const loadGrammar = grammarLoaders[canonicalId] as GrammarLoader | undefined;\n\n if (!loadGrammar) {\n return { id: PLAIN_TEXT_LANGUAGE, loadGrammar: null };\n }\n\n return { id: canonicalId, loadGrammar };\n};\n"],"mappings":";;;;;;;;AAkBA,MAAM,iBAAiB;CACrB,sBAAsB,OAAO;CAC7B,oBAAoB,OAAO;CAC3B,aAAa,OAAO;CACpB,YAAY,OAAO;CACnB,SAAS,OAAO;CAChB,WAAW,OAAO;CAClB,cAAc,OAAO;CACrB,WAAW,OAAO;CAClB,WAAW,OAAO;CAClB,YAAY,OAAO;CACnB,YAAY,OAAO;CACnB,cAAc,OAAO;CACrB,UAAU,OAAO;CACjB,eAAe,OAAO;CACtB,YAAY,OAAO;CACnB,YAAY,OAAO;CACnB,WAAW,OAAO;CAClB,YAAY,OAAO;CACnB,kBAAkB,OAAO;CACzB,YAAY,OAAO;CACnB,aAAa,OAAO;CACpB,cAAc,OAAO;CACrB,YAAY,OAAO;CACnB,WAAW,OAAO;CAClB,gBAAgB,OAAO;CACvB,aAAa,OAAO;CACpB,WAAW,OAAO;CAClB,kBAAkB,OAAO;CACzB,cAAc,OAAO;CACrB,cAAc,OAAO;CACrB,YAAY,OAAO;CACnB,YAAY,OAAO;CACnB,YAAY,OAAO;CACnB,WAAW,OAAO;CAClB,cAAc,OAAO;CACrB,aAAa,OAAO;CACpB,YAAY,OAAO;CACnB,WAAW,OAAO;CAClB,kBAAkB,OAAO;CACzB,WAAW,OAAO;CAClB,WAAW,OAAO;CAClB,YAAY,OAAO;AACrB;;AAMA,MAAa,mBAAmB,OAAO,KACrC,cACF;;;;;AAMA,MAAM,iBAAiB;CACrB,MAAM;CACN,OAAO;CACP,KAAK;CACL,SAAS;CACT,IAAI;CACJ,KAAK;CACL,YAAY;CACZ,QAAQ;CACR,KAAK;CACL,KAAK;CACL,IAAI;CACJ,OAAO;CACP,KAAK;CACL,IAAI;CACJ,IAAI;CACJ,KAAK;CACL,KAAK;CACL,KAAK;CACL,SAAS;CACT,KAAK;CACL,MAAM;CACN,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;CACP,aAAa;CACb,IAAI;CACJ,KAAK;CACL,KAAK;AACP;AAWA,MAAM,sBAAsB;;;;;;;;;;;;;;;AAgC5B,MAAa,uBACX,aACyB;CACzB,MAAM,sBAAsB,YAAY,GAAE,CAAE,KAAK,CAAC,CAAC,YAAY;CAE/D,MAAM,cACJ,eAAe,uBACd;CAEH,MAAM,cAAc,eAAe;CAEnC,IAAI,CAAC,aACH,OAAO;EAAE,IAAI;EAAqB,aAAa;CAAK;CAGtD,OAAO;EAAE,IAAI;EAAa;CAAY;AACxC"}
1
+ {"version":3,"file":"shikiLanguages.mjs","names":[],"sources":["../../../../src/components/IDE/shikiLanguages.ts"],"sourcesContent":["/**\n * Grammar registrations, as default-exported by the `shiki/langs/*` modules.\n */\nexport type LanguageGrammar =\n typeof import('shiki/langs/typescript.mjs')['default'];\n\n/**\n * Loads a single Shiki grammar (and its embedded dependencies).\n */\nexport type GrammarLoader = () => Promise<{ default: LanguageGrammar }>;\n\n/**\n * Shiki grammar loaders, keyed by the canonical Shiki language id.\n *\n * Import specifiers are written as literals (never template strings) so that\n * bundlers can statically analyse them and emit one lazily fetched chunk per\n * grammar instead of bundling every language up front.\n */\nexport const grammarLoaders = {\n astro: () => import('shiki/langs/astro.mjs'),\n bash: () => import('shiki/langs/bash.mjs'),\n css: () => import('shiki/langs/css.mjs'),\n html: () => import('shiki/langs/html.mjs'),\n javascript: () => import('shiki/langs/javascript.mjs'),\n json: () => import('shiki/langs/json.mjs'),\n json5: () => import('shiki/langs/json5.mjs'),\n jsonc: () => import('shiki/langs/jsonc.mjs'),\n markdown: () => import('shiki/langs/markdown.mjs'),\n svelte: () => import('shiki/langs/svelte.mjs'),\n tsx: () => import('shiki/langs/tsx.mjs'),\n typescript: () => import('shiki/langs/typescript.mjs'),\n vue: () => import('shiki/langs/vue.mjs'),\n xml: () => import('shiki/langs/xml.mjs'),\n yaml: () => import('shiki/langs/yaml.mjs'),\n // 'angular-html': () => import('shiki/langs/angular-html.mjs'),\n // 'angular-ts': () => import('shiki/langs/angular-ts.mjs'),\n // c: () => import('shiki/langs/c.mjs'),\n // cpp: () => import('shiki/langs/cpp.mjs'),\n // csharp: () => import('shiki/langs/csharp.mjs'),\n // csv: () => import('shiki/langs/csv.mjs'),\n // dart: () => import('shiki/langs/dart.mjs'),\n // diff: () => import('shiki/langs/diff.mjs'),\n // docker: () => import('shiki/langs/docker.mjs'),\n // go: () => import('shiki/langs/go.mjs'),\n // graphql: () => import('shiki/langs/graphql.mjs'),\n // http: () => import('shiki/langs/http.mjs'),\n // ini: () => import('shiki/langs/ini.mjs'),\n // java: () => import('shiki/langs/java.mjs'),\n // kotlin: () => import('shiki/langs/kotlin.mjs'),\n // less: () => import('shiki/langs/less.mjs'),\n // lua: () => import('shiki/langs/lua.mjs'),\n // nginx: () => import('shiki/langs/nginx.mjs'),\n // php: () => import('shiki/langs/php.mjs'),\n // powershell: () => import('shiki/langs/powershell.mjs'),\n // prisma: () => import('shiki/langs/prisma.mjs'),\n // python: () => import('shiki/langs/python.mjs'),\n // ruby: () => import('shiki/langs/ruby.mjs'),\n // rust: () => import('shiki/langs/rust.mjs'),\n // scss: () => import('shiki/langs/scss.mjs'),\n // sql: () => import('shiki/langs/sql.mjs'), // swift: () => import('shiki/langs/swift.mjs'),\n // toml: () => import('shiki/langs/toml.mjs'),\n} satisfies Record<string, GrammarLoader>;\n\n/** Canonical Shiki language ids this package can highlight. */\nexport type ShikiLanguageId = keyof typeof grammarLoaders;\n\n/** Every canonical language id that ships with a grammar loader. */\nexport const shikiLanguageIds = Object.keys(\n grammarLoaders\n) as ShikiLanguageId[];\n\n/**\n * Code fence names that are rendered by another grammar, mapped to the\n * canonical id that actually owns the grammar.\n */\nexport const grammarAliases = {\n cjs: 'javascript',\n console: 'bash',\n cts: 'typescript',\n dockerfile: 'docker',\n gql: 'graphql',\n htm: 'html',\n js: 'javascript',\n jsonc: 'json5',\n jsx: 'tsx',\n md: 'markdown',\n mdx: 'markdown',\n mjs: 'javascript',\n mts: 'typescript',\n postcss: 'css',\n sh: 'bash',\n shell: 'bash',\n shellscript: 'bash',\n ts: 'typescript',\n yml: 'yaml',\n zsh: 'bash',\n} satisfies Record<string, ShikiLanguageId>;\n\n/** Code fence names accepted as aliases of a canonical language id. */\nexport type ShikiLanguageAlias = keyof typeof grammarAliases;\n\n/**\n * Languages Shiki renders without any grammar. They are also used as the\n * fallback for languages this package does not ship a grammar for.\n */\nexport type PlainTextLanguage = 'plaintext' | 'text' | 'txt';\n\nconst PLAIN_TEXT_LANGUAGE = 'plaintext' satisfies PlainTextLanguage;\n\n/** Every language name accepted by the code block components. */\nexport type CodeLanguage =\n | ShikiLanguageId\n | ShikiLanguageAlias\n | PlainTextLanguage;\n\n/**\n * A language name resolved to what Shiki actually needs to highlight it.\n */\nexport type ResolvedCodeLanguage = {\n /** Canonical language id to pass to `codeToHtml` / `codeToHast`. */\n id: ShikiLanguageId | PlainTextLanguage;\n /** Grammar loader, or `null` when the language needs no grammar. */\n loadGrammar: GrammarLoader | null;\n};\n\n/**\n * Resolve a code fence language name to a canonical Shiki id and its grammar\n * loader.\n *\n * Unknown names resolve to plain text rather than to an arbitrary grammar, so\n * that `codeToHtml` never receives a language it has not loaded.\n *\n * @param language - Language name coming from a code fence or a `lang` prop.\n *\n * @example\n * resolveCodeLanguage('ts'); // { id: 'typescript', loadGrammar: fn }\n * resolveCodeLanguage('toml'); // { id: 'toml', loadGrammar: fn }\n * resolveCodeLanguage('brainfuck'); // { id: 'plaintext', loadGrammar: null }\n */\nexport const resolveCodeLanguage = (\n language: CodeLanguage | string | undefined | null\n): ResolvedCodeLanguage => {\n const normalizedLanguage = (language ?? '').trim().toLowerCase();\n\n const canonicalId =\n grammarAliases[normalizedLanguage as ShikiLanguageAlias] ??\n (normalizedLanguage as ShikiLanguageId);\n\n const loadGrammar = grammarLoaders[canonicalId] as GrammarLoader | undefined;\n\n if (!loadGrammar) {\n return { id: PLAIN_TEXT_LANGUAGE, loadGrammar: null };\n }\n\n return { id: canonicalId, loadGrammar };\n};\n"],"mappings":";;;;;;;;AAkBA,MAAa,iBAAiB;CAC5B,aAAa,OAAO;CACpB,YAAY,OAAO;CACnB,WAAW,OAAO;CAClB,YAAY,OAAO;CACnB,kBAAkB,OAAO;CACzB,YAAY,OAAO;CACnB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,gBAAgB,OAAO;CACvB,cAAc,OAAO;CACrB,WAAW,OAAO;CAClB,kBAAkB,OAAO;CACzB,WAAW,OAAO;CAClB,WAAW,OAAO;CAClB,YAAY,OAAO;AA4BrB;;AAMA,MAAa,mBAAmB,OAAO,KACrC,cACF;;;;;AAMA,MAAa,iBAAiB;CAC5B,KAAK;CACL,SAAS;CACT,KAAK;CACL,YAAY;CACZ,KAAK;CACL,KAAK;CACL,IAAI;CACJ,OAAO;CACP,KAAK;CACL,IAAI;CACJ,KAAK;CACL,KAAK;CACL,KAAK;CACL,SAAS;CACT,IAAI;CACJ,OAAO;CACP,aAAa;CACb,IAAI;CACJ,KAAK;CACL,KAAK;AACP;AAWA,MAAM,sBAAsB;;;;;;;;;;;;;;;AAgC5B,MAAa,uBACX,aACyB;CACzB,MAAM,sBAAsB,YAAY,GAAE,CAAE,KAAK,CAAC,CAAC,YAAY;CAE/D,MAAM,cACJ,eAAe,uBACd;CAEH,MAAM,cAAc,eAAe;CAEnC,IAAI,CAAC,aACH,OAAO;EAAE,IAAI;EAAqB,aAAa;CAAK;CAGtD,OAAO;EAAE,IAAI;EAAa;CAAY;AACxC"}
@@ -1 +1 @@
1
- {"version":3,"file":"shikiThemes.mjs","names":[],"sources":["../../../../src/components/IDE/shikiThemes.ts"],"sourcesContent":["/**\n * Themes every code block is highlighted with.\n *\n * Shiki is always asked for both, with `defaultColor: false`, so each token\n * carries its light and dark colour as the `--shiki-light` / `--shiki-dark`\n * custom properties rather than a resolved `color`. The markup is therefore\n * theme-agnostic: it can be produced once — at build time — and never has to be\n * recomputed in the browser when the resolved theme changes.\n */\nexport const SHIKI_THEMES = {\n light: 'github-light',\n dark: 'github-dark',\n} as const;\n\nexport type ShikiThemes = typeof SHIKI_THEMES;\n"],"mappings":";;;;;;;;;;AASA,MAAa,eAAe;CAC1B,OAAO;CACP,MAAM;AACR"}
1
+ {"version":3,"file":"shikiThemes.mjs","names":[],"sources":["../../../../src/components/IDE/shikiThemes.ts"],"sourcesContent":["/**\n * Themes every code block is highlighted with.\n *\n * Shiki is always asked for both, with `defaultColor: false`, so each token\n * carries its light and dark colour as the `--shiki-light` / `--shiki-dark`\n * custom properties rather than a resolved `color`. The markup is therefore\n * theme-agnostic: it can be produced once — at build time — and never has to be\n * recomputed in the browser when the resolved theme changes.\n */\nexport const SHIKI_THEMES = {\n light: 'github-light',\n dark: 'github-dark',\n} as const;\n\nexport type ShikiThemes = typeof SHIKI_THEMES;\n\n/** Every theme id the fine-grained Shiki bundle can resolve. */\nexport type ShikiThemeId = ShikiThemes[keyof ShikiThemes];\n"],"mappings":";;;;;;;;;;AASA,MAAa,eAAe;CAC1B,OAAO;CACP,MAAM;AACR"}
@@ -14,7 +14,7 @@ const checkboxVariants = cva([
14
14
  "ring-0 transition-all duration-300 ease-in-out hover:ring-4 focus-visible:ring-6",
15
15
  "checked:before:absolute checked:before:inset-0 checked:before:content-['✓']",
16
16
  "checked:before:flex checked:before:items-center checked:before:justify-center",
17
- "checked:before:text-text-opposite/80",
17
+ "checked:before:text-foreground-opposite/80",
18
18
  "rounded-xl [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-2xl",
19
19
  "after:absolute after:-inset-2 after:content-['']"
20
20
  ].join(" "), {
@@ -29,10 +29,10 @@ const checkboxVariants = cva([
29
29
  color: {
30
30
  primary: "border-primary/30 text-primary ring-primary/20 checked:border-primary checked:bg-primary",
31
31
  secondary: "border-secondary/30 text-secondary ring-secondary/20 checked:border-secondary checked:bg-secondary",
32
- neutral: "border-neutral/30 text-neutral ring-neutral/20 checked:border-neutral checked:bg-neutral",
32
+ neutral: "border-neutral/30 text-muted-foreground ring-neutral/20 checked:border-neutral checked:bg-neutral",
33
33
  light: "border-white/30 text-white ring-white/20 checked:border-white checked:bg-white",
34
- text: "border-text/30 text-text ring-text/20 checked:border-text checked:bg-text",
35
- "text-inverse": "border-text-inverse/30 text-text-inverse ring-text-inverse/20 checked:border-text-inverse checked:bg-text-inverse",
34
+ text: "border-text/30 text-foreground ring-text/20 checked:border-text checked:bg-text",
35
+ "text-inverse": "border-text-inverse/30 text-foreground-inverse ring-text-inverse/20 checked:border-text-inverse checked:bg-text-inverse",
36
36
  dark: "border-neutral-800/30 text-neutral-800 ring-neutral-800/20 checked:border-neutral-800 checked:bg-neutral-800",
37
37
  error: "border-error/30 text-error ring-error/20 checked:border-error checked:bg-error",
38
38
  success: "border-success/30 text-success ring-success/20 checked:border-success checked:bg-success",