@roadlittledawn/docs-design-system-react 0.2.1 → 0.2.2

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.
@@ -11,6 +11,8 @@ import "prismjs/components/prism-python";
11
11
  import "prismjs/components/prism-java";
12
12
  import "prismjs/components/prism-sql";
13
13
  import "prismjs/components/prism-yaml";
14
+ import "prismjs/components/prism-markup-templating";
15
+ import "prismjs/components/prism-php";
14
16
  export interface CodeSnippet {
15
17
  /** The code content */
16
18
  code: string;
@@ -39,5 +41,18 @@ interface CodeBlockProps {
39
41
  /** Additional CSS classes */
40
42
  className?: string;
41
43
  }
44
+ /**
45
+ * Register additional Prism languages via dynamic import.
46
+ * Call this before rendering CodeBlock with unsupported languages.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * await registerLanguages(async () => {
51
+ * await import('prismjs/components/prism-go');
52
+ * await import('prismjs/components/prism-rust');
53
+ * });
54
+ * ```
55
+ */
56
+ export declare function registerLanguages(loader: () => Promise<void>): Promise<void>;
42
57
  export declare function CodeBlock({ code, language, filename, highlightLines, snippets, path, className, }: CodeBlockProps): import("react/jsx-runtime").JSX.Element | null;
43
58
  export {};
@@ -52,6 +52,32 @@ import "prismjs/components/prism-python";
52
52
  import "prismjs/components/prism-java";
53
53
  import "prismjs/components/prism-sql";
54
54
  import "prismjs/components/prism-yaml";
55
+ import "prismjs/components/prism-markup-templating";
56
+ import "prismjs/components/prism-php";
57
+ /**
58
+ * Register additional Prism languages via dynamic import.
59
+ * Call this before rendering CodeBlock with unsupported languages.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * await registerLanguages(async () => {
64
+ * await import('prismjs/components/prism-go');
65
+ * await import('prismjs/components/prism-rust');
66
+ * });
67
+ * ```
68
+ */
69
+ export function registerLanguages(loader) {
70
+ return __awaiter(this, void 0, void 0, function () {
71
+ return __generator(this, function (_a) {
72
+ switch (_a.label) {
73
+ case 0: return [4 /*yield*/, loader()];
74
+ case 1:
75
+ _a.sent();
76
+ return [2 /*return*/];
77
+ }
78
+ });
79
+ });
80
+ }
55
81
  /**
56
82
  * Parses a markdown file content to extract code snippets
57
83
  */
@@ -103,6 +129,8 @@ function groupSnippetsByLanguage(snippets) {
103
129
  }
104
130
  return grouped;
105
131
  }
132
+ var ClipboardIcon = function () { return (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [_jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }), _jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })] })); };
133
+ var CheckIcon = function () { return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) })); };
106
134
  export function CodeBlock(_a) {
107
135
  var _this = this;
108
136
  var code = _a.code, language = _a.language, filename = _a.filename, highlightLines = _a.highlightLines, snippets = _a.snippets, path = _a.path, _b = _a.className, className = _b === void 0 ? "" : _b;
@@ -232,9 +260,12 @@ export function CodeBlock(_a) {
232
260
  var hasTabs = activeSnippets.length > 1;
233
261
  var hasLanguageDropdown = snippetsByLanguage.size > 1;
234
262
  var displayLanguage = currentSnippet.language || "text";
235
- return (_jsxs("div", { className: "dds-code-block ".concat(className), children: [_jsxs("div", { className: "dds-code-block-header", children: [_jsx("div", { className: "dds-code-block-header-left", children: hasTabs && (_jsx("div", { className: "dds-code-block-tabs", children: activeSnippets.map(function (snippet, index) { return (_jsx("button", { className: "dds-code-block-tab ".concat(index === activeTabIndex ? "dds-code-block-tab-active" : ""), onClick: function () { return setActiveTabIndex(index); }, type: "button", children: snippet.tabTitle || snippet.filename || "Tab ".concat(index + 1) }, index)); }) })) }), _jsxs("div", { className: "dds-code-block-header-right", children: [hasLanguageDropdown && (_jsx("select", { className: "dds-code-block-language-select", value: activeLanguage || "", onChange: function (e) {
263
+ var showFilenameLabel = !hasTabs && currentSnippet.filename;
264
+ return (_jsxs("div", { className: "dds-code-block ".concat(className), children: [_jsxs("div", { className: "dds-code-block-header", children: [_jsxs("div", { className: "dds-code-block-header-left", children: [hasTabs && (_jsx("div", { className: "dds-code-block-tabs", children: activeSnippets.map(function (snippet, index) { return (_jsx("button", { className: "dds-code-block-tab ".concat(index === activeTabIndex ? "dds-code-block-tab-active" : ""), onClick: function () { return setActiveTabIndex(index); }, type: "button", children: snippet.tabTitle || snippet.filename || "Tab ".concat(index + 1) }, index)); }) })), showFilenameLabel && (_jsx("span", { className: "dds-code-block-filename", children: currentSnippet.filename }))] }), _jsxs("div", { className: "dds-code-block-header-right", children: [hasLanguageDropdown && (_jsx("select", { className: "dds-code-block-language-select", value: activeLanguage || "", onChange: function (e) {
236
265
  setActiveLanguage(e.target.value);
237
266
  setActiveTabIndex(0);
238
- }, children: Array.from(snippetsByLanguage.keys()).map(function (lang) { return (_jsx("option", { value: lang, children: lang }, lang)); }) })), !hasLanguageDropdown && displayLanguage !== "text" && (_jsx("span", { className: "dds-code-block-language-label", children: displayLanguage })), _jsx("button", { className: "dds-code-block-copy-button", onClick: handleCopy, type: "button", "aria-label": "Copy code", children: copied ? "Copied!" : "Copy" })] })] }), _jsxs("div", { className: "dds-code-block-content", children: [_jsx("pre", { className: "language-".concat(displayLanguage), children: _jsx("code", { className: "language-".concat(displayLanguage), dangerouslySetInnerHTML: { __html: highlightedCode } }) }), currentSnippet.highlightLines &&
267
+ }, children: Array.from(snippetsByLanguage.keys()).map(function (lang) { return (_jsx("option", { value: lang, children: lang }, lang)); }) })), !hasLanguageDropdown &&
268
+ !showFilenameLabel &&
269
+ displayLanguage !== "text" && (_jsx("span", { className: "dds-code-block-language-label", children: displayLanguage })), _jsx("button", { className: "dds-code-block-copy-button", onClick: handleCopy, type: "button", "aria-label": copied ? "Copied" : "Copy code", children: copied ? _jsx(CheckIcon, {}) : _jsx(ClipboardIcon, {}) })] })] }), _jsxs("div", { className: "dds-code-block-content", children: [_jsx("pre", { className: "language-".concat(displayLanguage), children: _jsx("code", { className: "language-".concat(displayLanguage), dangerouslySetInnerHTML: { __html: highlightedCode } }) }), currentSnippet.highlightLines &&
239
270
  currentSnippet.highlightLines.length > 0 && (_jsx("div", { className: "dds-code-block-line-highlights", children: currentSnippet.highlightLines.map(function (lineNum) { return (_jsx("div", { className: "dds-code-block-line-highlight", style: { top: "".concat((lineNum - 1) * 1.5, "em") } }, lineNum)); }) }))] })] }));
240
271
  }
@@ -43,3 +43,19 @@ export declare const JSONExample: Story;
43
43
  * Bash/shell script example.
44
44
  */
45
45
  export declare const BashExample: Story;
46
+ /**
47
+ * Multiple TSX files displayed as flat tabs with bottom-border accent.
48
+ */
49
+ export declare const WithFilenameTabs: Story;
50
+ /**
51
+ * Single snippet with a filename — displays a flat filename label in the header.
52
+ */
53
+ export declare const SingleFilename: Story;
54
+ /**
55
+ * PHP syntax highlighting example.
56
+ */
57
+ export declare const PHPExample: Story;
58
+ /**
59
+ * Many tabs to verify horizontal scroll behavior.
60
+ */
61
+ export declare const ManyTabs: Story;
@@ -9,7 +9,7 @@ var meta = {
9
9
  parameters: {
10
10
  docs: {
11
11
  description: {
12
- component: "\nThe CodeBlock component provides a comprehensive solution for displaying code snippets in documentation.\n\n## Features\n\n- **Syntax Highlighting**: Uses PrismJS for syntax highlighting across many languages\n- **Copy to Clipboard**: One-click copy button for easy code sharing\n- **Line Highlighting**: Highlight specific lines to draw attention\n- **Tabs**: Display multiple code snippets in tabs (typically for different files)\n- **Language Switching**: Dropdown to switch between different language versions\n- **External Snippets**: Load code snippets from markdown files via path prop\n\n## When to Use\n\n- For code examples in documentation\n- When displaying multiple related code snippets\n- For showing code in different languages (TypeScript, JavaScript, etc.)\n- When you need users to easily copy code\n\n## When Not to Use\n\n- For inline code (use `<code>` tags)\n- For code that doesn't need syntax highlighting\n- For executable code editors (use a code editor component)\n\n## Accessibility\n\n- Copy button includes proper ARIA labels\n- Keyboard navigation for tabs and dropdowns\n- High contrast syntax highlighting colors\n ",
12
+ component: "\nThe CodeBlock component provides a comprehensive solution for displaying code snippets in documentation.\n\n## Features\n\n- **Syntax Highlighting**: Uses PrismJS for syntax highlighting across many languages\n- **Copy to Clipboard**: One-click copy button for easy code sharing\n- **Line Highlighting**: Highlight specific lines to draw attention\n- **Tabs**: Display multiple code snippets in tabs (typically for different files)\n- **Language Switching**: Dropdown to switch between different language versions\n- **Filename Labels**: Single-file snippets display a flat filename label in the header\n- **External Snippets**: Load code snippets from markdown files via path prop\n\n## Supported Languages\n\nThe following languages are bundled by default: JavaScript, TypeScript, JSX, TSX, CSS, Markdown, JSON, Bash, Ruby, Python, Java, SQL, YAML, and PHP.\n\nTo add additional languages, use the `registerLanguages` utility before rendering:\n\n```ts\nimport { registerLanguages, CodeBlock } from '@roadlittledawn/docs-design-system-react';\n\n// Call once at app startup or before rendering CodeBlock with new languages.\n// Prism is already loaded by the package \u2014 dynamic language imports\n// register themselves against it automatically.\nawait registerLanguages(async () => {\n await import('prismjs/components/prism-go');\n await import('prismjs/components/prism-rust');\n});\n```\n\n## When to Use\n\n- For code examples in documentation\n- When displaying multiple related code snippets\n- For showing code in different languages (TypeScript, JavaScript, etc.)\n- When you need users to easily copy code\n\n## When Not to Use\n\n- For inline code (use `<code>` tags)\n- For code that doesn't need syntax highlighting\n- For executable code editors (use a code editor component)\n\n## Accessibility\n\n- Copy button includes proper ARIA labels\n- Keyboard navigation for tabs and dropdowns\n- High contrast syntax highlighting colors\n ",
13
13
  },
14
14
  },
15
15
  },
@@ -152,3 +152,83 @@ export var BashExample = {
152
152
  filename: 'setup.sh',
153
153
  },
154
154
  };
155
+ /**
156
+ * Multiple TSX files displayed as flat tabs with bottom-border accent.
157
+ */
158
+ export var WithFilenameTabs = {
159
+ args: {
160
+ snippets: [
161
+ {
162
+ code: "import { CodeBlock } from '@docs-design-system/ui';\n\nexport function Example() {\n return (\n <CodeBlock\n code=\"console.log('hello')\"\n language=\"typescript\"\n />\n );\n}",
163
+ language: 'tsx',
164
+ filename: 'Example.tsx',
165
+ tabTitle: 'Example.tsx',
166
+ },
167
+ {
168
+ code: "import { CodeBlock } from '@docs-design-system/ui';\n\nexport function Advanced() {\n return (\n <CodeBlock\n snippets={[\n { code: 'const a = 1;', language: 'typescript', tabTitle: 'a.ts' },\n { code: 'const b = 2;', language: 'typescript', tabTitle: 'b.ts' },\n ]}\n />\n );\n}",
169
+ language: 'tsx',
170
+ filename: 'Advanced.tsx',
171
+ tabTitle: 'Advanced.tsx',
172
+ },
173
+ ],
174
+ },
175
+ };
176
+ /**
177
+ * Single snippet with a filename — displays a flat filename label in the header.
178
+ */
179
+ export var SingleFilename = {
180
+ args: {
181
+ code: "export default function Home() {\n return <h1>Welcome</h1>;\n}",
182
+ language: 'tsx',
183
+ filename: 'page.tsx',
184
+ },
185
+ };
186
+ /**
187
+ * PHP syntax highlighting example.
188
+ */
189
+ export var PHPExample = {
190
+ args: {
191
+ code: "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\n\nclass UserController extends Controller\n{\n public function index()\n {\n $users = User::all();\n return view('users.index', compact('users'));\n }\n\n public function show(int $id)\n {\n $user = User::findOrFail($id);\n return response()->json($user);\n }\n}",
192
+ language: 'php',
193
+ filename: 'UserController.php',
194
+ },
195
+ };
196
+ /**
197
+ * Many tabs to verify horizontal scroll behavior.
198
+ */
199
+ export var ManyTabs = {
200
+ args: {
201
+ snippets: [
202
+ {
203
+ code: "export const App = () => <div>App</div>;",
204
+ language: 'tsx',
205
+ tabTitle: 'App.tsx',
206
+ },
207
+ {
208
+ code: "export const Header = () => <header>Header</header>;",
209
+ language: 'tsx',
210
+ tabTitle: 'Header.tsx',
211
+ },
212
+ {
213
+ code: "export const Footer = () => <footer>Footer</footer>;",
214
+ language: 'tsx',
215
+ tabTitle: 'Footer.tsx',
216
+ },
217
+ {
218
+ code: "export const Sidebar = () => <aside>Sidebar</aside>;",
219
+ language: 'tsx',
220
+ tabTitle: 'Sidebar.tsx',
221
+ },
222
+ {
223
+ code: "export const Nav = () => <nav>Nav</nav>;",
224
+ language: 'tsx',
225
+ tabTitle: 'Navigation.tsx',
226
+ },
227
+ {
228
+ code: "export const Content = () => <main>Content</main>;",
229
+ language: 'tsx',
230
+ tabTitle: 'ContentArea.tsx',
231
+ },
232
+ ],
233
+ },
234
+ };
package/dist/styles.css CHANGED
@@ -141,20 +141,22 @@
141
141
 
142
142
  /* CodeBlock */
143
143
  --dds-code-block-border: #e5e7eb; /* gray-200 */
144
- --dds-code-block-radius: 8px;
145
- --dds-code-block-bg: #ffffff;
144
+ --dds-code-block-radius: 12px;
145
+ --dds-code-block-bg: #fafafa;
146
146
  --dds-code-block-margin: 1rem 0;
147
- --dds-code-block-header-bg: #ffffff;
148
- --dds-code-block-header-gap: 0.75rem;
149
- --dds-code-block-header-padding: 0.75rem 1rem;
150
- --dds-code-block-tab-padding: 0.5rem 1rem;
151
- --dds-code-block-tab-bg: #f3f4f6; /* gray-100 */
147
+ --dds-code-block-header-bg: #f5f5f5;
148
+ --dds-code-block-header-height: 2.25rem;
149
+ --dds-code-block-header-gap: 0.5rem;
150
+ --dds-code-block-header-padding: 0 1rem;
151
+ --dds-code-block-tab-padding: 0 0.75rem;
152
+ --dds-code-block-tab-bg: transparent;
152
153
  --dds-code-block-tab-text: #6b7280; /* gray-500 */
153
- --dds-code-block-tab-radius: 6px;
154
+ --dds-code-block-tab-radius: 0;
154
155
  --dds-code-block-tab-text-hover: #374151; /* gray-700 */
155
- --dds-code-block-tab-bg-hover: #e5e7eb; /* gray-200 */
156
+ --dds-code-block-tab-bg-hover: transparent;
156
157
  --dds-code-block-tab-text-active: #111827; /* gray-900 */
157
- --dds-code-block-tab-bg-active: #ffffff;
158
+ --dds-code-block-tab-bg-active: transparent;
159
+ --dds-code-block-tab-border-active: #3b82f6; /* blue-500 */
158
160
  --dds-code-block-select-padding: 0.375rem 0.75rem;
159
161
  --dds-code-block-select-border: #d1d5db; /* gray-300 */
160
162
  --dds-code-block-select-radius: 4px;
@@ -166,17 +168,17 @@
166
168
  --dds-code-block-select-focus-ring: rgba(59, 130, 246, 0.1);
167
169
  --dds-code-block-label-size: 0.875rem;
168
170
  --dds-code-block-label-text: #6b7280; /* gray-500 */
169
- --dds-code-block-copy-padding: 0.375rem 0.75rem;
170
- --dds-code-block-copy-bg: #ffffff;
171
- --dds-code-block-copy-border: #d1d5db; /* gray-300 */
171
+ --dds-code-block-copy-padding: 0.375rem;
172
+ --dds-code-block-copy-bg: transparent;
173
+ --dds-code-block-copy-border: transparent;
172
174
  --dds-code-block-copy-radius: 4px;
173
- --dds-code-block-copy-text: #374151; /* gray-700 */
175
+ --dds-code-block-copy-text: #9ca3af; /* gray-400 */
174
176
  --dds-code-block-copy-size: 0.875rem;
175
- --dds-code-block-copy-bg-hover: #f9fafb; /* gray-50 */
176
- --dds-code-block-copy-border-hover: #9ca3af; /* gray-400 */
177
- --dds-code-block-copy-bg-active: #f3f4f6; /* gray-100 */
178
- --dds-code-block-content-bg: #f9fafb; /* gray-50 */
179
- --dds-code-block-pre-padding: 1rem;
177
+ --dds-code-block-copy-bg-hover: rgba(0, 0, 0, 0.05);
178
+ --dds-code-block-copy-border-hover: transparent;
179
+ --dds-code-block-copy-bg-active: rgba(0, 0, 0, 0.08);
180
+ --dds-code-block-content-bg: #fafafa;
181
+ --dds-code-block-pre-padding: 1.25rem;
180
182
  --dds-code-block-text: #111827; /* gray-900 */
181
183
  --dds-code-block-highlight-bg: rgba(59, 130, 246, 0.2);
182
184
  --dds-code-block-highlight-border: #3b82f6; /* blue-500 */
@@ -184,6 +186,8 @@
184
186
  --dds-code-block-loading-text: #6b7280; /* gray-500 */
185
187
  --dds-code-block-error-text: #dc2626; /* red-600 */
186
188
  --dds-code-block-message-size: 0.875rem;
189
+ --dds-code-block-filename-text: #6b7280; /* gray-500 */
190
+ --dds-code-block-filename-size: 0.8125rem;
187
191
 
188
192
  /* Prism Syntax Highlighting */
189
193
  --dds-prism-comment: #6b7280; /* gray-500 */
@@ -294,15 +298,16 @@
294
298
  --dds-collapser-text: #e5e7eb; /* gray-200 */
295
299
 
296
300
  /* CodeBlock */
297
- --dds-code-block-bg: transparent;
298
- --dds-code-block-border: #4b5563; /* gray-600 */
299
- --dds-code-block-header-bg: transparent;
300
- --dds-code-block-tab-bg: rgba(255, 255, 255, 0.05);
301
+ --dds-code-block-bg: #0a0a0a;
302
+ --dds-code-block-border: #2e2e2e; /* hsla(0,0%,18%,1) */
303
+ --dds-code-block-header-bg: #141414;
304
+ --dds-code-block-tab-bg: transparent;
301
305
  --dds-code-block-tab-text: #9ca3af; /* gray-400 */
302
306
  --dds-code-block-tab-text-hover: #e5e7eb; /* gray-200 */
303
- --dds-code-block-tab-bg-hover: rgba(255, 255, 255, 0.1);
307
+ --dds-code-block-tab-bg-hover: transparent;
304
308
  --dds-code-block-tab-text-active: #f9fafb; /* gray-50 */
305
309
  --dds-code-block-tab-bg-active: transparent;
310
+ --dds-code-block-tab-border-active: #60a5fa; /* blue-400 */
306
311
  --dds-code-block-select-border: #4b5563; /* gray-600 */
307
312
  --dds-code-block-select-bg: transparent;
308
313
  --dds-code-block-select-text: #e5e7eb; /* gray-200 */
@@ -311,17 +316,19 @@
311
316
  --dds-code-block-select-focus-ring: rgba(96, 165, 250, 0.2);
312
317
  --dds-code-block-label-text: #9ca3af; /* gray-400 */
313
318
  --dds-code-block-copy-bg: transparent;
314
- --dds-code-block-copy-border: #4b5563; /* gray-600 */
315
- --dds-code-block-copy-text: #e5e7eb; /* gray-200 */
316
- --dds-code-block-copy-bg-hover: rgba(255, 255, 255, 0.05);
317
- --dds-code-block-copy-border-hover: #6b7280; /* gray-500 */
318
- --dds-code-block-copy-bg-active: rgba(255, 255, 255, 0.1);
319
- --dds-code-block-content-bg: transparent;
319
+ --dds-code-block-copy-border: transparent;
320
+ --dds-code-block-copy-text: #6b7280; /* gray-500 */
321
+ --dds-code-block-copy-bg-hover: rgba(255, 255, 255, 0.08);
322
+ --dds-code-block-copy-border-hover: transparent;
323
+ --dds-code-block-copy-bg-active: rgba(255, 255, 255, 0.12);
324
+ --dds-code-block-content-bg: #0a0a0a; /* hsla(0,0%,4%,1) */
320
325
  --dds-code-block-text: #e2e8f0; /* slate-200 */
321
326
  --dds-code-block-highlight-bg: rgba(96, 165, 250, 0.15);
322
327
  --dds-code-block-highlight-border: #60a5fa; /* blue-400 */
323
328
  --dds-code-block-loading-text: #9ca3af; /* gray-400 */
324
329
  --dds-code-block-error-text: #f87171; /* red-400 */
330
+ --dds-code-block-filename-text: #9ca3af; /* gray-400 */
331
+ --dds-code-block-filename-size: 0.8125rem;
325
332
 
326
333
  /* Prism Syntax - Dark palette */
327
334
  --dds-prism-comment: #9ca3af; /* gray-400 */
@@ -416,15 +423,16 @@
416
423
  --dds-collapser-text: #e5e7eb;
417
424
 
418
425
  /* CodeBlock */
419
- --dds-code-block-bg: transparent;
420
- --dds-code-block-border: #4b5563;
421
- --dds-code-block-header-bg: transparent;
422
- --dds-code-block-tab-bg: rgba(255, 255, 255, 0.05);
426
+ --dds-code-block-bg: #0a0a0a;
427
+ --dds-code-block-border: #262626;
428
+ --dds-code-block-header-bg: #141414;
429
+ --dds-code-block-tab-bg: transparent;
423
430
  --dds-code-block-tab-text: #9ca3af;
424
431
  --dds-code-block-tab-text-hover: #e5e7eb;
425
- --dds-code-block-tab-bg-hover: rgba(255, 255, 255, 0.1);
432
+ --dds-code-block-tab-bg-hover: transparent;
426
433
  --dds-code-block-tab-text-active: #f9fafb;
427
434
  --dds-code-block-tab-bg-active: transparent;
435
+ --dds-code-block-tab-border-active: #60a5fa;
428
436
  --dds-code-block-select-border: #4b5563;
429
437
  --dds-code-block-select-bg: transparent;
430
438
  --dds-code-block-select-text: #e5e7eb;
@@ -433,17 +441,19 @@
433
441
  --dds-code-block-select-focus-ring: rgba(96, 165, 250, 0.2);
434
442
  --dds-code-block-label-text: #9ca3af;
435
443
  --dds-code-block-copy-bg: transparent;
436
- --dds-code-block-copy-border: #4b5563;
437
- --dds-code-block-copy-text: #e5e7eb;
438
- --dds-code-block-copy-bg-hover: rgba(255, 255, 255, 0.05);
439
- --dds-code-block-copy-border-hover: #6b7280;
440
- --dds-code-block-copy-bg-active: rgba(255, 255, 255, 0.1);
441
- --dds-code-block-content-bg: transparent;
444
+ --dds-code-block-copy-border: transparent;
445
+ --dds-code-block-copy-text: #6b7280;
446
+ --dds-code-block-copy-bg-hover: rgba(255, 255, 255, 0.08);
447
+ --dds-code-block-copy-border-hover: transparent;
448
+ --dds-code-block-copy-bg-active: rgba(255, 255, 255, 0.12);
449
+ --dds-code-block-content-bg: #0a0a0a; /* hsla(0,0%,4%,1) */
442
450
  --dds-code-block-text: #e2e8f0;
443
451
  --dds-code-block-highlight-bg: rgba(96, 165, 250, 0.15);
444
452
  --dds-code-block-highlight-border: #60a5fa;
445
453
  --dds-code-block-loading-text: #9ca3af;
446
454
  --dds-code-block-error-text: #f87171;
455
+ --dds-code-block-filename-text: #9ca3af;
456
+ --dds-code-block-filename-size: 0.8125rem;
447
457
 
448
458
  /* Prism Syntax - Dark palette */
449
459
  --dds-prism-comment: #9ca3af;
@@ -456,6 +466,130 @@
456
466
  --dds-prism-regex: #fb923c;
457
467
  }
458
468
  }
469
+ /* Explicit dark mode via data attribute (overrides OS preference) */
470
+ [data-dds-theme="dark"] {
471
+ /* Heading / Typography */
472
+ --dds-heading-color: #f9fafb;
473
+ --dds-typography-caption-color: #9ca3af;
474
+
475
+ /* Button - Primary */
476
+ --dds-button-primary-bg: #3b82f6;
477
+ --dds-button-primary-bg-hover: #2563eb;
478
+ --dds-button-primary-text: #ffffff;
479
+ --dds-button-primary-focus-ring: #60a5fa;
480
+
481
+ /* Button - Secondary */
482
+ --dds-button-secondary-bg: transparent;
483
+ --dds-button-secondary-bg-hover: rgba(255, 255, 255, 0.1);
484
+ --dds-button-secondary-text: #e5e7eb;
485
+ --dds-button-secondary-focus-ring: #9ca3af;
486
+
487
+ /* Button - Outline */
488
+ --dds-button-outline-bg: transparent;
489
+ --dds-button-outline-bg-hover: rgba(255, 255, 255, 0.05);
490
+ --dds-button-outline-border: #6b7280;
491
+ --dds-button-outline-text: #e5e7eb;
492
+ --dds-button-outline-focus-ring: #9ca3af;
493
+
494
+ /* Focus Ring */
495
+ --dds-focus-ring-bg: transparent;
496
+
497
+ /* Card */
498
+ --dds-card-bg-blue: rgba(59, 130, 246, 0.08);
499
+ --dds-card-bg-green: rgba(34, 197, 94, 0.08);
500
+ --dds-card-bg-purple: rgba(168, 85, 247, 0.08);
501
+ --dds-card-bg-red: rgba(239, 68, 68, 0.08);
502
+ --dds-card-bg-yellow: rgba(234, 179, 8, 0.08);
503
+ --dds-card-bg-gray: rgba(156, 163, 175, 0.08);
504
+ --dds-card-bg-white: transparent;
505
+ --dds-card-border: #4b5563;
506
+ --dds-card-border-hover: #9ca3af;
507
+ --dds-card-shadow-hover: none;
508
+
509
+ --dds-card-title-blue: #93c5fd;
510
+ --dds-card-title-green: #86efac;
511
+ --dds-card-title-purple: #d8b4fe;
512
+ --dds-card-title-red: #fca5a5;
513
+ --dds-card-title-yellow: #fde047;
514
+ --dds-card-title-gray: #e5e7eb;
515
+
516
+ --dds-card-text-blue: #bfdbfe;
517
+ --dds-card-text-green: #bbf7d0;
518
+ --dds-card-text-purple: #e9d5ff;
519
+ --dds-card-text-red: #fecaca;
520
+ --dds-card-text-yellow: #fef08a;
521
+ --dds-card-text-gray: #d1d5db;
522
+
523
+ /* Link */
524
+ --dds-link-color: #60a5fa;
525
+ --dds-link-color-hover: #93c5fd;
526
+ --dds-link-decoration: #3b82f6;
527
+ --dds-link-decoration-hover: #60a5fa;
528
+
529
+ /* Callout */
530
+ --dds-callout-text: #e5e7eb;
531
+
532
+ --dds-callout-caution-bg: transparent;
533
+ --dds-callout-caution-title: #fca5a5;
534
+
535
+ --dds-callout-important-bg: transparent;
536
+ --dds-callout-important-title: #fcd34d;
537
+
538
+ --dds-callout-tip-bg: transparent;
539
+ --dds-callout-tip-title: #93c5fd;
540
+
541
+ --dds-callout-course-bg: transparent;
542
+ --dds-callout-course-title: #6ee7b7;
543
+
544
+ /* Collapser */
545
+ --dds-collapser-border: #4b5563;
546
+ --dds-collapser-button-hover-bg: rgba(255, 255, 255, 0.05);
547
+ --dds-collapser-icon-color: #9ca3af;
548
+ --dds-collapser-text: #e5e7eb;
549
+
550
+ /* CodeBlock */
551
+ --dds-code-block-bg: #0a0a0a;
552
+ --dds-code-block-border: #2e2e2e; /* hsla(0,0%,18%,1) */
553
+ --dds-code-block-header-bg: #141414;
554
+ --dds-code-block-tab-bg: transparent;
555
+ --dds-code-block-tab-text: #9ca3af;
556
+ --dds-code-block-tab-text-hover: #e5e7eb;
557
+ --dds-code-block-tab-bg-hover: transparent;
558
+ --dds-code-block-tab-text-active: #f9fafb;
559
+ --dds-code-block-tab-bg-active: transparent;
560
+ --dds-code-block-tab-border-active: #60a5fa;
561
+ --dds-code-block-select-border: #4b5563;
562
+ --dds-code-block-select-bg: transparent;
563
+ --dds-code-block-select-text: #e5e7eb;
564
+ --dds-code-block-select-border-hover: #6b7280;
565
+ --dds-code-block-select-border-focus: #60a5fa;
566
+ --dds-code-block-select-focus-ring: rgba(96, 165, 250, 0.2);
567
+ --dds-code-block-label-text: #9ca3af;
568
+ --dds-code-block-copy-bg: transparent;
569
+ --dds-code-block-copy-border: transparent;
570
+ --dds-code-block-copy-text: #6b7280;
571
+ --dds-code-block-copy-bg-hover: rgba(255, 255, 255, 0.08);
572
+ --dds-code-block-copy-border-hover: transparent;
573
+ --dds-code-block-copy-bg-active: rgba(255, 255, 255, 0.12);
574
+ --dds-code-block-content-bg: #0a0a0a; /* hsla(0,0%,4%,1) */
575
+ --dds-code-block-text: #e2e8f0;
576
+ --dds-code-block-highlight-bg: rgba(96, 165, 250, 0.15);
577
+ --dds-code-block-highlight-border: #60a5fa;
578
+ --dds-code-block-loading-text: #9ca3af;
579
+ --dds-code-block-error-text: #f87171;
580
+ --dds-code-block-filename-text: #9ca3af;
581
+ --dds-code-block-filename-size: 0.8125rem;
582
+
583
+ /* Prism Syntax - Dark palette */
584
+ --dds-prism-comment: #9ca3af;
585
+ --dds-prism-punctuation: #d1d5db;
586
+ --dds-prism-property: #f87171;
587
+ --dds-prism-string: #34d399;
588
+ --dds-prism-operator: #fbbf24;
589
+ --dds-prism-keyword: #60a5fa;
590
+ --dds-prism-function: #a78bfa;
591
+ --dds-prism-regex: #fb923c;
592
+ }
459
593
  /* Import PrismJS theme */
460
594
  /**
461
595
  * prism.js default theme for JavaScript, CSS and HTML
@@ -888,18 +1022,19 @@ a.no-text-decoration {
888
1022
  .dds-code-block-header {
889
1023
  display: flex;
890
1024
  justify-content: space-between;
891
- align-items: flex-end;
1025
+ align-items: center;
892
1026
  padding: 0;
893
1027
  background-color: var(--dds-code-block-header-bg);
894
1028
  border-bottom: 1px solid var(--dds-code-block-border);
895
- min-height: 2.75rem;
1029
+ height: var(--dds-code-block-header-height);
896
1030
  overflow: hidden;
897
1031
  }
898
1032
  .dds-code-block-header-left {
899
1033
  display: flex;
900
- align-items: flex-end;
1034
+ align-items: center;
901
1035
  flex: 1;
902
1036
  min-width: 0;
1037
+ height: 100%;
903
1038
  }
904
1039
  .dds-code-block-header-right {
905
1040
  display: flex;
@@ -915,7 +1050,8 @@ a.no-text-decoration {
915
1050
  overflow-x: auto;
916
1051
  overflow-y: hidden;
917
1052
  -webkit-overflow-scrolling: touch;
918
- align-items: flex-end;
1053
+ align-items: center;
1054
+ height: 100%;
919
1055
  /* Hide scrollbar but keep functionality */
920
1056
  scrollbar-width: none; /* Firefox */
921
1057
  -ms-overflow-style: none; /* IE and Edge */
@@ -926,18 +1062,18 @@ a.no-text-decoration {
926
1062
  .dds-code-block-tab {
927
1063
  padding: var(--dds-code-block-tab-padding);
928
1064
  background-color: var(--dds-code-block-tab-bg);
929
- border: 1px solid var(--dds-code-block-border);
930
- border-bottom: none;
931
- border-top-left-radius: var(--dds-code-block-tab-radius);
932
- border-top-right-radius: var(--dds-code-block-tab-radius);
1065
+ border: none;
1066
+ border-bottom: 2px solid transparent;
933
1067
  color: var(--dds-code-block-tab-text);
934
- font-size: var(--dds-code-block-tab-size, 0.875rem);
1068
+ font-size: 0.8125rem;
935
1069
  font-weight: var(--dds-font-medium);
936
1070
  cursor: pointer;
937
1071
  white-space: nowrap;
938
1072
  transition: var(--dds-transition-colors);
939
- margin-right: 2px;
940
1073
  position: relative;
1074
+ height: 100%;
1075
+ display: flex;
1076
+ align-items: center;
941
1077
  }
942
1078
  .dds-code-block-tab:hover {
943
1079
  color: var(--dds-code-block-tab-text-hover);
@@ -946,11 +1082,18 @@ a.no-text-decoration {
946
1082
  .dds-code-block-tab-active {
947
1083
  color: var(--dds-code-block-tab-text-active);
948
1084
  background-color: var(--dds-code-block-tab-bg-active);
949
- border-color: var(--dds-code-block-border);
1085
+ border-bottom-color: var(--dds-code-block-tab-border-active);
950
1086
  }
951
1087
  .dds-code-block-tab-active:hover {
952
1088
  background-color: var(--dds-code-block-tab-bg-active);
953
1089
  }
1090
+ .dds-code-block-filename {
1091
+ font-size: var(--dds-code-block-filename-size);
1092
+ color: var(--dds-code-block-filename-text);
1093
+ font-weight: var(--dds-font-medium);
1094
+ padding: var(--dds-code-block-header-padding);
1095
+ white-space: nowrap;
1096
+ }
954
1097
  .dds-code-block-language-select {
955
1098
  padding: var(--dds-code-block-select-padding);
956
1099
  border: 1px solid var(--dds-code-block-select-border);
@@ -979,18 +1122,20 @@ a.no-text-decoration {
979
1122
  .dds-code-block-copy-button {
980
1123
  padding: var(--dds-code-block-copy-padding);
981
1124
  background-color: var(--dds-code-block-copy-bg);
982
- border: 1px solid var(--dds-code-block-copy-border);
1125
+ border: none;
983
1126
  border-radius: var(--dds-code-block-copy-radius);
984
1127
  color: var(--dds-code-block-copy-text);
985
- font-size: var(--dds-code-block-copy-size);
986
- font-weight: var(--dds-font-medium);
987
1128
  cursor: pointer;
988
1129
  transition: var(--dds-transition-colors);
989
1130
  white-space: nowrap;
1131
+ display: flex;
1132
+ align-items: center;
1133
+ justify-content: center;
1134
+ width: 1.75rem;
1135
+ height: 1.75rem;
990
1136
  }
991
1137
  .dds-code-block-copy-button:hover {
992
1138
  background-color: var(--dds-code-block-copy-bg-hover);
993
- border-color: var(--dds-code-block-copy-border-hover);
994
1139
  }
995
1140
  .dds-code-block-copy-button:active {
996
1141
  background-color: var(--dds-code-block-copy-bg-active);
@@ -1037,11 +1182,13 @@ a.no-text-decoration {
1037
1182
  }
1038
1183
  .dds-code-block-line-highlights {
1039
1184
  position: absolute;
1040
- top: 0;
1185
+ top: var(--dds-code-block-pre-padding);
1041
1186
  left: 0;
1042
1187
  right: 0;
1043
1188
  bottom: 0;
1044
1189
  pointer-events: none;
1190
+ font-size: var(--dds-code-block-font-size, 0.875rem);
1191
+ line-height: var(--dds-code-block-line-height, 1.5);
1045
1192
  }
1046
1193
  .dds-code-block-line-highlight {
1047
1194
  position: absolute;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roadlittledawn/docs-design-system-react",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "license": "MIT",
5
5
  "description": "React components for documentation design system",
6
6
  "repository": {