@roadlittledawn/docs-design-system-react 0.2.0 → 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.
@@ -7,13 +7,12 @@ var defaultTitles = {
7
7
  };
8
8
  export function Callout(_a) {
9
9
  var variant = _a.variant, title = _a.title, children = _a.children, _b = _a.className, className = _b === void 0 ? "" : _b;
10
- var calloutClasses = [
11
- "dds-callout",
12
- "dds-callout-".concat(variant),
13
- className,
14
- ]
10
+ var calloutClasses = ["dds-callout", "dds-callout-".concat(variant), className]
15
11
  .filter(Boolean)
16
12
  .join(" ");
17
- var titleClasses = ["dds-callout-title", "dds-callout-title-".concat(variant)].join(" ");
18
- return (_jsxs("div", { className: calloutClasses, children: [title !== null && (_jsx("h4", { className: titleClasses, children: title || defaultTitles[variant] })), children] }));
13
+ var titleClasses = [
14
+ "dds-callout-title",
15
+ "dds-callout-title-".concat(variant),
16
+ ].join(" ");
17
+ return (_jsxs("div", { className: calloutClasses, children: [title !== null && (_jsx("p", { className: titleClasses, children: title || defaultTitles[variant] })), children] }));
19
18
  }
@@ -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
+ };
@@ -1,5 +1,7 @@
1
1
  import React from "react";
2
2
  interface HeadingProps {
3
+ /** Optionally override auto-generation of `id` attribute */
4
+ id?: string;
3
5
  /** Heading level (h1, h2, h3, or h4) */
4
6
  level: 1 | 2 | 3 | 4;
5
7
  /** Heading content */
@@ -7,5 +9,5 @@ interface HeadingProps {
7
9
  /** Additional CSS classes */
8
10
  className?: string;
9
11
  }
10
- export declare function Heading({ level, children, className }: HeadingProps): import("react/jsx-runtime").JSX.Element;
12
+ export declare function Heading({ level, children, id, className }: HeadingProps): import("react/jsx-runtime").JSX.Element;
11
13
  export {};
@@ -1,7 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import slugify from "../utils/slugify";
2
3
  export function Heading(_a) {
3
- var level = _a.level, children = _a.children, _b = _a.className, className = _b === void 0 ? "" : _b;
4
+ var _b;
5
+ var level = _a.level, children = _a.children, id = _a.id, _c = _a.className, className = _c === void 0 ? "" : _c;
4
6
  var Tag = "h".concat(level);
5
7
  var classNames = "dds-heading dds-heading-".concat(level, " ").concat(className).trim();
6
- return _jsx(Tag, { className: classNames, children: children });
8
+ var generatedId = typeof children === "string" ? (_b = slugify({ value: children })) !== null && _b !== void 0 ? _b : undefined : undefined;
9
+ var idAttr = id !== null && id !== void 0 ? id : generatedId;
10
+ return (_jsx(Tag, { id: idAttr, className: classNames, children: children }));
7
11
  }
package/dist/styles.css CHANGED
@@ -108,6 +108,7 @@
108
108
  /* Callout Colors and Styles */
109
109
  --dds-callout-text: #374151; /* gray-700 */
110
110
  --dds-callout-padding: 1.25rem; /* p-5 */
111
+ --dds-callout-margin: 1rem 0;
111
112
  --dds-callout-radius: 0.25rem; /* rounded */
112
113
  --dds-callout-title-size: 0.75rem; /* text-xs */
113
114
  --dds-callout-title-margin-bottom: 0.5rem; /* mb-2 */
@@ -140,20 +141,22 @@
140
141
 
141
142
  /* CodeBlock */
142
143
  --dds-code-block-border: #e5e7eb; /* gray-200 */
143
- --dds-code-block-radius: 8px;
144
- --dds-code-block-bg: #ffffff;
144
+ --dds-code-block-radius: 12px;
145
+ --dds-code-block-bg: #fafafa;
145
146
  --dds-code-block-margin: 1rem 0;
146
- --dds-code-block-header-bg: #ffffff;
147
- --dds-code-block-header-gap: 0.75rem;
148
- --dds-code-block-header-padding: 0.75rem 1rem;
149
- --dds-code-block-tab-padding: 0.5rem 1rem;
150
- --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;
151
153
  --dds-code-block-tab-text: #6b7280; /* gray-500 */
152
- --dds-code-block-tab-radius: 6px;
154
+ --dds-code-block-tab-radius: 0;
153
155
  --dds-code-block-tab-text-hover: #374151; /* gray-700 */
154
- --dds-code-block-tab-bg-hover: #e5e7eb; /* gray-200 */
156
+ --dds-code-block-tab-bg-hover: transparent;
155
157
  --dds-code-block-tab-text-active: #111827; /* gray-900 */
156
- --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 */
157
160
  --dds-code-block-select-padding: 0.375rem 0.75rem;
158
161
  --dds-code-block-select-border: #d1d5db; /* gray-300 */
159
162
  --dds-code-block-select-radius: 4px;
@@ -165,17 +168,17 @@
165
168
  --dds-code-block-select-focus-ring: rgba(59, 130, 246, 0.1);
166
169
  --dds-code-block-label-size: 0.875rem;
167
170
  --dds-code-block-label-text: #6b7280; /* gray-500 */
168
- --dds-code-block-copy-padding: 0.375rem 0.75rem;
169
- --dds-code-block-copy-bg: #ffffff;
170
- --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;
171
174
  --dds-code-block-copy-radius: 4px;
172
- --dds-code-block-copy-text: #374151; /* gray-700 */
175
+ --dds-code-block-copy-text: #9ca3af; /* gray-400 */
173
176
  --dds-code-block-copy-size: 0.875rem;
174
- --dds-code-block-copy-bg-hover: #f9fafb; /* gray-50 */
175
- --dds-code-block-copy-border-hover: #9ca3af; /* gray-400 */
176
- --dds-code-block-copy-bg-active: #f3f4f6; /* gray-100 */
177
- --dds-code-block-content-bg: #f9fafb; /* gray-50 */
178
- --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;
179
182
  --dds-code-block-text: #111827; /* gray-900 */
180
183
  --dds-code-block-highlight-bg: rgba(59, 130, 246, 0.2);
181
184
  --dds-code-block-highlight-border: #3b82f6; /* blue-500 */
@@ -183,6 +186,8 @@
183
186
  --dds-code-block-loading-text: #6b7280; /* gray-500 */
184
187
  --dds-code-block-error-text: #dc2626; /* red-600 */
185
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;
186
191
 
187
192
  /* Prism Syntax Highlighting */
188
193
  --dds-prism-comment: #6b7280; /* gray-500 */
@@ -197,7 +202,8 @@
197
202
  /* Collapser Colors and Styles */
198
203
  --dds-collapser-radius: 0.375rem; /* rounded-md */
199
204
  --dds-collapser-border: #e5e7eb; /* gray-200 */
200
- --dds-collapser-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
205
+ --dds-collapser-shadow:
206
+ 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
201
207
  --dds-collapser-button-padding: 0.75rem; /* p-3 */
202
208
  --dds-collapser-button-hover-bg: #f9fafb; /* gray-50 */
203
209
  --dds-collapser-icon-color: #6b7280; /* gray-500 */
@@ -292,15 +298,16 @@
292
298
  --dds-collapser-text: #e5e7eb; /* gray-200 */
293
299
 
294
300
  /* CodeBlock */
295
- --dds-code-block-bg: transparent;
296
- --dds-code-block-border: #4b5563; /* gray-600 */
297
- --dds-code-block-header-bg: transparent;
298
- --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;
299
305
  --dds-code-block-tab-text: #9ca3af; /* gray-400 */
300
306
  --dds-code-block-tab-text-hover: #e5e7eb; /* gray-200 */
301
- --dds-code-block-tab-bg-hover: rgba(255, 255, 255, 0.1);
307
+ --dds-code-block-tab-bg-hover: transparent;
302
308
  --dds-code-block-tab-text-active: #f9fafb; /* gray-50 */
303
309
  --dds-code-block-tab-bg-active: transparent;
310
+ --dds-code-block-tab-border-active: #60a5fa; /* blue-400 */
304
311
  --dds-code-block-select-border: #4b5563; /* gray-600 */
305
312
  --dds-code-block-select-bg: transparent;
306
313
  --dds-code-block-select-text: #e5e7eb; /* gray-200 */
@@ -309,17 +316,19 @@
309
316
  --dds-code-block-select-focus-ring: rgba(96, 165, 250, 0.2);
310
317
  --dds-code-block-label-text: #9ca3af; /* gray-400 */
311
318
  --dds-code-block-copy-bg: transparent;
312
- --dds-code-block-copy-border: #4b5563; /* gray-600 */
313
- --dds-code-block-copy-text: #e5e7eb; /* gray-200 */
314
- --dds-code-block-copy-bg-hover: rgba(255, 255, 255, 0.05);
315
- --dds-code-block-copy-border-hover: #6b7280; /* gray-500 */
316
- --dds-code-block-copy-bg-active: rgba(255, 255, 255, 0.1);
317
- --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) */
318
325
  --dds-code-block-text: #e2e8f0; /* slate-200 */
319
326
  --dds-code-block-highlight-bg: rgba(96, 165, 250, 0.15);
320
327
  --dds-code-block-highlight-border: #60a5fa; /* blue-400 */
321
328
  --dds-code-block-loading-text: #9ca3af; /* gray-400 */
322
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;
323
332
 
324
333
  /* Prism Syntax - Dark palette */
325
334
  --dds-prism-comment: #9ca3af; /* gray-400 */
@@ -414,15 +423,16 @@
414
423
  --dds-collapser-text: #e5e7eb;
415
424
 
416
425
  /* CodeBlock */
417
- --dds-code-block-bg: transparent;
418
- --dds-code-block-border: #4b5563;
419
- --dds-code-block-header-bg: transparent;
420
- --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;
421
430
  --dds-code-block-tab-text: #9ca3af;
422
431
  --dds-code-block-tab-text-hover: #e5e7eb;
423
- --dds-code-block-tab-bg-hover: rgba(255, 255, 255, 0.1);
432
+ --dds-code-block-tab-bg-hover: transparent;
424
433
  --dds-code-block-tab-text-active: #f9fafb;
425
434
  --dds-code-block-tab-bg-active: transparent;
435
+ --dds-code-block-tab-border-active: #60a5fa;
426
436
  --dds-code-block-select-border: #4b5563;
427
437
  --dds-code-block-select-bg: transparent;
428
438
  --dds-code-block-select-text: #e5e7eb;
@@ -431,17 +441,19 @@
431
441
  --dds-code-block-select-focus-ring: rgba(96, 165, 250, 0.2);
432
442
  --dds-code-block-label-text: #9ca3af;
433
443
  --dds-code-block-copy-bg: transparent;
434
- --dds-code-block-copy-border: #4b5563;
435
- --dds-code-block-copy-text: #e5e7eb;
436
- --dds-code-block-copy-bg-hover: rgba(255, 255, 255, 0.05);
437
- --dds-code-block-copy-border-hover: #6b7280;
438
- --dds-code-block-copy-bg-active: rgba(255, 255, 255, 0.1);
439
- --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) */
440
450
  --dds-code-block-text: #e2e8f0;
441
451
  --dds-code-block-highlight-bg: rgba(96, 165, 250, 0.15);
442
452
  --dds-code-block-highlight-border: #60a5fa;
443
453
  --dds-code-block-loading-text: #9ca3af;
444
454
  --dds-code-block-error-text: #f87171;
455
+ --dds-code-block-filename-text: #9ca3af;
456
+ --dds-code-block-filename-size: 0.8125rem;
445
457
 
446
458
  /* Prism Syntax - Dark palette */
447
459
  --dds-prism-comment: #9ca3af;
@@ -454,6 +466,130 @@
454
466
  --dds-prism-regex: #fb923c;
455
467
  }
456
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
+ }
457
593
  /* Import PrismJS theme */
458
594
  /**
459
595
  * prism.js default theme for JavaScript, CSS and HTML
@@ -658,6 +794,7 @@ pre[class*="language-"] {
658
794
  }
659
795
  .dds-callout {
660
796
  padding: var(--dds-callout-padding);
797
+ margin: var(--dds-callout-margin);
661
798
  border-radius: var(--dds-callout-radius);
662
799
  border: 1px solid;
663
800
  border-left-width: 6px;
@@ -885,18 +1022,19 @@ a.no-text-decoration {
885
1022
  .dds-code-block-header {
886
1023
  display: flex;
887
1024
  justify-content: space-between;
888
- align-items: flex-end;
1025
+ align-items: center;
889
1026
  padding: 0;
890
1027
  background-color: var(--dds-code-block-header-bg);
891
1028
  border-bottom: 1px solid var(--dds-code-block-border);
892
- min-height: 2.75rem;
1029
+ height: var(--dds-code-block-header-height);
893
1030
  overflow: hidden;
894
1031
  }
895
1032
  .dds-code-block-header-left {
896
1033
  display: flex;
897
- align-items: flex-end;
1034
+ align-items: center;
898
1035
  flex: 1;
899
1036
  min-width: 0;
1037
+ height: 100%;
900
1038
  }
901
1039
  .dds-code-block-header-right {
902
1040
  display: flex;
@@ -912,7 +1050,8 @@ a.no-text-decoration {
912
1050
  overflow-x: auto;
913
1051
  overflow-y: hidden;
914
1052
  -webkit-overflow-scrolling: touch;
915
- align-items: flex-end;
1053
+ align-items: center;
1054
+ height: 100%;
916
1055
  /* Hide scrollbar but keep functionality */
917
1056
  scrollbar-width: none; /* Firefox */
918
1057
  -ms-overflow-style: none; /* IE and Edge */
@@ -923,18 +1062,18 @@ a.no-text-decoration {
923
1062
  .dds-code-block-tab {
924
1063
  padding: var(--dds-code-block-tab-padding);
925
1064
  background-color: var(--dds-code-block-tab-bg);
926
- border: 1px solid var(--dds-code-block-border);
927
- border-bottom: none;
928
- border-top-left-radius: var(--dds-code-block-tab-radius);
929
- border-top-right-radius: var(--dds-code-block-tab-radius);
1065
+ border: none;
1066
+ border-bottom: 2px solid transparent;
930
1067
  color: var(--dds-code-block-tab-text);
931
- font-size: var(--dds-code-block-tab-size, 0.875rem);
1068
+ font-size: 0.8125rem;
932
1069
  font-weight: var(--dds-font-medium);
933
1070
  cursor: pointer;
934
1071
  white-space: nowrap;
935
1072
  transition: var(--dds-transition-colors);
936
- margin-right: 2px;
937
1073
  position: relative;
1074
+ height: 100%;
1075
+ display: flex;
1076
+ align-items: center;
938
1077
  }
939
1078
  .dds-code-block-tab:hover {
940
1079
  color: var(--dds-code-block-tab-text-hover);
@@ -943,11 +1082,18 @@ a.no-text-decoration {
943
1082
  .dds-code-block-tab-active {
944
1083
  color: var(--dds-code-block-tab-text-active);
945
1084
  background-color: var(--dds-code-block-tab-bg-active);
946
- border-color: var(--dds-code-block-border);
1085
+ border-bottom-color: var(--dds-code-block-tab-border-active);
947
1086
  }
948
1087
  .dds-code-block-tab-active:hover {
949
1088
  background-color: var(--dds-code-block-tab-bg-active);
950
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
+ }
951
1097
  .dds-code-block-language-select {
952
1098
  padding: var(--dds-code-block-select-padding);
953
1099
  border: 1px solid var(--dds-code-block-select-border);
@@ -976,18 +1122,20 @@ a.no-text-decoration {
976
1122
  .dds-code-block-copy-button {
977
1123
  padding: var(--dds-code-block-copy-padding);
978
1124
  background-color: var(--dds-code-block-copy-bg);
979
- border: 1px solid var(--dds-code-block-copy-border);
1125
+ border: none;
980
1126
  border-radius: var(--dds-code-block-copy-radius);
981
1127
  color: var(--dds-code-block-copy-text);
982
- font-size: var(--dds-code-block-copy-size);
983
- font-weight: var(--dds-font-medium);
984
1128
  cursor: pointer;
985
1129
  transition: var(--dds-transition-colors);
986
1130
  white-space: nowrap;
1131
+ display: flex;
1132
+ align-items: center;
1133
+ justify-content: center;
1134
+ width: 1.75rem;
1135
+ height: 1.75rem;
987
1136
  }
988
1137
  .dds-code-block-copy-button:hover {
989
1138
  background-color: var(--dds-code-block-copy-bg-hover);
990
- border-color: var(--dds-code-block-copy-border-hover);
991
1139
  }
992
1140
  .dds-code-block-copy-button:active {
993
1141
  background-color: var(--dds-code-block-copy-bg-active);
@@ -1034,11 +1182,13 @@ a.no-text-decoration {
1034
1182
  }
1035
1183
  .dds-code-block-line-highlights {
1036
1184
  position: absolute;
1037
- top: 0;
1185
+ top: var(--dds-code-block-pre-padding);
1038
1186
  left: 0;
1039
1187
  right: 0;
1040
1188
  bottom: 0;
1041
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);
1042
1192
  }
1043
1193
  .dds-code-block-line-highlight {
1044
1194
  position: absolute;
@@ -0,0 +1,7 @@
1
+ import { Options as SlugOptions } from "slug";
2
+ interface SlugifyProps {
3
+ value: string;
4
+ options?: SlugOptions | string;
5
+ }
6
+ export default function slugify({ value, options }: SlugifyProps): string | null;
7
+ export {};
@@ -0,0 +1,20 @@
1
+ import slug from "slug";
2
+ slug.extend({
3
+ "/": "-",
4
+ "\\": "-",
5
+ _: "-",
6
+ "-": "-",
7
+ "&": "and",
8
+ });
9
+ export default function slugify(_a) {
10
+ var value = _a.value, options = _a.options;
11
+ if (!value || value.match(/^\s+$/))
12
+ return null;
13
+ var slugified = typeof options === "string" ? slug(value, options) : slug(value, options);
14
+ // remove repetitive dashes
15
+ var repetitiveRemoved = slugified.replace(/-{2,}/g, "-");
16
+ // strip leading and trailing dashes
17
+ var dashesTrimmed = repetitiveRemoved.replace(/^-+/, "").replace(/-+$/, "");
18
+ // return null when empty
19
+ return dashesTrimmed || null;
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roadlittledawn/docs-design-system-react",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "license": "MIT",
5
5
  "description": "React components for documentation design system",
6
6
  "repository": {
@@ -25,11 +25,13 @@
25
25
  "dependencies": {
26
26
  "prismjs": "^1.29.0",
27
27
  "react": "^18.0.0",
28
- "react-dom": "^18.0.0"
28
+ "react-dom": "^18.0.0",
29
+ "slug": "^9.0.0"
29
30
  },
30
31
  "devDependencies": {
31
32
  "@types/react": "^18.0.0",
32
33
  "@types/react-dom": "^18.0.0",
34
+ "@types/slug": "^5.0.9",
33
35
  "postcss": "^8.4.0",
34
36
  "postcss-cli": "^11.0.0",
35
37
  "postcss-import": "^16.0.0",