@kushagradhawan/kookie-blocks 0.1.4 → 0.1.5

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 CHANGED
@@ -1,16 +1,21 @@
1
- /* Components CSS aggregator for Kookie Blocks (e.g., hero variants if styled). */
1
+ /* Components CSS aggregator for Kookie Blocks */
2
2
 
3
3
  /* ============================================
4
4
  Code Block Component Styles
5
5
  ============================================ */
6
6
 
7
- /* Code block wrapper - constrain width in flex containers */
7
+ /* Main docs code block wrapper */
8
8
 
9
- .code-block-wrapper {
10
- min-width: 0;
11
- max-width: 100%;
9
+ .docs-code-block {
12
10
  width: 100%;
11
+ }
12
+
13
+ /* Code content area - handles expand/collapse */
14
+
15
+ .code-content {
13
16
  overflow: hidden;
17
+ transition: max-height 0.3s ease-in-out;
18
+ position: relative;
14
19
  }
15
20
 
16
21
  /* Code block content (the pre part, below the header) */
@@ -56,14 +61,18 @@
56
61
  height: 0 !important;
57
62
  }
58
63
 
59
- .code-block-wrapper pre,
60
- .code-block-wrapper .code-block-content pre {
61
- overflow-x: visible; /* Let .code-block-content handle scrolling */
64
+ /* Pre elements inside code content */
65
+
66
+ .code-content pre,
67
+ .code-block-content pre {
68
+ overflow-x: visible;
62
69
  max-width: 100%;
63
70
  min-width: 0;
64
71
  margin: 0;
65
72
  width: 100%;
66
73
  box-sizing: border-box;
74
+ scrollbar-width: none;
75
+ -ms-overflow-style: none;
67
76
  }
68
77
 
69
78
  /* Ensure Shiki-generated pre elements fill width */
@@ -75,8 +84,8 @@
75
84
 
76
85
  /* Code elements inside pre */
77
86
 
78
- .code-block-wrapper pre code,
79
- .code-block-wrapper .code-block-content pre code {
87
+ .code-content pre code,
88
+ .code-block-content pre code {
80
89
  font-family: var(--font-mono);
81
90
  font-size: var(--font-size-2);
82
91
  line-height: 1.75;
@@ -89,8 +98,8 @@
89
98
 
90
99
  /* Shiki line spans */
91
100
 
92
- .code-block-wrapper pre code .line,
93
- .code-block-wrapper .code-block-content pre code .line {
101
+ .code-content pre code .line,
102
+ .code-block-content pre code .line {
94
103
  display: flex;
95
104
  align-items: center;
96
105
  gap: 0;
@@ -98,8 +107,8 @@
98
107
 
99
108
  /* Line numbers */
100
109
 
101
- .code-block-wrapper pre code .line::before,
102
- .code-block-wrapper .code-block-content pre code .line::before {
110
+ .code-content pre code .line::before,
111
+ .code-block-content pre code .line::before {
103
112
  counter-increment: line;
104
113
  content: counter(line);
105
114
  display: inline-block;
@@ -114,9 +123,41 @@
114
123
  margin-right: var(--space-4);
115
124
  }
116
125
 
126
+ /* Scroll shadow overlay for collapsed state */
127
+
128
+ .code-scroll-shadow {
129
+ position: absolute;
130
+ bottom: 0;
131
+ left: 0;
132
+ right: 0;
133
+ height: 80px;
134
+ background: linear-gradient(to top, var(--color-panel-solid), transparent);
135
+ pointer-events: none;
136
+ opacity: 0;
137
+ transition: opacity 0.2s ease-in-out;
138
+ z-index: 1;
139
+ }
140
+
141
+ .code-scroll-shadow.visible {
142
+ opacity: 1;
143
+ }
144
+
145
+ /* Action buttons styling */
146
+
147
+ .code-action-buttons {
148
+ flex-shrink: 0;
149
+ }
150
+
151
+ /* Chevron rotation animation */
152
+
153
+ .code-chevron {
154
+ transition: transform 0.2s ease-in-out;
155
+ }
156
+
117
157
  /* Default to light theme for all tokens (codeToHtml with defaultColor: false) */
118
158
 
119
- .code-block-wrapper pre.shiki span {
159
+ .code-block-content pre.shiki span,
160
+ .code-content pre.shiki span {
120
161
  color: var(--shiki-light) !important;
121
162
  font-style: var(--shiki-light-font-style);
122
163
  font-weight: var(--shiki-light-font-weight);
@@ -126,9 +167,12 @@
126
167
 
127
168
  /* Override with dark theme colors when inside a dark context */
128
169
 
129
- .dark .code-block-wrapper pre.shiki span,
130
- .dark-theme .code-block-wrapper pre.shiki span,
131
- [data-appearance="dark"] .code-block-wrapper pre.shiki span {
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
+ .dark .code-content pre.shiki span,
174
+ .dark-theme .code-content pre.shiki span,
175
+ [data-appearance="dark"] .code-content pre.shiki span {
132
176
  color: var(--shiki-dark) !important;
133
177
  font-style: var(--shiki-dark-font-style);
134
178
  font-weight: var(--shiki-dark-font-weight);
@@ -1,4 +1,4 @@
1
1
  import React from "react";
2
2
  import type { CodeBlockProps } from "./types";
3
- export declare function CodeBlock({ children, code, language, preview, showCopy, showLanguage, lightTheme, darkTheme, background, backgroundProps, }: CodeBlockProps): React.JSX.Element | null;
3
+ export declare function CodeBlock({ children, code, language, preview, showCopy, showLanguage, lightTheme, darkTheme, background, backgroundProps, }: CodeBlockProps): React.JSX.Element;
4
4
  //# sourceMappingURL=CodeBlock.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../../../src/components/code/CodeBlock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyB,MAAM,OAAO,CAAC;AAM9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAwD9C,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,4BA6ChB"}
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;AAmV9C,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 P=Object.create;var l=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var k=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var j=(o,t)=>{for(var e in t)l(o,e,{get:t[e],enumerable:!0})},f=(o,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of h(t))!F.call(o,s)&&s!==e&&l(o,s,{get:()=>t[s],enumerable:!(r=b(t,s))||r.enumerable});return o};var w=(o,t,e)=>(e=o!=null?P(k(o)):{},f(t||!o||!o.__esModule?l(e,"default",{value:o,enumerable:!0}):e,o)),B=o=>f(l({},"__esModule",{value:!0}),o);var T={};j(T,{CodeBlock:()=>S});module.exports=B(T);var n=w(require("react")),a=require("@kushagradhawan/kookie-ui"),u=require("./SyntaxHighlighter"),d=require("./CopyButton"),g=require("./LanguageBadge"),y=require("./PreviewSection");function v(o){if(!o)return"text";if(typeof o=="object"&&o!==null&&"props"in o){const t=o.props;if(t?.children&&typeof t.children=="object"){const p=(t.children.props?.className||"").match(/language-([\w-]+)/i);if(p)return p[1]}const r=(t?.className||"").match(/language-([\w-]+)/i);if(r)return r[1]}return"text"}function L(o){if(!o)return"";if(typeof o=="object"&&o!==null&&"props"in o){const t=o.props;if(t?.children&&typeof t.children=="object"){const r=t.children.props?.children;if(typeof r=="string")return r}if(typeof t?.children=="string")return t.children}return typeof o=="string"?o:""}function S({children:o,code:t,language:e,preview:r,showCopy:s=!0,showLanguage:m=!0,lightTheme:p,darkTheme:x,background:C,backgroundProps:N}){let c=t,i=e;return o&&!t&&(c=L(o),i=e||v(o)),i||(i="text"),!c&&!o?null:n.default.createElement(a.Flex,{direction:"column",className:"code-block-wrapper",style:{minWidth:0},my:"2"},r&&n.default.createElement(y.PreviewSection,{background:C,backgroundProps:N},r),n.default.createElement(a.Card,{size:"2",variant:"soft"},n.default.createElement(a.Flex,{gap:"2",direction:"column"},n.default.createElement(a.Flex,{align:"start",justify:"between"},m&&n.default.createElement(g.LanguageBadge,{language:i}),s&&c&&n.default.createElement(d.CopyButton,{code:c})),t&&n.default.createElement(u.SyntaxHighlighter,{code:t,language:i,lightTheme:p,darkTheme:x}),o&&!t&&n.default.createElement("div",{className:"code-block-content"},o))))}
1
+ "use strict";var z=Object.create;var b=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var I=Object.getPrototypeOf,$=Object.prototype.hasOwnProperty;var M=(o,t)=>{for(var r in t)b(o,r,{get:t[r],enumerable:!0})},w=(o,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of B(t))!$.call(o,i)&&i!==r&&b(o,i,{get:()=>t[i],enumerable:!(s=j(t,i))||s.enumerable});return o};var _=(o,t,r)=>(r=o!=null?z(I(o)):{},w(t||!o||!o.__esModule?b(r,"default",{value:o,enumerable:!0}):r,o)),D=o=>w(b({},"__esModule",{value:!0}),o);var q={};M(q,{CodeBlock:()=>W});module.exports=D(q);var e=_(require("react")),n=require("@kushagradhawan/kookie-ui"),v=require("@hugeicons/react"),C=require("@hugeicons/core-free-icons"),H=require("shiki");const m=360,A="one-light",J="one-dark-pro";function G({children:o,background:t="none",backgroundProps:r={}}){const{dotSize:s=24,color:i="var(--gray-10)",backgroundColor:d="var(--gray-2)",height:a,width:l="100%",radius:c="3"}=r;if(t==="none")return e.default.createElement(n.Card,{size:"1",variant:"soft"},e.default.createElement(n.Flex,{justify:"center",align:"center",py:"4"},e.default.createElement(n.Theme,{fontFamily:"sans"},o)));if(t==="dots"){const g={backgroundImage:`radial-gradient(circle, ${i} 1px, transparent 1px)`,borderRadius:`var(--radius-${c})`,backgroundSize:`${s}px ${s}px`,backgroundPosition:"center",backgroundColor:d,width:l,...a&&{height:a}};return e.default.createElement(n.Card,{size:"1",variant:"soft"},e.default.createElement(n.Flex,{justify:"center",align:"center",py:"4",style:g},e.default.createElement(n.Theme,{fontFamily:"sans"},o)))}const p={backgroundImage:`url(${t})`,backgroundSize:"cover",backgroundPosition:"center",backgroundRepeat:"no-repeat",borderRadius:`var(--radius-${c})`,width:l,...a&&{height:a}};return e.default.createElement(n.Card,{size:"1",variant:"soft"},e.default.createElement(n.Flex,{justify:"center",align:"center",py:"4",style:p},e.default.createElement(n.Theme,{fontFamily:"sans"},o)))}const O=(0,e.memo)(function({code:t,language:r,showCopy:s=!0,showLanguage:i=!0,lightTheme:d=A,darkTheme:a=J}){const[l,c]=(0,e.useState)(null),[p,g]=(0,e.useState)(!1),[u,h]=(0,e.useState)(m),[y,x]=(0,e.useState)(!1),S=(0,e.useRef)(null),f=(0,e.useRef)(null),T=u>m;(0,e.useEffect)(()=>{let P=!1;return(0,H.codeToHtml)(t,{lang:r,themes:{light:d,dark:a},defaultColor:!1}).then(E=>{P||c(E)}).catch(()=>{P||c(null)}),()=>{P=!0}},[t,r,d,a]),(0,e.useEffect)(()=>{S.current&&h(S.current.scrollHeight)},[l]),(0,e.useEffect)(()=>()=>{f.current&&clearTimeout(f.current)},[]);const N=(0,e.useCallback)(async()=>{if(t.trim())try{await navigator.clipboard.writeText(t),x(!0),f.current&&clearTimeout(f.current),f.current=setTimeout(()=>x(!1),2e3)}catch{}},[t]),L=r==="text"?"plaintext":r,F={maxHeight:p?`${u}px`:`${m}px`};return e.default.createElement(n.Box,{position:"relative"},e.default.createElement(n.Card,{size:"1",variant:"soft"},e.default.createElement(n.Flex,{direction:"column",gap:"3"},e.default.createElement(n.Flex,{gap:"2",justify:"between",align:"start"},i&&e.default.createElement(n.Code,{size:"1",color:"gray",highContrast:!0},L),e.default.createElement(n.Flex,{align:"center",gap:"2",className:"code-action-buttons"},s&&e.default.createElement(n.Button,{size:"2",variant:"ghost",color:"gray",onClick:N,tooltip:y?"Copied!":"Copy","aria-label":y?"Copied!":"Copy code"},e.default.createElement(v.HugeiconsIcon,{icon:y?C.Tick01Icon:C.Copy01Icon})," Copy"))),e.default.createElement(n.Box,{ref:S,style:F,className:"code-content"},l?e.default.createElement(n.Box,{className:"code-block-content",width:"100%",style:{minWidth:0},dangerouslySetInnerHTML:{__html:l}}):e.default.createElement("pre",{className:"code-block-content"},e.default.createElement(n.Code,{size:"3"},t))),T&&!p&&e.default.createElement(n.Box,{className:"code-scroll-shadow visible"}))))});function U(o){if(!o)return"";if(typeof o=="object"&&o!==null&&"props"in o){const t=o.props;if(t?.children&&typeof t.children=="object"){const s=t.children.props?.children;if(typeof s=="string")return s}if(typeof t?.children=="string")return t.children}return typeof o=="string"?o:""}function k(o){if(!o)return"text";if(typeof o=="object"&&o!==null&&"props"in o){const t=o.props;if(t?.children&&typeof t.children=="object"){const a=(t.children.props?.className||"").match(/language-([\w-]+)/i);if(a)return a[1]}const s=(t?.className||"").match(/language-([\w-]+)/i);if(s)return s[1]}return"text"}function X(o){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"}[o.toLowerCase()]||o.toLowerCase()}const K=(0,e.memo)(function({children:t,showCopy:r=!0,showLanguage:s=!0}){const[i,d]=(0,e.useState)(!1),[a,l]=(0,e.useState)(m),[c,p]=(0,e.useState)(!1),g=(0,e.useRef)(null),u=(0,e.useRef)(null),h=U(t),y=k(t),x=X(y),S=a>m;(0,e.useEffect)(()=>{g.current&&l(g.current.scrollHeight)},[t]),(0,e.useEffect)(()=>()=>{u.current&&clearTimeout(u.current)},[]);const f=(0,e.useCallback)(async()=>{if(h.trim())try{await navigator.clipboard.writeText(h),p(!0),u.current&&clearTimeout(u.current),u.current=setTimeout(()=>p(!1),2e3)}catch{}},[h]),T={maxHeight:i?`${a}px`:`${m}px`};return e.default.createElement(n.Box,{position:"relative"},e.default.createElement(n.Card,{size:"1",variant:"soft"},e.default.createElement(n.Flex,{direction:"column",gap:"3"},e.default.createElement(n.Flex,{gap:"2",justify:"between",align:"start"},s&&e.default.createElement(n.Code,{size:"1",color:"gray",highContrast:!0},x),e.default.createElement(n.Flex,{align:"center",gap:"2",className:"code-action-buttons"},r&&e.default.createElement(n.Button,{size:"2",variant:"ghost",color:"gray",onClick:f,tooltip:c?"Copied!":"Copy","aria-label":c?"Copied!":"Copy code"},e.default.createElement(v.HugeiconsIcon,{icon:c?C.Tick01Icon:C.Copy01Icon})," Copy"))),e.default.createElement(n.Box,{ref:g,style:T,className:"code-content"},e.default.createElement("div",{className:"code-block-content"},t)),S&&!i&&e.default.createElement(n.Box,{className:"code-scroll-shadow visible"}))))});function W({children:o,code:t,language:r,preview:s,showCopy:i=!0,showLanguage:d=!0,lightTheme:a,darkTheme:l,background:c,backgroundProps:p}){const g=t||o&&e.default.Children.count(o)>0,u=r||k(o)||"text";return e.default.createElement(n.Box,{className:"docs-code-block",mt:"6",mb:"8"},e.default.createElement(n.Flex,{direction:"column",gap:"2"},s&&e.default.createElement(G,{background:c,backgroundProps:p},s),t&&e.default.createElement(O,{code:t,language:u,showCopy:i,showLanguage:d,lightTheme:a,darkTheme:l}),o&&!t&&e.default.createElement(K,{showCopy:i,showLanguage:d},o)))}
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, { type ReactNode } from \"react\";\nimport { Card, Flex } from \"@kushagradhawan/kookie-ui\";\nimport { SyntaxHighlighter } from \"./SyntaxHighlighter\";\nimport { CopyButton } from \"./CopyButton\";\nimport { LanguageBadge } from \"./LanguageBadge\";\nimport { PreviewSection } from \"./PreviewSection\";\nimport type { CodeBlockProps } from \"./types\";\n\nfunction extractLanguageFromChildren(children?: ReactNode): string {\n if (!children) return \"text\";\n\n // Try to extract language from pre > code className\n if (typeof children === \"object\" && children !== null && \"props\" in children) {\n const childProps = (children as any).props;\n\n // If children is a <pre><code className=\"language-xxx\">\n if (childProps?.children && typeof childProps.children === \"object\") {\n const codeProps = (childProps.children as any).props;\n const className = codeProps?.className || \"\";\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n\n // Direct className on children\n const className = childProps?.className || \"\";\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n\n return \"text\";\n}\n\nfunction extractCodeFromChildren(children?: ReactNode): string {\n if (!children) return \"\";\n\n // Try to extract text from pre > code structure\n if (typeof children === \"object\" && children !== null && \"props\" in children) {\n const childProps = (children as any).props;\n\n // If children is <pre><code>...</code></pre>\n if (childProps?.children && typeof childProps.children === \"object\") {\n const codeProps = (childProps.children as any).props;\n const codeChildren = codeProps?.children;\n\n if (typeof codeChildren === \"string\") {\n return codeChildren;\n }\n }\n\n // Direct text content\n if (typeof childProps?.children === \"string\") {\n return childProps.children;\n }\n }\n\n if (typeof children === \"string\") {\n return children;\n }\n\n return \"\";\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 // Determine the code and language to display\n let displayCode = code;\n let displayLanguage = language;\n\n // If children are provided (pre-highlighted from MDX), extract code and language\n if (children && !code) {\n displayCode = extractCodeFromChildren(children);\n displayLanguage = language || extractLanguageFromChildren(children);\n }\n\n // Default language\n if (!displayLanguage) {\n displayLanguage = \"text\";\n }\n\n // If no code to display, render nothing\n if (!displayCode && !children) {\n return null;\n }\n\n return (\n <Flex direction=\"column\" className=\"code-block-wrapper\" style={{ minWidth: 0 }} my=\"2\">\n {preview && (\n <PreviewSection background={background} backgroundProps={backgroundProps}>\n {preview}\n </PreviewSection>\n )}\n\n <Card size=\"2\" variant=\"soft\">\n <Flex gap=\"2\" direction=\"column\">\n <Flex align=\"start\" justify=\"between\">\n {showLanguage && <LanguageBadge language={displayLanguage} />}\n {showCopy && displayCode && <CopyButton code={displayCode} />}\n </Flex>\n\n {/* If we have runtime code, use SyntaxHighlighter */}\n {code && <SyntaxHighlighter code={code} language={displayLanguage} lightTheme={lightTheme} darkTheme={darkTheme} />}\n\n {/* If we have pre-highlighted children from MDX, render them */}\n {children && !code && <div className=\"code-block-content\">{children}</div>}\n </Flex>\n </Card>\n </Flex>\n );\n}\n"],
5
- "mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,eAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAsC,oBACtCC,EAA2B,qCAC3BC,EAAkC,+BAClCC,EAA2B,wBAC3BC,EAA8B,2BAC9BC,EAA+B,4BAG/B,SAASC,EAA4BC,EAA8B,CACjE,GAAI,CAACA,EAAU,MAAO,OAGtB,GAAI,OAAOA,GAAa,UAAYA,IAAa,MAAQ,UAAWA,EAAU,CAC5E,MAAMC,EAAcD,EAAiB,MAGrC,GAAIC,GAAY,UAAY,OAAOA,EAAW,UAAa,SAAU,CAGnE,MAAMC,GAFaD,EAAW,SAAiB,OAClB,WAAa,IAClB,MAAM,oBAAoB,EAClD,GAAIC,EAAO,OAAOA,EAAM,CAAC,CAC3B,CAIA,MAAMA,GADYD,GAAY,WAAa,IACnB,MAAM,oBAAoB,EAClD,GAAIC,EAAO,OAAOA,EAAM,CAAC,CAC3B,CAEA,MAAO,MACT,CAEA,SAASC,EAAwBH,EAA8B,CAC7D,GAAI,CAACA,EAAU,MAAO,GAGtB,GAAI,OAAOA,GAAa,UAAYA,IAAa,MAAQ,UAAWA,EAAU,CAC5E,MAAMC,EAAcD,EAAiB,MAGrC,GAAIC,GAAY,UAAY,OAAOA,EAAW,UAAa,SAAU,CAEnE,MAAMG,EADaH,EAAW,SAAiB,OACf,SAEhC,GAAI,OAAOG,GAAiB,SAC1B,OAAOA,CAEX,CAGA,GAAI,OAAOH,GAAY,UAAa,SAClC,OAAOA,EAAW,QAEtB,CAEA,OAAI,OAAOD,GAAa,SACfA,EAGF,EACT,CAEO,SAAST,EAAU,CACxB,SAAAS,EACA,KAAAK,EACA,SAAAC,EACA,QAAAC,EACA,SAAAC,EAAW,GACX,aAAAC,EAAe,GACf,WAAAC,EACA,UAAAC,EACA,WAAAC,EACA,gBAAAC,CACF,EAAmB,CAEjB,IAAIC,EAAcT,EACdU,EAAkBT,EActB,OAXIN,GAAY,CAACK,IACfS,EAAcX,EAAwBH,CAAQ,EAC9Ce,EAAkBT,GAAYP,EAA4BC,CAAQ,GAI/De,IACHA,EAAkB,QAIhB,CAACD,GAAe,CAACd,EACZ,KAIP,EAAAgB,QAAA,cAAC,QAAK,UAAU,SAAS,UAAU,qBAAqB,MAAO,CAAE,SAAU,CAAE,EAAG,GAAG,KAChFT,GACC,EAAAS,QAAA,cAAC,kBAAe,WAAYJ,EAAY,gBAAiBC,GACtDN,CACH,EAGF,EAAAS,QAAA,cAAC,QAAK,KAAK,IAAI,QAAQ,QACrB,EAAAA,QAAA,cAAC,QAAK,IAAI,IAAI,UAAU,UACtB,EAAAA,QAAA,cAAC,QAAK,MAAM,QAAQ,QAAQ,WACzBP,GAAgB,EAAAO,QAAA,cAAC,iBAAc,SAAUD,EAAiB,EAC1DP,GAAYM,GAAe,EAAAE,QAAA,cAAC,cAAW,KAAMF,EAAa,CAC7D,EAGCT,GAAQ,EAAAW,QAAA,cAAC,qBAAkB,KAAMX,EAAM,SAAUU,EAAiB,WAAYL,EAAY,UAAWC,EAAW,EAGhHX,GAAY,CAACK,GAAQ,EAAAW,QAAA,cAAC,OAAI,UAAU,sBAAsBhB,CAAS,CACtE,CACF,CACF,CAEJ",
6
- "names": ["CodeBlock_exports", "__export", "CodeBlock", "__toCommonJS", "import_react", "import_kookie_ui", "import_SyntaxHighlighter", "import_CopyButton", "import_LanguageBadge", "import_PreviewSection", "extractLanguageFromChildren", "children", "childProps", "match", "extractCodeFromChildren", "codeChildren", "code", "language", "preview", "showCopy", "showLanguage", "lightTheme", "darkTheme", "background", "backgroundProps", "displayCode", "displayLanguage", "React"]
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 } 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 contentStyle: React.CSSProperties = {\n maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,\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 {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 if (!children) return \"\";\n if (typeof children === \"object\" && children !== null && \"props\" in children) {\n const childProps = (children as any).props;\n if (childProps?.children && typeof childProps.children === \"object\") {\n const codeProps = (childProps.children as any).props;\n const codeChildren = codeProps?.children;\n if (typeof codeChildren === \"string\") return codeChildren;\n }\n if (typeof childProps?.children === \"string\") return childProps.children;\n }\n if (typeof children === \"string\") return children;\n return \"\";\n}\n\nfunction extractLanguageFromChildren(children?: ReactNode): string {\n if (!children) return \"text\";\n if (typeof children === \"object\" && children !== null && \"props\" in children) {\n const childProps = (children as any).props;\n if (childProps?.children && typeof childProps.children === \"object\") {\n const codeProps = (childProps.children as any).props;\n const className = codeProps?.className || \"\";\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n const className = childProps?.className || \"\";\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n return \"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 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 {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": "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",
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", "contentStyle", "extractCodeFromChildren", "childProps", "codeChildren", "extractLanguageFromChildren", "match", "formatLanguageLabel", "lang", "ChildrenCodeSection", "preview", "hasCode"]
7
7
  }
@@ -1,2 +1,2 @@
1
- "use strict";var f=Object.create;var s=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var b=Object.getPrototypeOf,v=Object.prototype.hasOwnProperty;var x=(r,e)=>{for(var t in e)s(r,t,{get:e[t],enumerable:!0})},u=(r,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of S(e))!v.call(r,i)&&i!==t&&s(r,i,{get:()=>e[i],enumerable:!(a=m(e,i))||a.enumerable});return r};var P=(r,e,t)=>(t=r!=null?f(b(r)):{},u(e||!r||!r.__esModule?s(t,"default",{value:r,enumerable:!0}):t,r)),h=r=>u(s({},"__esModule",{value:!0}),r);var C={};x(C,{PreviewSection:()=>k});module.exports=h(C);var o=P(require("react")),n=require("@kushagradhawan/kookie-ui");function k({children:r,background:e="none",backgroundProps:t={}}){const{dotSize:a=24,color:i="var(--gray-10)",backgroundColor:l="var(--gray-2)",height:d="300px",width:g="100%",radius:c="3"}=t;if(e==="none")return o.default.createElement(n.Card,{size:"1",variant:"soft"},o.default.createElement(n.Flex,{justify:"center",align:"center",py:"4"},o.default.createElement(n.Theme,{fontFamily:"sans"},r)));if(e==="dots"){const y={backgroundImage:`radial-gradient(circle, ${i} 1px, transparent 1px)`,borderRadius:`var(--radius-${c})`,backgroundSize:`${a}px ${a}px`,backgroundPosition:"center",backgroundColor:l,height:d,width:g};return o.default.createElement(n.Card,{size:"1",variant:"soft"},o.default.createElement(n.Flex,{justify:"center",align:"center",py:"4",style:y},o.default.createElement(n.Theme,{fontFamily:"sans"},r)))}const p={backgroundImage:`url(${e})`,backgroundSize:"cover",backgroundPosition:"center",backgroundRepeat:"no-repeat",borderRadius:`var(--radius-${c})`,height:d,width:g};return o.default.createElement(n.Card,{size:"1",variant:"soft"},o.default.createElement(n.Flex,{justify:"center",align:"center",py:"4",style:p},o.default.createElement(n.Theme,{fontFamily:"sans"},r)))}
1
+ "use strict";var f=Object.create;var d=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var b=Object.getPrototypeOf,v=Object.prototype.hasOwnProperty;var P=(r,e)=>{for(var t in e)d(r,t,{get:e[t],enumerable:!0})},u=(r,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of S(e))!v.call(r,i)&&i!==t&&d(r,i,{get:()=>e[i],enumerable:!(a=m(e,i))||a.enumerable});return r};var h=(r,e,t)=>(t=r!=null?f(b(r)):{},u(e||!r||!r.__esModule?d(t,"default",{value:r,enumerable:!0}):t,r)),k=r=>u(d({},"__esModule",{value:!0}),r);var C={};P(C,{PreviewSection:()=>x});module.exports=k(C);var o=h(require("react")),n=require("@kushagradhawan/kookie-ui");function x({children:r,background:e="none",backgroundProps:t={}}){const{dotSize:a=24,color:i="var(--gray-10)",backgroundColor:l="var(--gray-2)",height:s,width:g="100%",radius:c="3"}=t;if(e==="none")return o.default.createElement(n.Card,{size:"1",variant:"soft"},o.default.createElement(n.Flex,{justify:"center",align:"center",py:"4"},o.default.createElement(n.Theme,{fontFamily:"sans"},r)));if(e==="dots"){const y={backgroundImage:`radial-gradient(circle, ${i} 1px, transparent 1px)`,borderRadius:`var(--radius-${c})`,backgroundSize:`${a}px ${a}px`,backgroundPosition:"center",backgroundColor:l,width:g,...s&&{height:s}};return o.default.createElement(n.Card,{size:"1",variant:"soft"},o.default.createElement(n.Flex,{justify:"center",align:"center",py:"4",style:y},o.default.createElement(n.Theme,{fontFamily:"sans"},r)))}const p={backgroundImage:`url(${e})`,backgroundSize:"cover",backgroundPosition:"center",backgroundRepeat:"no-repeat",borderRadius:`var(--radius-${c})`,width:g,...s&&{height:s}};return o.default.createElement(n.Card,{size:"1",variant:"soft"},o.default.createElement(n.Flex,{justify:"center",align:"center",py:"4",style:p},o.default.createElement(n.Theme,{fontFamily:"sans"},r)))}
2
2
  //# sourceMappingURL=PreviewSection.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/code/PreviewSection.tsx"],
4
- "sourcesContent": ["import React, { type ReactNode } from \"react\";\nimport { Card, Flex, Theme } from \"@kushagradhawan/kookie-ui\";\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\nexport function PreviewSection({ children, background = \"none\", backgroundProps = {} }: PreviewSectionProps) {\n const { dotSize = 24, color = \"var(--gray-10)\", backgroundColor = \"var(--gray-2)\", height = \"300px\", width = \"100%\", radius = \"3\" } = backgroundProps;\n\n // Render with no background (default card styling)\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 // Render with dots pattern background\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 height,\n width,\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 // Render with custom image background\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 height,\n width,\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"],
5
- "mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,oBAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAsC,oBACtCC,EAAkC,qCAe3B,SAASH,EAAe,CAAE,SAAAI,EAAU,WAAAC,EAAa,OAAQ,gBAAAC,EAAkB,CAAC,CAAE,EAAwB,CAC3G,KAAM,CAAE,QAAAC,EAAU,GAAI,MAAAC,EAAQ,iBAAkB,gBAAAC,EAAkB,gBAAiB,OAAAC,EAAS,QAAS,MAAAC,EAAQ,OAAQ,OAAAC,EAAS,GAAI,EAAIN,EAGtI,GAAID,IAAe,OACjB,OACE,EAAAQ,QAAA,cAAC,QAAK,KAAK,IAAI,QAAQ,QACrB,EAAAA,QAAA,cAAC,QAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,KACvC,EAAAA,QAAA,cAAC,SAAM,WAAW,QAAQT,CAAS,CACrC,CACF,EAKJ,GAAIC,IAAe,OAAQ,CACzB,MAAMS,EAAiC,CACrC,gBAAiB,2BAA2BN,CAAK,yBACjD,aAAc,gBAAgBI,CAAM,IACpC,eAAgB,GAAGL,CAAO,MAAMA,CAAO,KACvC,mBAAoB,SACpB,gBAAAE,EACA,OAAAC,EACA,MAAAC,CACF,EAEA,OACE,EAAAE,QAAA,cAAC,QAAK,KAAK,IAAI,QAAQ,QACrB,EAAAA,QAAA,cAAC,QAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,IAAI,MAAOC,GAClD,EAAAD,QAAA,cAAC,SAAM,WAAW,QAAQT,CAAS,CACrC,CACF,CAEJ,CAGA,MAAMW,EAAkC,CACtC,gBAAiB,OAAOV,CAAU,IAClC,eAAgB,QAChB,mBAAoB,SACpB,iBAAkB,YAClB,aAAc,gBAAgBO,CAAM,IACpC,OAAAF,EACA,MAAAC,CACF,EAEA,OACE,EAAAE,QAAA,cAAC,QAAK,KAAK,IAAI,QAAQ,QACrB,EAAAA,QAAA,cAAC,QAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,IAAI,MAAOE,GAClD,EAAAF,QAAA,cAAC,SAAM,WAAW,QAAQT,CAAS,CACrC,CACF,CAEJ",
4
+ "sourcesContent": ["import React, { type ReactNode } from \"react\";\nimport { Card, Flex, Theme } from \"@kushagradhawan/kookie-ui\";\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\nexport function 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 // Render with no background (default card styling)\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 // Render with dots pattern background\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 // Render with custom image background\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"],
5
+ "mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,oBAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAsC,oBACtCC,EAAkC,qCAe3B,SAASH,EAAe,CAAE,SAAAI,EAAU,WAAAC,EAAa,OAAQ,gBAAAC,EAAkB,CAAC,CAAE,EAAwB,CAC3G,KAAM,CAAE,QAAAC,EAAU,GAAI,MAAAC,EAAQ,iBAAkB,gBAAAC,EAAkB,gBAAiB,OAAAC,EAAQ,MAAAC,EAAQ,OAAQ,OAAAC,EAAS,GAAI,EAAIN,EAG5H,GAAID,IAAe,OACjB,OACE,EAAAQ,QAAA,cAAC,QAAK,KAAK,IAAI,QAAQ,QACrB,EAAAA,QAAA,cAAC,QAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,KACvC,EAAAA,QAAA,cAAC,SAAM,WAAW,QAAQT,CAAS,CACrC,CACF,EAKJ,GAAIC,IAAe,OAAQ,CACzB,MAAMS,EAAiC,CACrC,gBAAiB,2BAA2BN,CAAK,yBACjD,aAAc,gBAAgBI,CAAM,IACpC,eAAgB,GAAGL,CAAO,MAAMA,CAAO,KACvC,mBAAoB,SACpB,gBAAAE,EACA,MAAAE,EACA,GAAID,GAAU,CAAE,OAAAA,CAAO,CACzB,EAEA,OACE,EAAAG,QAAA,cAAC,QAAK,KAAK,IAAI,QAAQ,QACrB,EAAAA,QAAA,cAAC,QAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,IAAI,MAAOC,GAClD,EAAAD,QAAA,cAAC,SAAM,WAAW,QAAQT,CAAS,CACrC,CACF,CAEJ,CAGA,MAAMW,EAAkC,CACtC,gBAAiB,OAAOV,CAAU,IAClC,eAAgB,QAChB,mBAAoB,SACpB,iBAAkB,YAClB,aAAc,gBAAgBO,CAAM,IACpC,MAAAD,EACA,GAAID,GAAU,CAAE,OAAAA,CAAO,CACzB,EAEA,OACE,EAAAG,QAAA,cAAC,QAAK,KAAK,IAAI,QAAQ,QACrB,EAAAA,QAAA,cAAC,QAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,IAAI,MAAOE,GAClD,EAAAF,QAAA,cAAC,SAAM,WAAW,QAAQT,CAAS,CACrC,CACF,CAEJ",
6
6
  "names": ["PreviewSection_exports", "__export", "PreviewSection", "__toCommonJS", "import_react", "import_kookie_ui", "children", "background", "backgroundProps", "dotSize", "color", "backgroundColor", "height", "width", "radius", "React", "dotsStyle", "imageStyle"]
7
7
  }
@@ -1,4 +1,4 @@
1
1
  import React from "react";
2
2
  import type { CodeBlockProps } from "./types";
3
- export declare function CodeBlock({ children, code, language, preview, showCopy, showLanguage, lightTheme, darkTheme, background, backgroundProps, }: CodeBlockProps): React.JSX.Element | null;
3
+ export declare function CodeBlock({ children, code, language, preview, showCopy, showLanguage, lightTheme, darkTheme, background, backgroundProps, }: CodeBlockProps): React.JSX.Element;
4
4
  //# sourceMappingURL=CodeBlock.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../../../src/components/code/CodeBlock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyB,MAAM,OAAO,CAAC;AAM9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAwD9C,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,4BA6ChB"}
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;AAmV9C,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 from"react";import{Card as d,Flex as p}from"@kushagradhawan/kookie-ui";import{SyntaxHighlighter as g}from"./SyntaxHighlighter";import{CopyButton as y}from"./CopyButton";import{LanguageBadge as x}from"./LanguageBadge";import{PreviewSection as C}from"./PreviewSection";function N(o){if(!o)return"text";if(typeof o=="object"&&o!==null&&"props"in o){const t=o.props;if(t?.children&&typeof t.children=="object"){const a=(t.children.props?.className||"").match(/language-([\w-]+)/i);if(a)return a[1]}const r=(t?.className||"").match(/language-([\w-]+)/i);if(r)return r[1]}return"text"}function P(o){if(!o)return"";if(typeof o=="object"&&o!==null&&"props"in o){const t=o.props;if(t?.children&&typeof t.children=="object"){const r=t.children.props?.children;if(typeof r=="string")return r}if(typeof t?.children=="string")return t.children}return typeof o=="string"?o:""}function B({children:o,code:t,language:s,preview:r,showCopy:c=!0,showLanguage:l=!0,lightTheme:a,darkTheme:m,background:f,backgroundProps:u}){let i=t,n=s;return o&&!t&&(i=P(o),n=s||N(o)),n||(n="text"),!i&&!o?null:e.createElement(p,{direction:"column",className:"code-block-wrapper",style:{minWidth:0},my:"2"},r&&e.createElement(C,{background:f,backgroundProps:u},r),e.createElement(d,{size:"2",variant:"soft"},e.createElement(p,{gap:"2",direction:"column"},e.createElement(p,{align:"start",justify:"between"},l&&e.createElement(x,{language:n}),c&&i&&e.createElement(y,{code:i})),t&&e.createElement(g,{code:t,language:n,lightTheme:a,darkTheme:m}),o&&!t&&e.createElement("div",{className:"code-block-content"},o))))}export{B as CodeBlock};
1
+ import e,{useState as C,useRef as v,useEffect as b,useCallback as L,memo as F}from"react";import{Box as g,Card as T,Flex as u,Button as E,Code as H,Theme as N}from"@kushagradhawan/kookie-ui";import{HugeiconsIcon as z}from"@hugeicons/react";import{Copy01Icon as j,Tick01Icon as B}from"@hugeicons/core-free-icons";import{codeToHtml as A}from"shiki";const h=360,J="one-light",G="one-dark-pro";function O({children:o,background:t="none",backgroundProps:s={}}){const{dotSize:n=24,color:a="var(--gray-10)",backgroundColor:d="var(--gray-2)",height:r,width:c="100%",radius:i="3"}=s;if(t==="none")return e.createElement(T,{size:"1",variant:"soft"},e.createElement(u,{justify:"center",align:"center",py:"4"},e.createElement(N,{fontFamily:"sans"},o)));if(t==="dots"){const f={backgroundImage:`radial-gradient(circle, ${a} 1px, transparent 1px)`,borderRadius:`var(--radius-${i})`,backgroundSize:`${n}px ${n}px`,backgroundPosition:"center",backgroundColor:d,width:c,...r&&{height:r}};return e.createElement(T,{size:"1",variant:"soft"},e.createElement(u,{justify:"center",align:"center",py:"4",style:f},e.createElement(N,{fontFamily:"sans"},o)))}const p={backgroundImage:`url(${t})`,backgroundSize:"cover",backgroundPosition:"center",backgroundRepeat:"no-repeat",borderRadius:`var(--radius-${i})`,width:c,...r&&{height:r}};return e.createElement(T,{size:"1",variant:"soft"},e.createElement(u,{justify:"center",align:"center",py:"4",style:p},e.createElement(N,{fontFamily:"sans"},o)))}const U=F(function({code:t,language:s,showCopy:n=!0,showLanguage:a=!0,lightTheme:d=J,darkTheme:r=G}){const[c,i]=C(null),[p,f]=C(!1),[l,y]=C(h),[S,P]=C(!1),x=v(null),m=v(null),w=l>h;b(()=>{let k=!1;return A(t,{lang:s,themes:{light:d,dark:r},defaultColor:!1}).then(D=>{k||i(D)}).catch(()=>{k||i(null)}),()=>{k=!0}},[t,s,d,r]),b(()=>{x.current&&y(x.current.scrollHeight)},[c]),b(()=>()=>{m.current&&clearTimeout(m.current)},[]);const $=L(async()=>{if(t.trim())try{await navigator.clipboard.writeText(t),P(!0),m.current&&clearTimeout(m.current),m.current=setTimeout(()=>P(!1),2e3)}catch{}},[t]),M=s==="text"?"plaintext":s,_={maxHeight:p?`${l}px`:`${h}px`};return e.createElement(g,{position:"relative"},e.createElement(T,{size:"1",variant:"soft"},e.createElement(u,{direction:"column",gap:"3"},e.createElement(u,{gap:"2",justify:"between",align:"start"},a&&e.createElement(H,{size:"1",color:"gray",highContrast:!0},M),e.createElement(u,{align:"center",gap:"2",className:"code-action-buttons"},n&&e.createElement(E,{size:"2",variant:"ghost",color:"gray",onClick:$,tooltip:S?"Copied!":"Copy","aria-label":S?"Copied!":"Copy code"},e.createElement(z,{icon:S?B:j})," Copy"))),e.createElement(g,{ref:x,style:_,className:"code-content"},c?e.createElement(g,{className:"code-block-content",width:"100%",style:{minWidth:0},dangerouslySetInnerHTML:{__html:c}}):e.createElement("pre",{className:"code-block-content"},e.createElement(H,{size:"3"},t))),w&&!p&&e.createElement(g,{className:"code-scroll-shadow visible"}))))});function X(o){if(!o)return"";if(typeof o=="object"&&o!==null&&"props"in o){const t=o.props;if(t?.children&&typeof t.children=="object"){const n=t.children.props?.children;if(typeof n=="string")return n}if(typeof t?.children=="string")return t.children}return typeof o=="string"?o:""}function I(o){if(!o)return"text";if(typeof o=="object"&&o!==null&&"props"in o){const t=o.props;if(t?.children&&typeof t.children=="object"){const r=(t.children.props?.className||"").match(/language-([\w-]+)/i);if(r)return r[1]}const n=(t?.className||"").match(/language-([\w-]+)/i);if(n)return n[1]}return"text"}function K(o){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"}[o.toLowerCase()]||o.toLowerCase()}const W=F(function({children:t,showCopy:s=!0,showLanguage:n=!0}){const[a,d]=C(!1),[r,c]=C(h),[i,p]=C(!1),f=v(null),l=v(null),y=X(t),S=I(t),P=K(S),x=r>h;b(()=>{f.current&&c(f.current.scrollHeight)},[t]),b(()=>()=>{l.current&&clearTimeout(l.current)},[]);const m=L(async()=>{if(y.trim())try{await navigator.clipboard.writeText(y),p(!0),l.current&&clearTimeout(l.current),l.current=setTimeout(()=>p(!1),2e3)}catch{}},[y]),w={maxHeight:a?`${r}px`:`${h}px`};return e.createElement(g,{position:"relative"},e.createElement(T,{size:"1",variant:"soft"},e.createElement(u,{direction:"column",gap:"3"},e.createElement(u,{gap:"2",justify:"between",align:"start"},n&&e.createElement(H,{size:"1",color:"gray",highContrast:!0},P),e.createElement(u,{align:"center",gap:"2",className:"code-action-buttons"},s&&e.createElement(E,{size:"2",variant:"ghost",color:"gray",onClick:m,tooltip:i?"Copied!":"Copy","aria-label":i?"Copied!":"Copy code"},e.createElement(z,{icon:i?B:j})," Copy"))),e.createElement(g,{ref:f,style:w,className:"code-content"},e.createElement("div",{className:"code-block-content"},t)),x&&!a&&e.createElement(g,{className:"code-scroll-shadow visible"}))))});function R({children:o,code:t,language:s,preview:n,showCopy:a=!0,showLanguage:d=!0,lightTheme:r,darkTheme:c,background:i,backgroundProps:p}){const f=t||o&&e.Children.count(o)>0,l=s||I(o)||"text";return e.createElement(g,{className:"docs-code-block",mt:"6",mb:"8"},e.createElement(u,{direction:"column",gap:"2"},n&&e.createElement(O,{background:i,backgroundProps:p},n),t&&e.createElement(U,{code:t,language:l,showCopy:a,showLanguage:d,lightTheme:r,darkTheme:c}),o&&!t&&e.createElement(W,{showCopy:a,showLanguage:d},o)))}export{R 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, { type ReactNode } from \"react\";\nimport { Card, Flex } from \"@kushagradhawan/kookie-ui\";\nimport { SyntaxHighlighter } from \"./SyntaxHighlighter\";\nimport { CopyButton } from \"./CopyButton\";\nimport { LanguageBadge } from \"./LanguageBadge\";\nimport { PreviewSection } from \"./PreviewSection\";\nimport type { CodeBlockProps } from \"./types\";\n\nfunction extractLanguageFromChildren(children?: ReactNode): string {\n if (!children) return \"text\";\n\n // Try to extract language from pre > code className\n if (typeof children === \"object\" && children !== null && \"props\" in children) {\n const childProps = (children as any).props;\n\n // If children is a <pre><code className=\"language-xxx\">\n if (childProps?.children && typeof childProps.children === \"object\") {\n const codeProps = (childProps.children as any).props;\n const className = codeProps?.className || \"\";\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n\n // Direct className on children\n const className = childProps?.className || \"\";\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n\n return \"text\";\n}\n\nfunction extractCodeFromChildren(children?: ReactNode): string {\n if (!children) return \"\";\n\n // Try to extract text from pre > code structure\n if (typeof children === \"object\" && children !== null && \"props\" in children) {\n const childProps = (children as any).props;\n\n // If children is <pre><code>...</code></pre>\n if (childProps?.children && typeof childProps.children === \"object\") {\n const codeProps = (childProps.children as any).props;\n const codeChildren = codeProps?.children;\n\n if (typeof codeChildren === \"string\") {\n return codeChildren;\n }\n }\n\n // Direct text content\n if (typeof childProps?.children === \"string\") {\n return childProps.children;\n }\n }\n\n if (typeof children === \"string\") {\n return children;\n }\n\n return \"\";\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 // Determine the code and language to display\n let displayCode = code;\n let displayLanguage = language;\n\n // If children are provided (pre-highlighted from MDX), extract code and language\n if (children && !code) {\n displayCode = extractCodeFromChildren(children);\n displayLanguage = language || extractLanguageFromChildren(children);\n }\n\n // Default language\n if (!displayLanguage) {\n displayLanguage = \"text\";\n }\n\n // If no code to display, render nothing\n if (!displayCode && !children) {\n return null;\n }\n\n return (\n <Flex direction=\"column\" className=\"code-block-wrapper\" style={{ minWidth: 0 }} my=\"2\">\n {preview && (\n <PreviewSection background={background} backgroundProps={backgroundProps}>\n {preview}\n </PreviewSection>\n )}\n\n <Card size=\"2\" variant=\"soft\">\n <Flex gap=\"2\" direction=\"column\">\n <Flex align=\"start\" justify=\"between\">\n {showLanguage && <LanguageBadge language={displayLanguage} />}\n {showCopy && displayCode && <CopyButton code={displayCode} />}\n </Flex>\n\n {/* If we have runtime code, use SyntaxHighlighter */}\n {code && <SyntaxHighlighter code={code} language={displayLanguage} lightTheme={lightTheme} darkTheme={darkTheme} />}\n\n {/* If we have pre-highlighted children from MDX, render them */}\n {children && !code && <div className=\"code-block-content\">{children}</div>}\n </Flex>\n </Card>\n </Flex>\n );\n}\n"],
5
- "mappings": "AAAA,OAAOA,MAA+B,QACtC,OAAS,QAAAC,EAAM,QAAAC,MAAY,4BAC3B,OAAS,qBAAAC,MAAyB,sBAClC,OAAS,cAAAC,MAAkB,eAC3B,OAAS,iBAAAC,MAAqB,kBAC9B,OAAS,kBAAAC,MAAsB,mBAG/B,SAASC,EAA4BC,EAA8B,CACjE,GAAI,CAACA,EAAU,MAAO,OAGtB,GAAI,OAAOA,GAAa,UAAYA,IAAa,MAAQ,UAAWA,EAAU,CAC5E,MAAMC,EAAcD,EAAiB,MAGrC,GAAIC,GAAY,UAAY,OAAOA,EAAW,UAAa,SAAU,CAGnE,MAAMC,GAFaD,EAAW,SAAiB,OAClB,WAAa,IAClB,MAAM,oBAAoB,EAClD,GAAIC,EAAO,OAAOA,EAAM,CAAC,CAC3B,CAIA,MAAMA,GADYD,GAAY,WAAa,IACnB,MAAM,oBAAoB,EAClD,GAAIC,EAAO,OAAOA,EAAM,CAAC,CAC3B,CAEA,MAAO,MACT,CAEA,SAASC,EAAwBH,EAA8B,CAC7D,GAAI,CAACA,EAAU,MAAO,GAGtB,GAAI,OAAOA,GAAa,UAAYA,IAAa,MAAQ,UAAWA,EAAU,CAC5E,MAAMC,EAAcD,EAAiB,MAGrC,GAAIC,GAAY,UAAY,OAAOA,EAAW,UAAa,SAAU,CAEnE,MAAMG,EADaH,EAAW,SAAiB,OACf,SAEhC,GAAI,OAAOG,GAAiB,SAC1B,OAAOA,CAEX,CAGA,GAAI,OAAOH,GAAY,UAAa,SAClC,OAAOA,EAAW,QAEtB,CAEA,OAAI,OAAOD,GAAa,SACfA,EAGF,EACT,CAEO,SAASK,EAAU,CACxB,SAAAL,EACA,KAAAM,EACA,SAAAC,EACA,QAAAC,EACA,SAAAC,EAAW,GACX,aAAAC,EAAe,GACf,WAAAC,EACA,UAAAC,EACA,WAAAC,EACA,gBAAAC,CACF,EAAmB,CAEjB,IAAIC,EAAcT,EACdU,EAAkBT,EActB,OAXIP,GAAY,CAACM,IACfS,EAAcZ,EAAwBH,CAAQ,EAC9CgB,EAAkBT,GAAYR,EAA4BC,CAAQ,GAI/DgB,IACHA,EAAkB,QAIhB,CAACD,GAAe,CAACf,EACZ,KAIPR,EAAA,cAACE,EAAA,CAAK,UAAU,SAAS,UAAU,qBAAqB,MAAO,CAAE,SAAU,CAAE,EAAG,GAAG,KAChFc,GACChB,EAAA,cAACM,EAAA,CAAe,WAAYe,EAAY,gBAAiBC,GACtDN,CACH,EAGFhB,EAAA,cAACC,EAAA,CAAK,KAAK,IAAI,QAAQ,QACrBD,EAAA,cAACE,EAAA,CAAK,IAAI,IAAI,UAAU,UACtBF,EAAA,cAACE,EAAA,CAAK,MAAM,QAAQ,QAAQ,WACzBgB,GAAgBlB,EAAA,cAACK,EAAA,CAAc,SAAUmB,EAAiB,EAC1DP,GAAYM,GAAevB,EAAA,cAACI,EAAA,CAAW,KAAMmB,EAAa,CAC7D,EAGCT,GAAQd,EAAA,cAACG,EAAA,CAAkB,KAAMW,EAAM,SAAUU,EAAiB,WAAYL,EAAY,UAAWC,EAAW,EAGhHZ,GAAY,CAACM,GAAQd,EAAA,cAAC,OAAI,UAAU,sBAAsBQ,CAAS,CACtE,CACF,CACF,CAEJ",
6
- "names": ["React", "Card", "Flex", "SyntaxHighlighter", "CopyButton", "LanguageBadge", "PreviewSection", "extractLanguageFromChildren", "children", "childProps", "match", "extractCodeFromChildren", "codeChildren", "CodeBlock", "code", "language", "preview", "showCopy", "showLanguage", "lightTheme", "darkTheme", "background", "backgroundProps", "displayCode", "displayLanguage"]
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 } 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 contentStyle: React.CSSProperties = {\n maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,\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 {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 if (!children) return \"\";\n if (typeof children === \"object\" && children !== null && \"props\" in children) {\n const childProps = (children as any).props;\n if (childProps?.children && typeof childProps.children === \"object\") {\n const codeProps = (childProps.children as any).props;\n const codeChildren = codeProps?.children;\n if (typeof codeChildren === \"string\") return codeChildren;\n }\n if (typeof childProps?.children === \"string\") return childProps.children;\n }\n if (typeof children === \"string\") return children;\n return \"\";\n}\n\nfunction extractLanguageFromChildren(children?: ReactNode): string {\n if (!children) return \"text\";\n if (typeof children === \"object\" && children !== null && \"props\" in children) {\n const childProps = (children as any).props;\n if (childProps?.children && typeof childProps.children === \"object\") {\n const codeProps = (childProps.children as any).props;\n const className = codeProps?.className || \"\";\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n const className = childProps?.className || \"\";\n const match = className.match(/language-([\\w-]+)/i);\n if (match) return match[1];\n }\n return \"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 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 {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": "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",
6
+ "names": ["React", "useState", "useRef", "useEffect", "useCallback", "memo", "Box", "Card", "Flex", "Button", "Code", "Theme", "HugeiconsIcon", "Copy01Icon", "Tick01Icon", "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", "contentStyle", "extractCodeFromChildren", "childProps", "codeChildren", "extractLanguageFromChildren", "match", "formatLanguageLabel", "lang", "ChildrenCodeSection", "CodeBlock", "preview", "hasCode"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import r from"react";import{Card as t,Flex as o,Theme as i}from"@kushagradhawan/kookie-ui";function S({children:e,background:n="none",backgroundProps:c={}}){const{dotSize:a=24,color:u="var(--gray-10)",backgroundColor:l="var(--gray-2)",height:s="300px",width:d="100%",radius:g="3"}=c;if(n==="none")return r.createElement(t,{size:"1",variant:"soft"},r.createElement(o,{justify:"center",align:"center",py:"4"},r.createElement(i,{fontFamily:"sans"},e)));if(n==="dots"){const y={backgroundImage:`radial-gradient(circle, ${u} 1px, transparent 1px)`,borderRadius:`var(--radius-${g})`,backgroundSize:`${a}px ${a}px`,backgroundPosition:"center",backgroundColor:l,height:s,width:d};return r.createElement(t,{size:"1",variant:"soft"},r.createElement(o,{justify:"center",align:"center",py:"4",style:y},r.createElement(i,{fontFamily:"sans"},e)))}const p={backgroundImage:`url(${n})`,backgroundSize:"cover",backgroundPosition:"center",backgroundRepeat:"no-repeat",borderRadius:`var(--radius-${g})`,height:s,width:d};return r.createElement(t,{size:"1",variant:"soft"},r.createElement(o,{justify:"center",align:"center",py:"4",style:p},r.createElement(i,{fontFamily:"sans"},e)))}export{S as PreviewSection};
1
+ import r from"react";import{Card as o,Flex as i,Theme as a}from"@kushagradhawan/kookie-ui";function S({children:n,background:t="none",backgroundProps:c={}}){const{dotSize:s=24,color:u="var(--gray-10)",backgroundColor:l="var(--gray-2)",height:e,width:d="100%",radius:g="3"}=c;if(t==="none")return r.createElement(o,{size:"1",variant:"soft"},r.createElement(i,{justify:"center",align:"center",py:"4"},r.createElement(a,{fontFamily:"sans"},n)));if(t==="dots"){const y={backgroundImage:`radial-gradient(circle, ${u} 1px, transparent 1px)`,borderRadius:`var(--radius-${g})`,backgroundSize:`${s}px ${s}px`,backgroundPosition:"center",backgroundColor:l,width:d,...e&&{height:e}};return r.createElement(o,{size:"1",variant:"soft"},r.createElement(i,{justify:"center",align:"center",py:"4",style:y},r.createElement(a,{fontFamily:"sans"},n)))}const p={backgroundImage:`url(${t})`,backgroundSize:"cover",backgroundPosition:"center",backgroundRepeat:"no-repeat",borderRadius:`var(--radius-${g})`,width:d,...e&&{height:e}};return r.createElement(o,{size:"1",variant:"soft"},r.createElement(i,{justify:"center",align:"center",py:"4",style:p},r.createElement(a,{fontFamily:"sans"},n)))}export{S as PreviewSection};
2
2
  //# sourceMappingURL=PreviewSection.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/components/code/PreviewSection.tsx"],
4
- "sourcesContent": ["import React, { type ReactNode } from \"react\";\nimport { Card, Flex, Theme } from \"@kushagradhawan/kookie-ui\";\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\nexport function PreviewSection({ children, background = \"none\", backgroundProps = {} }: PreviewSectionProps) {\n const { dotSize = 24, color = \"var(--gray-10)\", backgroundColor = \"var(--gray-2)\", height = \"300px\", width = \"100%\", radius = \"3\" } = backgroundProps;\n\n // Render with no background (default card styling)\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 // Render with dots pattern background\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 height,\n width,\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 // Render with custom image background\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 height,\n width,\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"],
5
- "mappings": "AAAA,OAAOA,MAA+B,QACtC,OAAS,QAAAC,EAAM,QAAAC,EAAM,SAAAC,MAAa,4BAe3B,SAASC,EAAe,CAAE,SAAAC,EAAU,WAAAC,EAAa,OAAQ,gBAAAC,EAAkB,CAAC,CAAE,EAAwB,CAC3G,KAAM,CAAE,QAAAC,EAAU,GAAI,MAAAC,EAAQ,iBAAkB,gBAAAC,EAAkB,gBAAiB,OAAAC,EAAS,QAAS,MAAAC,EAAQ,OAAQ,OAAAC,EAAS,GAAI,EAAIN,EAGtI,GAAID,IAAe,OACjB,OACEN,EAAA,cAACC,EAAA,CAAK,KAAK,IAAI,QAAQ,QACrBD,EAAA,cAACE,EAAA,CAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,KACvCF,EAAA,cAACG,EAAA,CAAM,WAAW,QAAQE,CAAS,CACrC,CACF,EAKJ,GAAIC,IAAe,OAAQ,CACzB,MAAMQ,EAAiC,CACrC,gBAAiB,2BAA2BL,CAAK,yBACjD,aAAc,gBAAgBI,CAAM,IACpC,eAAgB,GAAGL,CAAO,MAAMA,CAAO,KACvC,mBAAoB,SACpB,gBAAAE,EACA,OAAAC,EACA,MAAAC,CACF,EAEA,OACEZ,EAAA,cAACC,EAAA,CAAK,KAAK,IAAI,QAAQ,QACrBD,EAAA,cAACE,EAAA,CAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,IAAI,MAAOY,GAClDd,EAAA,cAACG,EAAA,CAAM,WAAW,QAAQE,CAAS,CACrC,CACF,CAEJ,CAGA,MAAMU,EAAkC,CACtC,gBAAiB,OAAOT,CAAU,IAClC,eAAgB,QAChB,mBAAoB,SACpB,iBAAkB,YAClB,aAAc,gBAAgBO,CAAM,IACpC,OAAAF,EACA,MAAAC,CACF,EAEA,OACEZ,EAAA,cAACC,EAAA,CAAK,KAAK,IAAI,QAAQ,QACrBD,EAAA,cAACE,EAAA,CAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,IAAI,MAAOa,GAClDf,EAAA,cAACG,EAAA,CAAM,WAAW,QAAQE,CAAS,CACrC,CACF,CAEJ",
4
+ "sourcesContent": ["import React, { type ReactNode } from \"react\";\nimport { Card, Flex, Theme } from \"@kushagradhawan/kookie-ui\";\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\nexport function 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 // Render with no background (default card styling)\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 // Render with dots pattern background\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 // Render with custom image background\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"],
5
+ "mappings": "AAAA,OAAOA,MAA+B,QACtC,OAAS,QAAAC,EAAM,QAAAC,EAAM,SAAAC,MAAa,4BAe3B,SAASC,EAAe,CAAE,SAAAC,EAAU,WAAAC,EAAa,OAAQ,gBAAAC,EAAkB,CAAC,CAAE,EAAwB,CAC3G,KAAM,CAAE,QAAAC,EAAU,GAAI,MAAAC,EAAQ,iBAAkB,gBAAAC,EAAkB,gBAAiB,OAAAC,EAAQ,MAAAC,EAAQ,OAAQ,OAAAC,EAAS,GAAI,EAAIN,EAG5H,GAAID,IAAe,OACjB,OACEN,EAAA,cAACC,EAAA,CAAK,KAAK,IAAI,QAAQ,QACrBD,EAAA,cAACE,EAAA,CAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,KACvCF,EAAA,cAACG,EAAA,CAAM,WAAW,QAAQE,CAAS,CACrC,CACF,EAKJ,GAAIC,IAAe,OAAQ,CACzB,MAAMQ,EAAiC,CACrC,gBAAiB,2BAA2BL,CAAK,yBACjD,aAAc,gBAAgBI,CAAM,IACpC,eAAgB,GAAGL,CAAO,MAAMA,CAAO,KACvC,mBAAoB,SACpB,gBAAAE,EACA,MAAAE,EACA,GAAID,GAAU,CAAE,OAAAA,CAAO,CACzB,EAEA,OACEX,EAAA,cAACC,EAAA,CAAK,KAAK,IAAI,QAAQ,QACrBD,EAAA,cAACE,EAAA,CAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,IAAI,MAAOY,GAClDd,EAAA,cAACG,EAAA,CAAM,WAAW,QAAQE,CAAS,CACrC,CACF,CAEJ,CAGA,MAAMU,EAAkC,CACtC,gBAAiB,OAAOT,CAAU,IAClC,eAAgB,QAChB,mBAAoB,SACpB,iBAAkB,YAClB,aAAc,gBAAgBO,CAAM,IACpC,MAAAD,EACA,GAAID,GAAU,CAAE,OAAAA,CAAO,CACzB,EAEA,OACEX,EAAA,cAACC,EAAA,CAAK,KAAK,IAAI,QAAQ,QACrBD,EAAA,cAACE,EAAA,CAAK,QAAQ,SAAS,MAAM,SAAS,GAAG,IAAI,MAAOa,GAClDf,EAAA,cAACG,EAAA,CAAM,WAAW,QAAQE,CAAS,CACrC,CACF,CAEJ",
6
6
  "names": ["React", "Card", "Flex", "Theme", "PreviewSection", "children", "background", "backgroundProps", "dotSize", "color", "backgroundColor", "height", "width", "radius", "dotsStyle", "imageStyle"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kushagradhawan/kookie-blocks",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/KushagraDhawan1997/kookie-blocks.git"
@@ -93,10 +93,10 @@
93
93
  "dependencies": {
94
94
  "@hugeicons/core-free-icons": "^2.0.0",
95
95
  "@hugeicons/react": "^1.1.1",
96
- "@kushagradhawan/kookie-ui": "latest",
97
96
  "shiki": "^1.24.2"
98
97
  },
99
98
  "peerDependencies": {
99
+ "@kushagradhawan/kookie-ui": ">=0.1.0",
100
100
  "react": "^18.0.0 || ^19.0.0",
101
101
  "react-dom": "^18.0.0 || ^19.0.0"
102
102
  },
@@ -1,64 +1,346 @@
1
- import React, { type ReactNode } from "react";
2
- import { Card, Flex } from "@kushagradhawan/kookie-ui";
3
- import { SyntaxHighlighter } from "./SyntaxHighlighter";
4
- import { CopyButton } from "./CopyButton";
5
- import { LanguageBadge } from "./LanguageBadge";
6
- import { PreviewSection } from "./PreviewSection";
1
+ import React, { useState, useRef, useEffect, useCallback, memo, type ReactNode } from "react";
2
+ import { Box, Card, Flex, Button, Code, Theme } from "@kushagradhawan/kookie-ui";
3
+ import { HugeiconsIcon } from "@hugeicons/react";
4
+ import { Copy01Icon, Tick01Icon } from "@hugeicons/core-free-icons";
5
+ import { codeToHtml } from "shiki";
7
6
  import type { CodeBlockProps } from "./types";
8
7
 
9
- function extractLanguageFromChildren(children?: ReactNode): string {
10
- if (!children) return "text";
8
+ const COLLAPSED_HEIGHT = 360;
9
+ const DEFAULT_LIGHT_THEME = "one-light";
10
+ const DEFAULT_DARK_THEME = "one-dark-pro";
11
+
12
+ // ============================================
13
+ // Preview Section
14
+ // ============================================
15
+
16
+ interface PreviewSectionProps {
17
+ children: ReactNode;
18
+ background?: "none" | "dots" | string;
19
+ backgroundProps?: {
20
+ dotSize?: number;
21
+ color?: string;
22
+ backgroundColor?: string;
23
+ height?: string;
24
+ width?: string;
25
+ radius?: string;
26
+ };
27
+ }
28
+
29
+ function PreviewSection({ children, background = "none", backgroundProps = {} }: PreviewSectionProps) {
30
+ const { dotSize = 24, color = "var(--gray-10)", backgroundColor = "var(--gray-2)", height, width = "100%", radius = "3" } = backgroundProps;
31
+
32
+ if (background === "none") {
33
+ return (
34
+ <Card size="1" variant="soft">
35
+ <Flex justify="center" align="center" py="4">
36
+ <Theme fontFamily="sans">{children}</Theme>
37
+ </Flex>
38
+ </Card>
39
+ );
40
+ }
41
+
42
+ if (background === "dots") {
43
+ const dotsStyle: React.CSSProperties = {
44
+ backgroundImage: `radial-gradient(circle, ${color} 1px, transparent 1px)`,
45
+ borderRadius: `var(--radius-${radius})`,
46
+ backgroundSize: `${dotSize}px ${dotSize}px`,
47
+ backgroundPosition: "center",
48
+ backgroundColor,
49
+ width,
50
+ ...(height && { height }),
51
+ };
52
+
53
+ return (
54
+ <Card size="1" variant="soft">
55
+ <Flex justify="center" align="center" py="4" style={dotsStyle}>
56
+ <Theme fontFamily="sans">{children}</Theme>
57
+ </Flex>
58
+ </Card>
59
+ );
60
+ }
61
+
62
+ const imageStyle: React.CSSProperties = {
63
+ backgroundImage: `url(${background})`,
64
+ backgroundSize: "cover",
65
+ backgroundPosition: "center",
66
+ backgroundRepeat: "no-repeat",
67
+ borderRadius: `var(--radius-${radius})`,
68
+ width,
69
+ ...(height && { height }),
70
+ };
71
+
72
+ return (
73
+ <Card size="1" variant="soft">
74
+ <Flex justify="center" align="center" py="4" style={imageStyle}>
75
+ <Theme fontFamily="sans">{children}</Theme>
76
+ </Flex>
77
+ </Card>
78
+ );
79
+ }
80
+
81
+ // ============================================
82
+ // Code Section (for runtime highlighting)
83
+ // ============================================
11
84
 
12
- // Try to extract language from pre > code className
85
+ interface CodeSectionProps {
86
+ code: string;
87
+ language: string;
88
+ showCopy?: boolean;
89
+ showLanguage?: boolean;
90
+ lightTheme?: string;
91
+ darkTheme?: string;
92
+ }
93
+
94
+ const CodeSection = memo(function CodeSection({
95
+ code,
96
+ language,
97
+ showCopy = true,
98
+ showLanguage = true,
99
+ lightTheme = DEFAULT_LIGHT_THEME,
100
+ darkTheme = DEFAULT_DARK_THEME,
101
+ }: CodeSectionProps) {
102
+ const [highlighted, setHighlighted] = useState<string | null>(null);
103
+ const [isExpanded, setIsExpanded] = useState(false);
104
+ const [contentHeight, setContentHeight] = useState(COLLAPSED_HEIGHT);
105
+ const [copied, setCopied] = useState(false);
106
+ const contentRef = useRef<HTMLDivElement>(null);
107
+ const resetTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
108
+
109
+ const shouldShowToggle = contentHeight > COLLAPSED_HEIGHT;
110
+
111
+ useEffect(() => {
112
+ let cancelled = false;
113
+ codeToHtml(code, {
114
+ lang: language,
115
+ themes: { light: lightTheme, dark: darkTheme },
116
+ defaultColor: false,
117
+ })
118
+ .then((html) => {
119
+ if (!cancelled) setHighlighted(html);
120
+ })
121
+ .catch(() => {
122
+ if (!cancelled) setHighlighted(null);
123
+ });
124
+ return () => {
125
+ cancelled = true;
126
+ };
127
+ }, [code, language, lightTheme, darkTheme]);
128
+
129
+ useEffect(() => {
130
+ if (contentRef.current) {
131
+ setContentHeight(contentRef.current.scrollHeight);
132
+ }
133
+ }, [highlighted]);
134
+
135
+ useEffect(() => {
136
+ return () => {
137
+ if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);
138
+ };
139
+ }, []);
140
+
141
+ const handleCopy = useCallback(async () => {
142
+ if (!code.trim()) return;
143
+ try {
144
+ await navigator.clipboard.writeText(code);
145
+ setCopied(true);
146
+ if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);
147
+ resetTimeoutRef.current = setTimeout(() => setCopied(false), 2000);
148
+ } catch {
149
+ // Silently fail
150
+ }
151
+ }, [code]);
152
+
153
+ const displayLanguage = language === "text" ? "plaintext" : language;
154
+
155
+ const contentStyle: React.CSSProperties = {
156
+ maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,
157
+ };
158
+
159
+ return (
160
+ <Box position="relative">
161
+ <Card size="1" variant="soft">
162
+ <Flex direction="column" gap="3">
163
+ <Flex gap="2" justify="between" align="start">
164
+ {showLanguage && (
165
+ <Code size="1" color="gray" highContrast>
166
+ {displayLanguage}
167
+ </Code>
168
+ )}
169
+ <Flex align="center" gap="2" className="code-action-buttons">
170
+ {showCopy && (
171
+ <Button
172
+ size="2"
173
+ variant="ghost"
174
+ color="gray"
175
+ onClick={handleCopy}
176
+ tooltip={copied ? "Copied!" : "Copy"}
177
+ aria-label={copied ? "Copied!" : "Copy code"}
178
+ >
179
+ <HugeiconsIcon icon={copied ? Tick01Icon : Copy01Icon} /> Copy
180
+ </Button>
181
+ )}
182
+ </Flex>
183
+ </Flex>
184
+
185
+ <Box ref={contentRef} style={contentStyle} className="code-content">
186
+ {highlighted ? (
187
+ <Box className="code-block-content" width="100%" style={{ minWidth: 0 }} dangerouslySetInnerHTML={{ __html: highlighted }} />
188
+ ) : (
189
+ <pre className="code-block-content">
190
+ <Code size="3">{code}</Code>
191
+ </pre>
192
+ )}
193
+ </Box>
194
+
195
+ {shouldShowToggle && !isExpanded && <Box className="code-scroll-shadow visible" />}
196
+ </Flex>
197
+ </Card>
198
+ </Box>
199
+ );
200
+ });
201
+
202
+ // ============================================
203
+ // Children Code Section (for pre-highlighted MDX)
204
+ // ============================================
205
+
206
+ interface ChildrenCodeSectionProps {
207
+ children: ReactNode;
208
+ showCopy?: boolean;
209
+ showLanguage?: boolean;
210
+ }
211
+
212
+ function extractCodeFromChildren(children?: ReactNode): string {
213
+ if (!children) return "";
13
214
  if (typeof children === "object" && children !== null && "props" in children) {
14
215
  const childProps = (children as any).props;
216
+ if (childProps?.children && typeof childProps.children === "object") {
217
+ const codeProps = (childProps.children as any).props;
218
+ const codeChildren = codeProps?.children;
219
+ if (typeof codeChildren === "string") return codeChildren;
220
+ }
221
+ if (typeof childProps?.children === "string") return childProps.children;
222
+ }
223
+ if (typeof children === "string") return children;
224
+ return "";
225
+ }
15
226
 
16
- // If children is a <pre><code className="language-xxx">
227
+ function extractLanguageFromChildren(children?: ReactNode): string {
228
+ if (!children) return "text";
229
+ if (typeof children === "object" && children !== null && "props" in children) {
230
+ const childProps = (children as any).props;
17
231
  if (childProps?.children && typeof childProps.children === "object") {
18
232
  const codeProps = (childProps.children as any).props;
19
233
  const className = codeProps?.className || "";
20
234
  const match = className.match(/language-([\w-]+)/i);
21
235
  if (match) return match[1];
22
236
  }
23
-
24
- // Direct className on children
25
237
  const className = childProps?.className || "";
26
238
  const match = className.match(/language-([\w-]+)/i);
27
239
  if (match) return match[1];
28
240
  }
29
-
30
241
  return "text";
31
242
  }
32
243
 
33
- function extractCodeFromChildren(children?: ReactNode): string {
34
- if (!children) return "";
244
+ function formatLanguageLabel(lang: string): string {
245
+ const aliasMap: Record<string, string> = {
246
+ tsx: "TSX",
247
+ ts: "TS",
248
+ jsx: "JSX",
249
+ js: "JS",
250
+ javascript: "JS",
251
+ typescript: "TS",
252
+ css: "CSS",
253
+ html: "HTML",
254
+ json: "JSON",
255
+ bash: "SH",
256
+ sh: "SH",
257
+ shell: "SH",
258
+ text: "plaintext",
259
+ };
260
+ return aliasMap[lang.toLowerCase()] || lang.toLowerCase();
261
+ }
35
262
 
36
- // Try to extract text from pre > code structure
37
- if (typeof children === "object" && children !== null && "props" in children) {
38
- const childProps = (children as any).props;
263
+ const ChildrenCodeSection = memo(function ChildrenCodeSection({ children, showCopy = true, showLanguage = true }: ChildrenCodeSectionProps) {
264
+ const [isExpanded, setIsExpanded] = useState(false);
265
+ const [contentHeight, setContentHeight] = useState(COLLAPSED_HEIGHT);
266
+ const [copied, setCopied] = useState(false);
267
+ const contentRef = useRef<HTMLDivElement>(null);
268
+ const resetTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
39
269
 
40
- // If children is <pre><code>...</code></pre>
41
- if (childProps?.children && typeof childProps.children === "object") {
42
- const codeProps = (childProps.children as any).props;
43
- const codeChildren = codeProps?.children;
270
+ const code = extractCodeFromChildren(children);
271
+ const language = extractLanguageFromChildren(children);
272
+ const displayLanguage = formatLanguageLabel(language);
273
+
274
+ const shouldShowToggle = contentHeight > COLLAPSED_HEIGHT;
44
275
 
45
- if (typeof codeChildren === "string") {
46
- return codeChildren;
47
- }
276
+ useEffect(() => {
277
+ if (contentRef.current) {
278
+ setContentHeight(contentRef.current.scrollHeight);
48
279
  }
280
+ }, [children]);
281
+
282
+ useEffect(() => {
283
+ return () => {
284
+ if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);
285
+ };
286
+ }, []);
49
287
 
50
- // Direct text content
51
- if (typeof childProps?.children === "string") {
52
- return childProps.children;
288
+ const handleCopy = useCallback(async () => {
289
+ if (!code.trim()) return;
290
+ try {
291
+ await navigator.clipboard.writeText(code);
292
+ setCopied(true);
293
+ if (resetTimeoutRef.current) clearTimeout(resetTimeoutRef.current);
294
+ resetTimeoutRef.current = setTimeout(() => setCopied(false), 2000);
295
+ } catch {
296
+ // Silently fail
53
297
  }
54
- }
298
+ }, [code]);
55
299
 
56
- if (typeof children === "string") {
57
- return children;
58
- }
300
+ const contentStyle: React.CSSProperties = {
301
+ maxHeight: isExpanded ? `${contentHeight}px` : `${COLLAPSED_HEIGHT}px`,
302
+ };
59
303
 
60
- return "";
61
- }
304
+ return (
305
+ <Box position="relative">
306
+ <Card size="1" variant="soft">
307
+ <Flex direction="column" gap="3">
308
+ <Flex gap="2" justify="between" align="start">
309
+ {showLanguage && (
310
+ <Code size="1" color="gray" highContrast>
311
+ {displayLanguage}
312
+ </Code>
313
+ )}
314
+ <Flex align="center" gap="2" className="code-action-buttons">
315
+ {showCopy && (
316
+ <Button
317
+ size="2"
318
+ variant="ghost"
319
+ color="gray"
320
+ onClick={handleCopy}
321
+ tooltip={copied ? "Copied!" : "Copy"}
322
+ aria-label={copied ? "Copied!" : "Copy code"}
323
+ >
324
+ <HugeiconsIcon icon={copied ? Tick01Icon : Copy01Icon} /> Copy
325
+ </Button>
326
+ )}
327
+ </Flex>
328
+ </Flex>
329
+
330
+ <Box ref={contentRef} style={contentStyle} className="code-content">
331
+ <div className="code-block-content">{children}</div>
332
+ </Box>
333
+
334
+ {shouldShowToggle && !isExpanded && <Box className="code-scroll-shadow visible" />}
335
+ </Flex>
336
+ </Card>
337
+ </Box>
338
+ );
339
+ });
340
+
341
+ // ============================================
342
+ // Main CodeBlock Component
343
+ // ============================================
62
344
 
63
345
  export function CodeBlock({
64
346
  children,
@@ -72,48 +354,28 @@ export function CodeBlock({
72
354
  background,
73
355
  backgroundProps,
74
356
  }: CodeBlockProps) {
75
- // Determine the code and language to display
76
- let displayCode = code;
77
- let displayLanguage = language;
78
-
79
- // If children are provided (pre-highlighted from MDX), extract code and language
80
- if (children && !code) {
81
- displayCode = extractCodeFromChildren(children);
82
- displayLanguage = language || extractLanguageFromChildren(children);
83
- }
84
-
85
- // Default language
86
- if (!displayLanguage) {
87
- displayLanguage = "text";
88
- }
89
-
90
- // If no code to display, render nothing
91
- if (!displayCode && !children) {
92
- return null;
93
- }
357
+ const hasCode = code || (children && React.Children.count(children) > 0);
358
+ const displayLanguage = language || extractLanguageFromChildren(children) || "text";
94
359
 
95
360
  return (
96
- <Flex direction="column" className="code-block-wrapper" style={{ minWidth: 0 }} my="2">
97
- {preview && (
98
- <PreviewSection background={background} backgroundProps={backgroundProps}>
99
- {preview}
100
- </PreviewSection>
101
- )}
102
-
103
- <Card size="2" variant="soft">
104
- <Flex gap="2" direction="column">
105
- <Flex align="start" justify="between">
106
- {showLanguage && <LanguageBadge language={displayLanguage} />}
107
- {showCopy && displayCode && <CopyButton code={displayCode} />}
108
- </Flex>
361
+ <Box className="docs-code-block" mt="6" mb="8">
362
+ <Flex direction="column" gap="2">
363
+ {preview && (
364
+ <PreviewSection background={background} backgroundProps={backgroundProps}>
365
+ {preview}
366
+ </PreviewSection>
367
+ )}
109
368
 
110
- {/* If we have runtime code, use SyntaxHighlighter */}
111
- {code && <SyntaxHighlighter code={code} language={displayLanguage} lightTheme={lightTheme} darkTheme={darkTheme} />}
369
+ {code && (
370
+ <CodeSection code={code} language={displayLanguage} showCopy={showCopy} showLanguage={showLanguage} lightTheme={lightTheme} darkTheme={darkTheme} />
371
+ )}
112
372
 
113
- {/* If we have pre-highlighted children from MDX, render them */}
114
- {children && !code && <div className="code-block-content">{children}</div>}
115
- </Flex>
116
- </Card>
117
- </Flex>
373
+ {children && !code && (
374
+ <ChildrenCodeSection showCopy={showCopy} showLanguage={showLanguage}>
375
+ {children}
376
+ </ChildrenCodeSection>
377
+ )}
378
+ </Flex>
379
+ </Box>
118
380
  );
119
381
  }
@@ -15,7 +15,7 @@ interface PreviewSectionProps {
15
15
  }
16
16
 
17
17
  export function PreviewSection({ children, background = "none", backgroundProps = {} }: PreviewSectionProps) {
18
- const { dotSize = 24, color = "var(--gray-10)", backgroundColor = "var(--gray-2)", height = "300px", width = "100%", radius = "3" } = backgroundProps;
18
+ const { dotSize = 24, color = "var(--gray-10)", backgroundColor = "var(--gray-2)", height, width = "100%", radius = "3" } = backgroundProps;
19
19
 
20
20
  // Render with no background (default card styling)
21
21
  if (background === "none") {
@@ -36,8 +36,8 @@ export function PreviewSection({ children, background = "none", backgroundProps
36
36
  backgroundSize: `${dotSize}px ${dotSize}px`,
37
37
  backgroundPosition: "center",
38
38
  backgroundColor,
39
- height,
40
39
  width,
40
+ ...(height && { height }),
41
41
  };
42
42
 
43
43
  return (
@@ -56,8 +56,8 @@ export function PreviewSection({ children, background = "none", backgroundProps
56
56
  backgroundPosition: "center",
57
57
  backgroundRepeat: "no-repeat",
58
58
  borderRadius: `var(--radius-${radius})`,
59
- height,
60
59
  width,
60
+ ...(height && { height }),
61
61
  };
62
62
 
63
63
  return (
@@ -1,15 +1,19 @@
1
- /* Components CSS aggregator for Kookie Blocks (e.g., hero variants if styled). */
1
+ /* Components CSS aggregator for Kookie Blocks */
2
2
 
3
3
  /* ============================================
4
4
  Code Block Component Styles
5
5
  ============================================ */
6
6
 
7
- /* Code block wrapper - constrain width in flex containers */
8
- .code-block-wrapper {
9
- min-width: 0;
10
- max-width: 100%;
7
+ /* Main docs code block wrapper */
8
+ .docs-code-block {
11
9
  width: 100%;
10
+ }
11
+
12
+ /* Code content area - handles expand/collapse */
13
+ .code-content {
12
14
  overflow: hidden;
15
+ transition: max-height 0.3s ease-in-out;
16
+ position: relative;
13
17
  }
14
18
 
15
19
  /* Code block content (the pre part, below the header) */
@@ -52,14 +56,17 @@
52
56
  height: 0 !important;
53
57
  }
54
58
 
55
- .code-block-wrapper pre,
56
- .code-block-wrapper .code-block-content pre {
57
- overflow-x: visible; /* Let .code-block-content handle scrolling */
59
+ /* Pre elements inside code content */
60
+ .code-content pre,
61
+ .code-block-content pre {
62
+ overflow-x: visible;
58
63
  max-width: 100%;
59
64
  min-width: 0;
60
65
  margin: 0;
61
66
  width: 100%;
62
67
  box-sizing: border-box;
68
+ scrollbar-width: none;
69
+ -ms-overflow-style: none;
63
70
  }
64
71
 
65
72
  /* Ensure Shiki-generated pre elements fill width */
@@ -69,8 +76,8 @@
69
76
  }
70
77
 
71
78
  /* Code elements inside pre */
72
- .code-block-wrapper pre code,
73
- .code-block-wrapper .code-block-content pre code {
79
+ .code-content pre code,
80
+ .code-block-content pre code {
74
81
  font-family: var(--font-mono);
75
82
  font-size: var(--font-size-2);
76
83
  line-height: 1.75;
@@ -82,16 +89,16 @@
82
89
  }
83
90
 
84
91
  /* Shiki line spans */
85
- .code-block-wrapper pre code .line,
86
- .code-block-wrapper .code-block-content pre code .line {
92
+ .code-content pre code .line,
93
+ .code-block-content pre code .line {
87
94
  display: flex;
88
95
  align-items: center;
89
96
  gap: 0;
90
97
  }
91
98
 
92
99
  /* Line numbers */
93
- .code-block-wrapper pre code .line::before,
94
- .code-block-wrapper .code-block-content pre code .line::before {
100
+ .code-content pre code .line::before,
101
+ .code-block-content pre code .line::before {
95
102
  counter-increment: line;
96
103
  content: counter(line);
97
104
  display: inline-block;
@@ -104,8 +111,37 @@
104
111
  margin-right: var(--space-4);
105
112
  }
106
113
 
114
+ /* Scroll shadow overlay for collapsed state */
115
+ .code-scroll-shadow {
116
+ position: absolute;
117
+ bottom: 0;
118
+ left: 0;
119
+ right: 0;
120
+ height: 80px;
121
+ background: linear-gradient(to top, var(--color-panel-solid), transparent);
122
+ pointer-events: none;
123
+ opacity: 0;
124
+ transition: opacity 0.2s ease-in-out;
125
+ z-index: 1;
126
+ }
127
+
128
+ .code-scroll-shadow.visible {
129
+ opacity: 1;
130
+ }
131
+
132
+ /* Action buttons styling */
133
+ .code-action-buttons {
134
+ flex-shrink: 0;
135
+ }
136
+
137
+ /* Chevron rotation animation */
138
+ .code-chevron {
139
+ transition: transform 0.2s ease-in-out;
140
+ }
141
+
107
142
  /* Default to light theme for all tokens (codeToHtml with defaultColor: false) */
108
- .code-block-wrapper pre.shiki span {
143
+ .code-block-content pre.shiki span,
144
+ .code-content pre.shiki span {
109
145
  color: var(--shiki-light) !important;
110
146
  font-style: var(--shiki-light-font-style);
111
147
  font-weight: var(--shiki-light-font-weight);
@@ -113,9 +149,12 @@
113
149
  }
114
150
 
115
151
  /* Override with dark theme colors when inside a dark context */
116
- .dark .code-block-wrapper pre.shiki span,
117
- .dark-theme .code-block-wrapper pre.shiki span,
118
- [data-appearance="dark"] .code-block-wrapper pre.shiki span {
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
+ .dark .code-content pre.shiki span,
156
+ .dark-theme .code-content pre.shiki span,
157
+ [data-appearance="dark"] .code-content pre.shiki span {
119
158
  color: var(--shiki-dark) !important;
120
159
  font-style: var(--shiki-dark-font-style);
121
160
  font-weight: var(--shiki-dark-font-weight);
package/styles.css CHANGED
@@ -1,14 +1,17 @@
1
1
  /* Kookie Blocks base styles. Keep minimal; rely on Kookie UI tokens/utilities. */
2
- /* Components CSS aggregator for Kookie Blocks (e.g., hero variants if styled). */
2
+ /* Components CSS aggregator for Kookie Blocks */
3
3
  /* ============================================
4
4
  Code Block Component Styles
5
5
  ============================================ */
6
- /* Code block wrapper - constrain width in flex containers */
7
- .code-block-wrapper {
8
- min-width: 0;
9
- max-width: 100%;
6
+ /* Main docs code block wrapper */
7
+ .docs-code-block {
10
8
  width: 100%;
9
+ }
10
+ /* Code content area - handles expand/collapse */
11
+ .code-content {
11
12
  overflow: hidden;
13
+ transition: max-height 0.3s ease-in-out;
14
+ position: relative;
12
15
  }
13
16
  /* Code block content (the pre part, below the header) */
14
17
  .code-block-content {
@@ -47,14 +50,17 @@
47
50
  width: 0 !important;
48
51
  height: 0 !important;
49
52
  }
50
- .code-block-wrapper pre,
51
- .code-block-wrapper .code-block-content pre {
52
- overflow-x: visible; /* Let .code-block-content handle scrolling */
53
+ /* Pre elements inside code content */
54
+ .code-content pre,
55
+ .code-block-content pre {
56
+ overflow-x: visible;
53
57
  max-width: 100%;
54
58
  min-width: 0;
55
59
  margin: 0;
56
60
  width: 100%;
57
61
  box-sizing: border-box;
62
+ scrollbar-width: none;
63
+ -ms-overflow-style: none;
58
64
  }
59
65
  /* Ensure Shiki-generated pre elements fill width */
60
66
  .code-block-content > pre {
@@ -62,8 +68,8 @@
62
68
  min-width: 0;
63
69
  }
64
70
  /* Code elements inside pre */
65
- .code-block-wrapper pre code,
66
- .code-block-wrapper .code-block-content pre code {
71
+ .code-content pre code,
72
+ .code-block-content pre code {
67
73
  font-family: var(--font-mono);
68
74
  font-size: var(--font-size-2);
69
75
  line-height: 1.75;
@@ -74,15 +80,15 @@
74
80
  counter-reset: line;
75
81
  }
76
82
  /* Shiki line spans */
77
- .code-block-wrapper pre code .line,
78
- .code-block-wrapper .code-block-content pre code .line {
83
+ .code-content pre code .line,
84
+ .code-block-content pre code .line {
79
85
  display: flex;
80
86
  align-items: center;
81
87
  gap: 0;
82
88
  }
83
89
  /* Line numbers */
84
- .code-block-wrapper pre code .line::before,
85
- .code-block-wrapper .code-block-content pre code .line::before {
90
+ .code-content pre code .line::before,
91
+ .code-block-content pre code .line::before {
86
92
  counter-increment: line;
87
93
  content: counter(line);
88
94
  display: inline-block;
@@ -96,8 +102,33 @@
96
102
  flex-shrink: 0;
97
103
  margin-right: var(--space-4);
98
104
  }
105
+ /* Scroll shadow overlay for collapsed state */
106
+ .code-scroll-shadow {
107
+ position: absolute;
108
+ bottom: 0;
109
+ left: 0;
110
+ right: 0;
111
+ height: 80px;
112
+ background: linear-gradient(to top, var(--color-panel-solid), transparent);
113
+ pointer-events: none;
114
+ opacity: 0;
115
+ transition: opacity 0.2s ease-in-out;
116
+ z-index: 1;
117
+ }
118
+ .code-scroll-shadow.visible {
119
+ opacity: 1;
120
+ }
121
+ /* Action buttons styling */
122
+ .code-action-buttons {
123
+ flex-shrink: 0;
124
+ }
125
+ /* Chevron rotation animation */
126
+ .code-chevron {
127
+ transition: transform 0.2s ease-in-out;
128
+ }
99
129
  /* Default to light theme for all tokens (codeToHtml with defaultColor: false) */
100
- .code-block-wrapper pre.shiki span {
130
+ .code-block-content pre.shiki span,
131
+ .code-content pre.shiki span {
101
132
  color: var(--shiki-light) !important;
102
133
  font-style: var(--shiki-light-font-style);
103
134
  font-weight: var(--shiki-light-font-weight);
@@ -105,9 +136,12 @@
105
136
  text-decoration: var(--shiki-light-text-decoration);
106
137
  }
107
138
  /* Override with dark theme colors when inside a dark context */
108
- .dark .code-block-wrapper pre.shiki span,
109
- .dark-theme .code-block-wrapper pre.shiki span,
110
- [data-appearance="dark"] .code-block-wrapper pre.shiki span {
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
+ .dark .code-content pre.shiki span,
143
+ .dark-theme .code-content pre.shiki span,
144
+ [data-appearance="dark"] .code-content pre.shiki span {
111
145
  color: var(--shiki-dark) !important;
112
146
  font-style: var(--shiki-dark-font-style);
113
147
  font-weight: var(--shiki-dark-font-weight);