@kushagradhawan/kookie-blocks 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components.css +4 -67
- package/dist/cjs/components/code/CodeBlock.d.ts.map +1 -1
- package/dist/cjs/components/code/CodeBlock.js +1 -1
- package/dist/cjs/components/code/CodeBlock.js.map +2 -2
- package/dist/esm/components/code/CodeBlock.d.ts.map +1 -1
- package/dist/esm/components/code/CodeBlock.js +1 -1
- package/dist/esm/components/code/CodeBlock.js.map +3 -3
- package/package.json +1 -1
- package/src/components/code/CodeBlock.tsx +22 -9
- package/src/components/index.css +4 -63
- package/styles.css +4 -59
package/components.css
CHANGED
|
@@ -18,74 +18,17 @@
|
|
|
18
18
|
position: relative;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
/* Code block content (the pre part, below the header) */
|
|
22
|
-
|
|
23
|
-
.code-block-content {
|
|
24
|
-
width: 100%;
|
|
25
|
-
min-width: 0;
|
|
26
|
-
overflow-x: auto;
|
|
27
|
-
/* Hide scrollbars while keeping scroll functionality */
|
|
28
|
-
scrollbar-width: none; /* Firefox */
|
|
29
|
-
-ms-overflow-style: none; /* IE/Edge */
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/* Hide scrollbars for webkit browsers */
|
|
33
|
-
|
|
34
|
-
.code-block-content::-webkit-scrollbar,
|
|
35
|
-
.code-block-content::-webkit-scrollbar-horizontal,
|
|
36
|
-
.code-block-content::-webkit-scrollbar-vertical,
|
|
37
|
-
.code-block-content::-webkit-scrollbar-track,
|
|
38
|
-
.code-block-content::-webkit-scrollbar-thumb,
|
|
39
|
-
.code-block-content::-webkit-scrollbar-corner {
|
|
40
|
-
display: none !important;
|
|
41
|
-
width: 0 !important;
|
|
42
|
-
height: 0 !important;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/* Also hide scrollbars on any pre/code elements inside code content */
|
|
46
|
-
|
|
47
|
-
.code-block-content pre::-webkit-scrollbar,
|
|
48
|
-
.code-block-content pre::-webkit-scrollbar-horizontal,
|
|
49
|
-
.code-block-content pre::-webkit-scrollbar-vertical,
|
|
50
|
-
.code-block-content pre::-webkit-scrollbar-track,
|
|
51
|
-
.code-block-content pre::-webkit-scrollbar-thumb,
|
|
52
|
-
.code-block-content pre::-webkit-scrollbar-corner,
|
|
53
|
-
.code-block-content code::-webkit-scrollbar,
|
|
54
|
-
.code-block-content code::-webkit-scrollbar-horizontal,
|
|
55
|
-
.code-block-content code::-webkit-scrollbar-vertical,
|
|
56
|
-
.code-block-content code::-webkit-scrollbar-track,
|
|
57
|
-
.code-block-content code::-webkit-scrollbar-thumb,
|
|
58
|
-
.code-block-content code::-webkit-scrollbar-corner {
|
|
59
|
-
display: none !important;
|
|
60
|
-
width: 0 !important;
|
|
61
|
-
height: 0 !important;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
21
|
/* Pre elements inside code content */
|
|
65
22
|
|
|
66
|
-
.code-content pre
|
|
67
|
-
.code-block-content pre {
|
|
68
|
-
overflow-x: visible;
|
|
69
|
-
max-width: 100%;
|
|
70
|
-
min-width: 0;
|
|
23
|
+
.code-content pre {
|
|
71
24
|
margin: 0;
|
|
72
25
|
width: 100%;
|
|
73
26
|
box-sizing: border-box;
|
|
74
|
-
scrollbar-width: none;
|
|
75
|
-
-ms-overflow-style: none;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/* Ensure Shiki-generated pre elements fill width */
|
|
79
|
-
|
|
80
|
-
.code-block-content > pre {
|
|
81
|
-
width: 100% !important;
|
|
82
|
-
min-width: 0;
|
|
83
27
|
}
|
|
84
28
|
|
|
85
29
|
/* Code elements inside pre */
|
|
86
30
|
|
|
87
|
-
.code-content pre code
|
|
88
|
-
.code-block-content pre code {
|
|
31
|
+
.code-content pre code {
|
|
89
32
|
font-family: var(--font-mono);
|
|
90
33
|
font-size: var(--font-size-2);
|
|
91
34
|
line-height: 1.75;
|
|
@@ -98,8 +41,7 @@
|
|
|
98
41
|
|
|
99
42
|
/* Shiki line spans */
|
|
100
43
|
|
|
101
|
-
.code-content pre code .line
|
|
102
|
-
.code-block-content pre code .line {
|
|
44
|
+
.code-content pre code .line {
|
|
103
45
|
display: flex;
|
|
104
46
|
align-items: center;
|
|
105
47
|
gap: 0;
|
|
@@ -107,8 +49,7 @@
|
|
|
107
49
|
|
|
108
50
|
/* Line numbers */
|
|
109
51
|
|
|
110
|
-
.code-content pre code .line::before
|
|
111
|
-
.code-block-content pre code .line::before {
|
|
52
|
+
.code-content pre code .line::before {
|
|
112
53
|
counter-increment: line;
|
|
113
54
|
content: counter(line);
|
|
114
55
|
display: inline-block;
|
|
@@ -156,7 +97,6 @@
|
|
|
156
97
|
|
|
157
98
|
/* Default to light theme for all tokens (codeToHtml with defaultColor: false) */
|
|
158
99
|
|
|
159
|
-
.code-block-content pre.shiki span,
|
|
160
100
|
.code-content pre.shiki span {
|
|
161
101
|
color: var(--shiki-light) !important;
|
|
162
102
|
font-style: var(--shiki-light-font-style);
|
|
@@ -167,9 +107,6 @@
|
|
|
167
107
|
|
|
168
108
|
/* Override with dark theme colors when inside a dark context */
|
|
169
109
|
|
|
170
|
-
.dark .code-block-content pre.shiki span,
|
|
171
|
-
.dark-theme .code-block-content pre.shiki span,
|
|
172
|
-
[data-appearance="dark"] .code-block-content pre.shiki span,
|
|
173
110
|
.dark .code-content pre.shiki span,
|
|
174
111
|
.dark-theme .code-content pre.shiki span,
|
|
175
112
|
[data-appearance="dark"] .code-content pre.shiki span {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../../../src/components/code/CodeBlock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyE,MAAM,OAAO,CAAC;AAK9F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../../../src/components/code/CodeBlock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyE,MAAM,OAAO,CAAC;AAK9F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAiZ9C,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,QAAe,EACf,YAAmB,EACnB,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,GAChB,EAAE,cAAc,qBAyBhB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var B=Object.create;var
|
|
1
|
+
"use strict";var B=Object.create;var w=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var I=Object.getPrototypeOf,$=Object.prototype.hasOwnProperty;var M=(n,o)=>{for(var r in o)w(n,r,{get:o[r],enumerable:!0})},L=(n,o,r,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of A(o))!$.call(n,s)&&s!==r&&w(n,s,{get:()=>o[s],enumerable:!(i=j(o,s))||i.enumerable});return n};var D=(n,o,r)=>(r=n!=null?B(I(n)):{},L(o||!n||!n.__esModule?w(r,"default",{value:n,enumerable:!0}):r,n)),_=n=>L(w({},"__esModule",{value:!0}),n);var V={};M(V,{CodeBlock:()=>Q});module.exports=_(V);var e=D(require("react")),t=require("@kushagradhawan/kookie-ui"),b=require("@hugeicons/react"),d=require("@hugeicons/core-free-icons"),z=require("shiki");const y=360,J="one-light",G="one-dark-pro";function O({children:n,background:o="none",backgroundProps:r={}}){const{dotSize:i=24,color:s="var(--gray-10)",backgroundColor:l="var(--gray-2)",height:a,width:g="100%",radius:u="3"}=r;if(o==="none")return e.default.createElement(t.Card,{size:"1",variant:"soft"},e.default.createElement(t.Flex,{justify:"center",align:"center",py:"4"},e.default.createElement(t.Theme,{fontFamily:"sans"},n)));if(o==="dots"){const f={backgroundImage:`radial-gradient(circle, ${s} 1px, transparent 1px)`,borderRadius:`var(--radius-${u})`,backgroundSize:`${i}px ${i}px`,backgroundPosition:"center",backgroundColor:l,width:g,...a&&{height:a}};return e.default.createElement(t.Card,{size:"1",variant:"soft"},e.default.createElement(t.Flex,{justify:"center",align:"center",py:"4",style:f},e.default.createElement(t.Theme,{fontFamily:"sans"},n)))}const c={backgroundImage:`url(${o})`,backgroundSize:"cover",backgroundPosition:"center",backgroundRepeat:"no-repeat",borderRadius:`var(--radius-${u})`,width:g,...a&&{height:a}};return e.default.createElement(t.Card,{size:"1",variant:"soft"},e.default.createElement(t.Flex,{justify:"center",align:"center",py:"4",style:c},e.default.createElement(t.Theme,{fontFamily:"sans"},n)))}const U=(0,e.memo)(function({code:o,language:r,showCopy:i=!0,showLanguage:s=!0,lightTheme:l=J,darkTheme:a=G}){const[g,u]=(0,e.useState)(null),[c,f]=(0,e.useState)(!1),[p,m]=(0,e.useState)(y),[S,T]=(0,e.useState)(!1),C=(0,e.useRef)(null),h=(0,e.useRef)(null),v=p>y;(0,e.useEffect)(()=>{let x=!1;return(0,z.codeToHtml)(o,{lang:r,themes:{light:l,dark:a},defaultColor:!1}).then(N=>{x||u(N)}).catch(()=>{x||u(null)}),()=>{x=!0}},[o,r,l,a]),(0,e.useEffect)(()=>{C.current&&m(C.current.scrollHeight)},[g]),(0,e.useEffect)(()=>()=>{h.current&&clearTimeout(h.current)},[]);const k=(0,e.useCallback)(async()=>{if(o.trim())try{await navigator.clipboard.writeText(o),T(!0),h.current&&clearTimeout(h.current),h.current=setTimeout(()=>T(!1),2e3)}catch{}},[o]),P=r==="text"?"plaintext":r,H=(0,e.useCallback)(()=>{f(x=>!x)},[]),F={maxHeight:c?`${p}px`:`${y}px`};return e.default.createElement(t.Box,{position:"relative"},e.default.createElement(t.Card,{size:"1",variant:"soft"},e.default.createElement(t.Flex,{direction:"column",gap:"3"},e.default.createElement(t.Flex,{gap:"2",justify:"between",align:"start"},s&&e.default.createElement(t.Code,{size:"1",color:"gray",highContrast:!0},P),e.default.createElement(t.Flex,{align:"center",gap:"2",className:"code-action-buttons"},v&&e.default.createElement(t.Button,{size:"2",variant:"ghost",color:"gray",onClick:H,tooltip:c?"Collapse":"Expand","aria-label":c?"Collapse code":"Expand code"},e.default.createElement(b.HugeiconsIcon,{icon:d.ArrowDown01Icon,style:{transform:c?"rotate(180deg)":"rotate(0deg)"},className:"code-chevron"})),i&&e.default.createElement(t.Button,{size:"2",variant:"ghost",color:"gray",onClick:k,tooltip:S?"Copied!":"Copy","aria-label":S?"Copied!":"Copy code"},e.default.createElement(b.HugeiconsIcon,{icon:S?d.Tick01Icon:d.Copy01Icon})," Copy"))),e.default.createElement(t.Box,{ref:C,style:F,className:"code-content"},e.default.createElement(t.ScrollArea,{type:"auto",scrollbars:"horizontal"},g?e.default.createElement(t.Box,{dangerouslySetInnerHTML:{__html:g}}):e.default.createElement("pre",null,e.default.createElement(t.Code,{size:"3"},o)))),v&&!c&&e.default.createElement(t.Box,{className:"code-scroll-shadow visible"}))))});function X(n){const o=r=>{if(typeof r=="string")return r;if(typeof r=="number")return String(r);if(!r)return"";if(Array.isArray(r))return r.map(o).join("");if(typeof r=="object"&&"props"in r){const i=r.props;if(i?.children)return o(i.children)}return""};return o(n)}function E(n){const o=r=>{if(!r)return null;if(typeof r=="object"&&"props"in r){const i=r.props;if(i?.["data-language"])return i["data-language"];const s=i?.className||i?.class||"";if(typeof s=="string"){const l=s.match(/language-([\w-]+)/i);if(l)return l[1]}if(i?.children)if(Array.isArray(i.children))for(const l of i.children){const a=o(l);if(a)return a}else return o(i.children)}return null};return o(n)||"text"}function K(n){return{tsx:"TSX",ts:"TS",jsx:"JSX",js:"JS",javascript:"JS",typescript:"TS",css:"CSS",html:"HTML",json:"JSON",bash:"SH",sh:"SH",shell:"SH",text:"plaintext"}[n.toLowerCase()]||n.toLowerCase()}const q=(0,e.memo)(function({children:o,showCopy:r=!0,showLanguage:i=!0}){const[s,l]=(0,e.useState)(!1),[a,g]=(0,e.useState)(y),[u,c]=(0,e.useState)(!1),f=(0,e.useRef)(null),p=(0,e.useRef)(null),m=X(o),S=E(o),T=K(S),C=a>y;(0,e.useEffect)(()=>{f.current&&g(f.current.scrollHeight)},[o]),(0,e.useEffect)(()=>()=>{p.current&&clearTimeout(p.current)},[]);const h=(0,e.useCallback)(async()=>{if(m.trim())try{await navigator.clipboard.writeText(m),c(!0),p.current&&clearTimeout(p.current),p.current=setTimeout(()=>c(!1),2e3)}catch{}},[m]),v={maxHeight:s?`${a}px`:`${y}px`},k=(0,e.useCallback)(()=>{l(H=>!H)},[]);return e.default.createElement(t.Box,{position:"relative"},e.default.createElement(t.Card,{size:"1",variant:"soft"},e.default.createElement(t.Flex,{direction:"column",gap:"3"},e.default.createElement(t.Flex,{gap:"2",justify:"between",align:"start"},i&&e.default.createElement(t.Code,{size:"1",color:"gray",highContrast:!0},T),e.default.createElement(t.Flex,{align:"center",gap:"2",className:"code-action-buttons"},C&&e.default.createElement(t.Button,{size:"2",variant:"ghost",color:"gray",onClick:k,tooltip:s?"Collapse":"Expand","aria-label":s?"Collapse code":"Expand code"},e.default.createElement(b.HugeiconsIcon,{icon:d.ArrowDown01Icon,style:{transform:s?"rotate(180deg)":"rotate(0deg)"},className:"code-chevron"})),r&&e.default.createElement(t.Button,{size:"2",variant:"ghost",color:"gray",onClick:h,tooltip:u?"Copied!":"Copy","aria-label":u?"Copied!":"Copy code"},e.default.createElement(b.HugeiconsIcon,{icon:u?d.Tick01Icon:d.Copy01Icon})," Copy"))),e.default.createElement(t.Box,{ref:f,style:v,className:"code-content"},e.default.createElement(t.ScrollArea,{type:"auto",scrollbars:"horizontal"},o)),C&&!s&&e.default.createElement(t.Box,{className:"code-scroll-shadow visible"}))))});function Q({children:n,code:o,language:r,preview:i,showCopy:s=!0,showLanguage:l=!0,lightTheme:a,darkTheme:g,background:u,backgroundProps:c}){const f=o||n&&e.default.Children.count(n)>0,p=r||E(n)||"text";return e.default.createElement(t.Box,{className:"docs-code-block",mt:"6",mb:"8"},e.default.createElement(t.Flex,{direction:"column",gap:"2"},i&&e.default.createElement(O,{background:u,backgroundProps:c},i),o&&e.default.createElement(U,{code:o,language:p,showCopy:s,showLanguage:l,lightTheme:a,darkTheme:g}),n&&!o&&e.default.createElement(q,{showCopy:s,showLanguage:l},n)))}
|
|
2
2
|
//# sourceMappingURL=CodeBlock.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/components/code/CodeBlock.tsx"],
|
|
4
|
-
"sourcesContent": ["import React, { useState, useRef, useEffect, useCallback, memo, type ReactNode } from \"react\";\nimport { Box, Card, Flex, Button, Code, Theme } from \"@kushagradhawan/kookie-ui\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { Copy01Icon, Tick01Icon, ArrowDown01Icon } from \"@hugeicons/core-free-icons\";\nimport { codeToHtml } from \"shiki\";\nimport type { CodeBlockProps } from \"./types\";\n\nconst COLLAPSED_HEIGHT = 360;\nconst DEFAULT_LIGHT_THEME = \"one-light\";\nconst DEFAULT_DARK_THEME = \"one-dark-pro\";\n\n// ============================================\n// Preview Section\n// ============================================\n\ninterface PreviewSectionProps {\n children: ReactNode;\n background?: \"none\" | \"dots\" | string;\n backgroundProps?: {\n dotSize?: number;\n color?: string;\n backgroundColor?: string;\n height?: string;\n width?: string;\n radius?: string;\n };\n}\n\nfunction PreviewSection({ children, background = \"none\", backgroundProps = {} }: PreviewSectionProps) {\n const { dotSize = 24, color = \"var(--gray-10)\", backgroundColor = \"var(--gray-2)\", height, width = \"100%\", radius = \"3\" } = backgroundProps;\n\n if (background === \"none\") {\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\">\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n }\n\n if (background === \"dots\") {\n const dotsStyle: React.CSSProperties = {\n backgroundImage: `radial-gradient(circle, ${color} 1px, transparent 1px)`,\n borderRadius: `var(--radius-${radius})`,\n backgroundSize: `${dotSize}px ${dotSize}px`,\n backgroundPosition: \"center\",\n backgroundColor,\n width,\n ...(height && { height }),\n };\n\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\" style={dotsStyle}>\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n }\n\n const imageStyle: React.CSSProperties = {\n backgroundImage: `url(${background})`,\n backgroundSize: \"cover\",\n backgroundPosition: \"center\",\n backgroundRepeat: \"no-repeat\",\n borderRadius: `var(--radius-${radius})`,\n width,\n ...(height && { height }),\n };\n\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\" style={imageStyle}>\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n}\n\n// ============================================\n// Code Section (for runtime highlighting)\n// ============================================\n\ninterface CodeSectionProps {\n code: string;\n language: string;\n showCopy?: boolean;\n showLanguage?: boolean;\n lightTheme?: string;\n darkTheme?: string;\n}\n\nconst CodeSection = memo(function CodeSection({\n code,\n language,\n showCopy = true,\n showLanguage = true,\n lightTheme = DEFAULT_LIGHT_THEME,\n darkTheme = DEFAULT_DARK_THEME,\n}: CodeSectionProps) {\n const [highlighted, setHighlighted] = useState<string | null>(null);\n const [isExpanded, setIsExpanded] = useState(false);\n const [contentHeight, setContentHeight] = useState(COLLAPSED_HEIGHT);\n const [copied, setCopied] = useState(false);\n const contentRef = useRef<HTMLDivElement>(null);\n const resetTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const shouldShowToggle = contentHeight > COLLAPSED_HEIGHT;\n\n useEffect(() => {\n let cancelled = false;\n codeToHtml(code, {\n lang: language,\n themes: { light: lightTheme, dark: darkTheme },\n defaultColor: false,\n })\n .then((html) => {\n if (!cancelled) setHighlighted(html);\n })\n .catch(() => {\n if (!cancelled) setHighlighted(null);\n });\n return () => {\n cancelled = true;\n };\n }, [code, language, lightTheme, darkTheme]);\n\n useEffect(() => {\n if (contentRef.current) {\n setContentHeight(contentRef.current.scrollHeight);\n }\n }, [highlighted]);\n\n useEffect(() => {\n return () => {\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n };\n }, []);\n\n const handleCopy = useCallback(async () => {\n if (!code.trim()) return;\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n resetTimeoutRef.current = setTimeout(() => setCopied(false), 2000);\n } catch {\n // Silently fail\n }\n }, [code]);\n\n const displayLanguage = language === \"text\" ? \"plaintext\" : language;\n\n const handleToggle = useCallback(() => {\n setIsExpanded((prev) => !prev);\n }, []);\n\n const contentStyle: React.CSSProperties = {\n maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,\n };\n\n const chevronStyle: React.CSSProperties = {\n transform: isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\",\n };\n\n return (\n <Box position=\"relative\">\n <Card size=\"1\" variant=\"soft\">\n <Flex direction=\"column\" gap=\"3\">\n <Flex gap=\"2\" justify=\"between\" align=\"start\">\n {showLanguage && (\n <Code size=\"1\" color=\"gray\" highContrast>\n {displayLanguage}\n </Code>\n )}\n <Flex align=\"center\" gap=\"2\" className=\"code-action-buttons\">\n {shouldShowToggle && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleToggle}\n tooltip={isExpanded ? \"Collapse\" : \"Expand\"}\n aria-label={isExpanded ? \"Collapse code\" : \"Expand code\"}\n >\n <HugeiconsIcon icon={ArrowDown01Icon} style={chevronStyle} className=\"code-chevron\" />\n </Button>\n )}\n {showCopy && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleCopy}\n tooltip={copied ? \"Copied!\" : \"Copy\"}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n <HugeiconsIcon icon={copied ? Tick01Icon : Copy01Icon} /> Copy\n </Button>\n )}\n </Flex>\n </Flex>\n\n <Box ref={contentRef} style={contentStyle} className=\"code-content\">\n {highlighted ? (\n <Box className=\"code-block-content\" width=\"100%\" style={{ minWidth: 0 }} dangerouslySetInnerHTML={{ __html: highlighted }} />\n ) : (\n <pre className=\"code-block-content\">\n <Code size=\"3\">{code}</Code>\n </pre>\n )}\n </Box>\n\n {shouldShowToggle && !isExpanded && <Box className=\"code-scroll-shadow visible\" />}\n </Flex>\n </Card>\n </Box>\n );\n});\n\n// ============================================\n// Children Code Section (for pre-highlighted MDX)\n// ============================================\n\ninterface ChildrenCodeSectionProps {\n children: ReactNode;\n showCopy?: boolean;\n showLanguage?: boolean;\n}\n\nfunction extractCodeFromChildren(children?: ReactNode): string {\n const extractText = (node: any): string => {\n if (typeof node === \"string\") return node;\n if (typeof node === \"number\") return String(node);\n if (!node) return \"\";\n if (Array.isArray(node)) return node.map(extractText).join(\"\");\n if (typeof node === \"object\" && \"props\" in node) {\n const props = node.props;\n if (props?.children) return extractText(props.children);\n }\n return \"\";\n };\n return extractText(children);\n}\n\nfunction extractLanguageFromChildren(children?: ReactNode): string {\n const findLanguage = (node: any): string | null => {\n if (!node) return null;\n if (typeof node === \"object\" && \"props\" in node) {\n const props = node.props;\n const className = props?.className || props?.class || \"\";\n if (typeof className === \"string\") {\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n if (props?.children) {\n if (Array.isArray(props.children)) {\n for (const child of props.children) {\n const lang = findLanguage(child);\n if (lang) return lang;\n }\n } else {\n return findLanguage(props.children);\n }\n }\n }\n return null;\n };\n return findLanguage(children) || \"text\";\n}\n\nfunction formatLanguageLabel(lang: string): string {\n const aliasMap: Record<string, string> = {\n tsx: \"TSX\",\n ts: \"TS\",\n jsx: \"JSX\",\n js: \"JS\",\n javascript: \"JS\",\n typescript: \"TS\",\n css: \"CSS\",\n html: \"HTML\",\n json: \"JSON\",\n bash: \"SH\",\n sh: \"SH\",\n shell: \"SH\",\n text: \"plaintext\",\n };\n return aliasMap[lang.toLowerCase()] || lang.toLowerCase();\n}\n\nconst ChildrenCodeSection = memo(function ChildrenCodeSection({ children, showCopy = true, showLanguage = true }: ChildrenCodeSectionProps) {\n const [isExpanded, setIsExpanded] = useState(false);\n const [contentHeight, setContentHeight] = useState(COLLAPSED_HEIGHT);\n const [copied, setCopied] = useState(false);\n const contentRef = useRef<HTMLDivElement>(null);\n const resetTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const code = extractCodeFromChildren(children);\n const language = extractLanguageFromChildren(children);\n const displayLanguage = formatLanguageLabel(language);\n\n const shouldShowToggle = contentHeight > COLLAPSED_HEIGHT;\n\n useEffect(() => {\n if (contentRef.current) {\n setContentHeight(contentRef.current.scrollHeight);\n }\n }, [children]);\n\n useEffect(() => {\n return () => {\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n };\n }, []);\n\n const handleCopy = useCallback(async () => {\n if (!code.trim()) return;\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n resetTimeoutRef.current = setTimeout(() => setCopied(false), 2000);\n } catch {\n // Silently fail\n }\n }, [code]);\n\n const contentStyle: React.CSSProperties = {\n maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,\n };\n\n const handleToggle = useCallback(() => {\n setIsExpanded((prev) => !prev);\n }, []);\n\n const chevronStyle: React.CSSProperties = {\n transform: isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\",\n };\n\n return (\n <Box position=\"relative\">\n <Card size=\"1\" variant=\"soft\">\n <Flex direction=\"column\" gap=\"3\">\n <Flex gap=\"2\" justify=\"between\" align=\"start\">\n {showLanguage && (\n <Code size=\"1\" color=\"gray\" highContrast>\n {displayLanguage}\n </Code>\n )}\n <Flex align=\"center\" gap=\"2\" className=\"code-action-buttons\">\n {shouldShowToggle && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleToggle}\n tooltip={isExpanded ? \"Collapse\" : \"Expand\"}\n aria-label={isExpanded ? \"Collapse code\" : \"Expand code\"}\n >\n <HugeiconsIcon icon={ArrowDown01Icon} style={chevronStyle} className=\"code-chevron\" />\n </Button>\n )}\n {showCopy && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleCopy}\n tooltip={copied ? \"Copied!\" : \"Copy\"}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n <HugeiconsIcon icon={copied ? Tick01Icon : Copy01Icon} /> Copy\n </Button>\n )}\n </Flex>\n </Flex>\n\n <Box ref={contentRef} style={contentStyle} className=\"code-content\">\n <div className=\"code-block-content\">{children}</div>\n </Box>\n\n {shouldShowToggle && !isExpanded && <Box className=\"code-scroll-shadow visible\" />}\n </Flex>\n </Card>\n </Box>\n );\n});\n\n// ============================================\n// Main CodeBlock Component\n// ============================================\n\nexport function CodeBlock({\n children,\n code,\n language,\n preview,\n showCopy = true,\n showLanguage = true,\n lightTheme,\n darkTheme,\n background,\n backgroundProps,\n}: CodeBlockProps) {\n const hasCode = code || (children && React.Children.count(children) > 0);\n const displayLanguage = language || extractLanguageFromChildren(children) || \"text\";\n\n return (\n <Box className=\"docs-code-block\" mt=\"6\" mb=\"8\">\n <Flex direction=\"column\" gap=\"2\">\n {preview && (\n <PreviewSection background={background} backgroundProps={backgroundProps}>\n {preview}\n </PreviewSection>\n )}\n\n {code && (\n <CodeSection code={code} language={displayLanguage} showCopy={showCopy} showLanguage={showLanguage} lightTheme={lightTheme} darkTheme={darkTheme} />\n )}\n\n {children && !code && (\n <ChildrenCodeSection showCopy={showCopy} showLanguage={showLanguage}>\n {children}\n </ChildrenCodeSection>\n )}\n </Flex>\n </Box>\n );\n}\n"],
|
|
5
|
-
"mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAsF,oBACtFC,
|
|
4
|
+
"sourcesContent": ["import React, { useState, useRef, useEffect, useCallback, memo, type ReactNode } from \"react\";\nimport { Box, Card, Flex, Button, Code, Theme, ScrollArea } from \"@kushagradhawan/kookie-ui\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { Copy01Icon, Tick01Icon, ArrowDown01Icon } from \"@hugeicons/core-free-icons\";\nimport { codeToHtml } from \"shiki\";\nimport type { CodeBlockProps } from \"./types\";\n\nconst COLLAPSED_HEIGHT = 360;\nconst DEFAULT_LIGHT_THEME = \"one-light\";\nconst DEFAULT_DARK_THEME = \"one-dark-pro\";\n\n// ============================================\n// Preview Section\n// ============================================\n\ninterface PreviewSectionProps {\n children: ReactNode;\n background?: \"none\" | \"dots\" | string;\n backgroundProps?: {\n dotSize?: number;\n color?: string;\n backgroundColor?: string;\n height?: string;\n width?: string;\n radius?: string;\n };\n}\n\nfunction PreviewSection({ children, background = \"none\", backgroundProps = {} }: PreviewSectionProps) {\n const { dotSize = 24, color = \"var(--gray-10)\", backgroundColor = \"var(--gray-2)\", height, width = \"100%\", radius = \"3\" } = backgroundProps;\n\n if (background === \"none\") {\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\">\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n }\n\n if (background === \"dots\") {\n const dotsStyle: React.CSSProperties = {\n backgroundImage: `radial-gradient(circle, ${color} 1px, transparent 1px)`,\n borderRadius: `var(--radius-${radius})`,\n backgroundSize: `${dotSize}px ${dotSize}px`,\n backgroundPosition: \"center\",\n backgroundColor,\n width,\n ...(height && { height }),\n };\n\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\" style={dotsStyle}>\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n }\n\n const imageStyle: React.CSSProperties = {\n backgroundImage: `url(${background})`,\n backgroundSize: \"cover\",\n backgroundPosition: \"center\",\n backgroundRepeat: \"no-repeat\",\n borderRadius: `var(--radius-${radius})`,\n width,\n ...(height && { height }),\n };\n\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\" style={imageStyle}>\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n}\n\n// ============================================\n// Code Section (for runtime highlighting)\n// ============================================\n\ninterface CodeSectionProps {\n code: string;\n language: string;\n showCopy?: boolean;\n showLanguage?: boolean;\n lightTheme?: string;\n darkTheme?: string;\n}\n\nconst CodeSection = memo(function CodeSection({\n code,\n language,\n showCopy = true,\n showLanguage = true,\n lightTheme = DEFAULT_LIGHT_THEME,\n darkTheme = DEFAULT_DARK_THEME,\n}: CodeSectionProps) {\n const [highlighted, setHighlighted] = useState<string | null>(null);\n const [isExpanded, setIsExpanded] = useState(false);\n const [contentHeight, setContentHeight] = useState(COLLAPSED_HEIGHT);\n const [copied, setCopied] = useState(false);\n const contentRef = useRef<HTMLDivElement>(null);\n const resetTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const shouldShowToggle = contentHeight > COLLAPSED_HEIGHT;\n\n useEffect(() => {\n let cancelled = false;\n codeToHtml(code, {\n lang: language,\n themes: { light: lightTheme, dark: darkTheme },\n defaultColor: false,\n })\n .then((html) => {\n if (!cancelled) setHighlighted(html);\n })\n .catch(() => {\n if (!cancelled) setHighlighted(null);\n });\n return () => {\n cancelled = true;\n };\n }, [code, language, lightTheme, darkTheme]);\n\n useEffect(() => {\n if (contentRef.current) {\n setContentHeight(contentRef.current.scrollHeight);\n }\n }, [highlighted]);\n\n useEffect(() => {\n return () => {\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n };\n }, []);\n\n const handleCopy = useCallback(async () => {\n if (!code.trim()) return;\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n resetTimeoutRef.current = setTimeout(() => setCopied(false), 2000);\n } catch {\n // Silently fail\n }\n }, [code]);\n\n const displayLanguage = language === \"text\" ? \"plaintext\" : language;\n\n const handleToggle = useCallback(() => {\n setIsExpanded((prev) => !prev);\n }, []);\n\n const contentStyle: React.CSSProperties = {\n maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,\n };\n\n const chevronStyle: React.CSSProperties = {\n transform: isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\",\n };\n\n return (\n <Box position=\"relative\">\n <Card size=\"1\" variant=\"soft\">\n <Flex direction=\"column\" gap=\"3\">\n <Flex gap=\"2\" justify=\"between\" align=\"start\">\n {showLanguage && (\n <Code size=\"1\" color=\"gray\" highContrast>\n {displayLanguage}\n </Code>\n )}\n <Flex align=\"center\" gap=\"2\" className=\"code-action-buttons\">\n {shouldShowToggle && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleToggle}\n tooltip={isExpanded ? \"Collapse\" : \"Expand\"}\n aria-label={isExpanded ? \"Collapse code\" : \"Expand code\"}\n >\n <HugeiconsIcon icon={ArrowDown01Icon} style={chevronStyle} className=\"code-chevron\" />\n </Button>\n )}\n {showCopy && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleCopy}\n tooltip={copied ? \"Copied!\" : \"Copy\"}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n <HugeiconsIcon icon={copied ? Tick01Icon : Copy01Icon} /> Copy\n </Button>\n )}\n </Flex>\n </Flex>\n\n <Box ref={contentRef} style={contentStyle} className=\"code-content\">\n <ScrollArea type=\"auto\" scrollbars=\"horizontal\">\n {highlighted ? (\n <Box dangerouslySetInnerHTML={{ __html: highlighted }} />\n ) : (\n <pre>\n <Code size=\"3\">{code}</Code>\n </pre>\n )}\n </ScrollArea>\n </Box>\n\n {shouldShowToggle && !isExpanded && <Box className=\"code-scroll-shadow visible\" />}\n </Flex>\n </Card>\n </Box>\n );\n});\n\n// ============================================\n// Children Code Section (for pre-highlighted MDX)\n// ============================================\n\ninterface ChildrenCodeSectionProps {\n children: ReactNode;\n showCopy?: boolean;\n showLanguage?: boolean;\n}\n\nfunction extractCodeFromChildren(children?: ReactNode): string {\n const extractText = (node: any): string => {\n if (typeof node === \"string\") return node;\n if (typeof node === \"number\") return String(node);\n if (!node) return \"\";\n if (Array.isArray(node)) return node.map(extractText).join(\"\");\n if (typeof node === \"object\" && \"props\" in node) {\n const props = node.props;\n if (props?.children) return extractText(props.children);\n }\n return \"\";\n };\n return extractText(children);\n}\n\nfunction extractLanguageFromChildren(children?: ReactNode): string {\n const findLanguage = (node: any): string | null => {\n if (!node) return null;\n if (typeof node === \"object\" && \"props\" in node) {\n const props = node.props;\n\n // Check data-language attribute (rehype-pretty-code)\n if (props?.[\"data-language\"]) {\n return props[\"data-language\"];\n }\n\n // Check className for language-xxx\n const className = props?.className || props?.class || \"\";\n if (typeof className === \"string\") {\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n\n // Recursively check children\n if (props?.children) {\n if (Array.isArray(props.children)) {\n for (const child of props.children) {\n const lang = findLanguage(child);\n if (lang) return lang;\n }\n } else {\n return findLanguage(props.children);\n }\n }\n }\n return null;\n };\n return findLanguage(children) || \"text\";\n}\n\nfunction formatLanguageLabel(lang: string): string {\n const aliasMap: Record<string, string> = {\n tsx: \"TSX\",\n ts: \"TS\",\n jsx: \"JSX\",\n js: \"JS\",\n javascript: \"JS\",\n typescript: \"TS\",\n css: \"CSS\",\n html: \"HTML\",\n json: \"JSON\",\n bash: \"SH\",\n sh: \"SH\",\n shell: \"SH\",\n text: \"plaintext\",\n };\n return aliasMap[lang.toLowerCase()] || lang.toLowerCase();\n}\n\nconst ChildrenCodeSection = memo(function ChildrenCodeSection({ children, showCopy = true, showLanguage = true }: ChildrenCodeSectionProps) {\n const [isExpanded, setIsExpanded] = useState(false);\n const [contentHeight, setContentHeight] = useState(COLLAPSED_HEIGHT);\n const [copied, setCopied] = useState(false);\n const contentRef = useRef<HTMLDivElement>(null);\n const resetTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const code = extractCodeFromChildren(children);\n const language = extractLanguageFromChildren(children);\n const displayLanguage = formatLanguageLabel(language);\n\n const shouldShowToggle = contentHeight > COLLAPSED_HEIGHT;\n\n useEffect(() => {\n if (contentRef.current) {\n setContentHeight(contentRef.current.scrollHeight);\n }\n }, [children]);\n\n useEffect(() => {\n return () => {\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n };\n }, []);\n\n const handleCopy = useCallback(async () => {\n if (!code.trim()) return;\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n resetTimeoutRef.current = setTimeout(() => setCopied(false), 2000);\n } catch {\n // Silently fail\n }\n }, [code]);\n\n const contentStyle: React.CSSProperties = {\n maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,\n };\n\n const handleToggle = useCallback(() => {\n setIsExpanded((prev) => !prev);\n }, []);\n\n const chevronStyle: React.CSSProperties = {\n transform: isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\",\n };\n\n return (\n <Box position=\"relative\">\n <Card size=\"1\" variant=\"soft\">\n <Flex direction=\"column\" gap=\"3\">\n <Flex gap=\"2\" justify=\"between\" align=\"start\">\n {showLanguage && (\n <Code size=\"1\" color=\"gray\" highContrast>\n {displayLanguage}\n </Code>\n )}\n <Flex align=\"center\" gap=\"2\" className=\"code-action-buttons\">\n {shouldShowToggle && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleToggle}\n tooltip={isExpanded ? \"Collapse\" : \"Expand\"}\n aria-label={isExpanded ? \"Collapse code\" : \"Expand code\"}\n >\n <HugeiconsIcon icon={ArrowDown01Icon} style={chevronStyle} className=\"code-chevron\" />\n </Button>\n )}\n {showCopy && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleCopy}\n tooltip={copied ? \"Copied!\" : \"Copy\"}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n <HugeiconsIcon icon={copied ? Tick01Icon : Copy01Icon} /> Copy\n </Button>\n )}\n </Flex>\n </Flex>\n\n <Box ref={contentRef} style={contentStyle} className=\"code-content\">\n <ScrollArea type=\"auto\" scrollbars=\"horizontal\">\n {children}\n </ScrollArea>\n </Box>\n\n {shouldShowToggle && !isExpanded && <Box className=\"code-scroll-shadow visible\" />}\n </Flex>\n </Card>\n </Box>\n );\n});\n\n// ============================================\n// Main CodeBlock Component\n// ============================================\n\nexport function CodeBlock({\n children,\n code,\n language,\n preview,\n showCopy = true,\n showLanguage = true,\n lightTheme,\n darkTheme,\n background,\n backgroundProps,\n}: CodeBlockProps) {\n const hasCode = code || (children && React.Children.count(children) > 0);\n const displayLanguage = language || extractLanguageFromChildren(children) || \"text\";\n\n return (\n <Box className=\"docs-code-block\" mt=\"6\" mb=\"8\">\n <Flex direction=\"column\" gap=\"2\">\n {preview && (\n <PreviewSection background={background} backgroundProps={backgroundProps}>\n {preview}\n </PreviewSection>\n )}\n\n {code && (\n <CodeSection code={code} language={displayLanguage} showCopy={showCopy} showLanguage={showLanguage} lightTheme={lightTheme} darkTheme={darkTheme} />\n )}\n\n {children && !code && (\n <ChildrenCodeSection showCopy={showCopy} showLanguage={showLanguage}>\n {children}\n </ChildrenCodeSection>\n )}\n </Flex>\n </Box>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["CodeBlock_exports", "__export", "CodeBlock", "__toCommonJS", "import_react", "import_kookie_ui", "import_core_free_icons", "import_shiki", "COLLAPSED_HEIGHT", "DEFAULT_LIGHT_THEME", "DEFAULT_DARK_THEME", "PreviewSection", "children", "background", "backgroundProps", "dotSize", "color", "backgroundColor", "height", "width", "radius", "React", "dotsStyle", "imageStyle", "CodeSection", "code", "language", "showCopy", "showLanguage", "lightTheme", "darkTheme", "highlighted", "setHighlighted", "isExpanded", "setIsExpanded", "contentHeight", "setContentHeight", "copied", "setCopied", "contentRef", "resetTimeoutRef", "shouldShowToggle", "cancelled", "html", "handleCopy", "displayLanguage", "handleToggle", "prev", "contentStyle", "extractCodeFromChildren", "extractText", "node", "props", "extractLanguageFromChildren", "findLanguage", "className", "match", "child", "lang", "formatLanguageLabel", "ChildrenCodeSection", "preview", "hasCode"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../../../src/components/code/CodeBlock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyE,MAAM,OAAO,CAAC;AAK9F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../../../src/components/code/CodeBlock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyE,MAAM,OAAO,CAAC;AAK9F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAiZ9C,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,QAAe,EACf,YAAmB,EACnB,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,GAChB,EAAE,cAAc,qBAyBhB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e,{useState as
|
|
1
|
+
import e,{useState as C,useRef as H,useEffect as T,useCallback as P,memo as A}from"react";import{Box as f,Card as v,Flex as p,Button as L,Code as N,Theme as B,ScrollArea as I}from"@kushagradhawan/kookie-ui";import{HugeiconsIcon as E}from"@hugeicons/react";import{Copy01Icon as $,Tick01Icon as M,ArrowDown01Icon as D}from"@hugeicons/core-free-icons";import{codeToHtml as O}from"shiki";const m=360,U="one-light",X="one-dark-pro";function K({children:n,background:t="none",backgroundProps:o={}}){const{dotSize:r=24,color:i="var(--gray-10)",backgroundColor:a="var(--gray-2)",height:s,width:u="100%",radius:c="3"}=o;if(t==="none")return e.createElement(v,{size:"1",variant:"soft"},e.createElement(p,{justify:"center",align:"center",py:"4"},e.createElement(B,{fontFamily:"sans"},n)));if(t==="dots"){const d={backgroundImage:`radial-gradient(circle, ${i} 1px, transparent 1px)`,borderRadius:`var(--radius-${c})`,backgroundSize:`${r}px ${r}px`,backgroundPosition:"center",backgroundColor:a,width:u,...s&&{height:s}};return e.createElement(v,{size:"1",variant:"soft"},e.createElement(p,{justify:"center",align:"center",py:"4",style:d},e.createElement(B,{fontFamily:"sans"},n)))}const l={backgroundImage:`url(${t})`,backgroundSize:"cover",backgroundPosition:"center",backgroundRepeat:"no-repeat",borderRadius:`var(--radius-${c})`,width:u,...s&&{height:s}};return e.createElement(v,{size:"1",variant:"soft"},e.createElement(p,{justify:"center",align:"center",py:"4",style:l},e.createElement(B,{fontFamily:"sans"},n)))}const q=A(function({code:t,language:o,showCopy:r=!0,showLanguage:i=!0,lightTheme:a=U,darkTheme:s=X}){const[u,c]=C(null),[l,d]=C(!1),[g,S]=C(m),[x,w]=C(!1),y=H(null),h=H(null),k=g>m;T(()=>{let b=!1;return O(t,{lang:o,themes:{light:a,dark:s},defaultColor:!1}).then(G=>{b||c(G)}).catch(()=>{b||c(null)}),()=>{b=!0}},[t,o,a,s]),T(()=>{y.current&&S(y.current.scrollHeight)},[u]),T(()=>()=>{h.current&&clearTimeout(h.current)},[]);const z=P(async()=>{if(t.trim())try{await navigator.clipboard.writeText(t),w(!0),h.current&&clearTimeout(h.current),h.current=setTimeout(()=>w(!1),2e3)}catch{}},[t]),j=o==="text"?"plaintext":o,F=P(()=>{d(b=>!b)},[]),J={maxHeight:l?`${g}px`:`${m}px`};return e.createElement(f,{position:"relative"},e.createElement(v,{size:"1",variant:"soft"},e.createElement(p,{direction:"column",gap:"3"},e.createElement(p,{gap:"2",justify:"between",align:"start"},i&&e.createElement(N,{size:"1",color:"gray",highContrast:!0},j),e.createElement(p,{align:"center",gap:"2",className:"code-action-buttons"},k&&e.createElement(L,{size:"2",variant:"ghost",color:"gray",onClick:F,tooltip:l?"Collapse":"Expand","aria-label":l?"Collapse code":"Expand code"},e.createElement(E,{icon:D,style:{transform:l?"rotate(180deg)":"rotate(0deg)"},className:"code-chevron"})),r&&e.createElement(L,{size:"2",variant:"ghost",color:"gray",onClick:z,tooltip:x?"Copied!":"Copy","aria-label":x?"Copied!":"Copy code"},e.createElement(E,{icon:x?M:$})," Copy"))),e.createElement(f,{ref:y,style:J,className:"code-content"},e.createElement(I,{type:"auto",scrollbars:"horizontal"},u?e.createElement(f,{dangerouslySetInnerHTML:{__html:u}}):e.createElement("pre",null,e.createElement(N,{size:"3"},t)))),k&&!l&&e.createElement(f,{className:"code-scroll-shadow visible"}))))});function Q(n){const t=o=>{if(typeof o=="string")return o;if(typeof o=="number")return String(o);if(!o)return"";if(Array.isArray(o))return o.map(t).join("");if(typeof o=="object"&&"props"in o){const r=o.props;if(r?.children)return t(r.children)}return""};return t(n)}function _(n){const t=o=>{if(!o)return null;if(typeof o=="object"&&"props"in o){const r=o.props;if(r?.["data-language"])return r["data-language"];const i=r?.className||r?.class||"";if(typeof i=="string"){const a=i.match(/language-([\w-]+)/i);if(a)return a[1]}if(r?.children)if(Array.isArray(r.children))for(const a of r.children){const s=t(a);if(s)return s}else return t(r.children)}return null};return t(n)||"text"}function V(n){return{tsx:"TSX",ts:"TS",jsx:"JSX",js:"JS",javascript:"JS",typescript:"TS",css:"CSS",html:"HTML",json:"JSON",bash:"SH",sh:"SH",shell:"SH",text:"plaintext"}[n.toLowerCase()]||n.toLowerCase()}const W=A(function({children:t,showCopy:o=!0,showLanguage:r=!0}){const[i,a]=C(!1),[s,u]=C(m),[c,l]=C(!1),d=H(null),g=H(null),S=Q(t),x=_(t),w=V(x),y=s>m;T(()=>{d.current&&u(d.current.scrollHeight)},[t]),T(()=>()=>{g.current&&clearTimeout(g.current)},[]);const h=P(async()=>{if(S.trim())try{await navigator.clipboard.writeText(S),l(!0),g.current&&clearTimeout(g.current),g.current=setTimeout(()=>l(!1),2e3)}catch{}},[S]),k={maxHeight:i?`${s}px`:`${m}px`},z=P(()=>{a(F=>!F)},[]);return e.createElement(f,{position:"relative"},e.createElement(v,{size:"1",variant:"soft"},e.createElement(p,{direction:"column",gap:"3"},e.createElement(p,{gap:"2",justify:"between",align:"start"},r&&e.createElement(N,{size:"1",color:"gray",highContrast:!0},w),e.createElement(p,{align:"center",gap:"2",className:"code-action-buttons"},y&&e.createElement(L,{size:"2",variant:"ghost",color:"gray",onClick:z,tooltip:i?"Collapse":"Expand","aria-label":i?"Collapse code":"Expand code"},e.createElement(E,{icon:D,style:{transform:i?"rotate(180deg)":"rotate(0deg)"},className:"code-chevron"})),o&&e.createElement(L,{size:"2",variant:"ghost",color:"gray",onClick:h,tooltip:c?"Copied!":"Copy","aria-label":c?"Copied!":"Copy code"},e.createElement(E,{icon:c?M:$})," Copy"))),e.createElement(f,{ref:d,style:k,className:"code-content"},e.createElement(I,{type:"auto",scrollbars:"horizontal"},t)),y&&!i&&e.createElement(f,{className:"code-scroll-shadow visible"}))))});function re({children:n,code:t,language:o,preview:r,showCopy:i=!0,showLanguage:a=!0,lightTheme:s,darkTheme:u,background:c,backgroundProps:l}){const d=t||n&&e.Children.count(n)>0,g=o||_(n)||"text";return e.createElement(f,{className:"docs-code-block",mt:"6",mb:"8"},e.createElement(p,{direction:"column",gap:"2"},r&&e.createElement(K,{background:c,backgroundProps:l},r),t&&e.createElement(q,{code:t,language:g,showCopy:i,showLanguage:a,lightTheme:s,darkTheme:u}),n&&!t&&e.createElement(W,{showCopy:i,showLanguage:a},n)))}export{re as CodeBlock};
|
|
2
2
|
//# sourceMappingURL=CodeBlock.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/components/code/CodeBlock.tsx"],
|
|
4
|
-
"sourcesContent": ["import React, { useState, useRef, useEffect, useCallback, memo, type ReactNode } from \"react\";\nimport { Box, Card, Flex, Button, Code, Theme } from \"@kushagradhawan/kookie-ui\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { Copy01Icon, Tick01Icon, ArrowDown01Icon } from \"@hugeicons/core-free-icons\";\nimport { codeToHtml } from \"shiki\";\nimport type { CodeBlockProps } from \"./types\";\n\nconst COLLAPSED_HEIGHT = 360;\nconst DEFAULT_LIGHT_THEME = \"one-light\";\nconst DEFAULT_DARK_THEME = \"one-dark-pro\";\n\n// ============================================\n// Preview Section\n// ============================================\n\ninterface PreviewSectionProps {\n children: ReactNode;\n background?: \"none\" | \"dots\" | string;\n backgroundProps?: {\n dotSize?: number;\n color?: string;\n backgroundColor?: string;\n height?: string;\n width?: string;\n radius?: string;\n };\n}\n\nfunction PreviewSection({ children, background = \"none\", backgroundProps = {} }: PreviewSectionProps) {\n const { dotSize = 24, color = \"var(--gray-10)\", backgroundColor = \"var(--gray-2)\", height, width = \"100%\", radius = \"3\" } = backgroundProps;\n\n if (background === \"none\") {\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\">\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n }\n\n if (background === \"dots\") {\n const dotsStyle: React.CSSProperties = {\n backgroundImage: `radial-gradient(circle, ${color} 1px, transparent 1px)`,\n borderRadius: `var(--radius-${radius})`,\n backgroundSize: `${dotSize}px ${dotSize}px`,\n backgroundPosition: \"center\",\n backgroundColor,\n width,\n ...(height && { height }),\n };\n\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\" style={dotsStyle}>\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n }\n\n const imageStyle: React.CSSProperties = {\n backgroundImage: `url(${background})`,\n backgroundSize: \"cover\",\n backgroundPosition: \"center\",\n backgroundRepeat: \"no-repeat\",\n borderRadius: `var(--radius-${radius})`,\n width,\n ...(height && { height }),\n };\n\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\" style={imageStyle}>\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n}\n\n// ============================================\n// Code Section (for runtime highlighting)\n// ============================================\n\ninterface CodeSectionProps {\n code: string;\n language: string;\n showCopy?: boolean;\n showLanguage?: boolean;\n lightTheme?: string;\n darkTheme?: string;\n}\n\nconst CodeSection = memo(function CodeSection({\n code,\n language,\n showCopy = true,\n showLanguage = true,\n lightTheme = DEFAULT_LIGHT_THEME,\n darkTheme = DEFAULT_DARK_THEME,\n}: CodeSectionProps) {\n const [highlighted, setHighlighted] = useState<string | null>(null);\n const [isExpanded, setIsExpanded] = useState(false);\n const [contentHeight, setContentHeight] = useState(COLLAPSED_HEIGHT);\n const [copied, setCopied] = useState(false);\n const contentRef = useRef<HTMLDivElement>(null);\n const resetTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const shouldShowToggle = contentHeight > COLLAPSED_HEIGHT;\n\n useEffect(() => {\n let cancelled = false;\n codeToHtml(code, {\n lang: language,\n themes: { light: lightTheme, dark: darkTheme },\n defaultColor: false,\n })\n .then((html) => {\n if (!cancelled) setHighlighted(html);\n })\n .catch(() => {\n if (!cancelled) setHighlighted(null);\n });\n return () => {\n cancelled = true;\n };\n }, [code, language, lightTheme, darkTheme]);\n\n useEffect(() => {\n if (contentRef.current) {\n setContentHeight(contentRef.current.scrollHeight);\n }\n }, [highlighted]);\n\n useEffect(() => {\n return () => {\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n };\n }, []);\n\n const handleCopy = useCallback(async () => {\n if (!code.trim()) return;\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n resetTimeoutRef.current = setTimeout(() => setCopied(false), 2000);\n } catch {\n // Silently fail\n }\n }, [code]);\n\n const displayLanguage = language === \"text\" ? \"plaintext\" : language;\n\n const handleToggle = useCallback(() => {\n setIsExpanded((prev) => !prev);\n }, []);\n\n const contentStyle: React.CSSProperties = {\n maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,\n };\n\n const chevronStyle: React.CSSProperties = {\n transform: isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\",\n };\n\n return (\n <Box position=\"relative\">\n <Card size=\"1\" variant=\"soft\">\n <Flex direction=\"column\" gap=\"3\">\n <Flex gap=\"2\" justify=\"between\" align=\"start\">\n {showLanguage && (\n <Code size=\"1\" color=\"gray\" highContrast>\n {displayLanguage}\n </Code>\n )}\n <Flex align=\"center\" gap=\"2\" className=\"code-action-buttons\">\n {shouldShowToggle && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleToggle}\n tooltip={isExpanded ? \"Collapse\" : \"Expand\"}\n aria-label={isExpanded ? \"Collapse code\" : \"Expand code\"}\n >\n <HugeiconsIcon icon={ArrowDown01Icon} style={chevronStyle} className=\"code-chevron\" />\n </Button>\n )}\n {showCopy && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleCopy}\n tooltip={copied ? \"Copied!\" : \"Copy\"}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n <HugeiconsIcon icon={copied ? Tick01Icon : Copy01Icon} /> Copy\n </Button>\n )}\n </Flex>\n </Flex>\n\n <Box ref={contentRef} style={contentStyle} className=\"code-content\">\n {highlighted ? (\n <Box className=\"code-block-content\" width=\"100%\" style={{ minWidth: 0 }} dangerouslySetInnerHTML={{ __html: highlighted }} />\n ) : (\n <pre className=\"code-block-content\">\n <Code size=\"3\">{code}</Code>\n </pre>\n )}\n </Box>\n\n {shouldShowToggle && !isExpanded && <Box className=\"code-scroll-shadow visible\" />}\n </Flex>\n </Card>\n </Box>\n );\n});\n\n// ============================================\n// Children Code Section (for pre-highlighted MDX)\n// ============================================\n\ninterface ChildrenCodeSectionProps {\n children: ReactNode;\n showCopy?: boolean;\n showLanguage?: boolean;\n}\n\nfunction extractCodeFromChildren(children?: ReactNode): string {\n const extractText = (node: any): string => {\n if (typeof node === \"string\") return node;\n if (typeof node === \"number\") return String(node);\n if (!node) return \"\";\n if (Array.isArray(node)) return node.map(extractText).join(\"\");\n if (typeof node === \"object\" && \"props\" in node) {\n const props = node.props;\n if (props?.children) return extractText(props.children);\n }\n return \"\";\n };\n return extractText(children);\n}\n\nfunction extractLanguageFromChildren(children?: ReactNode): string {\n const findLanguage = (node: any): string | null => {\n if (!node) return null;\n if (typeof node === \"object\" && \"props\" in node) {\n const props = node.props;\n const className = props?.className || props?.class || \"\";\n if (typeof className === \"string\") {\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n if (props?.children) {\n if (Array.isArray(props.children)) {\n for (const child of props.children) {\n const lang = findLanguage(child);\n if (lang) return lang;\n }\n } else {\n return findLanguage(props.children);\n }\n }\n }\n return null;\n };\n return findLanguage(children) || \"text\";\n}\n\nfunction formatLanguageLabel(lang: string): string {\n const aliasMap: Record<string, string> = {\n tsx: \"TSX\",\n ts: \"TS\",\n jsx: \"JSX\",\n js: \"JS\",\n javascript: \"JS\",\n typescript: \"TS\",\n css: \"CSS\",\n html: \"HTML\",\n json: \"JSON\",\n bash: \"SH\",\n sh: \"SH\",\n shell: \"SH\",\n text: \"plaintext\",\n };\n return aliasMap[lang.toLowerCase()] || lang.toLowerCase();\n}\n\nconst ChildrenCodeSection = memo(function ChildrenCodeSection({ children, showCopy = true, showLanguage = true }: ChildrenCodeSectionProps) {\n const [isExpanded, setIsExpanded] = useState(false);\n const [contentHeight, setContentHeight] = useState(COLLAPSED_HEIGHT);\n const [copied, setCopied] = useState(false);\n const contentRef = useRef<HTMLDivElement>(null);\n const resetTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const code = extractCodeFromChildren(children);\n const language = extractLanguageFromChildren(children);\n const displayLanguage = formatLanguageLabel(language);\n\n const shouldShowToggle = contentHeight > COLLAPSED_HEIGHT;\n\n useEffect(() => {\n if (contentRef.current) {\n setContentHeight(contentRef.current.scrollHeight);\n }\n }, [children]);\n\n useEffect(() => {\n return () => {\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n };\n }, []);\n\n const handleCopy = useCallback(async () => {\n if (!code.trim()) return;\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n resetTimeoutRef.current = setTimeout(() => setCopied(false), 2000);\n } catch {\n // Silently fail\n }\n }, [code]);\n\n const contentStyle: React.CSSProperties = {\n maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,\n };\n\n const handleToggle = useCallback(() => {\n setIsExpanded((prev) => !prev);\n }, []);\n\n const chevronStyle: React.CSSProperties = {\n transform: isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\",\n };\n\n return (\n <Box position=\"relative\">\n <Card size=\"1\" variant=\"soft\">\n <Flex direction=\"column\" gap=\"3\">\n <Flex gap=\"2\" justify=\"between\" align=\"start\">\n {showLanguage && (\n <Code size=\"1\" color=\"gray\" highContrast>\n {displayLanguage}\n </Code>\n )}\n <Flex align=\"center\" gap=\"2\" className=\"code-action-buttons\">\n {shouldShowToggle && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleToggle}\n tooltip={isExpanded ? \"Collapse\" : \"Expand\"}\n aria-label={isExpanded ? \"Collapse code\" : \"Expand code\"}\n >\n <HugeiconsIcon icon={ArrowDown01Icon} style={chevronStyle} className=\"code-chevron\" />\n </Button>\n )}\n {showCopy && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleCopy}\n tooltip={copied ? \"Copied!\" : \"Copy\"}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n <HugeiconsIcon icon={copied ? Tick01Icon : Copy01Icon} /> Copy\n </Button>\n )}\n </Flex>\n </Flex>\n\n <Box ref={contentRef} style={contentStyle} className=\"code-content\">\n <div className=\"code-block-content\">{children}</div>\n </Box>\n\n {shouldShowToggle && !isExpanded && <Box className=\"code-scroll-shadow visible\" />}\n </Flex>\n </Card>\n </Box>\n );\n});\n\n// ============================================\n// Main CodeBlock Component\n// ============================================\n\nexport function CodeBlock({\n children,\n code,\n language,\n preview,\n showCopy = true,\n showLanguage = true,\n lightTheme,\n darkTheme,\n background,\n backgroundProps,\n}: CodeBlockProps) {\n const hasCode = code || (children && React.Children.count(children) > 0);\n const displayLanguage = language || extractLanguageFromChildren(children) || \"text\";\n\n return (\n <Box className=\"docs-code-block\" mt=\"6\" mb=\"8\">\n <Flex direction=\"column\" gap=\"2\">\n {preview && (\n <PreviewSection background={background} backgroundProps={backgroundProps}>\n {preview}\n </PreviewSection>\n )}\n\n {code && (\n <CodeSection code={code} language={displayLanguage} showCopy={showCopy} showLanguage={showLanguage} lightTheme={lightTheme} darkTheme={darkTheme} />\n )}\n\n {children && !code && (\n <ChildrenCodeSection showCopy={showCopy} showLanguage={showLanguage}>\n {children}\n </ChildrenCodeSection>\n )}\n </Flex>\n </Box>\n );\n}\n"],
|
|
5
|
-
"mappings": "AAAA,OAAOA,GAAS,YAAAC,EAAU,UAAAC,EAAQ,aAAAC,EAAW,eAAAC,EAAa,QAAAC,MAA4B,QACtF,OAAS,OAAAC,EAAK,QAAAC,EAAM,QAAAC,EAAM,UAAAC,EAAQ,QAAAC,EAAM,SAAAC,
|
|
6
|
-
"names": ["React", "useState", "useRef", "useEffect", "useCallback", "memo", "Box", "Card", "Flex", "Button", "Code", "Theme", "HugeiconsIcon", "Copy01Icon", "Tick01Icon", "ArrowDown01Icon", "codeToHtml", "COLLAPSED_HEIGHT", "DEFAULT_LIGHT_THEME", "DEFAULT_DARK_THEME", "PreviewSection", "children", "background", "backgroundProps", "dotSize", "color", "backgroundColor", "height", "width", "radius", "dotsStyle", "imageStyle", "CodeSection", "code", "language", "showCopy", "showLanguage", "lightTheme", "darkTheme", "highlighted", "setHighlighted", "isExpanded", "setIsExpanded", "contentHeight", "setContentHeight", "copied", "setCopied", "contentRef", "resetTimeoutRef", "shouldShowToggle", "cancelled", "html", "handleCopy", "displayLanguage", "handleToggle", "prev", "contentStyle", "extractCodeFromChildren", "extractText", "node", "props", "extractLanguageFromChildren", "findLanguage", "className", "match", "child", "lang", "formatLanguageLabel", "ChildrenCodeSection", "CodeBlock", "preview", "hasCode"]
|
|
4
|
+
"sourcesContent": ["import React, { useState, useRef, useEffect, useCallback, memo, type ReactNode } from \"react\";\nimport { Box, Card, Flex, Button, Code, Theme, ScrollArea } from \"@kushagradhawan/kookie-ui\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport { Copy01Icon, Tick01Icon, ArrowDown01Icon } from \"@hugeicons/core-free-icons\";\nimport { codeToHtml } from \"shiki\";\nimport type { CodeBlockProps } from \"./types\";\n\nconst COLLAPSED_HEIGHT = 360;\nconst DEFAULT_LIGHT_THEME = \"one-light\";\nconst DEFAULT_DARK_THEME = \"one-dark-pro\";\n\n// ============================================\n// Preview Section\n// ============================================\n\ninterface PreviewSectionProps {\n children: ReactNode;\n background?: \"none\" | \"dots\" | string;\n backgroundProps?: {\n dotSize?: number;\n color?: string;\n backgroundColor?: string;\n height?: string;\n width?: string;\n radius?: string;\n };\n}\n\nfunction PreviewSection({ children, background = \"none\", backgroundProps = {} }: PreviewSectionProps) {\n const { dotSize = 24, color = \"var(--gray-10)\", backgroundColor = \"var(--gray-2)\", height, width = \"100%\", radius = \"3\" } = backgroundProps;\n\n if (background === \"none\") {\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\">\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n }\n\n if (background === \"dots\") {\n const dotsStyle: React.CSSProperties = {\n backgroundImage: `radial-gradient(circle, ${color} 1px, transparent 1px)`,\n borderRadius: `var(--radius-${radius})`,\n backgroundSize: `${dotSize}px ${dotSize}px`,\n backgroundPosition: \"center\",\n backgroundColor,\n width,\n ...(height && { height }),\n };\n\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\" style={dotsStyle}>\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n }\n\n const imageStyle: React.CSSProperties = {\n backgroundImage: `url(${background})`,\n backgroundSize: \"cover\",\n backgroundPosition: \"center\",\n backgroundRepeat: \"no-repeat\",\n borderRadius: `var(--radius-${radius})`,\n width,\n ...(height && { height }),\n };\n\n return (\n <Card size=\"1\" variant=\"soft\">\n <Flex justify=\"center\" align=\"center\" py=\"4\" style={imageStyle}>\n <Theme fontFamily=\"sans\">{children}</Theme>\n </Flex>\n </Card>\n );\n}\n\n// ============================================\n// Code Section (for runtime highlighting)\n// ============================================\n\ninterface CodeSectionProps {\n code: string;\n language: string;\n showCopy?: boolean;\n showLanguage?: boolean;\n lightTheme?: string;\n darkTheme?: string;\n}\n\nconst CodeSection = memo(function CodeSection({\n code,\n language,\n showCopy = true,\n showLanguage = true,\n lightTheme = DEFAULT_LIGHT_THEME,\n darkTheme = DEFAULT_DARK_THEME,\n}: CodeSectionProps) {\n const [highlighted, setHighlighted] = useState<string | null>(null);\n const [isExpanded, setIsExpanded] = useState(false);\n const [contentHeight, setContentHeight] = useState(COLLAPSED_HEIGHT);\n const [copied, setCopied] = useState(false);\n const contentRef = useRef<HTMLDivElement>(null);\n const resetTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const shouldShowToggle = contentHeight > COLLAPSED_HEIGHT;\n\n useEffect(() => {\n let cancelled = false;\n codeToHtml(code, {\n lang: language,\n themes: { light: lightTheme, dark: darkTheme },\n defaultColor: false,\n })\n .then((html) => {\n if (!cancelled) setHighlighted(html);\n })\n .catch(() => {\n if (!cancelled) setHighlighted(null);\n });\n return () => {\n cancelled = true;\n };\n }, [code, language, lightTheme, darkTheme]);\n\n useEffect(() => {\n if (contentRef.current) {\n setContentHeight(contentRef.current.scrollHeight);\n }\n }, [highlighted]);\n\n useEffect(() => {\n return () => {\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n };\n }, []);\n\n const handleCopy = useCallback(async () => {\n if (!code.trim()) return;\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n resetTimeoutRef.current = setTimeout(() => setCopied(false), 2000);\n } catch {\n // Silently fail\n }\n }, [code]);\n\n const displayLanguage = language === \"text\" ? \"plaintext\" : language;\n\n const handleToggle = useCallback(() => {\n setIsExpanded((prev) => !prev);\n }, []);\n\n const contentStyle: React.CSSProperties = {\n maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,\n };\n\n const chevronStyle: React.CSSProperties = {\n transform: isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\",\n };\n\n return (\n <Box position=\"relative\">\n <Card size=\"1\" variant=\"soft\">\n <Flex direction=\"column\" gap=\"3\">\n <Flex gap=\"2\" justify=\"between\" align=\"start\">\n {showLanguage && (\n <Code size=\"1\" color=\"gray\" highContrast>\n {displayLanguage}\n </Code>\n )}\n <Flex align=\"center\" gap=\"2\" className=\"code-action-buttons\">\n {shouldShowToggle && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleToggle}\n tooltip={isExpanded ? \"Collapse\" : \"Expand\"}\n aria-label={isExpanded ? \"Collapse code\" : \"Expand code\"}\n >\n <HugeiconsIcon icon={ArrowDown01Icon} style={chevronStyle} className=\"code-chevron\" />\n </Button>\n )}\n {showCopy && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleCopy}\n tooltip={copied ? \"Copied!\" : \"Copy\"}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n <HugeiconsIcon icon={copied ? Tick01Icon : Copy01Icon} /> Copy\n </Button>\n )}\n </Flex>\n </Flex>\n\n <Box ref={contentRef} style={contentStyle} className=\"code-content\">\n <ScrollArea type=\"auto\" scrollbars=\"horizontal\">\n {highlighted ? (\n <Box dangerouslySetInnerHTML={{ __html: highlighted }} />\n ) : (\n <pre>\n <Code size=\"3\">{code}</Code>\n </pre>\n )}\n </ScrollArea>\n </Box>\n\n {shouldShowToggle && !isExpanded && <Box className=\"code-scroll-shadow visible\" />}\n </Flex>\n </Card>\n </Box>\n );\n});\n\n// ============================================\n// Children Code Section (for pre-highlighted MDX)\n// ============================================\n\ninterface ChildrenCodeSectionProps {\n children: ReactNode;\n showCopy?: boolean;\n showLanguage?: boolean;\n}\n\nfunction extractCodeFromChildren(children?: ReactNode): string {\n const extractText = (node: any): string => {\n if (typeof node === \"string\") return node;\n if (typeof node === \"number\") return String(node);\n if (!node) return \"\";\n if (Array.isArray(node)) return node.map(extractText).join(\"\");\n if (typeof node === \"object\" && \"props\" in node) {\n const props = node.props;\n if (props?.children) return extractText(props.children);\n }\n return \"\";\n };\n return extractText(children);\n}\n\nfunction extractLanguageFromChildren(children?: ReactNode): string {\n const findLanguage = (node: any): string | null => {\n if (!node) return null;\n if (typeof node === \"object\" && \"props\" in node) {\n const props = node.props;\n\n // Check data-language attribute (rehype-pretty-code)\n if (props?.[\"data-language\"]) {\n return props[\"data-language\"];\n }\n\n // Check className for language-xxx\n const className = props?.className || props?.class || \"\";\n if (typeof className === \"string\") {\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n\n // Recursively check children\n if (props?.children) {\n if (Array.isArray(props.children)) {\n for (const child of props.children) {\n const lang = findLanguage(child);\n if (lang) return lang;\n }\n } else {\n return findLanguage(props.children);\n }\n }\n }\n return null;\n };\n return findLanguage(children) || \"text\";\n}\n\nfunction formatLanguageLabel(lang: string): string {\n const aliasMap: Record<string, string> = {\n tsx: \"TSX\",\n ts: \"TS\",\n jsx: \"JSX\",\n js: \"JS\",\n javascript: \"JS\",\n typescript: \"TS\",\n css: \"CSS\",\n html: \"HTML\",\n json: \"JSON\",\n bash: \"SH\",\n sh: \"SH\",\n shell: \"SH\",\n text: \"plaintext\",\n };\n return aliasMap[lang.toLowerCase()] || lang.toLowerCase();\n}\n\nconst ChildrenCodeSection = memo(function ChildrenCodeSection({ children, showCopy = true, showLanguage = true }: ChildrenCodeSectionProps) {\n const [isExpanded, setIsExpanded] = useState(false);\n const [contentHeight, setContentHeight] = useState(COLLAPSED_HEIGHT);\n const [copied, setCopied] = useState(false);\n const contentRef = useRef<HTMLDivElement>(null);\n const resetTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const code = extractCodeFromChildren(children);\n const language = extractLanguageFromChildren(children);\n const displayLanguage = formatLanguageLabel(language);\n\n const shouldShowToggle = contentHeight > COLLAPSED_HEIGHT;\n\n useEffect(() => {\n if (contentRef.current) {\n setContentHeight(contentRef.current.scrollHeight);\n }\n }, [children]);\n\n useEffect(() => {\n return () => {\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n };\n }, []);\n\n const handleCopy = useCallback(async () => {\n if (!code.trim()) return;\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);\n resetTimeoutRef.current = setTimeout(() => setCopied(false), 2000);\n } catch {\n // Silently fail\n }\n }, [code]);\n\n const contentStyle: React.CSSProperties = {\n maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,\n };\n\n const handleToggle = useCallback(() => {\n setIsExpanded((prev) => !prev);\n }, []);\n\n const chevronStyle: React.CSSProperties = {\n transform: isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\",\n };\n\n return (\n <Box position=\"relative\">\n <Card size=\"1\" variant=\"soft\">\n <Flex direction=\"column\" gap=\"3\">\n <Flex gap=\"2\" justify=\"between\" align=\"start\">\n {showLanguage && (\n <Code size=\"1\" color=\"gray\" highContrast>\n {displayLanguage}\n </Code>\n )}\n <Flex align=\"center\" gap=\"2\" className=\"code-action-buttons\">\n {shouldShowToggle && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleToggle}\n tooltip={isExpanded ? \"Collapse\" : \"Expand\"}\n aria-label={isExpanded ? \"Collapse code\" : \"Expand code\"}\n >\n <HugeiconsIcon icon={ArrowDown01Icon} style={chevronStyle} className=\"code-chevron\" />\n </Button>\n )}\n {showCopy && (\n <Button\n size=\"2\"\n variant=\"ghost\"\n color=\"gray\"\n onClick={handleCopy}\n tooltip={copied ? \"Copied!\" : \"Copy\"}\n aria-label={copied ? \"Copied!\" : \"Copy code\"}\n >\n <HugeiconsIcon icon={copied ? Tick01Icon : Copy01Icon} /> Copy\n </Button>\n )}\n </Flex>\n </Flex>\n\n <Box ref={contentRef} style={contentStyle} className=\"code-content\">\n <ScrollArea type=\"auto\" scrollbars=\"horizontal\">\n {children}\n </ScrollArea>\n </Box>\n\n {shouldShowToggle && !isExpanded && <Box className=\"code-scroll-shadow visible\" />}\n </Flex>\n </Card>\n </Box>\n );\n});\n\n// ============================================\n// Main CodeBlock Component\n// ============================================\n\nexport function CodeBlock({\n children,\n code,\n language,\n preview,\n showCopy = true,\n showLanguage = true,\n lightTheme,\n darkTheme,\n background,\n backgroundProps,\n}: CodeBlockProps) {\n const hasCode = code || (children && React.Children.count(children) > 0);\n const displayLanguage = language || extractLanguageFromChildren(children) || \"text\";\n\n return (\n <Box className=\"docs-code-block\" mt=\"6\" mb=\"8\">\n <Flex direction=\"column\" gap=\"2\">\n {preview && (\n <PreviewSection background={background} backgroundProps={backgroundProps}>\n {preview}\n </PreviewSection>\n )}\n\n {code && (\n <CodeSection code={code} language={displayLanguage} showCopy={showCopy} showLanguage={showLanguage} lightTheme={lightTheme} darkTheme={darkTheme} />\n )}\n\n {children && !code && (\n <ChildrenCodeSection showCopy={showCopy} showLanguage={showLanguage}>\n {children}\n </ChildrenCodeSection>\n )}\n </Flex>\n </Box>\n );\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["React", "useState", "useRef", "useEffect", "useCallback", "memo", "Box", "Card", "Flex", "Button", "Code", "Theme", "ScrollArea", "HugeiconsIcon", "Copy01Icon", "Tick01Icon", "ArrowDown01Icon", "codeToHtml", "COLLAPSED_HEIGHT", "DEFAULT_LIGHT_THEME", "DEFAULT_DARK_THEME", "PreviewSection", "children", "background", "backgroundProps", "dotSize", "color", "backgroundColor", "height", "width", "radius", "dotsStyle", "imageStyle", "CodeSection", "code", "language", "showCopy", "showLanguage", "lightTheme", "darkTheme", "highlighted", "setHighlighted", "isExpanded", "setIsExpanded", "contentHeight", "setContentHeight", "copied", "setCopied", "contentRef", "resetTimeoutRef", "shouldShowToggle", "cancelled", "html", "handleCopy", "displayLanguage", "handleToggle", "prev", "contentStyle", "extractCodeFromChildren", "extractText", "node", "props", "extractLanguageFromChildren", "findLanguage", "className", "match", "child", "lang", "formatLanguageLabel", "ChildrenCodeSection", "CodeBlock", "preview", "hasCode"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useRef, useEffect, useCallback, memo, type ReactNode } from "react";
|
|
2
|
-
import { Box, Card, Flex, Button, Code, Theme } from "@kushagradhawan/kookie-ui";
|
|
2
|
+
import { Box, Card, Flex, Button, Code, Theme, ScrollArea } from "@kushagradhawan/kookie-ui";
|
|
3
3
|
import { HugeiconsIcon } from "@hugeicons/react";
|
|
4
4
|
import { Copy01Icon, Tick01Icon, ArrowDown01Icon } from "@hugeicons/core-free-icons";
|
|
5
5
|
import { codeToHtml } from "shiki";
|
|
@@ -203,13 +203,15 @@ const CodeSection = memo(function CodeSection({
|
|
|
203
203
|
</Flex>
|
|
204
204
|
|
|
205
205
|
<Box ref={contentRef} style={contentStyle} className="code-content">
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
<
|
|
211
|
-
|
|
212
|
-
|
|
206
|
+
<ScrollArea type="auto" scrollbars="horizontal">
|
|
207
|
+
{highlighted ? (
|
|
208
|
+
<Box dangerouslySetInnerHTML={{ __html: highlighted }} />
|
|
209
|
+
) : (
|
|
210
|
+
<pre>
|
|
211
|
+
<Code size="3">{code}</Code>
|
|
212
|
+
</pre>
|
|
213
|
+
)}
|
|
214
|
+
</ScrollArea>
|
|
213
215
|
</Box>
|
|
214
216
|
|
|
215
217
|
{shouldShowToggle && !isExpanded && <Box className="code-scroll-shadow visible" />}
|
|
@@ -249,11 +251,20 @@ function extractLanguageFromChildren(children?: ReactNode): string {
|
|
|
249
251
|
if (!node) return null;
|
|
250
252
|
if (typeof node === "object" && "props" in node) {
|
|
251
253
|
const props = node.props;
|
|
254
|
+
|
|
255
|
+
// Check data-language attribute (rehype-pretty-code)
|
|
256
|
+
if (props?.["data-language"]) {
|
|
257
|
+
return props["data-language"];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Check className for language-xxx
|
|
252
261
|
const className = props?.className || props?.class || "";
|
|
253
262
|
if (typeof className === "string") {
|
|
254
263
|
const match = className.match(/language-([\w-]+)/i);
|
|
255
264
|
if (match) return match[1];
|
|
256
265
|
}
|
|
266
|
+
|
|
267
|
+
// Recursively check children
|
|
257
268
|
if (props?.children) {
|
|
258
269
|
if (Array.isArray(props.children)) {
|
|
259
270
|
for (const child of props.children) {
|
|
@@ -377,7 +388,9 @@ const ChildrenCodeSection = memo(function ChildrenCodeSection({ children, showCo
|
|
|
377
388
|
</Flex>
|
|
378
389
|
|
|
379
390
|
<Box ref={contentRef} style={contentStyle} className="code-content">
|
|
380
|
-
<
|
|
391
|
+
<ScrollArea type="auto" scrollbars="horizontal">
|
|
392
|
+
{children}
|
|
393
|
+
</ScrollArea>
|
|
381
394
|
</Box>
|
|
382
395
|
|
|
383
396
|
{shouldShowToggle && !isExpanded && <Box className="code-scroll-shadow visible" />}
|
package/src/components/index.css
CHANGED
|
@@ -16,68 +16,15 @@
|
|
|
16
16
|
position: relative;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
/* Code block content (the pre part, below the header) */
|
|
20
|
-
.code-block-content {
|
|
21
|
-
width: 100%;
|
|
22
|
-
min-width: 0;
|
|
23
|
-
overflow-x: auto;
|
|
24
|
-
/* Hide scrollbars while keeping scroll functionality */
|
|
25
|
-
scrollbar-width: none; /* Firefox */
|
|
26
|
-
-ms-overflow-style: none; /* IE/Edge */
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/* Hide scrollbars for webkit browsers */
|
|
30
|
-
.code-block-content::-webkit-scrollbar,
|
|
31
|
-
.code-block-content::-webkit-scrollbar-horizontal,
|
|
32
|
-
.code-block-content::-webkit-scrollbar-vertical,
|
|
33
|
-
.code-block-content::-webkit-scrollbar-track,
|
|
34
|
-
.code-block-content::-webkit-scrollbar-thumb,
|
|
35
|
-
.code-block-content::-webkit-scrollbar-corner {
|
|
36
|
-
display: none !important;
|
|
37
|
-
width: 0 !important;
|
|
38
|
-
height: 0 !important;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/* Also hide scrollbars on any pre/code elements inside code content */
|
|
42
|
-
.code-block-content pre::-webkit-scrollbar,
|
|
43
|
-
.code-block-content pre::-webkit-scrollbar-horizontal,
|
|
44
|
-
.code-block-content pre::-webkit-scrollbar-vertical,
|
|
45
|
-
.code-block-content pre::-webkit-scrollbar-track,
|
|
46
|
-
.code-block-content pre::-webkit-scrollbar-thumb,
|
|
47
|
-
.code-block-content pre::-webkit-scrollbar-corner,
|
|
48
|
-
.code-block-content code::-webkit-scrollbar,
|
|
49
|
-
.code-block-content code::-webkit-scrollbar-horizontal,
|
|
50
|
-
.code-block-content code::-webkit-scrollbar-vertical,
|
|
51
|
-
.code-block-content code::-webkit-scrollbar-track,
|
|
52
|
-
.code-block-content code::-webkit-scrollbar-thumb,
|
|
53
|
-
.code-block-content code::-webkit-scrollbar-corner {
|
|
54
|
-
display: none !important;
|
|
55
|
-
width: 0 !important;
|
|
56
|
-
height: 0 !important;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
19
|
/* Pre elements inside code content */
|
|
60
|
-
.code-content pre
|
|
61
|
-
.code-block-content pre {
|
|
62
|
-
overflow-x: visible;
|
|
63
|
-
max-width: 100%;
|
|
64
|
-
min-width: 0;
|
|
20
|
+
.code-content pre {
|
|
65
21
|
margin: 0;
|
|
66
22
|
width: 100%;
|
|
67
23
|
box-sizing: border-box;
|
|
68
|
-
scrollbar-width: none;
|
|
69
|
-
-ms-overflow-style: none;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/* Ensure Shiki-generated pre elements fill width */
|
|
73
|
-
.code-block-content > pre {
|
|
74
|
-
width: 100% !important;
|
|
75
|
-
min-width: 0;
|
|
76
24
|
}
|
|
77
25
|
|
|
78
26
|
/* Code elements inside pre */
|
|
79
|
-
.code-content pre code
|
|
80
|
-
.code-block-content pre code {
|
|
27
|
+
.code-content pre code {
|
|
81
28
|
font-family: var(--font-mono);
|
|
82
29
|
font-size: var(--font-size-2);
|
|
83
30
|
line-height: 1.75;
|
|
@@ -89,16 +36,14 @@
|
|
|
89
36
|
}
|
|
90
37
|
|
|
91
38
|
/* Shiki line spans */
|
|
92
|
-
.code-content pre code .line
|
|
93
|
-
.code-block-content pre code .line {
|
|
39
|
+
.code-content pre code .line {
|
|
94
40
|
display: flex;
|
|
95
41
|
align-items: center;
|
|
96
42
|
gap: 0;
|
|
97
43
|
}
|
|
98
44
|
|
|
99
45
|
/* Line numbers */
|
|
100
|
-
.code-content pre code .line::before
|
|
101
|
-
.code-block-content pre code .line::before {
|
|
46
|
+
.code-content pre code .line::before {
|
|
102
47
|
counter-increment: line;
|
|
103
48
|
content: counter(line);
|
|
104
49
|
display: inline-block;
|
|
@@ -140,7 +85,6 @@
|
|
|
140
85
|
}
|
|
141
86
|
|
|
142
87
|
/* Default to light theme for all tokens (codeToHtml with defaultColor: false) */
|
|
143
|
-
.code-block-content pre.shiki span,
|
|
144
88
|
.code-content pre.shiki span {
|
|
145
89
|
color: var(--shiki-light) !important;
|
|
146
90
|
font-style: var(--shiki-light-font-style);
|
|
@@ -149,9 +93,6 @@
|
|
|
149
93
|
}
|
|
150
94
|
|
|
151
95
|
/* Override with dark theme colors when inside a dark context */
|
|
152
|
-
.dark .code-block-content pre.shiki span,
|
|
153
|
-
.dark-theme .code-block-content pre.shiki span,
|
|
154
|
-
[data-appearance="dark"] .code-block-content pre.shiki span,
|
|
155
96
|
.dark .code-content pre.shiki span,
|
|
156
97
|
.dark-theme .code-content pre.shiki span,
|
|
157
98
|
[data-appearance="dark"] .code-content pre.shiki span {
|
package/styles.css
CHANGED
|
@@ -13,63 +13,14 @@
|
|
|
13
13
|
transition: max-height 0.3s ease-in-out;
|
|
14
14
|
position: relative;
|
|
15
15
|
}
|
|
16
|
-
/* Code block content (the pre part, below the header) */
|
|
17
|
-
.code-block-content {
|
|
18
|
-
width: 100%;
|
|
19
|
-
min-width: 0;
|
|
20
|
-
overflow-x: auto;
|
|
21
|
-
/* Hide scrollbars while keeping scroll functionality */
|
|
22
|
-
scrollbar-width: none; /* Firefox */
|
|
23
|
-
-ms-overflow-style: none; /* IE/Edge */
|
|
24
|
-
}
|
|
25
|
-
/* Hide scrollbars for webkit browsers */
|
|
26
|
-
.code-block-content::-webkit-scrollbar,
|
|
27
|
-
.code-block-content::-webkit-scrollbar-horizontal,
|
|
28
|
-
.code-block-content::-webkit-scrollbar-vertical,
|
|
29
|
-
.code-block-content::-webkit-scrollbar-track,
|
|
30
|
-
.code-block-content::-webkit-scrollbar-thumb,
|
|
31
|
-
.code-block-content::-webkit-scrollbar-corner {
|
|
32
|
-
display: none !important;
|
|
33
|
-
width: 0 !important;
|
|
34
|
-
height: 0 !important;
|
|
35
|
-
}
|
|
36
|
-
/* Also hide scrollbars on any pre/code elements inside code content */
|
|
37
|
-
.code-block-content pre::-webkit-scrollbar,
|
|
38
|
-
.code-block-content pre::-webkit-scrollbar-horizontal,
|
|
39
|
-
.code-block-content pre::-webkit-scrollbar-vertical,
|
|
40
|
-
.code-block-content pre::-webkit-scrollbar-track,
|
|
41
|
-
.code-block-content pre::-webkit-scrollbar-thumb,
|
|
42
|
-
.code-block-content pre::-webkit-scrollbar-corner,
|
|
43
|
-
.code-block-content code::-webkit-scrollbar,
|
|
44
|
-
.code-block-content code::-webkit-scrollbar-horizontal,
|
|
45
|
-
.code-block-content code::-webkit-scrollbar-vertical,
|
|
46
|
-
.code-block-content code::-webkit-scrollbar-track,
|
|
47
|
-
.code-block-content code::-webkit-scrollbar-thumb,
|
|
48
|
-
.code-block-content code::-webkit-scrollbar-corner {
|
|
49
|
-
display: none !important;
|
|
50
|
-
width: 0 !important;
|
|
51
|
-
height: 0 !important;
|
|
52
|
-
}
|
|
53
16
|
/* Pre elements inside code content */
|
|
54
|
-
.code-content pre
|
|
55
|
-
.code-block-content pre {
|
|
56
|
-
overflow-x: visible;
|
|
57
|
-
max-width: 100%;
|
|
58
|
-
min-width: 0;
|
|
17
|
+
.code-content pre {
|
|
59
18
|
margin: 0;
|
|
60
19
|
width: 100%;
|
|
61
20
|
box-sizing: border-box;
|
|
62
|
-
scrollbar-width: none;
|
|
63
|
-
-ms-overflow-style: none;
|
|
64
|
-
}
|
|
65
|
-
/* Ensure Shiki-generated pre elements fill width */
|
|
66
|
-
.code-block-content > pre {
|
|
67
|
-
width: 100% !important;
|
|
68
|
-
min-width: 0;
|
|
69
21
|
}
|
|
70
22
|
/* Code elements inside pre */
|
|
71
|
-
.code-content pre code
|
|
72
|
-
.code-block-content pre code {
|
|
23
|
+
.code-content pre code {
|
|
73
24
|
font-family: var(--font-mono);
|
|
74
25
|
font-size: var(--font-size-2);
|
|
75
26
|
line-height: 1.75;
|
|
@@ -80,15 +31,13 @@
|
|
|
80
31
|
counter-reset: line;
|
|
81
32
|
}
|
|
82
33
|
/* Shiki line spans */
|
|
83
|
-
.code-content pre code .line
|
|
84
|
-
.code-block-content pre code .line {
|
|
34
|
+
.code-content pre code .line {
|
|
85
35
|
display: flex;
|
|
86
36
|
align-items: center;
|
|
87
37
|
gap: 0;
|
|
88
38
|
}
|
|
89
39
|
/* Line numbers */
|
|
90
|
-
.code-content pre code .line::before
|
|
91
|
-
.code-block-content pre code .line::before {
|
|
40
|
+
.code-content pre code .line::before {
|
|
92
41
|
counter-increment: line;
|
|
93
42
|
content: counter(line);
|
|
94
43
|
display: inline-block;
|
|
@@ -127,7 +76,6 @@
|
|
|
127
76
|
transition: transform 0.2s ease-in-out;
|
|
128
77
|
}
|
|
129
78
|
/* Default to light theme for all tokens (codeToHtml with defaultColor: false) */
|
|
130
|
-
.code-block-content pre.shiki span,
|
|
131
79
|
.code-content pre.shiki span {
|
|
132
80
|
color: var(--shiki-light) !important;
|
|
133
81
|
font-style: var(--shiki-light-font-style);
|
|
@@ -136,9 +84,6 @@
|
|
|
136
84
|
text-decoration: var(--shiki-light-text-decoration);
|
|
137
85
|
}
|
|
138
86
|
/* Override with dark theme colors when inside a dark context */
|
|
139
|
-
.dark .code-block-content pre.shiki span,
|
|
140
|
-
.dark-theme .code-block-content pre.shiki span,
|
|
141
|
-
[data-appearance="dark"] .code-block-content pre.shiki span,
|
|
142
87
|
.dark .code-content pre.shiki span,
|
|
143
88
|
.dark-theme .code-content pre.shiki span,
|
|
144
89
|
[data-appearance="dark"] .code-content pre.shiki span {
|