bertui-code 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +360 -0
- package/dist/bertui-code.css +275 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +2 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# 🎨 bertui-code
|
|
2
|
+
|
|
3
|
+
**Zero-config syntax highlighting for React. Built exclusively for the BertUI ecosystem.**
|
|
4
|
+
|
|
5
|
+
[](https://bertui.dev)
|
|
6
|
+
[](package.json)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
The simplest way to add beautiful, functional code blocks to your BertUI applications. Dark theme by default, copy button included, zero configuration required.
|
|
10
|
+
|
|
11
|
+
> ⚠️ **BertUI Compatibility Note:** bertui-code is built specifically for BertUI's build system. It uses ES modules and works with BertUI's transpiler. Some advanced JavaScript features may need workarounds in BertUI's JSX files.
|
|
12
|
+
|
|
13
|
+
## ✨ Features
|
|
14
|
+
|
|
15
|
+
- **Zero-config by default** - Just wrap your code
|
|
16
|
+
- **Multiple themes** - Dark, light, pink + custom colors
|
|
17
|
+
- **Built-in copy button** - One click to copy any code
|
|
18
|
+
- **Line numbers** - Optional, beautifully aligned
|
|
19
|
+
- **Inline code snippets** - Perfect for documentation
|
|
20
|
+
- **20+ language support** - Auto-detection included
|
|
21
|
+
- **BertUI-exclusive** - Optimized for BertUI's build system
|
|
22
|
+
- **Zero dependencies** - Except React (peer dependency)
|
|
23
|
+
- **Accessible** - Proper ARIA labels, keyboard navigation
|
|
24
|
+
|
|
25
|
+
## 📦 Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bun add bertui-code
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 🚀 Quick Start
|
|
32
|
+
|
|
33
|
+
```jsx
|
|
34
|
+
import { Code, InlineCode } from 'bertui-code';
|
|
35
|
+
|
|
36
|
+
// Basic usage (zero config!)
|
|
37
|
+
<Code>
|
|
38
|
+
const hello = "world";
|
|
39
|
+
console.log(hello);
|
|
40
|
+
</Code>
|
|
41
|
+
|
|
42
|
+
// With line numbers
|
|
43
|
+
<Code showLineNumbers>
|
|
44
|
+
function calculate(a, b) {
|
|
45
|
+
return a + b;
|
|
46
|
+
}
|
|
47
|
+
</Code>
|
|
48
|
+
|
|
49
|
+
// Inline code in paragraphs
|
|
50
|
+
<p>
|
|
51
|
+
Use the <InlineCode>useState</InlineCode> hook for state management.
|
|
52
|
+
</p>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## ⚠️ BertUI Compatibility Notes
|
|
56
|
+
|
|
57
|
+
BertUI's transpiler is lightweight and fast, but has some limitations. Here are workarounds for common issues:
|
|
58
|
+
|
|
59
|
+
### ✅ **DO: Use simple strings in JSX**
|
|
60
|
+
```jsx
|
|
61
|
+
// ✅ GOOD - Plain strings work perfectly
|
|
62
|
+
<Code>
|
|
63
|
+
console.log("Hello BertUI!");
|
|
64
|
+
</Code>
|
|
65
|
+
|
|
66
|
+
// ✅ GOOD - Pre-defined variables
|
|
67
|
+
const myCode = 'function test() {\n return "works";\n}';
|
|
68
|
+
<Code>{myCode}</Code>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### ❌ **AVOID: Complex template literals in JSX**
|
|
72
|
+
```jsx
|
|
73
|
+
// ❌ BAD - BertUI may freak out with nested backticks
|
|
74
|
+
<Code>
|
|
75
|
+
{`function test() {
|
|
76
|
+
return \`template literal\`;
|
|
77
|
+
}`}
|
|
78
|
+
</Code>
|
|
79
|
+
|
|
80
|
+
// ✅ GOOD - Escape properly or use variables
|
|
81
|
+
const code = 'function test() {\n return `template literal`;\n}';
|
|
82
|
+
<Code>{code}</Code>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### ✅ **Best Practice: Store code in variables**
|
|
86
|
+
```jsx
|
|
87
|
+
// Store complex code in variables
|
|
88
|
+
const exampleCode = `function complex() {
|
|
89
|
+
const data = { key: "value" };
|
|
90
|
+
return \`Template: \${data.key}\`;
|
|
91
|
+
}`;
|
|
92
|
+
|
|
93
|
+
// Then use in JSX
|
|
94
|
+
<Code>{exampleCode}</Code>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 🎨 Themes & Colors
|
|
98
|
+
|
|
99
|
+
### Built-in Themes
|
|
100
|
+
|
|
101
|
+
```jsx
|
|
102
|
+
// Dark (default)
|
|
103
|
+
<Code theme="dark">console.log("Dark theme");</Code>
|
|
104
|
+
|
|
105
|
+
// Light
|
|
106
|
+
<Code theme="light">// Perfect for docs</Code>
|
|
107
|
+
|
|
108
|
+
// Pink
|
|
109
|
+
<Code theme="pink">// For pink lovers! 🎀</Code>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Custom Colors
|
|
113
|
+
|
|
114
|
+
```jsx
|
|
115
|
+
<Code
|
|
116
|
+
theme="custom"
|
|
117
|
+
colors={{
|
|
118
|
+
background: '#0a0a0a',
|
|
119
|
+
text: '#00ff00',
|
|
120
|
+
header: '#1a1a1a',
|
|
121
|
+
border: '#00ff00',
|
|
122
|
+
meta: '#00ff00',
|
|
123
|
+
button: '#00ff00',
|
|
124
|
+
buttonText: '#0a0a0a',
|
|
125
|
+
success: '#00ff00'
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
// Custom hacker theme
|
|
129
|
+
</Code>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 📖 API Reference
|
|
133
|
+
|
|
134
|
+
### `<Code />` Component
|
|
135
|
+
|
|
136
|
+
| Prop | Type | Default | Description |
|
|
137
|
+
|------|------|---------|-------------|
|
|
138
|
+
| `children` | `string` | **Required** | The code to display |
|
|
139
|
+
| `language` | `string` | `'javascript'` | Programming language (`'auto'` for detection) |
|
|
140
|
+
| `theme` | `'dark' \| 'light' \| 'pink' \| 'custom'` | `'dark'` | Color theme |
|
|
141
|
+
| `colors` | `Object` | `{}` | Custom colors for `theme="custom"` |
|
|
142
|
+
| `showLineNumbers` | `boolean` | `false` | Show line numbers |
|
|
143
|
+
| `showCopyButton` | `boolean` | `true` | Show copy-to-clipboard button |
|
|
144
|
+
| `className` | `string` | `''` | Additional CSS classes |
|
|
145
|
+
|
|
146
|
+
### `<InlineCode />` Component
|
|
147
|
+
|
|
148
|
+
| Prop | Type | Default | Description |
|
|
149
|
+
|------|------|---------|-------------|
|
|
150
|
+
| `children` | `string` | **Required** | The inline code |
|
|
151
|
+
| `theme` | `'dark' \| 'light' \| 'pink'` | `'dark'` | Color theme |
|
|
152
|
+
|
|
153
|
+
### `detectLanguage(code: string): string`
|
|
154
|
+
|
|
155
|
+
Utility function to detect programming language from code content.
|
|
156
|
+
|
|
157
|
+
## 🌐 Language Support
|
|
158
|
+
|
|
159
|
+
bertui-code supports **20+ programming languages** with auto-detection:
|
|
160
|
+
|
|
161
|
+
- **Web**: JavaScript, TypeScript, JSX, HTML, CSS, JSON
|
|
162
|
+
- **Backend**: Python, Ruby, PHP, Java, Go, Rust, C, C++, C#
|
|
163
|
+
- **Data**: SQL, YAML, XML
|
|
164
|
+
- **Shell**: Bash, Shell, PowerShell
|
|
165
|
+
- **Other**: Markdown, Swift, Kotlin, Dart
|
|
166
|
+
|
|
167
|
+
```jsx
|
|
168
|
+
// Auto-detection
|
|
169
|
+
<Code language="auto">
|
|
170
|
+
def hello():
|
|
171
|
+
print("Auto-detected as Python!")
|
|
172
|
+
</Code>
|
|
173
|
+
|
|
174
|
+
// Manual specification
|
|
175
|
+
<Code language="rust">
|
|
176
|
+
fn main() {
|
|
177
|
+
println!("Hello Rust!");
|
|
178
|
+
}
|
|
179
|
+
</Code>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## 🔧 Advanced Usage Examples
|
|
183
|
+
|
|
184
|
+
### Documentation Page (BertUI-safe)
|
|
185
|
+
```jsx
|
|
186
|
+
import React from 'react';
|
|
187
|
+
import { Code, InlineCode } from 'bertui-code';
|
|
188
|
+
|
|
189
|
+
// Store code in variables (BertUI-safe pattern)
|
|
190
|
+
const apiExample = 'function fetchData(url) {\n return fetch(url).then(r => r.json());\n}';
|
|
191
|
+
|
|
192
|
+
const errorHandling = `interface Result<T> {
|
|
193
|
+
data: T | null;
|
|
194
|
+
error: string | null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function getUser(): Promise<Result<User>> {
|
|
198
|
+
try {
|
|
199
|
+
const response = await fetch('/api/user');
|
|
200
|
+
return { data: await response.json(), error: null };
|
|
201
|
+
} catch (error) {
|
|
202
|
+
return { data: null, error: error.message };
|
|
203
|
+
}
|
|
204
|
+
}`;
|
|
205
|
+
|
|
206
|
+
export default function Documentation() {
|
|
207
|
+
return (
|
|
208
|
+
<article style={{ padding: '2rem' }}>
|
|
209
|
+
<h1>API Reference</h1>
|
|
210
|
+
|
|
211
|
+
<p>
|
|
212
|
+
Import the component: <InlineCode>import {'{ Code }'} from 'bertui-code'</InlineCode>
|
|
213
|
+
</p>
|
|
214
|
+
|
|
215
|
+
<h2>Basic Example</h2>
|
|
216
|
+
<Code showLineNumbers>
|
|
217
|
+
{apiExample}
|
|
218
|
+
</Code>
|
|
219
|
+
|
|
220
|
+
<h2>Error Handling</h2>
|
|
221
|
+
<Code language="typescript" theme="light">
|
|
222
|
+
{errorHandling}
|
|
223
|
+
</Code>
|
|
224
|
+
</article>
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Interactive Component (BertUI-safe)
|
|
230
|
+
```jsx
|
|
231
|
+
import React, { useState } from 'react';
|
|
232
|
+
import { Code } from 'bertui-code';
|
|
233
|
+
|
|
234
|
+
export default function InteractiveDemo() {
|
|
235
|
+
const [theme, setTheme] = useState('dark');
|
|
236
|
+
|
|
237
|
+
// Store dynamic code in variable
|
|
238
|
+
const dynamicCode = `// Current theme: ${theme}
|
|
239
|
+
const user = {
|
|
240
|
+
name: "Developer",
|
|
241
|
+
preferences: {
|
|
242
|
+
theme: "${theme}",
|
|
243
|
+
timestamp: new Date().toISOString()
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
console.log(\`Hello \${user.name}!\`);`;
|
|
248
|
+
|
|
249
|
+
return (
|
|
250
|
+
<div style={{ padding: '1rem' }}>
|
|
251
|
+
<div style={{ marginBottom: '1rem' }}>
|
|
252
|
+
<label>
|
|
253
|
+
Select Theme:
|
|
254
|
+
<select
|
|
255
|
+
value={theme}
|
|
256
|
+
onChange={(e) => setTheme(e.target.value)}
|
|
257
|
+
style={{ marginLeft: '0.5rem', padding: '0.25rem' }}
|
|
258
|
+
>
|
|
259
|
+
<option value="dark">Dark</option>
|
|
260
|
+
<option value="light">Light</option>
|
|
261
|
+
<option value="pink">Pink</option>
|
|
262
|
+
</select>
|
|
263
|
+
</label>
|
|
264
|
+
</div>
|
|
265
|
+
|
|
266
|
+
<Code theme={theme} showLineNumbers>
|
|
267
|
+
{dynamicCode}
|
|
268
|
+
</Code>
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## 🛠️ Troubleshooting BertUI Issues
|
|
275
|
+
|
|
276
|
+
### Problem: "Unexpected return" or compilation errors
|
|
277
|
+
**Solution:** BertUI's transpiler sometimes struggles with:
|
|
278
|
+
- Nested template literals in JSX
|
|
279
|
+
- Complex string interpolation
|
|
280
|
+
- Certain JavaScript syntax in JSX attributes
|
|
281
|
+
|
|
282
|
+
**Workaround:**
|
|
283
|
+
```jsx
|
|
284
|
+
// ❌ Problematic
|
|
285
|
+
<Code>
|
|
286
|
+
{`function test() {
|
|
287
|
+
return \`Complex \${expression}\`;
|
|
288
|
+
}`}
|
|
289
|
+
</Code>
|
|
290
|
+
|
|
291
|
+
// ✅ Solution - Use variables
|
|
292
|
+
const safeCode = 'function test() {\n return `Complex ${expression}`;\n}';
|
|
293
|
+
<Code>{safeCode}</Code>
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Problem: Import not working
|
|
297
|
+
**Solution:** Make sure:
|
|
298
|
+
1. Package is installed : `bun install bertui-code`
|
|
299
|
+
2. BertUI restarted after installing
|
|
300
|
+
3. No cache issues: `rm -rf .bertui` then restart
|
|
301
|
+
|
|
302
|
+
### Problem: Colors not applying
|
|
303
|
+
**Solution:** Ensure custom colors object has all required properties:
|
|
304
|
+
```jsx
|
|
305
|
+
// Complete custom colors object
|
|
306
|
+
colors={{
|
|
307
|
+
background: '#...',
|
|
308
|
+
text: '#...',
|
|
309
|
+
header: '#...',
|
|
310
|
+
border: '#...',
|
|
311
|
+
meta: '#...',
|
|
312
|
+
button: '#...',
|
|
313
|
+
buttonHover: '#...',
|
|
314
|
+
buttonText: '#...',
|
|
315
|
+
success: '#...'
|
|
316
|
+
}}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## 📁 Project Structure
|
|
320
|
+
|
|
321
|
+
```
|
|
322
|
+
bertui-code/
|
|
323
|
+
├── src/
|
|
324
|
+
│ ├── Code.js # Main component (BertUI-safe JS)
|
|
325
|
+
│ ├── CopyButton.js # Copy button component
|
|
326
|
+
│ ├── InlineCode.js # Inline code component
|
|
327
|
+
│ └── index.js # Main exports
|
|
328
|
+
├── dist/
|
|
329
|
+
│ └── index.js # Built bundle (ES module)
|
|
330
|
+
├── package.json
|
|
331
|
+
└── README.md
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## 🤝 Compatibility
|
|
335
|
+
|
|
336
|
+
- **BertUI**: ✅ Fully compatible (built specifically for BertUI)
|
|
337
|
+
- **React**: ✅ 18.0.0+ (peer dependency)
|
|
338
|
+
- **Browsers**: ✅ Chrome, Firefox, Safari, Edge (modern)
|
|
339
|
+
- **Other Frameworks**: ❌ Not compatible (BertUI-exclusive optimizations)
|
|
340
|
+
|
|
341
|
+
## 📄 License
|
|
342
|
+
|
|
343
|
+
MIT © Pease Ernest
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
<div align="center">
|
|
348
|
+
<p>
|
|
349
|
+
<strong>Part of the BertUI ecosystem</strong><br/>
|
|
350
|
+
Built with ❤️ for developers who value simplicity and beauty
|
|
351
|
+
</p>
|
|
352
|
+
|
|
353
|
+
<p>
|
|
354
|
+
<a href="https://bertui-docswebsite.pages.dev/">BertUI Website</a> •
|
|
355
|
+
<a href="https://github.com/BunElysiaReact/bertui-code.git">GitHub</a> •
|
|
356
|
+
<a href="https://npmjs.com/package/bertui-code">npm</a>
|
|
357
|
+
</p>
|
|
358
|
+
</div>
|
|
359
|
+
```
|
|
360
|
+
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/* bertui-code - Zero-config syntax highlighting for BertUI */
|
|
2
|
+
|
|
3
|
+
/* Container */
|
|
4
|
+
.bertui-code {
|
|
5
|
+
background: #1e1e1e;
|
|
6
|
+
border-radius: 8px;
|
|
7
|
+
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
|
|
8
|
+
font-size: 14px;
|
|
9
|
+
line-height: 1.6;
|
|
10
|
+
margin: 1rem 0;
|
|
11
|
+
overflow: hidden;
|
|
12
|
+
color: #d4d4d4;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Header */
|
|
16
|
+
.bertui-code-header {
|
|
17
|
+
background: #2d2d2d;
|
|
18
|
+
padding: 8px 16px;
|
|
19
|
+
display: flex;
|
|
20
|
+
justify-content: space-between;
|
|
21
|
+
align-items: center;
|
|
22
|
+
border-bottom: 1px solid #3d3d3d;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.bertui-code-language {
|
|
26
|
+
color: #858585;
|
|
27
|
+
font-size: 13px;
|
|
28
|
+
font-weight: 500;
|
|
29
|
+
text-transform: lowercase;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Copy button */
|
|
33
|
+
.bertui-copy-button {
|
|
34
|
+
background: #3d3d3d;
|
|
35
|
+
border: none;
|
|
36
|
+
color: #d4d4d4;
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
padding: 4px 12px;
|
|
39
|
+
border-radius: 4px;
|
|
40
|
+
font-size: 12px;
|
|
41
|
+
transition: all 0.2s;
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
gap: 6px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.bertui-copy-button:hover {
|
|
48
|
+
background: #4d4d4d;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.bertui-copy-button.copied {
|
|
52
|
+
background: #2e7d32;
|
|
53
|
+
color: white;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Code content */
|
|
57
|
+
.bertui-code-content {
|
|
58
|
+
display: flex;
|
|
59
|
+
overflow-x: auto;
|
|
60
|
+
padding: 16px 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Line numbers */
|
|
64
|
+
.bertui-line-numbers {
|
|
65
|
+
color: #858585;
|
|
66
|
+
padding: 0 16px;
|
|
67
|
+
text-align: right;
|
|
68
|
+
user-select: none;
|
|
69
|
+
border-right: 1px solid #3d3d3d;
|
|
70
|
+
min-width: 40px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.bertui-line-numbers span {
|
|
74
|
+
display: block;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Code block */
|
|
78
|
+
.bertui-code-pre {
|
|
79
|
+
margin: 0;
|
|
80
|
+
padding: 0 16px;
|
|
81
|
+
flex: 1;
|
|
82
|
+
overflow-x: auto;
|
|
83
|
+
white-space: pre;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Syntax highlighting tokens (users can override) */
|
|
87
|
+
.token.keyword {
|
|
88
|
+
color: #569cd6;
|
|
89
|
+
font-weight: bold;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.token.string {
|
|
93
|
+
color: #ce9178;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.token.comment {
|
|
97
|
+
color: #6a9955;
|
|
98
|
+
font-style: italic;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.token.function {
|
|
102
|
+
color: #dcdcaa;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.token.number {
|
|
106
|
+
color: #b5cea8;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.token.operator {
|
|
110
|
+
color: #d4d4d4;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.token.punctuation {
|
|
114
|
+
color: #d4d4d4;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.token.class-name {
|
|
118
|
+
color: #4ec9b0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.token.parameter {
|
|
122
|
+
color: #9cdcfe;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Inline code */
|
|
126
|
+
.bertui-inline-code {
|
|
127
|
+
background: #2d2d2d;
|
|
128
|
+
color: #d4d4d4;
|
|
129
|
+
padding: 2px 6px;
|
|
130
|
+
border-radius: 4px;
|
|
131
|
+
font-family: 'Menlo', 'Monaco', monospace;
|
|
132
|
+
font-size: 0.9em;
|
|
133
|
+
line-height: 1.4;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Light theme variant */
|
|
137
|
+
.bertui-code.light-theme,
|
|
138
|
+
.bertui-code[data-theme="light"] {
|
|
139
|
+
background: #ffffff;
|
|
140
|
+
color: #374151;
|
|
141
|
+
border: 1px solid #e5e7eb;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.bertui-code.light-theme .bertui-code-header,
|
|
145
|
+
.bertui-code[data-theme="light"] .bertui-code-header {
|
|
146
|
+
background: #f3f4f6;
|
|
147
|
+
border-bottom: 1px solid #d1d5db;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.bertui-code.light-theme .bertui-code-language,
|
|
151
|
+
.bertui-code[data-theme="light"] .bertui-code-language {
|
|
152
|
+
color: #6b7280;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.bertui-code.light-theme .bertui-copy-button,
|
|
156
|
+
.bertui-code[data-theme="light"] .bertui-copy-button {
|
|
157
|
+
background: #e5e7eb;
|
|
158
|
+
color: #374151;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.bertui-code.light-theme .bertui-copy-button:hover,
|
|
162
|
+
.bertui-code[data-theme="light"] .bertui-copy-button:hover {
|
|
163
|
+
background: #d1d5db;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.bertui-code.light-theme .bertui-line-numbers,
|
|
167
|
+
.bertui-code[data-theme="light"] .bertui-line-numbers {
|
|
168
|
+
color: #6b7280;
|
|
169
|
+
border-right: 1px solid #d1d5db;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.bertui-code.light-theme .bertui-inline-code,
|
|
173
|
+
.bertui-code[data-theme="light"] .bertui-inline-code {
|
|
174
|
+
background: #e5e7eb;
|
|
175
|
+
color: #374151;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* Pink theme variant */
|
|
179
|
+
.bertui-code.pink-theme,
|
|
180
|
+
.bertui-code[data-theme="pink"] {
|
|
181
|
+
background: #fdf2f8;
|
|
182
|
+
color: #831843;
|
|
183
|
+
border: 1px solid #fbcfe8;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.bertui-code.pink-theme .bertui-code-header,
|
|
187
|
+
.bertui-code[data-theme="pink"] .bertui-code-header {
|
|
188
|
+
background: #fce7f3;
|
|
189
|
+
border-bottom: 1px solid #f9a8d4;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.bertui-code.pink-theme .bertui-code-language,
|
|
193
|
+
.bertui-code[data-theme="pink"] .bertui-code-language {
|
|
194
|
+
color: #be185d;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.bertui-code.pink-theme .bertui-copy-button,
|
|
198
|
+
.bertui-code[data-theme="pink"] .bertui-copy-button {
|
|
199
|
+
background: #f472b6;
|
|
200
|
+
color: white;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.bertui-code.pink-theme .bertui-copy-button:hover,
|
|
204
|
+
.bertui-code[data-theme="pink"] .bertui-copy-button:hover {
|
|
205
|
+
background: #ec4899;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.bertui-code.pink-theme .bertui-line-numbers,
|
|
209
|
+
.bertui-code[data-theme="pink"] .bertui-line-numbers {
|
|
210
|
+
color: #db2777;
|
|
211
|
+
border-right: 1px solid #f9a8d4;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.bertui-code.pink-theme .bertui-inline-code,
|
|
215
|
+
.bertui-code[data-theme="pink"] .bertui-inline-code {
|
|
216
|
+
background: #fce7f3;
|
|
217
|
+
color: #831843;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* Light theme syntax */
|
|
221
|
+
.bertui-code.light-theme .token.keyword,
|
|
222
|
+
.bertui-code[data-theme="light"] .token.keyword {
|
|
223
|
+
color: #059669;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.bertui-code.light-theme .token.string,
|
|
227
|
+
.bertui-code[data-theme="light"] .token.string {
|
|
228
|
+
color: #dc2626;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.bertui-code.light-theme .token.comment,
|
|
232
|
+
.bertui-code[data-theme="light"] .token.comment {
|
|
233
|
+
color: #6b7280;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* Pink theme syntax */
|
|
237
|
+
.bertui-code.pink-theme .token.keyword,
|
|
238
|
+
.bertui-code[data-theme="pink"] .token.keyword {
|
|
239
|
+
color: #db2777;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.bertui-code.pink-theme .token.string,
|
|
243
|
+
.bertui-code[data-theme="pink"] .token.string {
|
|
244
|
+
color: #ea580c;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.bertui-code.pink-theme .token.comment,
|
|
248
|
+
.bertui-code[data-theme="pink"] .token.comment {
|
|
249
|
+
color: #a855f7;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* Mobile responsiveness */
|
|
253
|
+
@media (max-width: 640px) {
|
|
254
|
+
.bertui-code {
|
|
255
|
+
font-size: 13px;
|
|
256
|
+
border-radius: 6px;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.bertui-code-content {
|
|
260
|
+
padding: 12px 0;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.bertui-code-header {
|
|
264
|
+
padding: 6px 12px;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.bertui-line-numbers {
|
|
268
|
+
padding: 0 12px;
|
|
269
|
+
min-width: 36px;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.bertui-code-pre {
|
|
273
|
+
padding: 0 12px;
|
|
274
|
+
}
|
|
275
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS module declaration for bertui-code styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
declare module 'bertui-code/bertui-code.css' {
|
|
6
|
+
const styles: {
|
|
7
|
+
/** bertui-code container class */
|
|
8
|
+
readonly 'bertui-code': string;
|
|
9
|
+
/** Code block header */
|
|
10
|
+
readonly 'bertui-code-header': string;
|
|
11
|
+
/** Language label */
|
|
12
|
+
readonly 'bertui-code-language': string;
|
|
13
|
+
/** Copy button */
|
|
14
|
+
readonly 'bertui-copy-button': string;
|
|
15
|
+
/** Copy button copied state */
|
|
16
|
+
readonly 'copied': string;
|
|
17
|
+
/** Code content wrapper */
|
|
18
|
+
readonly 'bertui-code-content': string;
|
|
19
|
+
/** Line numbers container */
|
|
20
|
+
readonly 'bertui-line-numbers': string;
|
|
21
|
+
/** Individual line number */
|
|
22
|
+
readonly 'bertui-line-number': string;
|
|
23
|
+
/** Preformatted code block */
|
|
24
|
+
readonly 'bertui-code-pre': string;
|
|
25
|
+
/** Inline code element */
|
|
26
|
+
readonly 'bertui-inline-code': string;
|
|
27
|
+
/** Syntax highlighting tokens */
|
|
28
|
+
readonly 'token': string;
|
|
29
|
+
readonly 'keyword': string;
|
|
30
|
+
readonly 'string': string;
|
|
31
|
+
readonly 'comment': string;
|
|
32
|
+
readonly 'function': string;
|
|
33
|
+
readonly 'number': string;
|
|
34
|
+
readonly 'operator': string;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default styles;
|
|
38
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import r from"react";import f,{useState as k}from"react";function e({code:t,themeColors:n={}}){let[d,o]=k(!1),u=async()=>{try{await navigator.clipboard.writeText(t),o(!0),setTimeout(()=>o(!1),2000)}catch(p){let a=document.createElement("textarea");a.value=t,a.style.position="fixed",a.style.opacity="0",document.body.appendChild(a),a.select(),document.execCommand("copy"),document.body.removeChild(a),o(!0),setTimeout(()=>o(!1),2000)}},i={background:d?n.success||"#2e7d32":n.button||"#3d3d3d",border:"none",color:n.buttonText||"#d4d4d4",cursor:"pointer",padding:"4px 12px",borderRadius:"4px",fontSize:"12px",transition:"all 0.2s"};return f.createElement("button",{onClick:u,title:d?"Copied!":"Copy code",style:i,onMouseEnter:(p)=>{if(!d)p.currentTarget.style.background=n.buttonHover||"#4d4d4d"},onMouseLeave:(p)=>{if(!d)p.currentTarget.style.background=n.button||"#3d3d3d"}},d?"✓":"\uD83D\uDCCB")}function y({children:t,language:n="javascript",showLineNumbers:d=!1,showCopyButton:o=!0,className:u="",theme:i="dark",colors:p={}}){let x=t.split(`
|
|
2
|
+
`).length,c=v(i,p);return r.createElement("div",{className:`bertui-code ${u}`,style:{background:c.background,borderRadius:"8px",fontFamily:"'Menlo', 'Monaco', monospace",fontSize:"14px",margin:"1rem 0",overflow:"hidden",color:c.text}},[r.createElement("div",{key:"header",style:{background:c.header,padding:"8px 16px",display:"flex",justifyContent:"space-between",alignItems:"center",borderBottom:`1px solid ${c.border}`}},[r.createElement("span",{key:"language",style:{color:c.meta,fontSize:"12px",fontWeight:"500"}},n),o&&r.createElement(e,{key:"copy",code:t,themeColors:c})].filter(Boolean)),r.createElement("div",{key:"content",style:{display:"flex",padding:"16px 0"}},[d&&r.createElement("div",{key:"lines",style:{color:c.meta,padding:"0 16px",textAlign:"right",userSelect:"none",minWidth:"40px"}},Array.from({length:x}).map((T,b)=>r.createElement("span",{key:b,style:{display:"block",paddingRight:"8px"}},b+1))),r.createElement("pre",{key:"pre",style:{margin:0,padding:"0 16px",flex:1,overflowX:"auto"}},r.createElement("code",{className:`language-${n}`,style:{color:c.text,background:"transparent",fontFamily:"inherit"}},t))].filter(Boolean))])}function v(t,n={}){let d={dark:{background:"#1e1e1e",header:"#2d2d2d",text:"#d4d4d4",meta:"#858585",border:"#3d3d3d",button:"#3d3d3d",buttonHover:"#4d4d4d",buttonText:"#d4d4d4",success:"#2e7d32"},light:{background:"#ffffff",header:"#f3f4f6",text:"#374151",meta:"#6b7280",border:"#d1d5db",button:"#e5e7eb",buttonHover:"#d1d5db",buttonText:"#374151",success:"#10b981"},pink:{background:"#fdf2f8",header:"#fce7f3",text:"#831843",meta:"#be185d",border:"#f472b6",button:"#f472b6",buttonHover:"#ec4899",buttonText:"#ffffff",success:"#10b981"}};return{...d[t]||d.dark,...n}}function M(t){let n={javascript:/(\bconsole\.|\bfunction\b|\bconst\b|\blet\b|\bvar\b|\bimport\b|\bexport\b)/,typescript:/(:\s*\w+\s*[=;]|\binterface\b|\btype\b|\bnamespace\b)/,python:/(\bdef\b|\bclass\b|\bimport\b|\bfrom\b|\bprint\b|:\s*$)/,html:/(<!DOCTYPE|<\/?\w+[^>]*>|&[a-z]+;)/,css:/({[^}]*}|\.\w+\s*{|#\w+\s*{|\bcolor:\s*)/,rust:/(\bfn\b|\blet\b|\bmut\b|\bimpl\b|->\s*\w+)/,cpp:/(#include|std::|cout\s*<<|->\s*\w+)/,java:/(public\s+class|System\.out\.println|\bvoid\b\s+\w+\s*\()/,go:/(\bfunc\b|\bpackage\b|:=|fmt\.Println)/,php:/(<\?php|\$\w+\s*=|echo\s+)/,sql:/(\bSELECT\b|\bFROM\b|\bWHERE\b|\bJOIN\b)/,shell:/(^\s*#!|\$\w+|mkdir\s+|cd\s+)/,json:/^\s*[{[]/,yaml:/(^[\w-]+:\s|^- )/,markdown:/(^#+|^-{3,}|^\s*\[)/,xml:/(<\?xml|<\/?[\w:]+>)/,ruby:/(\bdef\b|\bend\b|\bputs\b|:\w+=>)/,swift:/(\bfunc\b|\bvar\b|\blet\b|:\s*\w+\s*{)/,kotlin:/(\bfun\b|\bval\b|\bvar\b|:\s*\w+\s*[=;])/},d=t.toLowerCase();for(let[o,u]of Object.entries(n))if(u.test(d))return o;return"plaintext"}import S from"react";function E({children:t,theme:n="dark"}){let d={dark:{background:"#2d2d2d",color:"#d4d4d4"},light:{background:"#e5e7eb",color:"#374151"},pink:{background:"#fce7f3",color:"#831843"}},o=d[n]||d.dark;return S.createElement("code",{style:{background:o.background,color:o.color,padding:"2px 6px",borderRadius:"4px",fontFamily:"'Menlo', 'Monaco', monospace",fontSize:"0.9em"}},t)}export{M as detectLanguage,E as InlineCode,y as Code};
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bertui-code",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"./bertui-code.css": {
|
|
13
|
+
"import": "./dist/bertui-code.css",
|
|
14
|
+
"types": "./dist/bertui-code.css.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": ["dist"],
|
|
18
|
+
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "bun build src/index.js --outdir dist --target browser --format esm --minify --external react --external fs --external path",
|
|
21
|
+
"dev": "bun build src/index.js --outdir dist --target browser --format esm --watch --external react --external fs --external path"
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
"keywords": ["react", "syntax-highlighting", "bertui", "code"],
|
|
25
|
+
"author": "Your Name",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"react": "^18.0.0"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|