@roadlittledawn/docs-design-system-react 0.2.1 → 0.3.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/dist/components/CodeBlock.d.ts +15 -0
- package/dist/components/CodeBlock.js +33 -2
- package/dist/components/CodeBlock.stories.d.ts +16 -0
- package/dist/components/CodeBlock.stories.js +81 -1
- package/dist/components/Collapser.d.ts +10 -2
- package/dist/components/Collapser.js +15 -4
- package/dist/components/Collapser.stories.d.ts +1 -1
- package/dist/components/Collapser.stories.js +3 -2
- package/dist/components/CollapserGroup.d.ts +15 -0
- package/dist/components/CollapserGroup.js +56 -0
- package/dist/components/CollapserGroup.stories.d.ts +29 -0
- package/dist/components/CollapserGroup.stories.js +77 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/styles.css +211 -57
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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 &&
|
|
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
|
+
};
|
|
@@ -5,14 +5,22 @@ interface CollapserProps {
|
|
|
5
5
|
/** Optional ID for the title element */
|
|
6
6
|
id?: string;
|
|
7
7
|
/**
|
|
8
|
-
* Whether the collapser should be open by default
|
|
8
|
+
* Whether the collapser should be open by default (uncontrolled)
|
|
9
9
|
* @default false
|
|
10
10
|
*/
|
|
11
11
|
defaultOpen?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Controlled open state (used by CollapserGroup)
|
|
14
|
+
*/
|
|
15
|
+
open?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Callback when toggle is clicked (used by CollapserGroup)
|
|
18
|
+
*/
|
|
19
|
+
onToggle?: () => void;
|
|
12
20
|
/** Content to show/hide when toggling */
|
|
13
21
|
children: ReactNode;
|
|
14
22
|
/** Additional CSS classes */
|
|
15
23
|
className?: string;
|
|
16
24
|
}
|
|
17
|
-
export declare function Collapser({ title, id, defaultOpen, children, className, }: CollapserProps): import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
export declare function Collapser({ title, id, defaultOpen, open: controlledOpen, onToggle, children, className, }: CollapserProps): import("react/jsx-runtime").JSX.Element;
|
|
18
26
|
export {};
|
|
@@ -2,19 +2,30 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState, useRef, useEffect } from "react";
|
|
3
3
|
import { useKeyPress } from "../hooks/useKeyPress";
|
|
4
4
|
export function Collapser(_a) {
|
|
5
|
-
var title = _a.title, id = _a.id, _b = _a.defaultOpen, defaultOpen = _b === void 0 ? false : _b, children = _a.children, _c = _a.className, className = _c === void 0 ? "" : _c;
|
|
6
|
-
var _d = useState(defaultOpen),
|
|
5
|
+
var title = _a.title, id = _a.id, _b = _a.defaultOpen, defaultOpen = _b === void 0 ? false : _b, controlledOpen = _a.open, onToggle = _a.onToggle, children = _a.children, _c = _a.className, className = _c === void 0 ? "" : _c;
|
|
6
|
+
var _d = useState(defaultOpen), uncontrolledOpen = _d[0], setUncontrolledOpen = _d[1];
|
|
7
|
+
var isControlled = controlledOpen !== undefined;
|
|
8
|
+
var isOpen = isControlled ? controlledOpen : uncontrolledOpen;
|
|
7
9
|
var _e = useState(undefined), height = _e[0], setHeight = _e[1];
|
|
8
10
|
var contentRef = useRef(null);
|
|
9
11
|
// Keyboard shortcuts: 's' or 'f' to show, 'h' to hide
|
|
10
|
-
useKeyPress(['s', 'f', 'h'], function (e) {
|
|
12
|
+
useKeyPress(['s', 'f', 'h'], function (e) {
|
|
13
|
+
if (!isControlled) {
|
|
14
|
+
setUncontrolledOpen(e.key !== 'h');
|
|
15
|
+
}
|
|
16
|
+
});
|
|
11
17
|
useEffect(function () {
|
|
12
18
|
if (contentRef.current) {
|
|
13
19
|
setHeight(contentRef.current.scrollHeight);
|
|
14
20
|
}
|
|
15
21
|
}, [children]);
|
|
16
22
|
var toggleOpen = function () {
|
|
17
|
-
|
|
23
|
+
if (onToggle) {
|
|
24
|
+
onToggle();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
setUncontrolledOpen(!uncontrolledOpen);
|
|
28
|
+
}
|
|
18
29
|
};
|
|
19
30
|
var collapserClasses = ["dds-collapser", className]
|
|
20
31
|
.filter(Boolean)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Collapser } from './Collapser';
|
|
3
|
+
import { CollapserGroup } from './CollapserGroup';
|
|
3
4
|
/**
|
|
4
5
|
* The Collapser component creates expandable/collapsible content sections with smooth animations.
|
|
5
6
|
*/
|
|
@@ -55,8 +56,8 @@ export var ComplexContent = {
|
|
|
55
56
|
},
|
|
56
57
|
};
|
|
57
58
|
/**
|
|
58
|
-
* Multiple collapsers in a FAQ-style layout.
|
|
59
|
+
* Multiple collapsers in a FAQ-style layout using CollapserGroup.
|
|
59
60
|
*/
|
|
60
61
|
export var FAQExample = {
|
|
61
|
-
render: function () { return (_jsxs(
|
|
62
|
+
render: function () { return (_jsxs(CollapserGroup, { children: [_jsx(Collapser, { title: "What is this documentation system?", children: _jsx("p", { children: "This is a comprehensive documentation design system that provides reusable components and guidelines for creating effective technical documentation." }) }), _jsx(Collapser, { title: "How do I get started?", children: _jsx("p", { children: "Start by installing the component package, then explore the components in Storybook to understand their usage and configuration options." }) }), _jsx(Collapser, { title: "Can I customize the components?", children: _jsx("p", { children: "Yes! All components accept a className prop for custom styling, and you can override the default styles using CSS." }) }), _jsx(Collapser, { title: "Is this accessible?", children: _jsx("p", { children: "Accessibility is a core principle. All components follow WAI-ARIA best practices and are keyboard navigable." }) })] })); },
|
|
62
63
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface CollapserGroupProps {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
/** Spacing between collapsers (CSS gap value) */
|
|
5
|
+
spacing?: string;
|
|
6
|
+
/** Allow multiple collapsers to be open simultaneously */
|
|
7
|
+
allowMultiple?: boolean;
|
|
8
|
+
/** Index(es) of collapser(s) that should be open by default */
|
|
9
|
+
defaultOpen?: number | number[];
|
|
10
|
+
/** Callback when collapser open state changes */
|
|
11
|
+
onChange?: (openIndexes: number[]) => void;
|
|
12
|
+
/** Additional CSS classes */
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const CollapserGroup: React.FC<CollapserGroupProps>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
13
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
14
|
+
if (ar || !(i in from)) {
|
|
15
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
16
|
+
ar[i] = from[i];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
20
|
+
};
|
|
21
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
22
|
+
import { useState, Children, cloneElement, isValidElement } from 'react';
|
|
23
|
+
import { Collapser } from './Collapser';
|
|
24
|
+
export var CollapserGroup = function (_a) {
|
|
25
|
+
var children = _a.children, _b = _a.spacing, spacing = _b === void 0 ? '0.5rem' : _b, _c = _a.allowMultiple, allowMultiple = _c === void 0 ? true : _c, defaultOpen = _a.defaultOpen, onChange = _a.onChange, _d = _a.className, className = _d === void 0 ? '' : _d;
|
|
26
|
+
var _e = useState(function () {
|
|
27
|
+
if (defaultOpen === undefined)
|
|
28
|
+
return [];
|
|
29
|
+
return Array.isArray(defaultOpen) ? defaultOpen : [defaultOpen];
|
|
30
|
+
}), openIndexes = _e[0], setOpenIndexes = _e[1];
|
|
31
|
+
var handleToggle = function (index) {
|
|
32
|
+
setOpenIndexes(function (prev) {
|
|
33
|
+
var next;
|
|
34
|
+
if (allowMultiple) {
|
|
35
|
+
next = prev.includes(index)
|
|
36
|
+
? prev.filter(function (i) { return i !== index; })
|
|
37
|
+
: __spreadArray(__spreadArray([], prev, true), [index], false);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
next = prev.includes(index) ? [] : [index];
|
|
41
|
+
}
|
|
42
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(next);
|
|
43
|
+
return next;
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
return (_jsx("div", { className: "dds-collapser-group ".concat(className).trim(), style: { gap: spacing }, children: Children.map(children, function (child, index) {
|
|
47
|
+
if (!isValidElement(child))
|
|
48
|
+
return child;
|
|
49
|
+
// Only inject props if child is a Collapser component
|
|
50
|
+
if (child.type === Collapser) {
|
|
51
|
+
return cloneElement(child, __assign(__assign({}, child.props), { open: openIndexes.includes(index), onToggle: function () { return handleToggle(index); } }));
|
|
52
|
+
}
|
|
53
|
+
return child;
|
|
54
|
+
}) }));
|
|
55
|
+
};
|
|
56
|
+
CollapserGroup.displayName = 'CollapserGroup';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { CollapserGroup } from './CollapserGroup';
|
|
3
|
+
/**
|
|
4
|
+
* CollapserGroup manages multiple Collapser components with consistent spacing
|
|
5
|
+
* and optional accordion behavior.
|
|
6
|
+
*/
|
|
7
|
+
declare const meta: Meta<typeof CollapserGroup>;
|
|
8
|
+
export default meta;
|
|
9
|
+
type Story = StoryObj<typeof CollapserGroup>;
|
|
10
|
+
/**
|
|
11
|
+
* Basic group with default spacing, allowing multiple collapsers to be open.
|
|
12
|
+
*/
|
|
13
|
+
export declare const Basic: Story;
|
|
14
|
+
/**
|
|
15
|
+
* Accordion mode - only one collapser can be open at a time.
|
|
16
|
+
*/
|
|
17
|
+
export declare const AccordionMode: Story;
|
|
18
|
+
/**
|
|
19
|
+
* Custom spacing between collapsers.
|
|
20
|
+
*/
|
|
21
|
+
export declare const CustomSpacing: Story;
|
|
22
|
+
/**
|
|
23
|
+
* One collapser open by default.
|
|
24
|
+
*/
|
|
25
|
+
export declare const DefaultOpen: Story;
|
|
26
|
+
/**
|
|
27
|
+
* Multiple collapsers open by default.
|
|
28
|
+
*/
|
|
29
|
+
export declare const MultipleDefaultOpen: Story;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { CollapserGroup } from './CollapserGroup';
|
|
14
|
+
import { Collapser } from './Collapser';
|
|
15
|
+
/**
|
|
16
|
+
* CollapserGroup manages multiple Collapser components with consistent spacing
|
|
17
|
+
* and optional accordion behavior.
|
|
18
|
+
*/
|
|
19
|
+
var meta = {
|
|
20
|
+
title: 'Components/CollapserGroup',
|
|
21
|
+
component: CollapserGroup,
|
|
22
|
+
tags: ['autodocs'],
|
|
23
|
+
parameters: {
|
|
24
|
+
docs: {
|
|
25
|
+
description: {
|
|
26
|
+
component: "\nCollapserGroup provides a container for multiple Collapser components with built-in spacing and accordion functionality.\n\n## When to Use\n\n- FAQ sections with multiple questions\n- Accordion-style navigation or content sections\n- Any grouped collapsible content that needs consistent spacing\n- When you want only one section open at a time (accordion mode)\n\n## When Not to Use\n\n- For a single Collapser (use Collapser directly)\n- When collapsers need independent styling or spacing\n\n## Accessibility\n\n- Maintains all Collapser accessibility features\n- Keyboard navigation works within the group\n- Accordion mode provides clear single-selection behavior\n ",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
export default meta;
|
|
32
|
+
/**
|
|
33
|
+
* Basic group with default spacing, allowing multiple collapsers to be open.
|
|
34
|
+
*/
|
|
35
|
+
export var Basic = {
|
|
36
|
+
args: {
|
|
37
|
+
spacing: '0.5rem',
|
|
38
|
+
allowMultiple: true,
|
|
39
|
+
},
|
|
40
|
+
render: function (args) { return (_jsxs(CollapserGroup, __assign({}, args, { children: [_jsx(Collapser, { title: "What is this documentation system?", children: _jsx("p", { children: "This is a comprehensive documentation design system that provides reusable components and guidelines for creating effective technical documentation." }) }), _jsx(Collapser, { title: "How do I get started?", children: _jsx("p", { children: "Start by installing the component package, then explore the components in Storybook to understand their usage and configuration options." }) }), _jsx(Collapser, { title: "Can I customize the components?", children: _jsx("p", { children: "Yes! All components accept a className prop for custom styling, and you can override the default styles using CSS." }) })] }))); },
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Accordion mode - only one collapser can be open at a time.
|
|
44
|
+
*/
|
|
45
|
+
export var AccordionMode = {
|
|
46
|
+
args: {
|
|
47
|
+
allowMultiple: false,
|
|
48
|
+
},
|
|
49
|
+
render: function (args) { return (_jsxs(CollapserGroup, __assign({}, args, { children: [_jsxs(Collapser, { title: "Installation", children: [_jsx("p", { children: "Install the package using npm or yarn:" }), _jsx("pre", { children: "npm install @roadlittledawn/docs-design-system" })] }), _jsxs(Collapser, { title: "Configuration", children: [_jsx("p", { children: "Import the CSS and components in your application:" }), _jsx("pre", { children: "import '@roadlittledawn/docs-design-system/dist/styles.css';" })] }), _jsxs(Collapser, { title: "Usage", children: [_jsx("p", { children: "Use the components in your React application:" }), _jsx("pre", { children: '<Button variant="primary">Click me</Button>' })] })] }))); },
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Custom spacing between collapsers.
|
|
53
|
+
*/
|
|
54
|
+
export var CustomSpacing = {
|
|
55
|
+
args: {
|
|
56
|
+
spacing: '1.5rem',
|
|
57
|
+
},
|
|
58
|
+
render: function (args) { return (_jsxs(CollapserGroup, __assign({}, args, { children: [_jsx(Collapser, { title: "Section 1", children: _jsx("p", { children: "Content with larger spacing between sections." }) }), _jsx(Collapser, { title: "Section 2", children: _jsx("p", { children: "This makes the layout more breathable." }) }), _jsx(Collapser, { title: "Section 3", children: _jsx("p", { children: "Useful for prominent content sections." }) })] }))); },
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* One collapser open by default.
|
|
62
|
+
*/
|
|
63
|
+
export var DefaultOpen = {
|
|
64
|
+
args: {
|
|
65
|
+
defaultOpen: 0,
|
|
66
|
+
},
|
|
67
|
+
render: function (args) { return (_jsxs(CollapserGroup, __assign({}, args, { children: [_jsx(Collapser, { title: "Getting Started", children: _jsx("p", { children: "This section is open by default." }) }), _jsx(Collapser, { title: "Advanced Topics", children: _jsx("p", { children: "This section starts closed." }) }), _jsx(Collapser, { title: "API Reference", children: _jsx("p", { children: "This section also starts closed." }) })] }))); },
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Multiple collapsers open by default.
|
|
71
|
+
*/
|
|
72
|
+
export var MultipleDefaultOpen = {
|
|
73
|
+
args: {
|
|
74
|
+
defaultOpen: [0, 2],
|
|
75
|
+
},
|
|
76
|
+
render: function (args) { return (_jsxs(CollapserGroup, __assign({}, args, { children: [_jsx(Collapser, { title: "Introduction", children: _jsx("p", { children: "This section is open by default." }) }), _jsx(Collapser, { title: "Installation", children: _jsx("p", { children: "This section starts closed." }) }), _jsx(Collapser, { title: "Quick Start", children: _jsx("p", { children: "This section is also open by default." }) })] }))); },
|
|
77
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from './components/Callout';
|
|
|
3
3
|
export * from './components/Card';
|
|
4
4
|
export * from './components/CardGrid';
|
|
5
5
|
export * from './components/Collapser';
|
|
6
|
+
export * from './components/CollapserGroup';
|
|
6
7
|
export * from './components/CodeBlock';
|
|
7
8
|
export * from './components/Typography';
|
|
8
9
|
export * from './components/Heading';
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './components/Callout';
|
|
|
4
4
|
export * from './components/Card';
|
|
5
5
|
export * from './components/CardGrid';
|
|
6
6
|
export * from './components/Collapser';
|
|
7
|
+
export * from './components/CollapserGroup';
|
|
7
8
|
export * from './components/CodeBlock';
|
|
8
9
|
export * from './components/Typography';
|
|
9
10
|
export * from './components/Heading';
|
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:
|
|
145
|
-
--dds-code-block-bg: #
|
|
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: #
|
|
148
|
-
--dds-code-block-header-
|
|
149
|
-
--dds-code-block-header-
|
|
150
|
-
--dds-code-block-
|
|
151
|
-
--dds-code-block-tab-
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
170
|
-
--dds-code-block-copy-bg:
|
|
171
|
-
--dds-code-block-copy-border:
|
|
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: #
|
|
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:
|
|
176
|
-
--dds-code-block-copy-border-hover:
|
|
177
|
-
--dds-code-block-copy-bg-active:
|
|
178
|
-
--dds-code-block-content-bg: #
|
|
179
|
-
--dds-code-block-pre-padding:
|
|
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:
|
|
298
|
-
--dds-code-block-border: #
|
|
299
|
-
--dds-code-block-header-bg:
|
|
300
|
-
--dds-code-block-tab-bg:
|
|
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:
|
|
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:
|
|
315
|
-
--dds-code-block-copy-text: #
|
|
316
|
-
--dds-code-block-copy-bg-hover: rgba(255, 255, 255, 0.
|
|
317
|
-
--dds-code-block-copy-border-hover:
|
|
318
|
-
--dds-code-block-copy-bg-active: rgba(255, 255, 255, 0.
|
|
319
|
-
--dds-code-block-content-bg:
|
|
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:
|
|
420
|
-
--dds-code-block-border: #
|
|
421
|
-
--dds-code-block-header-bg:
|
|
422
|
-
--dds-code-block-tab-bg:
|
|
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:
|
|
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:
|
|
437
|
-
--dds-code-block-copy-text: #
|
|
438
|
-
--dds-code-block-copy-bg-hover: rgba(255, 255, 255, 0.
|
|
439
|
-
--dds-code-block-copy-border-hover:
|
|
440
|
-
--dds-code-block-copy-bg-active: rgba(255, 255, 255, 0.
|
|
441
|
-
--dds-code-block-content-bg:
|
|
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
|
|
@@ -878,6 +1012,13 @@ a.no-text-decoration {
|
|
|
878
1012
|
padding: var(--dds-collapser-content-padding);
|
|
879
1013
|
color: var(--dds-collapser-text);
|
|
880
1014
|
}
|
|
1015
|
+
.dds-collapser-group {
|
|
1016
|
+
display: flex;
|
|
1017
|
+
flex-direction: column;
|
|
1018
|
+
}
|
|
1019
|
+
.dds-collapser-group > .dds-collapser {
|
|
1020
|
+
margin: 0;
|
|
1021
|
+
}
|
|
881
1022
|
.dds-code-block {
|
|
882
1023
|
border: 1px solid var(--dds-code-block-border);
|
|
883
1024
|
border-radius: var(--dds-code-block-radius);
|
|
@@ -888,18 +1029,19 @@ a.no-text-decoration {
|
|
|
888
1029
|
.dds-code-block-header {
|
|
889
1030
|
display: flex;
|
|
890
1031
|
justify-content: space-between;
|
|
891
|
-
align-items:
|
|
1032
|
+
align-items: center;
|
|
892
1033
|
padding: 0;
|
|
893
1034
|
background-color: var(--dds-code-block-header-bg);
|
|
894
1035
|
border-bottom: 1px solid var(--dds-code-block-border);
|
|
895
|
-
|
|
1036
|
+
height: var(--dds-code-block-header-height);
|
|
896
1037
|
overflow: hidden;
|
|
897
1038
|
}
|
|
898
1039
|
.dds-code-block-header-left {
|
|
899
1040
|
display: flex;
|
|
900
|
-
align-items:
|
|
1041
|
+
align-items: center;
|
|
901
1042
|
flex: 1;
|
|
902
1043
|
min-width: 0;
|
|
1044
|
+
height: 100%;
|
|
903
1045
|
}
|
|
904
1046
|
.dds-code-block-header-right {
|
|
905
1047
|
display: flex;
|
|
@@ -915,7 +1057,8 @@ a.no-text-decoration {
|
|
|
915
1057
|
overflow-x: auto;
|
|
916
1058
|
overflow-y: hidden;
|
|
917
1059
|
-webkit-overflow-scrolling: touch;
|
|
918
|
-
align-items:
|
|
1060
|
+
align-items: center;
|
|
1061
|
+
height: 100%;
|
|
919
1062
|
/* Hide scrollbar but keep functionality */
|
|
920
1063
|
scrollbar-width: none; /* Firefox */
|
|
921
1064
|
-ms-overflow-style: none; /* IE and Edge */
|
|
@@ -926,18 +1069,18 @@ a.no-text-decoration {
|
|
|
926
1069
|
.dds-code-block-tab {
|
|
927
1070
|
padding: var(--dds-code-block-tab-padding);
|
|
928
1071
|
background-color: var(--dds-code-block-tab-bg);
|
|
929
|
-
border:
|
|
930
|
-
border-bottom:
|
|
931
|
-
border-top-left-radius: var(--dds-code-block-tab-radius);
|
|
932
|
-
border-top-right-radius: var(--dds-code-block-tab-radius);
|
|
1072
|
+
border: none;
|
|
1073
|
+
border-bottom: 2px solid transparent;
|
|
933
1074
|
color: var(--dds-code-block-tab-text);
|
|
934
|
-
font-size:
|
|
1075
|
+
font-size: 0.8125rem;
|
|
935
1076
|
font-weight: var(--dds-font-medium);
|
|
936
1077
|
cursor: pointer;
|
|
937
1078
|
white-space: nowrap;
|
|
938
1079
|
transition: var(--dds-transition-colors);
|
|
939
|
-
margin-right: 2px;
|
|
940
1080
|
position: relative;
|
|
1081
|
+
height: 100%;
|
|
1082
|
+
display: flex;
|
|
1083
|
+
align-items: center;
|
|
941
1084
|
}
|
|
942
1085
|
.dds-code-block-tab:hover {
|
|
943
1086
|
color: var(--dds-code-block-tab-text-hover);
|
|
@@ -946,11 +1089,18 @@ a.no-text-decoration {
|
|
|
946
1089
|
.dds-code-block-tab-active {
|
|
947
1090
|
color: var(--dds-code-block-tab-text-active);
|
|
948
1091
|
background-color: var(--dds-code-block-tab-bg-active);
|
|
949
|
-
border-color: var(--dds-code-block-border);
|
|
1092
|
+
border-bottom-color: var(--dds-code-block-tab-border-active);
|
|
950
1093
|
}
|
|
951
1094
|
.dds-code-block-tab-active:hover {
|
|
952
1095
|
background-color: var(--dds-code-block-tab-bg-active);
|
|
953
1096
|
}
|
|
1097
|
+
.dds-code-block-filename {
|
|
1098
|
+
font-size: var(--dds-code-block-filename-size);
|
|
1099
|
+
color: var(--dds-code-block-filename-text);
|
|
1100
|
+
font-weight: var(--dds-font-medium);
|
|
1101
|
+
padding: var(--dds-code-block-header-padding);
|
|
1102
|
+
white-space: nowrap;
|
|
1103
|
+
}
|
|
954
1104
|
.dds-code-block-language-select {
|
|
955
1105
|
padding: var(--dds-code-block-select-padding);
|
|
956
1106
|
border: 1px solid var(--dds-code-block-select-border);
|
|
@@ -979,18 +1129,20 @@ a.no-text-decoration {
|
|
|
979
1129
|
.dds-code-block-copy-button {
|
|
980
1130
|
padding: var(--dds-code-block-copy-padding);
|
|
981
1131
|
background-color: var(--dds-code-block-copy-bg);
|
|
982
|
-
border:
|
|
1132
|
+
border: none;
|
|
983
1133
|
border-radius: var(--dds-code-block-copy-radius);
|
|
984
1134
|
color: var(--dds-code-block-copy-text);
|
|
985
|
-
font-size: var(--dds-code-block-copy-size);
|
|
986
|
-
font-weight: var(--dds-font-medium);
|
|
987
1135
|
cursor: pointer;
|
|
988
1136
|
transition: var(--dds-transition-colors);
|
|
989
1137
|
white-space: nowrap;
|
|
1138
|
+
display: flex;
|
|
1139
|
+
align-items: center;
|
|
1140
|
+
justify-content: center;
|
|
1141
|
+
width: 1.75rem;
|
|
1142
|
+
height: 1.75rem;
|
|
990
1143
|
}
|
|
991
1144
|
.dds-code-block-copy-button:hover {
|
|
992
1145
|
background-color: var(--dds-code-block-copy-bg-hover);
|
|
993
|
-
border-color: var(--dds-code-block-copy-border-hover);
|
|
994
1146
|
}
|
|
995
1147
|
.dds-code-block-copy-button:active {
|
|
996
1148
|
background-color: var(--dds-code-block-copy-bg-active);
|
|
@@ -1037,11 +1189,13 @@ a.no-text-decoration {
|
|
|
1037
1189
|
}
|
|
1038
1190
|
.dds-code-block-line-highlights {
|
|
1039
1191
|
position: absolute;
|
|
1040
|
-
top:
|
|
1192
|
+
top: var(--dds-code-block-pre-padding);
|
|
1041
1193
|
left: 0;
|
|
1042
1194
|
right: 0;
|
|
1043
1195
|
bottom: 0;
|
|
1044
1196
|
pointer-events: none;
|
|
1197
|
+
font-size: var(--dds-code-block-font-size, 0.875rem);
|
|
1198
|
+
line-height: var(--dds-code-block-line-height, 1.5);
|
|
1045
1199
|
}
|
|
1046
1200
|
.dds-code-block-line-highlight {
|
|
1047
1201
|
position: absolute;
|