@djangocfg/ui-tools 2.1.285 → 2.1.286

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 (71) hide show
  1. package/dist/DocsLayout-BCVU6TTX.cjs +2027 -0
  2. package/dist/DocsLayout-BCVU6TTX.cjs.map +1 -0
  3. package/dist/DocsLayout-ERETJLLV.mjs +2020 -0
  4. package/dist/DocsLayout-ERETJLLV.mjs.map +1 -0
  5. package/dist/{PlaygroundLayout-O52C6HK5.css → DocsLayout-MBFIB4NO.css} +1 -1
  6. package/dist/{PrettyCode.client-SGDGQTYT.cjs → PrettyCode.client-5GABIN2I.cjs} +57 -35
  7. package/dist/PrettyCode.client-5GABIN2I.cjs.map +1 -0
  8. package/dist/{PrettyCode.client-DW5LTG47.mjs → PrettyCode.client-IZTXXYHG.mjs} +57 -35
  9. package/dist/PrettyCode.client-IZTXXYHG.mjs.map +1 -0
  10. package/dist/chunk-IULI4XII.cjs +1129 -0
  11. package/dist/chunk-IULI4XII.cjs.map +1 -0
  12. package/dist/chunk-VZGQC3NG.mjs +1100 -0
  13. package/dist/chunk-VZGQC3NG.mjs.map +1 -0
  14. package/dist/index.cjs +88 -552
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +18 -6
  17. package/dist/index.d.ts +18 -6
  18. package/dist/index.mjs +25 -496
  19. package/dist/index.mjs.map +1 -1
  20. package/package.json +6 -6
  21. package/src/tools/OpenapiViewer/.claude/.sidecar/activity.jsonl +4 -0
  22. package/src/tools/OpenapiViewer/.claude/.sidecar/map_cache.json +30 -0
  23. package/src/tools/OpenapiViewer/.claude/.sidecar/usage.json +5 -0
  24. package/src/tools/OpenapiViewer/.claude/project-map.md +23 -0
  25. package/src/tools/OpenapiViewer/OpenapiViewer.story.tsx +28 -2
  26. package/src/tools/OpenapiViewer/README.md +104 -51
  27. package/src/tools/OpenapiViewer/components/DocsLayout/ApiIntroSection.tsx +64 -0
  28. package/src/tools/OpenapiViewer/components/DocsLayout/DocsView.tsx +137 -0
  29. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc.tsx +268 -0
  30. package/src/tools/OpenapiViewer/components/DocsLayout/SchemaCopyMenu.tsx +139 -0
  31. package/src/tools/OpenapiViewer/components/DocsLayout/Sidebar.tsx +211 -0
  32. package/src/tools/OpenapiViewer/components/DocsLayout/SlideInPlayground.tsx +101 -0
  33. package/src/tools/OpenapiViewer/components/DocsLayout/TryItSheet.tsx +57 -0
  34. package/src/tools/OpenapiViewer/components/DocsLayout/anchor.ts +11 -0
  35. package/src/tools/OpenapiViewer/components/DocsLayout/grouping.ts +71 -0
  36. package/src/tools/OpenapiViewer/components/DocsLayout/index.tsx +166 -0
  37. package/src/tools/OpenapiViewer/components/DocsLayout/schemaFields.ts +121 -0
  38. package/src/tools/OpenapiViewer/components/DocsLayout/sidebarLabel.ts +60 -0
  39. package/src/tools/OpenapiViewer/components/index.ts +5 -2
  40. package/src/tools/OpenapiViewer/components/shared/BodyFormEditor.tsx +422 -0
  41. package/src/tools/OpenapiViewer/components/shared/EndpointDraftSync.tsx +108 -0
  42. package/src/tools/OpenapiViewer/components/shared/EndpointResetButton.tsx +50 -0
  43. package/src/tools/OpenapiViewer/components/{PlaygroundLayout → shared}/RequestPanel.tsx +174 -87
  44. package/src/tools/OpenapiViewer/components/shared/SendButton.tsx +91 -0
  45. package/src/tools/OpenapiViewer/components/{PlaygroundLayout → shared}/ui.tsx +5 -4
  46. package/src/tools/OpenapiViewer/context/PlaygroundContext.tsx +82 -8
  47. package/src/tools/OpenapiViewer/hooks/useEndpointDraft.ts +142 -0
  48. package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +126 -13
  49. package/src/tools/OpenapiViewer/index.tsx +3 -7
  50. package/src/tools/OpenapiViewer/lazy.tsx +6 -27
  51. package/src/tools/OpenapiViewer/types.ts +44 -0
  52. package/src/tools/OpenapiViewer/utils/formatters.ts +2 -23
  53. package/src/tools/OpenapiViewer/utils/index.ts +3 -1
  54. package/src/tools/OpenapiViewer/utils/schemaExport.ts +206 -0
  55. package/src/tools/OpenapiViewer/utils/url.ts +202 -0
  56. package/src/tools/PrettyCode/PrettyCode.client.tsx +42 -8
  57. package/src/tools/PrettyCode/index.tsx +6 -0
  58. package/dist/PlaygroundLayout-DHUATCHB.cjs +0 -798
  59. package/dist/PlaygroundLayout-DHUATCHB.cjs.map +0 -1
  60. package/dist/PlaygroundLayout-NONWOVQR.mjs +0 -791
  61. package/dist/PlaygroundLayout-NONWOVQR.mjs.map +0 -1
  62. package/dist/PrettyCode.client-DW5LTG47.mjs.map +0 -1
  63. package/dist/PrettyCode.client-SGDGQTYT.cjs.map +0 -1
  64. package/dist/chunk-5FKE7OME.cjs +0 -369
  65. package/dist/chunk-5FKE7OME.cjs.map +0 -1
  66. package/dist/chunk-BKWDHJKF.mjs +0 -356
  67. package/dist/chunk-BKWDHJKF.mjs.map +0 -1
  68. package/src/tools/OpenapiViewer/components/PlaygroundLayout/EndpointList.tsx +0 -228
  69. package/src/tools/OpenapiViewer/components/PlaygroundLayout/index.tsx +0 -107
  70. /package/dist/{PlaygroundLayout-O52C6HK5.css.map → DocsLayout-MBFIB4NO.css.map} +0 -0
  71. /package/src/tools/OpenapiViewer/components/{PlaygroundLayout → shared}/ResponsePanel.tsx +0 -0
@@ -8,7 +8,7 @@ var i18n = require('@djangocfg/i18n');
8
8
  var hooks = require('@djangocfg/ui-core/hooks');
9
9
  var jsxRuntime = require('react/jsx-runtime');
10
10
 
11
- var PrettyCode = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ data, language, className, mode, inline = false, customBg, isCompact = false, scrollIsolation }) => {
11
+ var PrettyCode = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ data, language, className, mode, inline = false, customBg, isCompact = false, scrollIsolation, maxLines }) => {
12
12
  const containerRef = react.useRef(null);
13
13
  const t = i18n.useAppT();
14
14
  const detectedTheme = hooks.useResolvedTheme();
@@ -21,6 +21,12 @@ var PrettyCode = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ data, language, cla
21
21
  const isDarkMode = currentTheme === "dark";
22
22
  const prismTheme = isDarkMode ? prismReactRenderer.themes.vsDark : prismReactRenderer.themes.vsLight;
23
23
  const contentJson = typeof data === "string" ? data : JSON.stringify(data || {}, null, 2);
24
+ const lineCount = contentJson ? contentJson.split("\n").length : 0;
25
+ const lineHeightRatio = isCompact ? 1.4 : 1.5;
26
+ const fontSizePx = isCompact ? 12 : 14;
27
+ const verticalPadPx = 16 + 12;
28
+ const shouldScroll = maxLines !== void 0 && lineCount > maxLines;
29
+ const maxHeightPx = maxLines !== void 0 ? maxLines * fontSizePx * lineHeightRatio + verticalPadPx : void 0;
24
30
  if (!contentJson || contentJson.trim() === "") {
25
31
  const emptyBgClass = customBg || (isDarkMode ? "bg-zinc-900" : "bg-white");
26
32
  const emptyBorderClass = isDarkMode ? "border-zinc-700" : "border-border";
@@ -122,41 +128,57 @@ var PrettyCode = /* @__PURE__ */ chunkWGEGR3DF_cjs.__name(({ data, language, cla
122
128
  }
123
129
  const bgClass = customBg || (isDarkMode ? "bg-zinc-900" : "bg-white");
124
130
  const borderClass = isDarkMode ? "border-zinc-700" : "border-border";
125
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: `group relative h-full ${bgClass} rounded-lg border ${borderClass} ${className || ""}`, children: [
126
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity duration-150 z-30", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
127
- chunk2SMCH62O_cjs.FloatingToolbar,
128
- {
129
- containerRef,
130
- scrollIsolation,
131
- label: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-muted/80 text-muted-foreground border border-border/50 backdrop-blur-sm", children: displayLanguage }),
132
- children: /* @__PURE__ */ jsxRuntime.jsx(chunk2SMCH62O_cjs.CopyAction, { value: contentJson, title: labels.copyCode })
133
- }
134
- ) }) }),
135
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsx(prismReactRenderer.Highlight, { theme: prismTheme, code: contentJson, language: normalizedLanguage, children: ({ className: className2, style, tokens, getLineProps, getTokenProps }) => {
136
- const { backgroundColor: _bg, ...restStyle } = style;
137
- return /* @__PURE__ */ jsxRuntime.jsx(
138
- "pre",
139
- {
140
- className: `${className2} rounded-lg`,
141
- style: {
142
- ...restStyle,
143
- margin: 0,
144
- padding: "2.5rem 1rem 1rem 1rem",
145
- fontSize,
146
- lineHeight: isCompact ? 1.4 : 1.5,
147
- fontFamily: "monospace",
148
- whiteSpace: "pre-wrap",
149
- wordBreak: "break-word",
150
- overflowWrap: "break-word"
151
- },
152
- children: tokens.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { ...getLineProps({ line }), children: line.map((token, key) => /* @__PURE__ */ jsxRuntime.jsx("span", { ...getTokenProps({ token }) }, key)) }, i))
153
- }
154
- );
155
- } }) })
156
- ] });
131
+ return /* @__PURE__ */ jsxRuntime.jsxs(
132
+ "div",
133
+ {
134
+ ref: containerRef,
135
+ className: `group relative ${bgClass} rounded-lg border ${borderClass} ${className || ""}`,
136
+ style: (
137
+ // maxHeight caps growth at ``maxLines`` rows; without maxLines we
138
+ // let the block grow to fit its content (no scroll).
139
+ maxHeightPx ? { maxHeight: `${maxHeightPx}px` } : void 0
140
+ ),
141
+ children: [
142
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-x-0 top-0 pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity duration-150 z-30", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
143
+ chunk2SMCH62O_cjs.FloatingToolbar,
144
+ {
145
+ containerRef,
146
+ scrollIsolation: shouldScroll ? scrollIsolation : false,
147
+ label: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-muted/80 text-muted-foreground border border-border/50 backdrop-blur-sm", children: displayLanguage }),
148
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunk2SMCH62O_cjs.CopyAction, { value: contentJson, title: labels.copyCode })
149
+ }
150
+ ) }) }),
151
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: shouldScroll ? "h-full overflow-auto" : "", style: shouldScroll ? { maxHeight: maxHeightPx } : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(prismReactRenderer.Highlight, { theme: prismTheme, code: contentJson, language: normalizedLanguage, children: ({ className: className2, style, tokens, getLineProps, getTokenProps }) => {
152
+ const { backgroundColor: _bg, ...restStyle } = style;
153
+ return /* @__PURE__ */ jsxRuntime.jsx(
154
+ "pre",
155
+ {
156
+ className: `${className2} rounded-lg`,
157
+ style: {
158
+ ...restStyle,
159
+ margin: 0,
160
+ // Top padding gives the hover toolbar room to sit over
161
+ // the first line without covering it. Before: 2.5rem —
162
+ // too much empty space on short snippets. Now: 1rem,
163
+ // toolbar overlays with translucent bg on hover only.
164
+ padding: "1rem 1rem 0.75rem 1rem",
165
+ fontSize,
166
+ lineHeight: lineHeightRatio,
167
+ fontFamily: "monospace",
168
+ whiteSpace: "pre-wrap",
169
+ wordBreak: "break-word",
170
+ overflowWrap: "break-word"
171
+ },
172
+ children: tokens.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { ...getLineProps({ line }), children: line.map((token, key) => /* @__PURE__ */ jsxRuntime.jsx("span", { ...getTokenProps({ token }) }, key)) }, i))
173
+ }
174
+ );
175
+ } }) })
176
+ ]
177
+ }
178
+ );
157
179
  }, "PrettyCode");
158
180
  var PrettyCode_client_default = PrettyCode;
159
181
 
160
182
  module.exports = PrettyCode_client_default;
161
- //# sourceMappingURL=PrettyCode.client-SGDGQTYT.cjs.map
162
- //# sourceMappingURL=PrettyCode.client-SGDGQTYT.cjs.map
183
+ //# sourceMappingURL=PrettyCode.client-5GABIN2I.cjs.map
184
+ //# sourceMappingURL=PrettyCode.client-5GABIN2I.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/PrettyCode/PrettyCode.client.tsx"],"names":["__name","useRef","useAppT","useResolvedTheme","useMemo","themes","jsx","Highlight","className","jsxs","FloatingToolbar","CopyAction"],"mappings":";;;;;;;;;;AA2BA,IAAM,UAAA,mBAAaA,wBAAA,CAAA,CAAC,EAAE,IAAA,EAAM,UAAU,SAAA,EAAW,IAAA,EAAM,MAAA,GAAS,KAAA,EAAO,QAAA,EAAU,SAAA,GAAY,KAAA,EAAO,eAAA,EAAiB,UAAS,KAAuB;AACnJ,EAAA,MAAM,YAAA,GAAeC,aAAuB,IAAI,CAAA;AAChD,EAAA,MAAM,IAAIC,YAAA,EAAQ;AAClB,EAAA,MAAM,gBAAgBC,sBAAA,EAAiB;AAEvC,EAAA,MAAM,MAAA,GAASC,cAAQ,OAAO;AAAA,IAC5B,QAAA,EAAU,EAAE,qBAAqB,CAAA;AAAA,IACjC,SAAA,EAAW,EAAE,sBAAsB;AAAA,GACrC,CAAA,EAAI,CAAC,CAAC,CAAC,CAAA;AAGP,EAAA,MAAM,QAAA,GAAW,YAAY,SAAA,GAAY,UAAA;AAGzC,EAAA,MAAM,eAAe,IAAA,IAAQ,aAAA;AAC7B,EAAA,MAAM,aAAa,YAAA,KAAiB,MAAA;AAGpC,EAAA,MAAM,UAAA,GAAa,UAAA,GAAaC,yBAAA,CAAO,MAAA,GAASA,yBAAA,CAAO,OAAA;AAGvD,EAAA,MAAM,WAAA,GAAc,OAAO,IAAA,KAAS,QAAA,GAAW,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,IAAA,IAAQ,EAAC,EAAG,IAAA,EAAM,CAAC,CAAA;AAIxF,EAAA,MAAM,YAAY,WAAA,GAAc,WAAA,CAAY,KAAA,CAAM,IAAI,EAAE,MAAA,GAAS,CAAA;AACjE,EAAA,MAAM,eAAA,GAAkB,YAAY,GAAA,GAAM,GAAA;AAC1C,EAAA,MAAM,UAAA,GAAa,YAAY,EAAA,GAAK,EAAA;AAGpC,EAAA,MAAM,gBAAgB,EAAA,GAAK,EAAA;AAC3B,EAAA,MAAM,YAAA,GAAe,QAAA,KAAa,MAAA,IAAa,SAAA,GAAY,QAAA;AAC3D,EAAA,MAAM,cAAc,QAAA,KAAa,MAAA,GAC7B,QAAA,GAAW,UAAA,GAAa,kBAAkB,aAAA,GAC1C,MAAA;AAGJ,EAAA,IAAI,CAAC,WAAA,IAAe,WAAA,CAAY,IAAA,OAAW,EAAA,EAAI;AAC7C,IAAA,MAAM,YAAA,GAAe,QAAA,KAAa,UAAA,GAAa,aAAA,GAAgB,UAAA,CAAA;AAC/D,IAAA,MAAM,gBAAA,GAAmB,aAAa,iBAAA,GAAoB,eAAA;AAC1D,IAAA,uBACEC,cAAA,CAAC,SAAI,SAAA,EAAW,CAAA,gBAAA,EAAmB,YAAY,CAAA,mBAAA,EAAsB,gBAAgB,CAAA,CAAA,EAAI,SAAA,IAAa,EAAE,CAAA,CAAA,EACtG,yCAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4BACb,QAAA,kBAAAA,cAAA,CAAC,GAAA,EAAA,EAAE,WAAU,sCAAA,EAAwC,QAAA,EAAA,MAAA,CAAO,SAAA,EAAU,CAAA,EACxE,CAAA,EACF,CAAA;AAAA,EAEJ;AAGA,EAAA,MAAM,sBAAA,6CAA0B,IAAA,KAAyB;AACvD,IAAA,QAAQ,IAAA,CAAK,aAAY;AAAG,MAC1B,KAAK,MAAA;AAAA,MACL,KAAK,OAAA;AACH,QAAA,OAAO,MAAA;AAAA,MACT,KAAK,QAAA;AAAA,MACL,KAAK,IAAA;AACH,QAAA,OAAO,QAAA;AAAA,MACT,KAAK,YAAA;AAAA,MACL,KAAK,IAAA;AACH,QAAA,OAAO,YAAA;AAAA,MACT,KAAK,YAAA;AAAA,MACL,KAAK,IAAA;AACH,QAAA,OAAO,YAAA;AAAA,MACT,KAAK,MAAA;AACH,QAAA,OAAO,MAAA;AAAA,MACT,KAAK,MAAA;AAAA,MACL,KAAK,KAAA;AACH,QAAA,OAAO,MAAA;AAAA,MACT,KAAK,MAAA;AACH,QAAA,OAAO,MAAA;AAAA,MACT,KAAK,KAAA;AACH,QAAA,OAAO,KAAA;AAAA,MACT,KAAK,KAAA;AACH,QAAA,OAAO,KAAA;AAAA,MACT,KAAK,KAAA;AACH,QAAA,OAAO,KAAA;AAAA,MACT,KAAK,UAAA;AAAA,MACL,KAAK,IAAA;AACH,QAAA,OAAO,UAAA;AAAA,MACT,KAAK,WAAA;AAAA,MACL,KAAK,MAAA;AACH,QAAA,OAAO,MAAA;AAAA,MACT,KAAK,SAAA;AACH,QAAA,OAAO,SAAA;AAAA,MACT;AACE,QAAA,OAAO,IAAA,CAAK,OAAO,CAAC,CAAA,CAAE,aAAY,GAAI,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA;AACtD,EACF,CAAA,EAtC+B,wBAAA,CAAA;AAyC/B,EAAA,MAAM,sBAAsB,MAAM;AAChC,IAAA,MAAM,IAAA,GAAO,SAAS,WAAA,EAAY;AAGlC,IAAA,QAAQ,IAAA;AAAM,MACZ,KAAK,YAAA;AAAA,MACL,KAAK,IAAA;AACH,QAAA,OAAO,YAAA;AAAA,MACT,KAAK,YAAA;AAAA,MACL,KAAK,IAAA;AACH,QAAA,OAAO,YAAA;AAAA;AAAA,MACT,KAAK,QAAA;AAAA,MACL,KAAK,IAAA;AACH,QAAA,OAAO,QAAA;AAAA,MACT,KAAK,MAAA;AACH,QAAA,OAAO,MAAA;AAAA,MACT,KAAK,KAAA;AACH,QAAA,OAAO,KAAA;AAAA,MACT,KAAK,MAAA;AACH,QAAA,OAAO,QAAA;AAAA,MACT,KAAK,KAAA;AACH,QAAA,OAAO,QAAA;AAAA,MACT,KAAK,MAAA;AAAA,MACL,KAAK,OAAA;AACH,QAAA,OAAO,MAAA;AAAA,MACT,KAAK,KAAA;AACH,QAAA,OAAO,KAAA;AAAA,MACT,KAAK,MAAA;AAAA,MACL,KAAK,KAAA;AACH,QAAA,OAAO,MAAA;AAAA,MACT,KAAK,UAAA;AAAA,MACL,KAAK,IAAA;AACH,QAAA,OAAO,UAAA;AAAA,MACT,KAAK,SAAA;AACH,QAAA,OAAO,MAAA;AAAA;AAAA,MACT;AAGE,QAAA,OAAO,IAAA,IAAQ,MAAA;AAAA;AACnB,EACF,CAAA,GAAG;AAEH,EAAA,MAAM,eAAA,GAAkB,uBAAuB,QAAQ,CAAA;AAEvD,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,aAAA,GAAgB,QAAA,KAAa,UAAA,GAAa,aAAA,GAAgB,aAAA,CAAA;AAChE,IAAA,uBACEA,cAAA,CAACC,4BAAA,EAAA,EAAU,KAAA,EAAO,UAAA,EAAY,MAAM,WAAA,EAAa,QAAA,EAAU,kBAAA,EACxD,QAAA,EAAA,CAAC,EAAE,SAAA,EAAAC,UAAAA,EAAW,KAAA,EAAO,MAAA,EAAQ,eAAc,qBAC1CF,cAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,GAAGE,UAAS,CAAA,CAAA,EAAI,aAAa,CAAA,mBAAA,EAAsB,SAAA,GAAY,YAAY,SAAS,CAAA,uBAAA,CAAA;AAAA,QAC/F,KAAA,EAAO;AAAA,UACL,GAAG,KAAA;AAAA,UACH,QAAA;AAAA,UACA,UAAA,EAAY;AAAA,SACd;AAAA,QAEC,iBAAO,GAAA,CAAI,CAAC,SACX,IAAA,CAAK,GAAA,CAAI,CAAC,KAAA,EAAO,GAAA,oCACd,MAAA,EAAA,EAAgB,GAAG,cAAc,EAAE,KAAA,EAAO,CAAA,EAAA,EAAhC,GAAmC,CAC/C,CACF;AAAA;AAAA,KACH,EAEJ,CAAA;AAAA,EAEJ;AAGA,EAAA,MAAM,OAAA,GAAU,QAAA,KAAa,UAAA,GAAa,aAAA,GAAgB,UAAA,CAAA;AAC1D,EAAA,MAAM,WAAA,GAAc,aAAa,iBAAA,GAAoB,eAAA;AAErD,EAAA,uBACEC,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,YAAA;AAAA,MACL,WAAW,CAAA,eAAA,EAAkB,OAAO,sBAAsB,WAAW,CAAA,CAAA,EAAI,aAAa,EAAE,CAAA,CAAA;AAAA,MACxF,KAAA;AAAA;AAAA;AAAA,QAGE,cAAc,EAAE,SAAA,EAAW,CAAA,EAAG,WAAW,MAAK,GAAI;AAAA,OAAA;AAAA,MAOpD,QAAA,EAAA;AAAA,wBAAAH,cAAA,CAAC,SAAI,SAAA,EAAU,qHAAA,EACb,QAAA,kBAAAA,cAAA,CAAC,KAAA,EAAA,EAAI,WAAU,qBAAA,EACb,QAAA,kBAAAA,cAAA;AAAA,UAACI,iCAAA;AAAA,UAAA;AAAA,YACC,YAAA;AAAA,YACA,eAAA,EAAiB,eAAe,eAAA,GAAkB,KAAA;AAAA,YAClD,KAAA,kBACEJ,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+IACb,QAAA,EAAA,eAAA,EACH,CAAA;AAAA,YAGF,yCAACK,4BAAA,EAAA,EAAW,KAAA,EAAO,WAAA,EAAa,KAAA,EAAO,OAAO,QAAA,EAAU;AAAA;AAAA,WAE5D,CAAA,EACF,CAAA;AAAA,wBAEAL,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,GAAe,sBAAA,GAAyB,EAAA,EAAI,KAAA,EAAO,YAAA,GAAe,EAAE,SAAA,EAAW,WAAA,EAAY,GAAI,MAAA,EAC7G,QAAA,kBAAAA,cAAA,CAACC,4BAAA,EAAA,EAAU,KAAA,EAAO,UAAA,EAAY,IAAA,EAAM,WAAA,EAAa,QAAA,EAAU,kBAAA,EACxD,QAAA,EAAA,CAAC,EAAE,SAAA,EAAAC,UAAAA,EAAW,KAAA,EAAO,MAAA,EAAQ,YAAA,EAAc,eAAc,KAAM;AAE9D,UAAA,MAAM,EAAE,eAAA,EAAiB,GAAA,EAAK,GAAG,WAAU,GAAI,KAAA;AAC/C,UAAA,uBACAF,cAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAW,GAAGE,UAAS,CAAA,WAAA,CAAA;AAAA,cACvB,KAAA,EAAO;AAAA,gBACL,GAAG,SAAA;AAAA,gBACH,MAAA,EAAQ,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAKR,OAAA,EAAS,wBAAA;AAAA,gBACT,QAAA;AAAA,gBACA,UAAA,EAAY,eAAA;AAAA,gBACZ,UAAA,EAAY,WAAA;AAAA,gBACZ,UAAA,EAAY,UAAA;AAAA,gBACZ,SAAA,EAAW,YAAA;AAAA,gBACX,YAAA,EAAc;AAAA,eAChB;AAAA,cAEC,QAAA,EAAA,MAAA,CAAO,GAAA,CAAI,CAAC,IAAA,EAAM,CAAA,qBACjBF,cAAA,CAAC,KAAA,EAAA,EAAa,GAAG,YAAA,CAAa,EAAE,IAAA,EAAM,GACnC,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,KAAA,EAAO,GAAA,qBAChBA,cAAA,CAAC,MAAA,EAAA,EAAgB,GAAG,aAAA,CAAc,EAAE,KAAA,EAAO,CAAA,EAAA,EAAhC,GAAmC,CAC/C,CAAA,EAAA,EAHO,CAIV,CACD;AAAA;AAAA,WACH;AAAA,QACD,GACH,CAAA,EACF;AAAA;AAAA;AAAA,GACF;AAEJ,CAAA,EAtOmB,YAAA,CAAA;AAwOnB,IAAO,yBAAA,GAAQ","file":"PrettyCode.client-5GABIN2I.cjs","sourcesContent":["'use client';\n\nimport { Highlight, Language, themes } from 'prism-react-renderer';\nimport React, { useMemo, useRef } from 'react';\n\nimport { useAppT } from '@djangocfg/i18n';\nimport { useResolvedTheme } from '@djangocfg/ui-core/hooks';\nimport { FloatingToolbar } from '../../components/FloatingToolbar';\nimport { CopyAction } from '../../components/FloatingToolbar/actions';\n\ninterface PrettyCodeProps {\n data: string | object;\n language: Language;\n className?: string;\n mode?: 'dark' | 'light';\n inline?: boolean;\n customBg?: string; // Custom background class\n isCompact?: boolean; // Compact mode for smaller font sizes\n scrollIsolation?: boolean; // Block scroll capture until user clicks (default: true)\n /**\n * Line count at which the viewer starts to scroll instead of growing.\n * ``undefined`` (default) = always grows to fit content, no scroll.\n * Set e.g. ``50`` to cap short snippets inline and scroll long ones.\n */\n maxLines?: number;\n}\n\nconst PrettyCode = ({ data, language, className, mode, inline = false, customBg, isCompact = false, scrollIsolation, maxLines }: PrettyCodeProps) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const t = useAppT();\n const detectedTheme = useResolvedTheme();\n\n const labels = useMemo(() => ({\n copyCode: t('tools.code.copyCode'),\n noContent: t('tools.code.noContent'),\n }), [t]);\n\n // Font size based on compact mode\n const fontSize = isCompact ? '0.75rem' : '0.875rem'; // 12px vs 14px\n\n // Use provided mode or fall back to detected theme\n const currentTheme = mode || detectedTheme;\n const isDarkMode = currentTheme === 'dark';\n\n // Select the Prism theme based on the current theme\n const prismTheme = isDarkMode ? themes.vsDark : themes.vsLight;\n\n // Convert form object to JSON string with proper formatting\n const contentJson = typeof data === 'string' ? data : JSON.stringify(data || {}, null, 2);\n\n // Enable scroll only when content exceeds maxLines. Otherwise the block\n // grows to fit — short snippets feel natural, long ones get a cap.\n const lineCount = contentJson ? contentJson.split('\\n').length : 0;\n const lineHeightRatio = isCompact ? 1.4 : 1.5;\n const fontSizePx = isCompact ? 12 : 14;\n // Vertical padding of the <pre> (top + bottom, in px) — keep in sync\n // with the padding string below.\n const verticalPadPx = 16 + 12; // 1rem top + 0.75rem bottom (≈)\n const shouldScroll = maxLines !== undefined && lineCount > maxLines;\n const maxHeightPx = maxLines !== undefined\n ? maxLines * fontSizePx * lineHeightRatio + verticalPadPx\n : undefined;\n \n // Handle empty content\n if (!contentJson || contentJson.trim() === '') {\n const emptyBgClass = customBg || (isDarkMode ? 'bg-zinc-900' : 'bg-white');\n const emptyBorderClass = isDarkMode ? 'border-zinc-700' : 'border-border';\n return (\n <div className={`relative h-full ${emptyBgClass} rounded-sm border ${emptyBorderClass} ${className || ''}`}>\n <div className=\"h-full overflow-auto p-4\">\n <p className=\"text-muted-foreground text-sm italic\">{labels.noContent}</p>\n </div>\n </div>\n );\n }\n\n // Get display name for language badge\n const getLanguageDisplayName = (lang: string): string => {\n switch (lang.toLowerCase()) {\n case 'bash':\n case 'shell':\n return 'Bash';\n case 'python':\n case 'py':\n return 'Python';\n case 'javascript':\n case 'js':\n return 'JavaScript';\n case 'typescript':\n case 'ts':\n return 'TypeScript';\n case 'json':\n return 'JSON';\n case 'yaml':\n case 'yml':\n return 'YAML';\n case 'html':\n return 'HTML';\n case 'css':\n return 'CSS';\n case 'sql':\n return 'SQL';\n case 'xml':\n return 'XML';\n case 'markdown':\n case 'md':\n return 'Markdown';\n case 'plaintext':\n case 'text':\n return 'Text';\n case 'mermaid':\n return 'Mermaid';\n default:\n return lang.charAt(0).toUpperCase() + lang.slice(1);\n }\n };\n\n // Normalize language for Prism - use only basic supported languages\n const normalizedLanguage = (() => {\n const lang = language.toLowerCase();\n \n // Try basic languages that are definitely supported\n switch (lang) {\n case 'javascript':\n case 'js':\n return 'javascript';\n case 'typescript':\n case 'ts':\n return 'typescript'; // Try TypeScript first\n case 'python':\n case 'py':\n return 'python';\n case 'json':\n return 'json';\n case 'css':\n return 'css';\n case 'html':\n return 'markup';\n case 'xml':\n return 'markup';\n case 'bash':\n case 'shell':\n return 'bash';\n case 'sql':\n return 'sql';\n case 'yaml':\n case 'yml':\n return 'yaml';\n case 'markdown':\n case 'md':\n return 'markdown';\n case 'mermaid':\n return 'text'; // Mermaid is handled separately in MarkdownMessage\n default:\n // For unknown languages, try to use the original name first\n // If it doesn't work, Prism will fallback to plain text\n return lang || 'text';\n }\n })();\n\n const displayLanguage = getLanguageDisplayName(language);\n\n if (inline) {\n const inlineBgClass = customBg || (isDarkMode ? 'bg-zinc-800' : 'bg-zinc-100');\n return (\n <Highlight theme={prismTheme} code={contentJson} language={normalizedLanguage as Language}>\n {({ className, style, tokens, getTokenProps }) => (\n <code\n className={`${className} ${inlineBgClass} px-2 py-1 rounded ${isCompact ? 'text-xs' : 'text-sm'} font-mono inline-block`}\n style={{\n ...style,\n fontSize,\n fontFamily: 'monospace',\n }}\n >\n {tokens.map((line) => (\n line.map((token, key) => (\n <span key={key} {...getTokenProps({ token })} />\n ))\n ))}\n </code>\n )}\n </Highlight>\n );\n }\n\n // Different backgrounds for dark/light - light mode uses white for better contrast with vsLight theme\n const bgClass = customBg || (isDarkMode ? 'bg-zinc-900' : 'bg-white');\n const borderClass = isDarkMode ? 'border-zinc-700' : 'border-border';\n\n return (\n <div\n ref={containerRef}\n className={`group relative ${bgClass} rounded-lg border ${borderClass} ${className || ''}`}\n style={\n // maxHeight caps growth at ``maxLines`` rows; without maxLines we\n // let the block grow to fit its content (no scroll).\n maxHeightPx ? { maxHeight: `${maxHeightPx}px` } : undefined\n }\n >\n {/* Toolbar: hidden by default, appears on hover. Absolute overlay so it doesn't shift layout.\n scrollIsolation is force-disabled when content fits without scrolling —\n otherwise the \"Click to scroll\" prompt shows on a block that has\n nothing to scroll, which reads as a bug. */}\n <div className=\"absolute inset-x-0 top-0 pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity duration-150 z-30\">\n <div className=\"pointer-events-auto\">\n <FloatingToolbar\n containerRef={containerRef}\n scrollIsolation={shouldScroll ? scrollIsolation : false}\n label={\n <span className=\"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-muted/80 text-muted-foreground border border-border/50 backdrop-blur-sm\">\n {displayLanguage}\n </span>\n }\n >\n <CopyAction value={contentJson} title={labels.copyCode} />\n </FloatingToolbar>\n </div>\n </div>\n\n <div className={shouldScroll ? 'h-full overflow-auto' : ''} style={shouldScroll ? { maxHeight: maxHeightPx } : undefined}>\n <Highlight theme={prismTheme} code={contentJson} language={normalizedLanguage as Language}>\n {({ className, style, tokens, getLineProps, getTokenProps }) => {\n // Remove background from Prism theme - we use our own via CSS\n const { backgroundColor: _bg, ...restStyle } = style;\n return (\n <pre\n className={`${className} rounded-lg`}\n style={{\n ...restStyle,\n margin: 0,\n // Top padding gives the hover toolbar room to sit over\n // the first line without covering it. Before: 2.5rem —\n // too much empty space on short snippets. Now: 1rem,\n // toolbar overlays with translucent bg on hover only.\n padding: '1rem 1rem 0.75rem 1rem',\n fontSize,\n lineHeight: lineHeightRatio,\n fontFamily: 'monospace',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n overflowWrap: 'break-word',\n }}\n >\n {tokens.map((line, i) => (\n <div key={i} {...getLineProps({ line })}>\n {line.map((token, key) => (\n <span key={key} {...getTokenProps({ token })} />\n ))}\n </div>\n ))}\n </pre>\n )}}\n </Highlight>\n </div>\n </div>\n );\n};\n\nexport default PrettyCode; "]}
@@ -6,7 +6,7 @@ import { useAppT } from '@djangocfg/i18n';
6
6
  import { useResolvedTheme } from '@djangocfg/ui-core/hooks';
7
7
  import { jsx, jsxs } from 'react/jsx-runtime';
8
8
 
9
- var PrettyCode = /* @__PURE__ */ __name(({ data, language, className, mode, inline = false, customBg, isCompact = false, scrollIsolation }) => {
9
+ var PrettyCode = /* @__PURE__ */ __name(({ data, language, className, mode, inline = false, customBg, isCompact = false, scrollIsolation, maxLines }) => {
10
10
  const containerRef = useRef(null);
11
11
  const t = useAppT();
12
12
  const detectedTheme = useResolvedTheme();
@@ -19,6 +19,12 @@ var PrettyCode = /* @__PURE__ */ __name(({ data, language, className, mode, inli
19
19
  const isDarkMode = currentTheme === "dark";
20
20
  const prismTheme = isDarkMode ? themes.vsDark : themes.vsLight;
21
21
  const contentJson = typeof data === "string" ? data : JSON.stringify(data || {}, null, 2);
22
+ const lineCount = contentJson ? contentJson.split("\n").length : 0;
23
+ const lineHeightRatio = isCompact ? 1.4 : 1.5;
24
+ const fontSizePx = isCompact ? 12 : 14;
25
+ const verticalPadPx = 16 + 12;
26
+ const shouldScroll = maxLines !== void 0 && lineCount > maxLines;
27
+ const maxHeightPx = maxLines !== void 0 ? maxLines * fontSizePx * lineHeightRatio + verticalPadPx : void 0;
22
28
  if (!contentJson || contentJson.trim() === "") {
23
29
  const emptyBgClass = customBg || (isDarkMode ? "bg-zinc-900" : "bg-white");
24
30
  const emptyBorderClass = isDarkMode ? "border-zinc-700" : "border-border";
@@ -120,41 +126,57 @@ var PrettyCode = /* @__PURE__ */ __name(({ data, language, className, mode, inli
120
126
  }
121
127
  const bgClass = customBg || (isDarkMode ? "bg-zinc-900" : "bg-white");
122
128
  const borderClass = isDarkMode ? "border-zinc-700" : "border-border";
123
- return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: `group relative h-full ${bgClass} rounded-lg border ${borderClass} ${className || ""}`, children: [
124
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity duration-150 z-30", children: /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx(
125
- FloatingToolbar,
126
- {
127
- containerRef,
128
- scrollIsolation,
129
- label: /* @__PURE__ */ jsx("span", { className: "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-muted/80 text-muted-foreground border border-border/50 backdrop-blur-sm", children: displayLanguage }),
130
- children: /* @__PURE__ */ jsx(CopyAction, { value: contentJson, title: labels.copyCode })
131
- }
132
- ) }) }),
133
- /* @__PURE__ */ jsx("div", { className: "h-full overflow-auto", children: /* @__PURE__ */ jsx(Highlight, { theme: prismTheme, code: contentJson, language: normalizedLanguage, children: ({ className: className2, style, tokens, getLineProps, getTokenProps }) => {
134
- const { backgroundColor: _bg, ...restStyle } = style;
135
- return /* @__PURE__ */ jsx(
136
- "pre",
137
- {
138
- className: `${className2} rounded-lg`,
139
- style: {
140
- ...restStyle,
141
- margin: 0,
142
- padding: "2.5rem 1rem 1rem 1rem",
143
- fontSize,
144
- lineHeight: isCompact ? 1.4 : 1.5,
145
- fontFamily: "monospace",
146
- whiteSpace: "pre-wrap",
147
- wordBreak: "break-word",
148
- overflowWrap: "break-word"
149
- },
150
- children: tokens.map((line, i) => /* @__PURE__ */ jsx("div", { ...getLineProps({ line }), children: line.map((token, key) => /* @__PURE__ */ jsx("span", { ...getTokenProps({ token }) }, key)) }, i))
151
- }
152
- );
153
- } }) })
154
- ] });
129
+ return /* @__PURE__ */ jsxs(
130
+ "div",
131
+ {
132
+ ref: containerRef,
133
+ className: `group relative ${bgClass} rounded-lg border ${borderClass} ${className || ""}`,
134
+ style: (
135
+ // maxHeight caps growth at ``maxLines`` rows; without maxLines we
136
+ // let the block grow to fit its content (no scroll).
137
+ maxHeightPx ? { maxHeight: `${maxHeightPx}px` } : void 0
138
+ ),
139
+ children: [
140
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-x-0 top-0 pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity duration-150 z-30", children: /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx(
141
+ FloatingToolbar,
142
+ {
143
+ containerRef,
144
+ scrollIsolation: shouldScroll ? scrollIsolation : false,
145
+ label: /* @__PURE__ */ jsx("span", { className: "inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-muted/80 text-muted-foreground border border-border/50 backdrop-blur-sm", children: displayLanguage }),
146
+ children: /* @__PURE__ */ jsx(CopyAction, { value: contentJson, title: labels.copyCode })
147
+ }
148
+ ) }) }),
149
+ /* @__PURE__ */ jsx("div", { className: shouldScroll ? "h-full overflow-auto" : "", style: shouldScroll ? { maxHeight: maxHeightPx } : void 0, children: /* @__PURE__ */ jsx(Highlight, { theme: prismTheme, code: contentJson, language: normalizedLanguage, children: ({ className: className2, style, tokens, getLineProps, getTokenProps }) => {
150
+ const { backgroundColor: _bg, ...restStyle } = style;
151
+ return /* @__PURE__ */ jsx(
152
+ "pre",
153
+ {
154
+ className: `${className2} rounded-lg`,
155
+ style: {
156
+ ...restStyle,
157
+ margin: 0,
158
+ // Top padding gives the hover toolbar room to sit over
159
+ // the first line without covering it. Before: 2.5rem —
160
+ // too much empty space on short snippets. Now: 1rem,
161
+ // toolbar overlays with translucent bg on hover only.
162
+ padding: "1rem 1rem 0.75rem 1rem",
163
+ fontSize,
164
+ lineHeight: lineHeightRatio,
165
+ fontFamily: "monospace",
166
+ whiteSpace: "pre-wrap",
167
+ wordBreak: "break-word",
168
+ overflowWrap: "break-word"
169
+ },
170
+ children: tokens.map((line, i) => /* @__PURE__ */ jsx("div", { ...getLineProps({ line }), children: line.map((token, key) => /* @__PURE__ */ jsx("span", { ...getTokenProps({ token }) }, key)) }, i))
171
+ }
172
+ );
173
+ } }) })
174
+ ]
175
+ }
176
+ );
155
177
  }, "PrettyCode");
156
178
  var PrettyCode_client_default = PrettyCode;
157
179
 
158
180
  export { PrettyCode_client_default as default };
159
- //# sourceMappingURL=PrettyCode.client-DW5LTG47.mjs.map
160
- //# sourceMappingURL=PrettyCode.client-DW5LTG47.mjs.map
181
+ //# sourceMappingURL=PrettyCode.client-IZTXXYHG.mjs.map
182
+ //# sourceMappingURL=PrettyCode.client-IZTXXYHG.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/PrettyCode/PrettyCode.client.tsx"],"names":["className"],"mappings":"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","file":"PrettyCode.client-IZTXXYHG.mjs","sourcesContent":["'use client';\n\nimport { Highlight, Language, themes } from 'prism-react-renderer';\nimport React, { useMemo, useRef } from 'react';\n\nimport { useAppT } from '@djangocfg/i18n';\nimport { useResolvedTheme } from '@djangocfg/ui-core/hooks';\nimport { FloatingToolbar } from '../../components/FloatingToolbar';\nimport { CopyAction } from '../../components/FloatingToolbar/actions';\n\ninterface PrettyCodeProps {\n data: string | object;\n language: Language;\n className?: string;\n mode?: 'dark' | 'light';\n inline?: boolean;\n customBg?: string; // Custom background class\n isCompact?: boolean; // Compact mode for smaller font sizes\n scrollIsolation?: boolean; // Block scroll capture until user clicks (default: true)\n /**\n * Line count at which the viewer starts to scroll instead of growing.\n * ``undefined`` (default) = always grows to fit content, no scroll.\n * Set e.g. ``50`` to cap short snippets inline and scroll long ones.\n */\n maxLines?: number;\n}\n\nconst PrettyCode = ({ data, language, className, mode, inline = false, customBg, isCompact = false, scrollIsolation, maxLines }: PrettyCodeProps) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const t = useAppT();\n const detectedTheme = useResolvedTheme();\n\n const labels = useMemo(() => ({\n copyCode: t('tools.code.copyCode'),\n noContent: t('tools.code.noContent'),\n }), [t]);\n\n // Font size based on compact mode\n const fontSize = isCompact ? '0.75rem' : '0.875rem'; // 12px vs 14px\n\n // Use provided mode or fall back to detected theme\n const currentTheme = mode || detectedTheme;\n const isDarkMode = currentTheme === 'dark';\n\n // Select the Prism theme based on the current theme\n const prismTheme = isDarkMode ? themes.vsDark : themes.vsLight;\n\n // Convert form object to JSON string with proper formatting\n const contentJson = typeof data === 'string' ? data : JSON.stringify(data || {}, null, 2);\n\n // Enable scroll only when content exceeds maxLines. Otherwise the block\n // grows to fit — short snippets feel natural, long ones get a cap.\n const lineCount = contentJson ? contentJson.split('\\n').length : 0;\n const lineHeightRatio = isCompact ? 1.4 : 1.5;\n const fontSizePx = isCompact ? 12 : 14;\n // Vertical padding of the <pre> (top + bottom, in px) — keep in sync\n // with the padding string below.\n const verticalPadPx = 16 + 12; // 1rem top + 0.75rem bottom (≈)\n const shouldScroll = maxLines !== undefined && lineCount > maxLines;\n const maxHeightPx = maxLines !== undefined\n ? maxLines * fontSizePx * lineHeightRatio + verticalPadPx\n : undefined;\n \n // Handle empty content\n if (!contentJson || contentJson.trim() === '') {\n const emptyBgClass = customBg || (isDarkMode ? 'bg-zinc-900' : 'bg-white');\n const emptyBorderClass = isDarkMode ? 'border-zinc-700' : 'border-border';\n return (\n <div className={`relative h-full ${emptyBgClass} rounded-sm border ${emptyBorderClass} ${className || ''}`}>\n <div className=\"h-full overflow-auto p-4\">\n <p className=\"text-muted-foreground text-sm italic\">{labels.noContent}</p>\n </div>\n </div>\n );\n }\n\n // Get display name for language badge\n const getLanguageDisplayName = (lang: string): string => {\n switch (lang.toLowerCase()) {\n case 'bash':\n case 'shell':\n return 'Bash';\n case 'python':\n case 'py':\n return 'Python';\n case 'javascript':\n case 'js':\n return 'JavaScript';\n case 'typescript':\n case 'ts':\n return 'TypeScript';\n case 'json':\n return 'JSON';\n case 'yaml':\n case 'yml':\n return 'YAML';\n case 'html':\n return 'HTML';\n case 'css':\n return 'CSS';\n case 'sql':\n return 'SQL';\n case 'xml':\n return 'XML';\n case 'markdown':\n case 'md':\n return 'Markdown';\n case 'plaintext':\n case 'text':\n return 'Text';\n case 'mermaid':\n return 'Mermaid';\n default:\n return lang.charAt(0).toUpperCase() + lang.slice(1);\n }\n };\n\n // Normalize language for Prism - use only basic supported languages\n const normalizedLanguage = (() => {\n const lang = language.toLowerCase();\n \n // Try basic languages that are definitely supported\n switch (lang) {\n case 'javascript':\n case 'js':\n return 'javascript';\n case 'typescript':\n case 'ts':\n return 'typescript'; // Try TypeScript first\n case 'python':\n case 'py':\n return 'python';\n case 'json':\n return 'json';\n case 'css':\n return 'css';\n case 'html':\n return 'markup';\n case 'xml':\n return 'markup';\n case 'bash':\n case 'shell':\n return 'bash';\n case 'sql':\n return 'sql';\n case 'yaml':\n case 'yml':\n return 'yaml';\n case 'markdown':\n case 'md':\n return 'markdown';\n case 'mermaid':\n return 'text'; // Mermaid is handled separately in MarkdownMessage\n default:\n // For unknown languages, try to use the original name first\n // If it doesn't work, Prism will fallback to plain text\n return lang || 'text';\n }\n })();\n\n const displayLanguage = getLanguageDisplayName(language);\n\n if (inline) {\n const inlineBgClass = customBg || (isDarkMode ? 'bg-zinc-800' : 'bg-zinc-100');\n return (\n <Highlight theme={prismTheme} code={contentJson} language={normalizedLanguage as Language}>\n {({ className, style, tokens, getTokenProps }) => (\n <code\n className={`${className} ${inlineBgClass} px-2 py-1 rounded ${isCompact ? 'text-xs' : 'text-sm'} font-mono inline-block`}\n style={{\n ...style,\n fontSize,\n fontFamily: 'monospace',\n }}\n >\n {tokens.map((line) => (\n line.map((token, key) => (\n <span key={key} {...getTokenProps({ token })} />\n ))\n ))}\n </code>\n )}\n </Highlight>\n );\n }\n\n // Different backgrounds for dark/light - light mode uses white for better contrast with vsLight theme\n const bgClass = customBg || (isDarkMode ? 'bg-zinc-900' : 'bg-white');\n const borderClass = isDarkMode ? 'border-zinc-700' : 'border-border';\n\n return (\n <div\n ref={containerRef}\n className={`group relative ${bgClass} rounded-lg border ${borderClass} ${className || ''}`}\n style={\n // maxHeight caps growth at ``maxLines`` rows; without maxLines we\n // let the block grow to fit its content (no scroll).\n maxHeightPx ? { maxHeight: `${maxHeightPx}px` } : undefined\n }\n >\n {/* Toolbar: hidden by default, appears on hover. Absolute overlay so it doesn't shift layout.\n scrollIsolation is force-disabled when content fits without scrolling —\n otherwise the \"Click to scroll\" prompt shows on a block that has\n nothing to scroll, which reads as a bug. */}\n <div className=\"absolute inset-x-0 top-0 pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity duration-150 z-30\">\n <div className=\"pointer-events-auto\">\n <FloatingToolbar\n containerRef={containerRef}\n scrollIsolation={shouldScroll ? scrollIsolation : false}\n label={\n <span className=\"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-muted/80 text-muted-foreground border border-border/50 backdrop-blur-sm\">\n {displayLanguage}\n </span>\n }\n >\n <CopyAction value={contentJson} title={labels.copyCode} />\n </FloatingToolbar>\n </div>\n </div>\n\n <div className={shouldScroll ? 'h-full overflow-auto' : ''} style={shouldScroll ? { maxHeight: maxHeightPx } : undefined}>\n <Highlight theme={prismTheme} code={contentJson} language={normalizedLanguage as Language}>\n {({ className, style, tokens, getLineProps, getTokenProps }) => {\n // Remove background from Prism theme - we use our own via CSS\n const { backgroundColor: _bg, ...restStyle } = style;\n return (\n <pre\n className={`${className} rounded-lg`}\n style={{\n ...restStyle,\n margin: 0,\n // Top padding gives the hover toolbar room to sit over\n // the first line without covering it. Before: 2.5rem —\n // too much empty space on short snippets. Now: 1rem,\n // toolbar overlays with translucent bg on hover only.\n padding: '1rem 1rem 0.75rem 1rem',\n fontSize,\n lineHeight: lineHeightRatio,\n fontFamily: 'monospace',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n overflowWrap: 'break-word',\n }}\n >\n {tokens.map((line, i) => (\n <div key={i} {...getLineProps({ line })}>\n {line.map((token, key) => (\n <span key={key} {...getTokenProps({ token })} />\n ))}\n </div>\n ))}\n </pre>\n )}}\n </Highlight>\n </div>\n </div>\n );\n};\n\nexport default PrettyCode; "]}